From 7bd1a8b654eb44fea275cc1387eaa6ade51a5831 Mon Sep 17 00:00:00 2001 From: archer <545436317@qq.com> Date: Fri, 5 Dec 2025 10:39:58 +0800 Subject: [PATCH] feat: save chat --- packages/global/core/chat/helperBot/type.ts | 7 +- packages/global/core/chat/type.ts | 2 +- .../global/openapi/core/chat/helperBot/api.ts | 6 +- .../service/core/chat/HelperBot/chatSchema.ts | 3 +- .../chat/HelperBot/dispatch/topAgent/index.ts | 29 ++++- .../core/chat/HelperBot/dispatch/type.ts | 9 +- packages/service/core/chat/HelperBot/utils.ts | 103 ++++++++++++++++++ .../api/core/chat/helperBot/completions.ts | 18 ++- 8 files changed, 166 insertions(+), 11 deletions(-) create mode 100644 packages/service/core/chat/HelperBot/utils.ts diff --git a/packages/global/core/chat/helperBot/type.ts b/packages/global/core/chat/helperBot/type.ts index 498742cb7..5ff7d40ce 100644 --- a/packages/global/core/chat/helperBot/type.ts +++ b/packages/global/core/chat/helperBot/type.ts @@ -21,12 +21,13 @@ export const HelperBotChatSchema = z.object({ type: HelperBotTypeEnum, userId: z.string(), createTime: z.date(), - updateTime: z.date() + updateTime: z.date(), + metadata: z.record(z.string(), z.any()).optional() }); export type HelperBotChatType = z.infer; // AI schema -const AIChatItemValueItemSchema = z.union([ +export const AIChatItemValueItemSchema = z.union([ z.object({ text: z.object({ content: z.string() @@ -41,10 +42,12 @@ const AIChatItemValueItemSchema = z.union([ tool: ToolModuleResponseItemSchema }) ]); +export type AIChatItemValueItemType = z.infer; const AIChatItemSchema = z.object({ obj: z.literal(ChatRoleEnum.AI), value: z.array(AIChatItemValueItemSchema) }); +export type AIChatItemType = z.infer; const HelperBotChatRoleSchema = z.union([ UserChatItemSchema, diff --git a/packages/global/core/chat/type.ts b/packages/global/core/chat/type.ts index f9d619511..12273102e 100644 --- a/packages/global/core/chat/type.ts +++ b/packages/global/core/chat/type.ts @@ -58,7 +58,7 @@ export type ChatWithAppSchema = Omit & { /* --------- chat item ---------- */ // User export const UserChatItemFileItemSchema = z.object({ - type: z.enum(Object.values(ChatFileTypeEnum)), + type: z.enum(ChatFileTypeEnum), name: z.string().optional(), key: z.string().optional(), url: z.string() diff --git a/packages/global/openapi/core/chat/helperBot/api.ts b/packages/global/openapi/core/chat/helperBot/api.ts index 9d537d0c2..42c06622d 100644 --- a/packages/global/openapi/core/chat/helperBot/api.ts +++ b/packages/global/openapi/core/chat/helperBot/api.ts @@ -1,11 +1,13 @@ import { PaginationPropsSchema, PaginationResponseSchema } from '../../../type'; import { type HelperBotChatItemSiteType, + HelperBotTypeEnum, HelperBotTypeEnumSchema, topAgentParamsSchema } from '../../../../core/chat/helperBot/type'; import { z } from 'zod'; import type { PaginationResponse } from '../../../../../web/common/fetch/type'; +import { ChatFileTypeEnum } from '../../../../core/chat/constants'; // 分页获取记录 export const GetHelperBotChatRecordsParamsSchema = z @@ -46,7 +48,7 @@ export const HelperBotCompletionsParamsSchema = z.object({ query: z.string(), files: z.array( z.object({ - type: z.enum(['image', 'file']), + type: z.enum(ChatFileTypeEnum), key: z.string(), url: z.string().optional(), name: z.string() @@ -54,7 +56,7 @@ export const HelperBotCompletionsParamsSchema = z.object({ ), metadata: z.discriminatedUnion('type', [ z.object({ - type: z.literal('topAgent'), + type: z.literal(HelperBotTypeEnum.topAgent), data: topAgentParamsSchema }) ]) diff --git a/packages/service/core/chat/HelperBot/chatSchema.ts b/packages/service/core/chat/HelperBot/chatSchema.ts index 1ba519cd0..25fafc78f 100644 --- a/packages/service/core/chat/HelperBot/chatSchema.ts +++ b/packages/service/core/chat/HelperBot/chatSchema.ts @@ -25,7 +25,8 @@ const HelperBotChatSchema = new Schema({ updateTime: { type: Date, default: () => new Date() - } + }, + metadata: Object }); HelperBotChatSchema.index({ type: 1, userId: 1, chatId: 1 }, { unique: true }); diff --git a/packages/service/core/chat/HelperBot/dispatch/topAgent/index.ts b/packages/service/core/chat/HelperBot/dispatch/topAgent/index.ts index 65d735671..ab3beccb5 100644 --- a/packages/service/core/chat/HelperBot/dispatch/topAgent/index.ts +++ b/packages/service/core/chat/HelperBot/dispatch/topAgent/index.ts @@ -1,10 +1,35 @@ -import type { HelperBotDispatchParamsType } from '../type'; +import type { HelperBotDispatchParamsType, HelperBotDispatchResponseType } from '../type'; import { helperChats2GPTMessages } from '@fastgpt/global/core/chat/helperBot/adaptor'; -export const dispatchTopAgent = async (props: HelperBotDispatchParamsType) => { +export const dispatchTopAgent = async ( + props: HelperBotDispatchParamsType +): Promise => { const { query, files, metadata, histories } = props; const messages = helperChats2GPTMessages({ messages: histories, reserveTool: false }); + // 拿工具资源参考 FastGPT/projects/app/src/pages/api/core/app/tool/getSystemToolTemplates.ts + + /* + 流输出 + onReasoning({ text }) { + if (!aiChatReasoning) return; + workflowStreamResponse?.({ + event: SseResponseEventEnum.answer, + data: textAdaptGptResponse({ + reasoning_content: text + }) + }); + }, + onStreaming({ text }) { + if (!isResponseAnswerText) return; + workflowStreamResponse?.({ + event: SseResponseEventEnum.answer, + data: textAdaptGptResponse({ + text + }) + }); + } + */ }; diff --git a/packages/service/core/chat/HelperBot/dispatch/type.ts b/packages/service/core/chat/HelperBot/dispatch/type.ts index 1e37c5217..a0eac4a11 100644 --- a/packages/service/core/chat/HelperBot/dispatch/type.ts +++ b/packages/service/core/chat/HelperBot/dispatch/type.ts @@ -1,6 +1,9 @@ import { z } from 'zod'; import { HelperBotCompletionsParamsSchema } from '../../../../../global/openapi/core/chat/helperBot/api'; -import { HelperBotChatItemSchema } from '@fastgpt/global/core/chat/helperBot/type'; +import { + AIChatItemValueItemSchema, + HelperBotChatItemSchema +} from '@fastgpt/global/core/chat/helperBot/type'; import { WorkflowResponseFnSchema } from '../../../workflow/dispatch/type'; export const HelperBotDispatchParamsSchema = z.object({ @@ -12,5 +15,7 @@ export const HelperBotDispatchParamsSchema = z.object({ }); export type HelperBotDispatchParamsType = z.infer; -export const HelperBotDispatchResponseSchema = z.object({}); +export const HelperBotDispatchResponseSchema = z.object({ + aiResponse: z.array(AIChatItemValueItemSchema) +}); export type HelperBotDispatchResponseType = z.infer; diff --git a/packages/service/core/chat/HelperBot/utils.ts b/packages/service/core/chat/HelperBot/utils.ts new file mode 100644 index 000000000..b9d3045fd --- /dev/null +++ b/packages/service/core/chat/HelperBot/utils.ts @@ -0,0 +1,103 @@ +import type { HelperBotTypeEnum } from '@fastgpt/global/core/chat/helperBot/type'; +import type { HelperBotCompletionsParamsType } from '@fastgpt/global/openapi/core/chat/helperBot/api'; +import { MongoHelperBotChat } from './chatSchema'; +import type { + AIChatItemValueItemType, + UserChatItemValueItemType +} from '@fastgpt/global/core/chat/type'; +import { MongoHelperBotChatItem } from './chatItemSchema'; +import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants'; +import { mongoSessionRun } from 'common/mongo/sessionRun'; + +export const pushChatRecords = async ({ + type, + userId, + chatId, + chatItemId, + query, + files, + aiResponse, + memories, + metadata +}: { + type: HelperBotTypeEnum; + userId: string; + chatId: string; + chatItemId: string; + query: string; + files: HelperBotCompletionsParamsType['files']; + aiResponse: AIChatItemValueItemType[]; + memories?: Record; + metadata?: Record; +}) => { + const chat = await MongoHelperBotChat.findOne( + { + type, + userId, + chatId + }, + '_id metadata' + ).lean(); + const metadataUpdate = { + ...chat?.metadata, + ...metadata + }; + + const userValue: UserChatItemValueItemType[] = [ + ...files.map((file) => ({ + file: { + type: file.type, + name: file.name, + url: '', + key: file.key || '' + } + })), + ...(query + ? [ + { + text: { + content: query + } + } + ] + : []) + ]; + + await mongoSessionRun(async (session) => { + await MongoHelperBotChatItem.create( + [ + { + userId, + chatId, + dataId: chatItemId, + obj: ChatRoleEnum.Human, + value: userValue + }, + { + userId, + chatId, + dataId: chatItemId, + obj: ChatRoleEnum.AI, + value: aiResponse, + memories + } + ], + { session, ordered: true } + ); + + await MongoHelperBotChat.updateOne( + { + type, + userId, + chatId + }, + { + updateTime: new Date(), + metadata: metadataUpdate + }, + { + session + } + ); + }); +}; diff --git a/projects/app/src/pages/api/core/chat/helperBot/completions.ts b/projects/app/src/pages/api/core/chat/helperBot/completions.ts index 72a1728e4..c4c6867ed 100644 --- a/projects/app/src/pages/api/core/chat/helperBot/completions.ts +++ b/projects/app/src/pages/api/core/chat/helperBot/completions.ts @@ -8,6 +8,7 @@ import { authCert } from '@fastgpt/service/support/permission/auth/common'; import { MongoHelperBotChatItem } from '@fastgpt/service/core/chat/HelperBot/chatItemSchema'; import { getWorkflowResponseWrite } from '@fastgpt/service/core/workflow/dispatch/utils'; import { dispatchMap } from '@fastgpt/service/core/chat/HelperBot/dispatch/index'; +import { pushChatRecords } from '@fastgpt/service/core/chat/HelperBot/utils'; export type completionsBody = HelperBotCompletionsParamsType; @@ -37,9 +38,24 @@ async function handler(req: ApiRequestProps, res: ApiResponseTy // 执行不同逻辑 const fn = dispatchMap[metadata.type]; - const result = await fn({}); + const result = await fn({ + query, + files, + metadata, + histories, + workflowResponseWrite + }); // Save chat + await pushChatRecords({ + type: metadata.type, + userId, + chatId, + chatItemId, + query, + files, + aiResponse: result.aiResponse + }); // Push usage }