Shun Miyazawa 11 месяцев назад
Родитель
Сommit
4ad05e1e27

+ 20 - 21
apps/app/src/features/openai/client/components/AiAssistant/AiAssistantSidebar/AiAssistantSidebar.tsx

@@ -21,7 +21,7 @@ import { useEditorAssistant } from '../../../services/editor-assistant';
 import { useKnowledgeAssistant, useFetchAndSetMessageDataEffect } from '../../../services/knowledge-assistant';
 import { useAiAssistantSidebar } from '../../../stores/ai-assistant';
 
-import { MessageCard } from './MessageCard';
+import { MessageCard, type MessageCardRole } from './MessageCard';
 import { ResizableTextarea } from './ResizableTextArea';
 
 import styles from './AiAssistantSidebar.module.scss';
@@ -68,21 +68,20 @@ const AiAssistantSidebarSubstance: React.FC<AiAssistantSidebarSubstanceProps> =
 
     // Views
     initialView: initialViewForKnowledgeAssistant,
+    generateMessageCard: generateMessageCardForKnowledgeAssistant,
     headerIcon: headerIconForKnowledgeAssistant,
     headerText: headerTextForKnowledgeAssistant,
     placeHolder: placeHolderForKnowledgeAssistant,
   } = useKnowledgeAssistant();
 
   const {
-    initialView: initialViewForEditorAssistant,
     createThread: createThreadForEditorAssistant,
     postMessage: postMessageForEditorAssistant,
     processMessage: processMessageForEditorAssistant,
-    isActionButtonShown,
-    accept,
-    reject,
 
     // Views
+    initialView: initialViewForEditorAssistant,
+    generateMessageCard: generateMessageCardForEditorAssistant,
     headerIcon: headerIconForEditorAssistant,
     headerText: headerTextForEditorAssistant,
     placeHolder: placeHolderForEditorAssistant,
@@ -114,6 +113,19 @@ const AiAssistantSidebarSubstance: React.FC<AiAssistantSidebarSubstanceProps> =
       : initialViewForKnowledgeAssistant;
   }, [initialViewForEditorAssistant, initialViewForKnowledgeAssistant, isEditorAssistant]);
 
+  const messageCard = useCallback(
+    (role: MessageCardRole, children: string, messageId?: string, messageLogs?: MessageLog[], generatingAnswerMessage?: MessageLog) => {
+      if (isEditorAssistant) {
+        if (messageId == null || messageLogs == null) {
+          return <></>;
+        }
+        return generateMessageCardForEditorAssistant(role, children, messageId, messageLogs, generatingAnswerMessage);
+      }
+
+      return generateMessageCardForKnowledgeAssistant(role, children);
+    }, [generateMessageCardForEditorAssistant, generateMessageCardForKnowledgeAssistant, isEditorAssistant],
+  );
+
   const headerIcon = useMemo(() => {
     return isEditorAssistant
       ? headerIconForEditorAssistant
@@ -298,13 +310,6 @@ const AiAssistantSidebarSubstance: React.FC<AiAssistantSidebarSubstanceProps> =
     }
   };
 
