Просмотр исходного кода

Modularize postMessage and processMessage respectively

Shun Miyazawa 1 год назад
Родитель
Сommit
ed3c2038bd

+ 23 - 22
apps/app/src/features/openai/client/components/AiAssistant/AiAssistantSidebar/AiAssistantSidebar.tsx

@@ -7,7 +7,6 @@ import { useForm, Controller } from 'react-hook-form';
 import { useTranslation } from 'react-i18next';
 import { Collapse, UncontrolledTooltip } from 'reactstrap';
 import SimpleBar from 'simplebar-react';
-import type { z } from 'zod';
 
 import { apiv3Post } from '~/client/util/apiv3-client';
 import { toastError } from '~/client/util/toastr';
@@ -15,10 +14,16 @@ import { useGrowiCloudUri } from '~/stores-universal/context';
 import loggerFactory from '~/utils/logger';
 
 import type { AiAssistantHasId } from '../../../../interfaces/ai-assistant';
-import { SseMessageSchema, SseDetectedDiffSchema, SseFinalizedSchema } from '../../../../interfaces/editor-assistant/sse-schemas';
 import { MessageErrorCode, StreamErrorCode } from '../../../../interfaces/message-error';
 import type { IThreadRelationHasId } from '../../../../interfaces/thread-relation';
-import { postMessageForKnowledgeAssistant, postMessageForEditorAssistant } from '../../../services/ai-assistant';
+import {
+  postMessage as postMessageForEditorAssistant,
+  processMessage as processMessageForEditorAssistant,
+} from '../../../services/editor-assistant';
+import {
+  postMessage as postMessageForKnowledgeAssistant,
+  processMessage as processMessageForKnowledgeAssistant,
+} from '../../../services/knowledge-assistant';
 import { useAiAssistantSidebar } from '../../../stores/ai-assistant';
 import { useSWRMUTxMessages } from '../../../stores/message';
 import { useSWRMUTxThreads } from '../../../stores/thread';
