chat updates

This commit is contained in:
Nate Kelley 2025-03-17 17:19:34 -06:00
parent 9c0838209e
commit 0ad6eb3a00
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
10 changed files with 113 additions and 10 deletions

View File

@ -12,6 +12,7 @@ export interface BusterChat {
created_by_id: string;
created_by_name: string;
created_by_avatar: string | null;
feedback: 'negative' | null;
// pinned_message_id: string | null; MAYBE WE NEED THIS?
}

View File

@ -7,7 +7,8 @@ import {
getChat_server,
updateChat,
deleteChat,
getListLogs
getListLogs,
duplicateChat
} from './requests';
import type { IBusterChat, IBusterChatMessage } from '@/api/asset_interfaces/chat';
import { queryKeys } from '@/api/query_keys';
@ -115,10 +116,22 @@ export const prefetchGetChat = async (
};
export const useUpdateChat = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: updateChat,
onMutate: () => {
onMutate: (data) => {
//this is actually handled in @useChatUpdate file
//except for the chat title and feedback
if (data.title || data.feedback !== undefined) {
const options = queryKeys.chatsGetChat(data.id);
queryClient.setQueryData(options.queryKey, (old) => {
return {
...old!,
...data
};
});
}
}
});
};
@ -158,3 +171,9 @@ export const useGetChatMessage = <TData = IBusterChatMessage>(
});
return data;
};
export const useDuplicateChat = () => {
return useMutation({
mutationFn: duplicateChat
});
};

View File

