Yuki Takei 1 год назад
Родитель
Сommit
66eaeaff43

+ 18 - 0
apps/app/src/client/components/RagSearch/MessageCard.tsx

@@ -0,0 +1,18 @@
+import type { ReactNode } from 'react';
+
+type Props = {
+  children?: ReactNode,
+  right?: boolean,
+}
+
+export const MessageCard = (props: Props): JSX.Element => {
+  const { children, right } = props;
+
+  return (
+    <div className={`card d-inline-flex ${right ? 'align-self-end' : 'align-self-start'}`} style={{ maxWidth: '75%' }}>
+      <div className="card-body">
+        {children}
+      </div>
+    </div>
+  );
+};

+ 44 - 16
apps/app/src/client/components/RagSearch/RagSearchModal.tsx

@@ -4,29 +4,55 @@ import { Modal, ModalBody, ModalHeader } from 'reactstrap';
 
 
 import { apiv3Post } from '~/client/util/apiv3-client';
 import { apiv3Post } from '~/client/util/apiv3-client';
 import { useRagSearchModal } from '~/stores/rag-search';
 import { useRagSearchModal } from '~/stores/rag-search';
+import loggerFactory from '~/utils/logger';
+
+import { MessageCard } from './MessageCard';
+
+
+const logger = loggerFactory('growi:clinet:components:RagSearchModal');
+
+
+type Message = {
+  id: string,
+  content: string,
+  isUserMessage?: boolean,
+}
 
 
 const RagSearchModal = (): JSX.Element => {
 const RagSearchModal = (): JSX.Element => {
-  const [userMessage, setUserMessage] = useState('');
-  const [assistantMessage, setAssistantMessage] = useState<Array<string>>([]);
+
+  const [input, setInput] = useState('');
+
+  const [threadId, setThreadId] = useState<string | undefined>();
+  const [messages, setMessages] = useState<Message[]>([]);
 
 
   const { data: ragSearchModalData, close: closeRagSearchModal } = useRagSearchModal();
   const { data: ragSearchModalData, close: closeRagSearchModal } = useRagSearchModal();
 
 
   const onClickSubmitUserMessageHandler = async() => {
   const onClickSubmitUserMessageHandler = async() => {
+    const newUserMessage = { id: messages.length.toString(), content: input, isUserMessage: true };
+    setMessages(msgs => [...msgs, newUserMessage]);
+
+    setInput('');
+
     try {
     try {
-      const res = await apiv3Post('/openai/chat', { userMessage });
+      const res = await apiv3Post('/openai/chat', { userMessage: input, threadId });
       const assistantMessageData = res.data.messages;
       const assistantMessageData = res.data.messages;
 
 
-      const messages: string[] = [];
-      for (const message of assistantMessageData.data.reverse()) {
-        messages.push(`${message.role} > ${message.content[0].text.value}`);
-      }
+      if (assistantMessageData.data.length > 0) {
+        const newMessages: Message[] = assistantMessageData.data.reverse()
+          .map((message: any) => {
+            return {
+              id: message.id,
+              content: message.content[0].text.value,
+            };
+          });
 
 
-      setAssistantMessage(messages);
-      setUserMessage('');
+        setMessages(msgs => [...msgs, ...newMessages]);
+        setThreadId(assistantMessageData.data[0].threadId);
+      }
 
 
     }
     }
     catch (err) {
     catch (err) {
-      //
+      logger.error(err.toString());
     }
     }
   };
   };
 
 
@@ -38,19 +64,21 @@ const RagSearchModal = (): JSX.Element => {
           GROWI Assistant
           GROWI Assistant
         </ModalHeader>
         </ModalHeader>
 
 
-        <p>
-          { assistantMessage }
-        </p>
+        <div className="vstack gap-4">
+          { messages.map(message => (
+            <MessageCard key={message.id} right={message.isUserMessage}>{message.content}</MessageCard>
+          )) }
+        </div>
 
 
-        <div className="input-group mb-2">
+        <div className="input-group mt-5">
           <input
           <input
             type="text"
             type="text"
             className="form-control"
             className="form-control"
             placeholder="お手伝いできることはありますか?"
             placeholder="お手伝いできることはありますか?"
             aria-label="Recipient's username"
             aria-label="Recipient's username"
             aria-describedby="button-addon2"
             aria-describedby="button-addon2"
-            value={userMessage}
-            onChange={e => setUserMessage(e.target.value)}
+            value={input}
+            onChange={e => setInput(e.target.value)}
           />
           />
           <button
           <button
             type="button"
             type="button"