2
0
Эх сурвалжийг харах

Implementation of annotationReplacer()

Shun Miyazawa 1 жил өмнө
parent
commit
945d09cadc

+ 3 - 7
apps/app/src/features/openai/server/routes/message.ts

@@ -14,7 +14,7 @@ import loggerFactory from '~/utils/logger';
 
 import { MessageErrorCode, type StreamErrorCode } from '../../interfaces/message-error';
 import { openaiClient } from '../services';
-import { extructPageDataFromMessageEvent } from '../services/extract-page-data-from-message-event';
+import { annotationReplacer } from '../services/annotation-replacer';
 import { getStreamErrorCode } from '../services/getStreamErrorCode';
 
 import { certifyAiService } from './middlewares/certify-ai-service';
@@ -78,14 +78,14 @@ export const postMessageHandlersFactory: PostMessageHandlersFactory = (crowi) =>
         'Cache-Control': 'no-cache, no-transform',
       });
 
-      const messageDeltaHandler = (delta: MessageDelta) => {
+      const messageDeltaHandler = async(delta: MessageDelta) => {
+        await annotationReplacer(delta);
         res.write(`data: ${JSON.stringify(delta)}\n\n`);
       };
 
       const sendError = (message: string, code?: StreamErrorCode) => {
         res.write(`error: ${JSON.stringify({ code, message })}\n\n`);
       };
-
       stream.on('event', (delta) => {
         if (delta.event === 'thread.run.failed') {
           const errorMessage = delta.data.last_error?.message;
@@ -96,10 +96,6 @@ export const postMessageHandlersFactory: PostMessageHandlersFactory = (crowi) =>
           sendError(errorMessage, getStreamErrorCode(errorMessage));
         }
       });
-      stream.on('messageDone', async(event) => {
-        const pageData = await extructPageDataFromMessageEvent(event);
-        // res.write();
-      });
       stream.on('messageDelta', messageDeltaHandler);
       stream.once('messageDone', () => {
         stream.off('messageDelta', messageDeltaHandler);

+ 29 - 0
apps/app/src/features/openai/server/services/annotation-replacer.ts

@@ -0,0 +1,29 @@
+import type { IPageHasId } from '@growi/core/dist/interfaces';
+import type { MessageDelta } from 'openai/resources/beta/threads/messages.mjs';
+
+import VectorStoreFileRelationModel, { type VectorStoreFileRelation } from '~/features/openai/server/models/vector-store-file-relation';
+
+type PopulatedVectorStoreFileRelation = Omit<VectorStoreFileRelation, 'pageId'> & { pageId: IPageHasId }
+
+export const annotationReplacer = async(delta: MessageDelta): Promise<void> => {
+  const content = delta.content?.[0];
+
+  if (content?.type === 'text' && content?.text?.annotations != null) {
+    const annotations = content?.text?.annotations;
+    for await (const annotation of annotations) {
+      if (annotation.type === 'file_citation' && annotation.text != null) {
+
+        const vectorStoreFileRelation = await VectorStoreFileRelationModel
+          .findOne({ fileIds: { $in: [annotation.file_citation?.file_id] } })
+          .populate('pageId', 'path') as PopulatedVectorStoreFileRelation;
+
+        if (vectorStoreFileRelation != null) {
+          content.text.value = content.text.value?.replace(
+            annotation.text,
+            ` [出典:[${vectorStoreFileRelation.pageId.path}](http://localhost:3000/${vectorStoreFileRelation.pageId._id})]`,
+          );
+        }
+      }
+    }
+  }
+};

+ 0 - 27
apps/app/src/features/openai/server/services/extract-page-data-from-message-event.ts

@@ -1,27 +0,0 @@
-import type { Message } from 'openai/resources/beta/threads/messages.mjs';
-
-import VectorStoreFileRelationModel from '~/features/openai/server/models/vector-store-file-relation';
-
-interface Page {
-  path: string;
-  id: string;
-}
-
-export const extructPageDataFromMessageEvent = async(message: Message): Promise<Page[]> => {
-  const fileIds: string[] = [];
-  for (const content of message.content) {
-    if (content.type === 'text') {
-      for (const annotation of content.text.annotations) {
-        if (annotation.type === 'file_citation') {
-          fileIds.push(annotation.file_citation.file_id);
-        }
-      }
-    }
-  }
-
-  const pageData: Page[] = await VectorStoreFileRelationModel
-    .find({ fileIds: { $in: fileIds } })
-    .populate('pageId', 'path');
-
-  return pageData;
-};