@@ -33,15 +38,6 @@ const logger = loggerFactory('growi:openai:client:components:AiAssistantSidebar'
 
 const moduleClass = styles['grw-ai-assistant-sidebar'] ?? '';
 
-const handleIfSuccessfullyParsed = <T, >(data: T, zSchema: z.ZodSchema<T>,
-  callback: (data: T) => void,
-): void => {
-  const parsed = zSchema.safeParse(data);
-  if (parsed.success) {
-    callback(data);
-  }
-};
-
 type Message = {
   id: string,
   content: string,
@@ -226,18 +222,23 @@ const AiAssistantSidebarSubstance: React.FC<AiAssistantSidebarSubstanceProps> =
           const trimmedLine = line.trim();
           if (trimmedLine.startsWith('data:')) {
             const data = JSON.parse(line.replace('data: ', ''));
-            if (data.content != null) {
-              textValues.push(data.content[0].text.value);
-            }
 
-            handleIfSuccessfullyParsed(data, SseMessageSchema, (data) => {
-              textValues.push(data.appendedMessage);
+            processMessageForKnowledgeAssistant(data, {
+              onMessage: (data) => {
+                textValues.push(data.content[0].text.value);
+              },
             });
-            handleIfSuccessfullyParsed(data, SseDetectedDiffSchema, (data) => {
-              console.log('sse diff', { data });
-            });
-            handleIfSuccessfullyParsed(data, SseFinalizedSchema, (data) => {
-              console.log('sse finalized', { data });
+
+            processMessageForEditorAssistant(data, {
+              onMessage: (data) => {
+                textValues.push(data.appendedMessage);
+              },
+              onDetectedDiff: (data) => {
+                console.log('sse diff', { data });
+              },
+              onFinalized: (data) => {
+                console.log('sse finalized', { data });
+              },
             });
           }
           else if (trimmedLine.startsWith('error:')) {

+ 0 - 31
apps/app/src/features/openai/client/services/ai-assistant.ts

@@ -17,34 +17,3 @@ export const setDefaultAiAssistant = async(id: string, isDefault: boolean): Prom
 export const deleteAiAssistant = async(id: string): Promise<void> => {
   await apiv3Delete(`/openai/ai-assistant/${id}`);
 };
-
-export const postMessageForKnowledgeAssistant = async(
-    aiAssistantId: string, threadId: string, userMessage: string, summaryMode?: boolean,
-): Promise<Response> => {
-  const response = await fetch('/_api/v3/openai/message', {
-    method: 'POST',
-    headers: { 'Content-Type': 'application/json' },
-    body: JSON.stringify({
-      aiAssistantId,
-      threadId,
-      userMessage,
-      summaryMode,
-    }),
-  });
-  return response;
-};
-
-export const postMessageForEditorAssistant = async(threadId: string, userMessage: string, markdown: string, aiAssistantId?: string): Promise<Response> => {
-  const response = await fetch('/_api/v3/openai/edit', {
-    method: 'POST',
-    headers: { 'Content-Type': 'application/json' },
-    body: JSON.stringify({
-      aiAssistantId,
-      threadId,
-      userMessage,
-      markdown,
-    }),
-  });
-
-  return response;
-};

+ 40 - 0
apps/app/src/features/openai/client/services/editor-assistant.ts

@@ -0,0 +1,40 @@
+import {
+  SseMessageSchema,
+  SseDetectedDiffSchema,
+  SseFinalizedSchema,
+  type SseMessage,
+  type SseDetectedDiff,
+  type SseFinalized,
+} from '~/features/openai/interfaces/editor-assistant/sse-schemas';
+import { handleIfSuccessfullyParsed } from '~/features/openai/utils/handle-if-successfully-parsed';
+
+export const postMessage = async(threadId: string, userMessage: string, markdown: string, aiAssistantId?: string): Promise<Response> => {
+  const response = await fetch('/_api/v3/openai/edit', {
+    method: 'POST',
+    headers: { 'Content-Type': 'application/json' },
+    body: JSON.stringify({
+      aiAssistantId,
+      threadId,
+      userMessage,
+      markdown,
+    }),
+  });
+
+  return response;
+};
+
+export const processMessage = (data: unknown, handler: {
+  onMessage: (data: SseMessage) => void,
+  onDetectedDiff: (data: SseDetectedDiff) => void,
+  onFinalized: (data: SseFinalized) => void,
+}): void => {
+  handleIfSuccessfullyParsed(data, SseMessageSchema, (data: SseMessage) => {
+    handler.onMessage(data);
+  });
+  handleIfSuccessfullyParsed(data, SseDetectedDiffSchema, (data: SseDetectedDiff) => {
+    handler.onDetectedDiff(data);
+  });
+  handleIfSuccessfullyParsed(data, SseFinalizedSchema, (data: SseFinalized) => {
+    handler.onFinalized(data);
+  });
+};

+ 25 - 0
apps/app/src/features/openai/client/services/knowledge-assistant.ts

@@ -0,0 +1,25 @@
+import { SseMessageSchema, type SseMessage } from '~/features/openai/interfaces/knowledge-assistant/sse-schemas';
+import { handleIfSuccessfullyParsed } from '~/features/openai/utils/handle-if-successfully-parsed';
+
+export const postMessage = async(
+    aiAssistantId: string, threadId: string, userMessage: string, summaryMode?: boolean,
+): Promise<Response> => {
+  const response = await fetch('/_api/v3/openai/message', {
+    method: 'POST',
+    headers: { 'Content-Type': 'application/json' },
+    body: JSON.stringify({
+      aiAssistantId,
+      threadId,
+      userMessage,
+      summaryMode,
+    }),
+  });
+  return response;
+};
+
+export const processMessage = (data: unknown,
+    handler: {onMessage: (data: SseMessage) => void}) : void => {
+  handleIfSuccessfullyParsed(data, SseMessageSchema, (data: SseMessage) => {
+    handler.onMessage(data);
+  });
+};

+ 16 - 0
apps/app/src/features/openai/interfaces/knowledge-assistant/sse-schemas.ts

@@ -0,0 +1,16 @@
+import { z } from 'zod';
+
+// Schema definitions
+export const SseMessageSchema = z.object({
+  content: z.array(z.object({
+    index: z.number(),
+    type: z.string(),
+    text: z.object({
+      value: z.string().describe('The message that should be appended to the chat window'),
+    }),
+  })),
+});
+
+
+// Type definitions
+export type SseMessage = z.infer<typeof SseMessageSchema>;

+ 10 - 0
apps/app/src/features/openai/utils/handle-if-successfully-parsed.ts

@@ -0,0 +1,10 @@
+import type { z } from 'zod';
+
+export const handleIfSuccessfullyParsed = <T, >(data: T, zSchema: z.ZodSchema<T>,
+  callback: (data: T) => void,
+): void => {
+  const parsed = zSchema.safeParse(data);
+  if (parsed.success) {
+    callback(data);
+  }
+};