Shun Miyazawa 1 yıl önce
ebeveyn
işleme
5c561ad827

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

@@ -15,6 +15,7 @@ import loggerFactory from '~/utils/logger';
 
 import type { AiAssistantHasId } from '../../../../interfaces/ai-assistant';
 import { MessageErrorCode, StreamErrorCode } from '../../../../interfaces/message-error';
+import { ThreadType } from '../../../../interfaces/thread-relation';
 import type { IThreadRelationHasId } from '../../../../interfaces/thread-relation';
 import { useEditorAssistant } from '../../../services/editor-assistant';
 import { useKnowledgeAssistant } from '../../../services/knowledge-assistant';
@@ -160,7 +161,7 @@ const AiAssistantSidebarSubstance: React.FC<AiAssistantSidebarSubstanceProps> =
     if (currentThreadId_ == null) {
       try {
         const res = await apiv3Post<IThreadRelationHasId>('/openai/thread', {
-          isEditorAssistant,
+          threadType: isEditorAssistant ? ThreadType.EDITOR : ThreadType.KNOWLEDGE,
           aiAssistantId: isEditorAssistant ? selectedAiAssistant?._id : aiAssistantData?._id,
           initialUserMessage: isEditorAssistant ? undefined : newUserMessage.content,
         });

+ 8 - 1
apps/app/src/features/openai/interfaces/thread-relation.ts

@@ -2,12 +2,19 @@ import type { IUser, Ref, HasObjectId } from '@growi/core';
 
 import type { AiAssistant } from './ai-assistant';
 
+
+export const ThreadType = {
+  KNOWLEDGE: 'knowledge',
+  EDITOR: 'editor',
+} as const;
+
+export type ThreadType = typeof ThreadType[keyof typeof ThreadType];
 export interface IThreadRelation {
   userId: Ref<IUser>
   aiAssistant: Ref<AiAssistant>
   threadId: string;
   title?: string;
-  isEditorAssistant: boolean;
+  threadType: ThreadType;
   expiredAt: Date;
 }
 

+ 4 - 3
apps/app/src/features/openai/server/models/thread-relation.ts

@@ -3,7 +3,7 @@ import { type Model, type Document, Schema } from 'mongoose';
 
 import { getOrCreateModel } from '~/server/util/mongoose-utils';
 
-import type { IThreadRelation } from '../../interfaces/thread-relation';
+import { type IThreadRelation, ThreadType } from '../../interfaces/thread-relation';
 
 const DAYS_UNTIL_EXPIRATION = 3;
 
@@ -37,8 +37,9 @@ const schema = new Schema<ThreadRelationDocument, ThreadRelationModel>({
   title: {
     type: String,
   },
-  isEditorAssistant: {
-    type: Boolean,
+  threadType: {
+    type: String,
+    enum: Object.values(ThreadType),
     required: true,
   },
   expiredAt: {

+ 5 - 3
apps/app/src/features/openai/server/routes/thread.ts

@@ -10,6 +10,7 @@ import { apiV3FormValidator } from '~/server/middlewares/apiv3-form-validator';
 import type { ApiV3Response } from '~/server/routes/apiv3/interfaces/apiv3-response';
 import loggerFactory from '~/utils/logger';
 
+import { ThreadType } from '../../interfaces/thread-relation';
 import { getOpenaiService } from '../services/openai';
 
 import { certifyAiService } from './middlewares/certify-ai-service';
@@ -17,7 +18,7 @@ import { certifyAiService } from './middlewares/certify-ai-service';
 const logger = loggerFactory('growi:routes:apiv3:openai:thread');
 
 type ReqBody = {
-  isEditorAssistant: boolean,
+  threadType: ThreadType,
   aiAssistantId?: string,
   initialUserMessage?: string,
 }
@@ -30,6 +31,7 @@ export const createThreadHandlersFactory: CreateThreadFactory = (crowi) => {
   const loginRequiredStrictly = require('~/server/middlewares/login-required')(crowi);
 
   const validator: ValidationChain[] = [
+    body('threadType').isIn(Object.values(ThreadType)).withMessage('threadType must be one of "editor" or "knowledge"'),
     body('aiAssistantId').optional().isMongoId().withMessage('aiAssistantId must be string'),
     body('initialUserMessage').optional().isString().withMessage('initialUserMessage must be string'),
   ];
@@ -44,8 +46,8 @@ export const createThreadHandlersFactory: CreateThreadFactory = (crowi) => {
       }
 
       try {
-        const { aiAssistantId, initialUserMessage, isEditorAssistant } = req.body;
-        const thread = await openaiService.createThread(req.user._id, isEditorAssistant, aiAssistantId, initialUserMessage);
+        const { threadType, aiAssistantId, initialUserMessage } = req.body;
+        const thread = await openaiService.createThread(req.user._id, threadType, aiAssistantId, initialUserMessage);
         return res.apiv3(thread);
       }
       catch (err) {

+ 6 - 5
apps/app/src/features/openai/server/services/openai.ts

@@ -33,6 +33,7 @@ import {
   type AccessibleAiAssistants, type AiAssistant, AiAssistantAccessScope, AiAssistantShareScope,
 } from '../../interfaces/ai-assistant';
 import type { MessageListParams } from '../../interfaces/message';
+import { ThreadType } from '../../interfaces/thread-relation';
 import { removeGlobPath } from '../../utils/remove-glob-path';
 import AiAssistantModel, { type AiAssistantDocument } from '../models/ai-assistant';
 import { convertMarkdownToHtml } from '../utils/convert-markdown-to-html';
@@ -65,7 +66,7 @@ const convertPathPatternsToRegExp = (pagePathPatterns: string[]): Array<string |
 };
 
 export interface IOpenaiService {
-  createThread(userId: string, isEditorAssistant: boolean, aiAssistantId?: string, initialUserMessage?: string): Promise<ThreadRelationDocument>;
+  createThread(userId: string, threadType: ThreadType, aiAssistantId?: string, initialUserMessage?: string): Promise<ThreadRelationDocument>;
   getThreadsByAiAssistantId(aiAssistantId: string): Promise<ThreadRelationDocument[]>
   deleteThread(threadRelationId: string): Promise<ThreadRelationDocument>;
   deleteExpiredThreads(limit: number, apiCallInterval: number): Promise<void>; // for CronJob
@@ -117,7 +118,7 @@ class OpenaiService implements IOpenaiService {
     return threadTitle;
   }
 
-  async createThread(userId: string, isEditorAssistant: boolean, aiAssistantId?: string, initialUserMessage?: string): Promise<ThreadRelationDocument> {
+  async createThread(userId: string, threadType: ThreadType, aiAssistantId?: string, initialUserMessage?: string): Promise<ThreadRelationDocument> {
     let threadTitle: string | null = null;
     if (initialUserMessage != null) {
       try {
@@ -133,7 +134,7 @@ class OpenaiService implements IOpenaiService {
       const thread = await this.client.createThread(vectorStoreRelation?.vectorStoreId);
       const threadRelation = await ThreadRelationModel.create({
         userId,
-        isEditorAssistant,
+        threadType,
         aiAssistant: aiAssistantId,
         threadId: thread.id,
         title: threadTitle,
@@ -158,8 +159,8 @@ class OpenaiService implements IOpenaiService {
     }
   }
 
-  async getThreadsByAiAssistantId(aiAssistantId: string): Promise<ThreadRelationDocument[]> {
-    const threadRelations = await ThreadRelationModel.find({ aiAssistant: aiAssistantId, isEditorAssistant: false });
+  async getThreadsByAiAssistantId(aiAssistantId: string, threadType: ThreadType = ThreadType.KNOWLEDGE): Promise<ThreadRelationDocument[]> {
+    const threadRelations = await ThreadRelationModel.find({ aiAssistant: aiAssistantId, threadType });
     return threadRelations;
   }