-  const clickAcceptHandler = useCallback(() => {
-    accept();
-  }, [accept]);
-
-  const clickDiscardHandler = useCallback(() => {
-    reject();
-  }, [reject]);
 
   return (
     <>
@@ -328,15 +333,9 @@ const AiAssistantSidebarSubstance: React.FC<AiAssistantSidebarSubstanceProps> =
             ? (
               <div className="vstack gap-4 pb-2">
                 { messageLogs.map(message => (
-                  <MessageCard
-                    key={message.id}
-                    role={message.isUserMessage ? 'user' : 'assistant'}
-                    showActionButtons={isActionButtonShown(message.id, messageLogs, generatingAnswerMessage)}
-                    onAccept={clickAcceptHandler}
-                    onDiscard={clickDiscardHandler}
-                  >
-                    {message.content}
-                  </MessageCard>
+                  <>
+                    {messageCard(message.isUserMessage ? 'user' : 'assistant', message.content, message.id, messageLogs, generatingAnswerMessage)}
+                  </>
                 )) }
                 { generatingAnswerMessage != null && (
                   <MessageCard role="assistant">{generatingAnswerMessage.content}</MessageCard>

+ 3 - 1
apps/app/src/features/openai/client/components/AiAssistant/AiAssistantSidebar/MessageCard.tsx

@@ -106,8 +106,10 @@ const AssistantMessageCard = ({
   );
 };
 
+export type MessageCardRole = 'user' | 'assistant';
+
 type Props = {
-  role: 'user' | 'assistant',
+  role: MessageCardRole,
   children: string,
   showActionButtons?: boolean,
   onDiscard?: () => void,

+ 53 - 41
apps/app/src/features/openai/client/services/editor-assistant.tsx

@@ -33,6 +33,7 @@ import type { MessageLog } from '../../interfaces/message';
 import type { IThreadRelationHasId } from '../../interfaces/thread-relation';
 import { ThreadType } from '../../interfaces/thread-relation';
 import { AiAssistantDropdown } from '../components/AiAssistant/AiAssistantSidebar/AiAssistantDropdown';
+import { MessageCard, type MessageCardRole } from '../components/AiAssistant/AiAssistantSidebar/MessageCard';
 import { QuickMenuList } from '../components/AiAssistant/AiAssistantSidebar/QuickMenuList';
 import { useAiAssistantSidebar } from '../stores/ai-assistant';
 
@@ -50,8 +51,8 @@ interface ProcessMessage {
   }): void;
 }
 
-interface IsActionButtonShown {
-  (messageId: string, messageLogs: MessageLog[], generatingAnswerMessage?: MessageLog): boolean;
+interface GenerateMessageCard {
+  (role: MessageCardRole, children: string, messageId: string, messageLogs: MessageLog[], generatingAnswerMessage?: MessageLog): JSX.Element;
 }
 
 type DetectedDiff = Array<{
@@ -64,12 +65,10 @@ type UseEditorAssistant = () => {
   createThread: CreateThread,
   postMessage: PostMessage,
   processMessage: ProcessMessage,
-  isActionButtonShown: IsActionButtonShown,
-  accept: () => void,
-  reject: () => void,
 
   // Views
   initialView: JSX.Element,
+  generateMessageCard: GenerateMessageCard,
   headerIcon: JSX.Element,
   headerText: JSX.Element,
   placeHolder: string,
@@ -191,44 +190,11 @@ export const useEditorAssistant: UseEditorAssistant = () => {
     });
   }, [mutateIsEnableUnifiedMergeView]);
 
-  const accept = useCallback(() => {
-    if (codeMirrorEditor?.view == null) {
-      return;
-    }
-
-    acceptAllChunks(codeMirrorEditor.view);
-    mutateIsEnableUnifiedMergeView(false);
-  }, [codeMirrorEditor?.view, mutateIsEnableUnifiedMergeView]);
-
-  const reject = useCallback(() => {
-    mutateIsEnableUnifiedMergeView(false);
-  }, [mutateIsEnableUnifiedMergeView]);
-
   const selectTextHandler = useCallback((selectedText: string, selectedTextFirstLineNumber: number) => {
     setSelectedText(selectedText);
     lineRef.current = selectedTextFirstLineNumber;
   }, []);
 
-  const isActionButtonShown: IsActionButtonShown = useCallback((messageId: string, messageLogs: MessageLog[], generatingAnswerMessage: MessageLog) => {
-    if (!aiAssistantSidebarData?.isEditorAssistant) {
-      return false;
-    }
-
-    if (generatingAnswerMessage != null) {
-      return false;
-    }
-
-    const latestAssistantMessageLogId = messageLogs
-      .filter(message => !message.isUserMessage)
-      .slice(-1)[0];
-
-    if (messageId === latestAssistantMessageLogId?.id) {
-      return true;
-    }
-
-    return false;
-  }, [aiAssistantSidebarData?.isEditorAssistant]);
-
   // Effects
   useTextSelectionEffect(codeMirrorEditor, selectTextHandler);
 
@@ -342,16 +308,62 @@ export const useEditorAssistant: UseEditorAssistant = () => {
     );
   }, [selectedAiAssistant]);
 
+
+  const generateMessageCard: GenerateMessageCard = useCallback((role, children, messageId, messageLogs, generatingAnswerMessage) => {
+    const isActionButtonShown = (() => {
+      if (!aiAssistantSidebarData?.isEditorAssistant) {
+        return false;
+      }
+
+      if (generatingAnswerMessage != null) {
+        return false;
+      }
+
+      const latestAssistantMessageLogId = messageLogs
+        .filter(message => !message.isUserMessage)
+        .slice(-1)[0];
+
+      if (messageId === latestAssistantMessageLogId?.id) {
+        return true;
+      }
+
+      return false;
+    })();
+
+
+    const accept = () => {
+      if (codeMirrorEditor?.view == null) {
+        return;
+      }
+
+      acceptAllChunks(codeMirrorEditor.view);
+      mutateIsEnableUnifiedMergeView(false);
+    };
+
+    const reject = () => {
+      mutateIsEnableUnifiedMergeView(false);
+    };
+
+    return (
+      <MessageCard
+        role={role}
+        showActionButtons={isActionButtonShown}
+        onAccept={accept}
+        onDiscard={reject}
+      >
+        {children}
+      </MessageCard>
+    );
+  }, [aiAssistantSidebarData?.isEditorAssistant, codeMirrorEditor?.view, mutateIsEnableUnifiedMergeView]);
+
   return {
     createThread,
     postMessage,
     processMessage,
-    isActionButtonShown,
-    accept,
-    reject,
 
     // Views
     initialView,
+    generateMessageCard,
     headerIcon,
     headerText,
     placeHolder,

+ 17 - 0
apps/app/src/features/openai/client/services/knowledge-assistant.tsx

@@ -11,6 +11,7 @@ import type { MessageLog } from '../../interfaces/message';
 import type { IThreadRelationHasId } from '../../interfaces/thread-relation';
 import { ThreadType } from '../../interfaces/thread-relation';
 import { AiAssistantChatInitialView } from '../components/AiAssistant/AiAssistantSidebar/AiAssistantChatInitialView';
+import { MessageCard, type MessageCardRole } from '../components/AiAssistant/AiAssistantSidebar/MessageCard';
 import { useAiAssistantSidebar } from '../stores/ai-assistant';
 import { useSWRMUTxMessages } from '../stores/message';
 import { useSWRMUTxThreads } from '../stores/thread';
@@ -29,6 +30,10 @@ interface ProcessMessage {
   ): void;
 }
 
+interface GenerateMessageCard {
+  (role: MessageCardRole, children: string): JSX.Element;
+}
+
 type UseKnowledgeAssistant = () => {
   createThread: CreateThread
   postMessage: PostMessage
@@ -36,6 +41,7 @@ type UseKnowledgeAssistant = () => {
 
   // Views
   initialView: JSX.Element
+  generateMessageCard: GenerateMessageCard,
   headerIcon: JSX.Element
   headerText: JSX.Element
   placeHolder: string
@@ -113,6 +119,16 @@ export const useKnowledgeAssistant: UseKnowledgeAssistant = () => {
     );
   }, [aiAssistantSidebarData?.aiAssistantData]);
 
+  const generateMessageCard: GenerateMessageCard = useCallback((role, children) => {
+    return (
+      <MessageCard
+        role={role}
+      >
+        {children}
+      </MessageCard>
+    );
+  }, []);
+
   return {
     // Functions
     createThread,
@@ -121,6 +137,7 @@ export const useKnowledgeAssistant: UseKnowledgeAssistant = () => {
 
     // Views
     initialView,
+    generateMessageCard,
     headerIcon,
     headerText,
     placeHolder,