@ -2,6 +2,7 @@ import { mainApi } from '../instances';
import { serverFetch } from '../../createServerInstance';
import type { BusterChatListItem, BusterChat } from '@/api/asset_interfaces/chat';
import type {
DuplicateChatParams,
GetChatListParams,
GetChatParams,
UpdateChatParams
@ -55,3 +56,13 @@ export const updateChat = async ({ id, ...data }: UpdateChatParams): Promise<Bus
export const deleteChat = async (ids: string[]): Promise<void> => {
return mainApi.delete(`${CHATS_BASE}`, { data: { ids } }).then((res) => res.data);
};
export const duplicateChat = async ({
id,
message_id,
share_with_same_people
}: DuplicateChatParams): Promise<BusterChat> => {
return mainApi
.post(`${CHATS_BASE}/duplicate`, { id, message_id, share_with_same_people })
.then((res) => res.data);
};

View File

@ -37,8 +37,6 @@ export type UpdateMetricParams = {
chart_config?: BusterChartConfigProps;
/** Flag to save the current draft state */
save_draft?: boolean;
/** Feedback status for the metric */
feedback?: 'negative';
/** Admin only: verification status update */
status?: VerificationStatus;
/** file in yaml format to update */

View File

@ -3,6 +3,7 @@ import { QueryClient } from '@tanstack/react-query';
import { useMemoizedFn, useDebounceFn } from '@/hooks';
import {
deleteMetrics,
duplicateMetric,
getMetric,
getMetric_server,
getMetricData,
@ -382,3 +383,9 @@ export const useRemoveMetricFromDashboard = () => {
mutationFn: removeMetricFromDashboard
});
};
export const useDuplicateMetric = () => {
return useMutation({
mutationFn: duplicateMetric
});
};

View File

@ -51,6 +51,8 @@ export interface UpdateChatParams {
title?: string;
/** Optional flag to set the chat's favorite status */
is_favorited?: boolean;
/** Optional feedback to set for the chat */
feedback?: 'negative' | null;
}
export interface ChatsSearchParams {
@ -63,6 +65,13 @@ export interface DuplicateChatParams {
id: string;
/** The message ID to start the duplication from */
message_id: string;
/** The target chat ID to duplicate content to */
chat_id: string;
/** Whether to share the duplicated chat with the same people as the source chat */
share_with_same_people: boolean;
}
export interface DuplicateChatResponse {
/** The unique identifier of the duplicated chat */
id: string;
/** The title of the duplicated chat */
title: string;
}

View File

@ -8,6 +8,7 @@ import { ChatInput } from './ChatInput';
const autoClass = 'mx-auto max-w-[600px] w-full';
export const ChatContent: React.FC<{}> = React.memo(({}) => {
const chatId = useChatIndividualContextSelector((state) => state.chatId);
const chatMessageIds = useChatIndividualContextSelector((state) => state.chatMessageIds);
return (
@ -16,7 +17,7 @@ export const ChatContent: React.FC<{}> = React.memo(({}) => {
<div className="pb-8">
{chatMessageIds?.map((messageId) => (
<div key={messageId} className={autoClass}>
<ChatMessageBlock key={messageId} messageId={messageId} />
<ChatMessageBlock key={messageId} messageId={messageId} chatId={chatId || ''} />
</div>
))}
</div>

View File

@ -5,7 +5,8 @@ import { useGetChatMessage } from '@/api/buster_rest/chats';
export const ChatMessageBlock: React.FC<{
messageId: string;
}> = React.memo(({ messageId }) => {
chatId: string;
}> = React.memo(({ messageId, chatId }) => {
const requestMessage = useGetChatMessage(messageId, (message) => message?.request_message);
const isCompletedStream = useGetChatMessage(messageId, (x) => x?.isCompletedStream);
@ -14,7 +15,11 @@ export const ChatMessageBlock: React.FC<{
return (
<div className={'flex flex-col space-y-3.5 py-2 pr-3 pl-4'} id={messageId}>
<ChatUserMessage requestMessage={requestMessage} />
<ChatResponseMessages isCompletedStream={isCompletedStream!} messageId={messageId} />
<ChatResponseMessages
isCompletedStream={isCompletedStream!}
messageId={messageId}
chatId={chatId}
/>
</div>
);
});

View File

@ -0,0 +1,48 @@
import React from 'react';
import { Button } from '@/components/ui/buttons';
import { AppTooltip } from '@/components/ui/tooltip';
import { Copy, ThumbsDown } from '@/components/ui/icons';
import { ThumbsDown as ThumbsDownFilled } from '@/components/ui/icons/NucleoIconFilled';
import { useDuplicateChat, useGetChat, useUpdateChat } from '@/api/buster_rest/chats';
export const ChatMessageOptions: React.FC<{
messageId: string;
chatId: string;
}> = React.memo(({ messageId, chatId }) => {
const { mutateAsync: duplicateChat, isPending: isCopying } = useDuplicateChat();
const { mutateAsync: updateChat } = useUpdateChat();
const { data: feedback } = useGetChat({ id: chatId }, (data) => data.feedback);
return (
<div className="flex items-center gap-1">
<AppTooltip title="Duplicate message">
<Button
variant="ghost"
prefix={<Copy />}
loading={isCopying}
onClick={() =>
duplicateChat({
id: chatId,
message_id: messageId,
share_with_same_people: false
})
}
/>
</AppTooltip>
<AppTooltip title="Report message">
<Button
variant="ghost"
prefix={feedback === 'negative' ? <ThumbsDownFilled /> : <ThumbsDown />}
onClick={() =>
updateChat({
id: chatId,
feedback: feedback === 'negative' ? null : 'negative'
})
}
/>
</AppTooltip>
</div>
);
});
ChatMessageOptions.displayName = 'ChatMessageOptions';

View File

@ -3,14 +3,16 @@ import { MessageContainer } from '../MessageContainer';
import { ChatResponseMessageSelector } from './ChatResponseMessageSelector';
import { ChatResponseReasoning } from './ChatResponseReasoning';
import { useGetChatMessage } from '@/api/buster_rest/chats';
import { ChatMessageOptions } from '../ChatMessageOptions';
interface ChatResponseMessagesProps {
isCompletedStream: boolean;
messageId: string;
chatId: string;
}
export const ChatResponseMessages: React.FC<ChatResponseMessagesProps> = React.memo(
({ isCompletedStream, messageId }) => {
({ chatId, isCompletedStream, messageId }) => {
const responseMessageIds = useGetChatMessage(messageId, (x) => x?.response_message_ids || [])!;
const lastReasoningMessageId = useGetChatMessage(
messageId,
@ -36,6 +38,8 @@ export const ChatResponseMessages: React.FC<ChatResponseMessagesProps> = React.m
/>
</React.Fragment>
))}
{isCompletedStream && <ChatMessageOptions messageId={messageId} chatId={chatId} />}
</MessageContainer>
);
}