From f60cd60c33d08bb388a1c62ded15b86a4a1d154e Mon Sep 17 00:00:00 2001 From: xilesun <2013xile@gmail.com> Date: Thu, 10 Apr 2025 14:07:42 +0800 Subject: [PATCH] chore: use-context-selector --- .../createDetailsWithPaginationUISchema.ts | 11 - .../details-single/createDetailsUISchema.ts | 11 - .../form/createCreateFormBlockUISchema.ts | 12 - .../plugins/@nocobase/plugin-ai/package.json | 3 +- .../ai-employees/chatbox/AIEmployeeHeader.tsx | 4 +- .../client/ai-employees/chatbox/ChatBox.tsx | 8 +- .../ai-employees/chatbox/ChatBoxContext.tsx | 133 ++++++----- .../ai-employees/chatbox/Conversations.tsx | 12 +- .../ai-employees/chatbox/FieldSelector.tsx | 5 +- .../client/ai-employees/chatbox/InfoForm.tsx | 8 +- .../client/ai-employees/chatbox/Messages.tsx | 3 +- .../client/ai-employees/chatbox/Sender.tsx | 20 +- .../ai-employees/chatbox/SenderFooter.tsx | 2 +- .../ai-employees/chatbox/SenderHeader.tsx | 5 +- .../ai-employees/chatbox/SenderPrefix.tsx | 4 +- .../initializer/AIEmployeeButton.tsx | 2 +- .../src/server/__tests__/ui-schema.test.ts | 1 - .../src/server/resource/aiConversations.ts | 215 ++++++++++-------- 18 files changed, 234 insertions(+), 225 deletions(-) diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-multi/createDetailsWithPaginationUISchema.ts b/packages/core/client/src/modules/blocks/data-blocks/details-multi/createDetailsWithPaginationUISchema.ts index 479453bdbe..d48f5dda67 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/details-multi/createDetailsWithPaginationUISchema.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/details-multi/createDetailsWithPaginationUISchema.ts @@ -50,17 +50,6 @@ export function createDetailsWithPaginationUISchema(options: { 'x-read-pretty': true, 'x-use-component-props': 'useDetailsWithPaginationProps', properties: { - [uid()]: { - type: 'void', - 'x-initializer': hideActionInitializer ? undefined : 'aiEmployees:configure', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 16, - }, - }, - properties: {}, - }, [uid()]: { type: 'void', 'x-initializer': hideActionInitializer ? undefined : 'details:configureActions', diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-single/createDetailsUISchema.ts b/packages/core/client/src/modules/blocks/data-blocks/details-single/createDetailsUISchema.ts index c902caf3de..914565ae77 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/details-single/createDetailsUISchema.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/details-single/createDetailsUISchema.ts @@ -51,17 +51,6 @@ export function createDetailsUISchema(options: { 'x-read-pretty': true, 'x-use-component-props': 'useDetailsProps', properties: { - [uid()]: { - type: 'void', - 'x-initializer': 'aiEmployees:configure', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 16, - }, - }, - properties: {}, - }, [uid()]: { type: 'void', 'x-initializer': 'details:configureActions', diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/createCreateFormBlockUISchema.ts b/packages/core/client/src/modules/blocks/data-blocks/form/createCreateFormBlockUISchema.ts index e1e097316a..2d3f37234c 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/form/createCreateFormBlockUISchema.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/form/createCreateFormBlockUISchema.ts @@ -60,18 +60,6 @@ export function createCreateFormBlockUISchema(options: CreateFormBlockUISchemaOp 'x-initializer': 'form:configureFields', properties: {}, }, - [uid()]: { - type: 'void', - 'x-initializer': 'aiEmployees:configure', - 'x-component': 'ActionBar', - 'x-component-props': { - layout: 'one-column', - style: { - marginBottom: 8, - }, - }, - properties: {}, - }, [uid()]: { type: 'void', 'x-initializer': 'createForm:configureActions', diff --git a/packages/plugins/@nocobase/plugin-ai/package.json b/packages/plugins/@nocobase/plugin-ai/package.json index fa999e2040..a738afe039 100644 --- a/packages/plugins/@nocobase/plugin-ai/package.json +++ b/packages/plugins/@nocobase/plugin-ai/package.json @@ -17,6 +17,7 @@ "@langchain/core": "^0.3.39", "@langchain/deepseek": "^0.0.1", "@langchain/openai": "^0.4.3", - "snowflake-id": "^1.1.0" + "snowflake-id": "^1.1.0", + "use-context-selector": "^2.0.0" } } diff --git a/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/AIEmployeeHeader.tsx b/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/AIEmployeeHeader.tsx index 2eeedbb8bf..3e49fec162 100644 --- a/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/AIEmployeeHeader.tsx +++ b/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/AIEmployeeHeader.tsx @@ -19,13 +19,11 @@ import { Sender } from '@ant-design/x'; import { ProfileCard } from '../ProfileCard'; export const AIEmployeeHeader: React.FC = () => { - const t = useT(); - const { token } = useToken(); const { service: { loading }, aiEmployees, } = useAIEmployeesContext(); - const { switchAIEmployee } = useChatBoxContext(); + const switchAIEmployee = useChatBoxContext('switchAIEmployee'); return ( { - const { setOpen, startNewConversation, currentEmployee } = useContext(ChatBoxContext); + const setOpen = useChatBoxContext('setOpen'); + const startNewConversation = useChatBoxContext('startNewConversation'); + const currentEmployee = useChatBoxContext('currentEmployee'); const { token } = useToken(); const [showConversations, setShowConversations] = useState(false); const { selectable } = useAISelectionContext(); diff --git a/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/ChatBoxContext.tsx b/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/ChatBoxContext.tsx index 6e51b4a7ba..0ef0eaf6fd 100644 --- a/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/ChatBoxContext.tsx +++ b/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/ChatBoxContext.tsx @@ -19,7 +19,7 @@ import { } from '../types'; import { Avatar, GetProp, GetRef, Button, Alert, Space, Popover } from 'antd'; import type { Sender } from '@ant-design/x'; -import React, { createContext, useContext, useEffect, useState, useRef, useMemo } from 'react'; +import React, { useContext, useEffect, useState, useRef, useMemo, useCallback } from 'react'; import { Bubble } from '@ant-design/x'; import { useAPIClient, useRequest } from '@nocobase/client'; import { AIEmployeesContext } from '../AIEmployeesProvider'; @@ -31,8 +31,8 @@ import { uid } from '@formily/shared'; import { useT } from '../../locale'; import { createForm, Form } from '@formily/core'; import { ProfileCard } from '../ProfileCard'; -import _ from 'lodash'; import { InfoFormMessage } from './InfoForm'; +import { createContext, useContextSelector } from 'use-context-selector'; export const ChatBoxContext = createContext<{ setOpen: (open: boolean) => void; @@ -213,7 +213,8 @@ export const useSetChatBoxContext = () => { conversations.refresh(); }, }; - if (!_.isEmpty(infoForm?.values)) { + const hasInfoFormValues = Object.values(infoForm?.values || []).filter(Boolean).length; + if (hasInfoFormValues) { sendOptions.infoFormValues = { ...infoForm.values }; } setSenderValue(''); @@ -230,71 +231,77 @@ export const useSetChatBoxContext = () => { } }; - const switchAIEmployee = (aiEmployee: AIEmployee) => { - const greetingMsg = { - key: uid(), - role: aiEmployee.username, - content: { - type: 'greeting', - content: aiEmployee.greeting || t('Default greeting message', { nickname: aiEmployee.nickname }), - }, - }; - setCurrentEmployee(aiEmployee); - setSenderPlaceholder(aiEmployee.chatSettings?.senderPlaceholder); - infoForm.reset(); - senderRef.current?.focus(); - if (!currentConversation) { - setMessages([greetingMsg]); - } else { - addMessage(greetingMsg); - setSenderValue(''); - } - }; - - const startNewConversation = () => { - setCurrentConversation(undefined); - setCurrentEmployee(null); - setSenderValue(''); - infoForm.reset(); - setMessages([]); - senderRef.current?.focus(); - }; - - const triggerShortcut = (options: ShortcutOptions) => { - const { aiEmployee, message, infoFormValues, autoSend } = options; - updateRole(aiEmployee); - if (!open) { - setOpen(true); - } - if (currentConversation) { - setCurrentConversation(undefined); - setMessages([]); - } - setCurrentEmployee(aiEmployee); - if (message && message.type === 'text') { - setSenderValue(message.content); - } else { - setSenderValue(''); - } - setMessages([ - { + const switchAIEmployee = useCallback( + (aiEmployee: AIEmployee) => { + const greetingMsg = { key: uid(), role: aiEmployee.username, content: { type: 'greeting', content: aiEmployee.greeting || t('Default greeting message', { nickname: aiEmployee.nickname }), }, - }, - ]); + }; + setCurrentEmployee(aiEmployee); + setSenderPlaceholder(aiEmployee.chatSettings?.senderPlaceholder); + infoForm.reset(); + senderRef.current?.focus(); + if (!currentConversation) { + setMessages([greetingMsg]); + } else { + addMessage(greetingMsg); + setSenderValue(''); + } + }, + [currentConversation, infoForm], + ); + + const startNewConversation = useCallback(() => { + setCurrentConversation(undefined); + setCurrentEmployee(null); + setSenderValue(''); + infoForm.reset(); + setMessages([]); senderRef.current?.focus(); - infoForm.setValues(infoFormValues); - if (autoSend) { - send({ - aiEmployee, - messages: [message], - }); - } - }; + }, [infoForm]); + + const triggerShortcut = useCallback( + (options: ShortcutOptions) => { + const { aiEmployee, message, infoFormValues, autoSend } = options; + updateRole(aiEmployee); + if (!open) { + setOpen(true); + } + if (currentConversation) { + setCurrentConversation(undefined); + setMessages([]); + } + setCurrentEmployee(aiEmployee); + if (message && message.type === 'text') { + setSenderValue(message.content); + } else { + setSenderValue(''); + } + setMessages([ + { + key: uid(), + role: aiEmployee.username, + content: { + type: 'greeting', + content: aiEmployee.greeting || t('Default greeting message', { nickname: aiEmployee.nickname }), + }, + }, + ]); + senderRef.current?.focus(); + infoForm.setValues(infoFormValues); + if (autoSend) { + send({ + aiEmployee, + messages: [message], + }); + } + }, + [open, currentConversation, infoForm], + ); useEffect(() => { if (!aiEmployees) { @@ -343,6 +350,6 @@ export const useSetChatBoxContext = () => { }; }; -export const useChatBoxContext = () => { - return useContext(ChatBoxContext); +export const useChatBoxContext = (name: string) => { + return useContextSelector(ChatBoxContext, (v) => v[name]); }; diff --git a/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/Conversations.tsx b/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/Conversations.tsx index cb5dd9a124..816eeb70b3 100644 --- a/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/Conversations.tsx +++ b/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/Conversations.tsx @@ -22,13 +22,11 @@ export const Conversations: React.FC = () => { const api = useAPIClient(); const { modal, message } = App.useApp(); const { token } = useToken(); - const { - conversations: conversationsService, - currentConversation, - setCurrentConversation, - setMessages, - startNewConversation, - } = useChatBoxContext(); + const conversationsService = useChatBoxContext('conversations'); + const currentConversation = useChatBoxContext('currentConversation'); + const setCurrentConversation = useChatBoxContext('setCurrentConversation'); + const setMessages = useChatBoxContext('setMessages'); + const startNewConversation = useChatBoxContext('startNewConversation'); const { loading: ConversationsLoading, data: conversationsRes } = conversationsService; const conversations: ConversationsProps['items'] = (conversationsRes || []).map((conversation) => ({ key: conversation.sessionId, diff --git a/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/FieldSelector.tsx b/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/FieldSelector.tsx index 327adb1a75..71c27362c5 100644 --- a/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/FieldSelector.tsx +++ b/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/FieldSelector.tsx @@ -14,7 +14,10 @@ import { useChatBoxContext } from './ChatBoxContext'; import { useAISelectionContext } from '../selector/AISelectorProvider'; export const FieldSelector: React.FC = () => { - const { currentEmployee, senderValue, setSenderValue, senderRef } = useChatBoxContext(); + const currentEmployee = useChatBoxContext('currentEmployee'); + const senderValue = useChatBoxContext('senderValue'); + const setSenderValue = useChatBoxContext('setSenderValue'); + const senderRef = useChatBoxContext('senderRef'); const { startSelect } = useAISelectionContext(); const handleSelect = () => { diff --git a/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/InfoForm.tsx b/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/InfoForm.tsx index 0807a3c658..a58a0782c4 100644 --- a/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/InfoForm.tsx +++ b/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/InfoForm.tsx @@ -7,7 +7,7 @@ * For more information, please refer to: https://www.nocobase.com/agreement. */ -import React, { useMemo } from 'react'; +import React, { memo, useMemo } from 'react'; import { AIEmployee } from '../types'; import { SchemaComponent } from '@nocobase/client'; import { BlockSelector } from '../selector/BlockSelector'; @@ -87,8 +87,8 @@ export const ReadPrettyInfoForm: React.FC<{ export const InfoFormMessage: React.FC<{ values: any; -}> = ({ values }) => { - const { currentEmployee } = useChatBoxContext(); +}> = memo(({ values }) => { + const currentEmployee = useChatBoxContext('currentEmployee'); const t = useT(); const form = useMemo( () => @@ -122,4 +122,4 @@ export const InfoFormMessage: React.FC<{ /> ); -}; +}); diff --git a/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/Messages.tsx b/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/Messages.tsx index 87e4a92d53..2af8046aa5 100644 --- a/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/Messages.tsx +++ b/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/Messages.tsx @@ -13,7 +13,8 @@ import { useChatBoxContext } from './ChatBoxContext'; import { ReactComponent as EmptyIcon } from '../empty-icon.svg'; export const Messages: React.FC = () => { - const { messages, roles } = useChatBoxContext(); + const messages = useChatBoxContext('messages'); + const roles = useChatBoxContext('roles'); return ( <> {messages?.length ? ( diff --git a/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/Sender.tsx b/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/Sender.tsx index a62444bb9c..8e61052457 100644 --- a/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/Sender.tsx +++ b/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/Sender.tsx @@ -19,17 +19,15 @@ import { SenderFooter } from './SenderFooter'; export const Sender: React.FC = memo(() => { const t = useT(); - const { - senderValue, - setSenderValue, - senderPlaceholder, - send, - currentConversation, - currentEmployee, - responseLoading, - showInfoForm, - senderRef, - } = useChatBoxContext(); + const senderValue = useChatBoxContext('senderValue'); + const setSenderValue = useChatBoxContext('setSenderValue'); + const senderPlaceholder = useChatBoxContext('senderPlaceholder'); + const send = useChatBoxContext('send'); + const currentConversation = useChatBoxContext('currentConversation'); + const currentEmployee = useChatBoxContext('currentEmployee'); + const responseLoading = useChatBoxContext('responseLoading'); + const showInfoForm = useChatBoxContext('showInfoForm'); + const senderRef = useChatBoxContext('senderRef'); return ( = ({ components }) => { const t = useT(); const { SendButton, LoadingButton } = components; - const { responseLoading: loading } = useChatBoxContext(); + const { responseLoading: loading } = useChatBoxContext('responseLoading'); return ( diff --git a/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/SenderHeader.tsx b/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/SenderHeader.tsx index 8b48dac04f..54b67cf352 100644 --- a/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/SenderHeader.tsx +++ b/packages/plugins/@nocobase/plugin-ai/src/client/ai-employees/chatbox/SenderHeader.tsx @@ -21,7 +21,10 @@ import { uid } from '@formily/shared'; export const SenderHeader: React.FC = () => { const t = useT(); const { token } = useToken(); - const { currentEmployee, startNewConversation, showInfoForm, infoForm: form } = useChatBoxContext(); + const currentEmployee = useChatBoxContext('currentEmployee'); + const startNewConversation = useChatBoxContext('startNewConversation'); + const showInfoForm = useChatBoxContext('showInfoForm'); + const form = useChatBoxContext('infoForm'); return currentEmployee ? ( showInfoForm ? ( { - const { currentEmployee } = useContext(ChatBoxContext); + const currentEmployee = useChatBoxContext('currentEmployee'); return currentEmployee ? ( = withDynamicSchemaProps(({ aiEmployee, taskDesc, message, infoForm: infoFormValues, autoSend }) => { - const { triggerShortcut } = useChatBoxContext(); + const triggerShortcut = useChatBoxContext('triggerShortcut'); const fieldSchema = useFieldSchema(); const { render } = useSchemaToolbarRender(fieldSchema); const variables = useVariables(); diff --git a/packages/plugins/@nocobase/plugin-ai/src/server/__tests__/ui-schema.test.ts b/packages/plugins/@nocobase/plugin-ai/src/server/__tests__/ui-schema.test.ts index 3af94fd56a..ea40b28018 100644 --- a/packages/plugins/@nocobase/plugin-ai/src/server/__tests__/ui-schema.test.ts +++ b/packages/plugins/@nocobase/plugin-ai/src/server/__tests__/ui-schema.test.ts @@ -204,7 +204,6 @@ it('should convert ui schema to json schema', async () => { _isJSONSchemaObject: true, version: '2.0', type: 'void', - 'x-initializer': 'aiEmployees:configure', 'x-component': 'ActionBar', 'x-component-props': { layout: 'one-column', diff --git a/packages/plugins/@nocobase/plugin-ai/src/server/resource/aiConversations.ts b/packages/plugins/@nocobase/plugin-ai/src/server/resource/aiConversations.ts index 3defcaf97c..279a6d48a3 100644 --- a/packages/plugins/@nocobase/plugin-ai/src/server/resource/aiConversations.ts +++ b/packages/plugins/@nocobase/plugin-ai/src/server/resource/aiConversations.ts @@ -127,99 +127,131 @@ export default { ctx.res.end(); return next(); } - const conversation = await ctx.db.getRepository('aiConversations').findOne({ - filterByTk: sessionId, - }); - if (!conversation) { - ctx.res.write(`data: ${JSON.stringify({ type: 'error', body: 'conversation not found' })}\n\n`); - ctx.res.end(); - return next(); - } - const employee = await ctx.db.getRepository('aiEmployees').findOne({ - filter: { - username: aiEmployee, - }, - }); - if (!employee) { - ctx.res.write(`data: ${JSON.stringify({ type: 'error', body: 'AI employee not found' })}\n\n`); - ctx.res.end(); - return next(); - } - const modelSettings = employee.modelSettings; - if (!modelSettings?.llmService) { - ctx.log.error('llmService not configured'); - ctx.res.write(`data: ${JSON.stringify({ type: 'error', body: 'Chat error warning' })}\n\n`); - ctx.res.end(); - return next(); - } - const service = await ctx.db.getRepository('llmServices').findOne({ - filter: { - name: modelSettings.llmService, - }, - }); - if (!service) { - ctx.log.error('llmService not found'); - ctx.res.write(`data: ${JSON.stringify({ type: 'error', body: 'Chat error warning' })}\n\n`); - ctx.res.end(); - return next(); - } - const plugin = ctx.app.pm.get('ai') as PluginAIServer; - const providerOptions = plugin.aiManager.llmProviders.get(service.provider); - if (!providerOptions) { - ctx.log.error('llmService provider not found'); - ctx.res.write(`data: ${JSON.stringify({ type: 'error', body: 'Chat error warning' })}\n\n`); - ctx.res.end(); - return next(); - } - - try { - await ctx.db.getRepository('aiConversations.messages', sessionId).create({ - values: messages.map((message: any) => ({ - messageId: snowflake.generate(), - role: message.role, - content: message.content, - })), - }); - } catch (err) { - ctx.log.error(err); - ctx.res.write(`data: ${JSON.stringify({ type: 'error', body: 'Chat error warning' })}\n\n`); - ctx.res.end(); - return next(); - } - ctx.status = 200; - const userMessages = []; - for (const msg of messages) { - if (msg.role !== 'user' && msg.role !== 'info') { - continue; - } - let content = msg.content.content; - if (msg.content.type === 'info') { - content = await parseInfoMessage(ctx.db, employee, content); - } - userMessages.push({ - role: 'user', - content, - }); - } - const msgs = [ - { - role: 'system', - content: employee.about, - }, - ...userMessages, - ]; - const Provider = providerOptions.provider; - const provider = new Provider({ - app: ctx.app, - serviceOptions: service.options, - chatOptions: { - ...modelSettings, - messages: msgs, - }, - }); let stream: any; try { - stream = await provider.stream(); + const conversation = await ctx.db.getRepository('aiConversations').findOne({ + filterByTk: sessionId, + }); + if (!conversation) { + ctx.res.write(`data: ${JSON.stringify({ type: 'error', body: 'conversation not found' })}\n\n`); + ctx.res.end(); + return next(); + } + const employee = await ctx.db.getRepository('aiEmployees').findOne({ + filter: { + username: aiEmployee, + }, + }); + if (!employee) { + ctx.res.write(`data: ${JSON.stringify({ type: 'error', body: 'AI employee not found' })}\n\n`); + ctx.res.end(); + return next(); + } + const modelSettings = employee.modelSettings; + if (!modelSettings?.llmService) { + ctx.log.error('llmService not configured'); + ctx.res.write(`data: ${JSON.stringify({ type: 'error', body: 'Chat error warning' })}\n\n`); + ctx.res.end(); + return next(); + } + const service = await ctx.db.getRepository('llmServices').findOne({ + filter: { + name: modelSettings.llmService, + }, + }); + if (!service) { + ctx.log.error('llmService not found'); + ctx.res.write(`data: ${JSON.stringify({ type: 'error', body: 'Chat error warning' })}\n\n`); + ctx.res.end(); + return next(); + } + const plugin = ctx.app.pm.get('ai') as PluginAIServer; + const providerOptions = plugin.aiManager.llmProviders.get(service.provider); + if (!providerOptions) { + ctx.log.error('llmService provider not found'); + ctx.res.write(`data: ${JSON.stringify({ type: 'error', body: 'Chat error warning' })}\n\n`); + ctx.res.end(); + return next(); + } + + const historyMessages = await ctx.db.getRepository('aiConversations.messages', sessionId).find({ + sort: ['messageId'], + }); + const history = []; + for (const msg of historyMessages) { + let content = msg.content.content; + if (msg.content.type === 'info') { + content = await parseInfoMessage(ctx.db, employee, content); + } + let role = msg.role; + if (role === 'info' || role === 'user') { + role = 'user'; + } else { + role = 'ai'; + } + history.push({ + role, + content, + }); + } + try { + await ctx.db.getRepository('aiConversations.messages', sessionId).create({ + values: messages.map((message: any) => ({ + messageId: snowflake.generate(), + role: message.role, + content: message.content, + })), + }); + } catch (err) { + ctx.log.error(err); + ctx.res.write(`data: ${JSON.stringify({ type: 'error', body: 'Chat error warning' })}\n\n`); + ctx.res.end(); + return next(); + } + ctx.status = 200; + const userMessages = []; + for (const msg of messages) { + if (msg.role !== 'user' && msg.role !== 'info') { + continue; + } + let content = msg.content.content; + if (msg.content.type === 'info') { + content = await parseInfoMessage(ctx.db, employee, content); + } + if (!content) { + continue; + } + userMessages.push({ + role: 'user', + content, + }); + } + const msgs = [ + { + role: 'system', + content: employee.about, + }, + ...history, + ...userMessages, + ]; + console.log(msgs); + const Provider = providerOptions.provider; + const provider = new Provider({ + app: ctx.app, + serviceOptions: service.options, + chatOptions: { + ...modelSettings, + messages: msgs, + }, + }); + try { + stream = await provider.stream(); + } catch (err) { + ctx.log.error(err); + ctx.res.write(`data: ${JSON.stringify({ type: 'error', body: 'Chat error warning' })}\n\n`); + ctx.res.end(); + return next(); + } } catch (err) { ctx.log.error(err); ctx.res.write(`data: ${JSON.stringify({ type: 'error', body: 'Chat error warning' })}\n\n`); @@ -239,6 +271,7 @@ export default { ctx.res.end(); return next(); } + console.log(message); await ctx.db.getRepository('aiConversations.messages', sessionId).create({ values: { messageId: snowflake.generate(),