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

Merge pull request #9797 from weseek/feat/163509-hide-chat-history-for-editor-assistant

feat: Hide chat history for editor assistant
Yuki Takei 1 год назад
Родитель
Сommit
32526c320e

+ 3 - 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';
@@ -46,7 +47,7 @@ type FormData = {
 };
 
 type AiAssistantSidebarSubstanceProps = {
-  isEditorAssistant?: boolean;
+  isEditorAssistant: boolean;
   aiAssistantData?: AiAssistantHasId;
   threadData?: IThreadRelationHasId;
   closeAiAssistantSidebar: () => void
@@ -160,6 +161,7 @@ const AiAssistantSidebarSubstance: React.FC<AiAssistantSidebarSubstanceProps> =
     if (currentThreadId_ == null) {
       try {
         const res = await apiv3Post<IThreadRelationHasId>('/openai/thread', {
+          type: isEditorAssistant ? ThreadType.EDITOR : ThreadType.KNOWLEDGE,
           aiAssistantId: isEditorAssistant ? selectedAiAssistant?._id : aiAssistantData?._id,
           initialUserMessage: isEditorAssistant ? undefined : newUserMessage.content,
         });

+ 9 - 0
apps/app/src/features/openai/interfaces/thread-relation.ts

@@ -2,11 +2,20 @@ 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;
+  type: ThreadType;
   expiredAt: Date;
 }
 

+ 6 - 1
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,6 +37,11 @@ const schema = new Schema<ThreadRelationDocument, ThreadRelationModel>({
   title: {
     type: String,
   },
+  type: {
+    type: String,
+    enum: Object.values(ThreadType),
+    required: true,
+  },
   expiredAt: {
     type: Date,
     default: generateExpirationDate,

+ 5 - 2
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,6 +18,7 @@ import { certifyAiService } from './middlewares/certify-ai-service';
 const logger = loggerFactory('growi:routes:apiv3:openai:thread');
 
 type ReqBody = {
+  type: ThreadType,
   aiAssistantId?: string,
   initialUserMessage?: string,
 }
@@ -29,6 +31,7 @@ export const createThreadHandlersFactory: CreateThreadFactory = (crowi) => {
   const loginRequiredStrictly = require('~/server/middlewares/login-required')(crowi);
 
   const validator: ValidationChain[] = [
+    body('type').isIn(Object.values(ThreadType)).withMessage('type 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'),
   ];
@@ -43,8 +46,8 @@ export const createThreadHandlersFactory: CreateThreadFactory = (crowi) => {
       }
 
       try {
-        const { aiAssistantId, initialUserMessage } = req.body;
-        const thread = await openaiService.createThread(req.user._id, aiAssistantId, initialUserMessage);
+        const { type, aiAssistantId, initialUserMessage } = req.body;
+        const thread = await openaiService.createThread(req.user._id, type, aiAssistantId, initialUserMessage);
         return res.apiv3(thread);
       }
       catch (err) {

+ 5 - 0
apps/app/src/features/openai/server/services/normalize-data/normalize-thread-relation-expired-at/normalize-thread-relation-expired-at.integ.ts

@@ -2,10 +2,12 @@ import { faker } from '@faker-js/faker';
 import { addDays, subDays } from 'date-fns';
 import { Types } from 'mongoose';
 
+import { ThreadType } from '../../../../interfaces/thread-relation';
 import ThreadRelation from '../../../models/thread-relation';
 
 import { MAX_DAYS_UNTIL_EXPIRATION, normalizeExpiredAtForThreadRelations } from './normalize-thread-relation-expired-at';
 
+
 describe('normalizeExpiredAtForThreadRelations', () => {
 
   it('should update expiredAt to 3 days from now for expired thread relations', async() => {
@@ -17,6 +19,7 @@ describe('normalizeExpiredAtForThreadRelations', () => {
       threadId: 'test-thread',
       aiAssistant: new Types.ObjectId(),
       expiredAt: expiredDate,
+      type: ThreadType.KNOWLEDGE,
     });
     await threadRelation.save();
 
@@ -39,6 +42,7 @@ describe('normalizeExpiredAtForThreadRelations', () => {
       threadId: 'test-thread-2',
       aiAssistant: new Types.ObjectId(),
       expiredAt: nonExpiredDate,
+      type: ThreadType.KNOWLEDGE,
     });
     await threadRelation.save();
 
@@ -59,6 +63,7 @@ describe('normalizeExpiredAtForThreadRelations', () => {
       threadId: 'test-thread-3',
       aiAssistant: new Types.ObjectId(),
       expiredAt: nonExpiredDate,
+      type: ThreadType.KNOWLEDGE,
     });
     await threadRelation.save();
 

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

@@ -34,6 +34,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';
@@ -66,7 +67,7 @@ const convertPathPatternsToRegExp = (pagePathPatterns: string[]): Array<string |
 };
 
 export interface IOpenaiService {
-  createThread(userId: string, aiAssistantId?: string, initialUserMessage?: string): Promise<ThreadRelationDocument>;
+  createThread(userId: string, type: 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
@@ -118,7 +119,7 @@ class OpenaiService implements IOpenaiService {
     return threadTitle;
   }
 
-  async createThread(userId: string, aiAssistantId?: string, initialUserMessage?: string): Promise<ThreadRelationDocument> {
+  async createThread(userId: string, type: ThreadType, aiAssistantId?: string, initialUserMessage?: string): Promise<ThreadRelationDocument> {
     let threadTitle: string | null = null;
     if (initialUserMessage != null) {
       try {
@@ -134,6 +135,7 @@ class OpenaiService implements IOpenaiService {
       const thread = await this.client.createThread(vectorStoreRelation?.vectorStoreId);
       const threadRelation = await ThreadRelationModel.create({
         userId,
+        type,
         aiAssistant: aiAssistantId,
         threadId: thread.id,
         title: threadTitle,
@@ -158,8 +160,8 @@ class OpenaiService implements IOpenaiService {
     }
   }
 
-  async getThreadsByAiAssistantId(aiAssistantId: string): Promise<ThreadRelationDocument[]> {
-    const threadRelations = await ThreadRelationModel.find({ aiAssistant: aiAssistantId });
+  async getThreadsByAiAssistantId(aiAssistantId: string, type: ThreadType = ThreadType.KNOWLEDGE): Promise<ThreadRelationDocument[]> {
+    const threadRelations = await ThreadRelationModel.find({ aiAssistant: aiAssistantId, type });
     return threadRelations;
   }