mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 21:49:25 +08:00
chore: use-context-selector
This commit is contained in:
parent
c3b03776ae
commit
f60cd60c33
@ -50,17 +50,6 @@ export function createDetailsWithPaginationUISchema(options: {
|
|||||||
'x-read-pretty': true,
|
'x-read-pretty': true,
|
||||||
'x-use-component-props': 'useDetailsWithPaginationProps',
|
'x-use-component-props': 'useDetailsWithPaginationProps',
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
'x-initializer': hideActionInitializer ? undefined : 'aiEmployees:configure',
|
|
||||||
'x-component': 'ActionBar',
|
|
||||||
'x-component-props': {
|
|
||||||
style: {
|
|
||||||
marginBottom: 16,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
properties: {},
|
|
||||||
},
|
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-initializer': hideActionInitializer ? undefined : 'details:configureActions',
|
'x-initializer': hideActionInitializer ? undefined : 'details:configureActions',
|
||||||
|
@ -51,17 +51,6 @@ export function createDetailsUISchema(options: {
|
|||||||
'x-read-pretty': true,
|
'x-read-pretty': true,
|
||||||
'x-use-component-props': 'useDetailsProps',
|
'x-use-component-props': 'useDetailsProps',
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
'x-initializer': 'aiEmployees:configure',
|
|
||||||
'x-component': 'ActionBar',
|
|
||||||
'x-component-props': {
|
|
||||||
style: {
|
|
||||||
marginBottom: 16,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
properties: {},
|
|
||||||
},
|
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-initializer': 'details:configureActions',
|
'x-initializer': 'details:configureActions',
|
||||||
|
@ -60,18 +60,6 @@ export function createCreateFormBlockUISchema(options: CreateFormBlockUISchemaOp
|
|||||||
'x-initializer': 'form:configureFields',
|
'x-initializer': 'form:configureFields',
|
||||||
properties: {},
|
properties: {},
|
||||||
},
|
},
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
'x-initializer': 'aiEmployees:configure',
|
|
||||||
'x-component': 'ActionBar',
|
|
||||||
'x-component-props': {
|
|
||||||
layout: 'one-column',
|
|
||||||
style: {
|
|
||||||
marginBottom: 8,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
properties: {},
|
|
||||||
},
|
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-initializer': 'createForm:configureActions',
|
'x-initializer': 'createForm:configureActions',
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"@langchain/core": "^0.3.39",
|
"@langchain/core": "^0.3.39",
|
||||||
"@langchain/deepseek": "^0.0.1",
|
"@langchain/deepseek": "^0.0.1",
|
||||||
"@langchain/openai": "^0.4.3",
|
"@langchain/openai": "^0.4.3",
|
||||||
"snowflake-id": "^1.1.0"
|
"snowflake-id": "^1.1.0",
|
||||||
|
"use-context-selector": "^2.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,11 @@ import { Sender } from '@ant-design/x';
|
|||||||
import { ProfileCard } from '../ProfileCard';
|
import { ProfileCard } from '../ProfileCard';
|
||||||
|
|
||||||
export const AIEmployeeHeader: React.FC = () => {
|
export const AIEmployeeHeader: React.FC = () => {
|
||||||
const t = useT();
|
|
||||||
const { token } = useToken();
|
|
||||||
const {
|
const {
|
||||||
service: { loading },
|
service: { loading },
|
||||||
aiEmployees,
|
aiEmployees,
|
||||||
} = useAIEmployeesContext();
|
} = useAIEmployeesContext();
|
||||||
const { switchAIEmployee } = useChatBoxContext();
|
const switchAIEmployee = useChatBoxContext('switchAIEmployee');
|
||||||
return (
|
return (
|
||||||
<Sender.Header closable={false}>
|
<Sender.Header closable={false}>
|
||||||
<List
|
<List
|
||||||
|
@ -7,19 +7,21 @@
|
|||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useContext, useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Layout, Card, Button } from 'antd';
|
import { Layout, Card, Button } from 'antd';
|
||||||
import { CloseOutlined, ExpandOutlined, EditOutlined, LayoutOutlined } from '@ant-design/icons';
|
import { CloseOutlined, ExpandOutlined, EditOutlined, LayoutOutlined } from '@ant-design/icons';
|
||||||
import { useToken } from '@nocobase/client';
|
import { useToken } from '@nocobase/client';
|
||||||
const { Header, Footer, Sider, Content } = Layout;
|
const { Header, Footer, Sider, Content } = Layout;
|
||||||
import { ChatBoxContext } from './ChatBoxContext';
|
import { useChatBoxContext } from './ChatBoxContext';
|
||||||
import { Conversations } from './Conversations';
|
import { Conversations } from './Conversations';
|
||||||
import { Messages } from './Messages';
|
import { Messages } from './Messages';
|
||||||
import { Sender } from './Sender';
|
import { Sender } from './Sender';
|
||||||
import { useAISelectionContext } from '../selector/AISelectorProvider';
|
import { useAISelectionContext } from '../selector/AISelectorProvider';
|
||||||
|
|
||||||
export const ChatBox: React.FC = () => {
|
export const ChatBox: React.FC = () => {
|
||||||
const { setOpen, startNewConversation, currentEmployee } = useContext(ChatBoxContext);
|
const setOpen = useChatBoxContext('setOpen');
|
||||||
|
const startNewConversation = useChatBoxContext('startNewConversation');
|
||||||
|
const currentEmployee = useChatBoxContext('currentEmployee');
|
||||||
const { token } = useToken();
|
const { token } = useToken();
|
||||||
const [showConversations, setShowConversations] = useState(false);
|
const [showConversations, setShowConversations] = useState(false);
|
||||||
const { selectable } = useAISelectionContext();
|
const { selectable } = useAISelectionContext();
|
||||||
|
@ -19,7 +19,7 @@ import {
|
|||||||
} from '../types';
|
} from '../types';
|
||||||
import { Avatar, GetProp, GetRef, Button, Alert, Space, Popover } from 'antd';
|
import { Avatar, GetProp, GetRef, Button, Alert, Space, Popover } from 'antd';
|
||||||
import type { Sender } from '@ant-design/x';
|
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 { Bubble } from '@ant-design/x';
|
||||||
import { useAPIClient, useRequest } from '@nocobase/client';
|
import { useAPIClient, useRequest } from '@nocobase/client';
|
||||||
import { AIEmployeesContext } from '../AIEmployeesProvider';
|
import { AIEmployeesContext } from '../AIEmployeesProvider';
|
||||||
@ -31,8 +31,8 @@ import { uid } from '@formily/shared';
|
|||||||
import { useT } from '../../locale';
|
import { useT } from '../../locale';
|
||||||
import { createForm, Form } from '@formily/core';
|
import { createForm, Form } from '@formily/core';
|
||||||
import { ProfileCard } from '../ProfileCard';
|
import { ProfileCard } from '../ProfileCard';
|
||||||
import _ from 'lodash';
|
|
||||||
import { InfoFormMessage } from './InfoForm';
|
import { InfoFormMessage } from './InfoForm';
|
||||||
|
import { createContext, useContextSelector } from 'use-context-selector';
|
||||||
|
|
||||||
export const ChatBoxContext = createContext<{
|
export const ChatBoxContext = createContext<{
|
||||||
setOpen: (open: boolean) => void;
|
setOpen: (open: boolean) => void;
|
||||||
@ -213,7 +213,8 @@ export const useSetChatBoxContext = () => {
|
|||||||
conversations.refresh();
|
conversations.refresh();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if (!_.isEmpty(infoForm?.values)) {
|
const hasInfoFormValues = Object.values(infoForm?.values || []).filter(Boolean).length;
|
||||||
|
if (hasInfoFormValues) {
|
||||||
sendOptions.infoFormValues = { ...infoForm.values };
|
sendOptions.infoFormValues = { ...infoForm.values };
|
||||||
}
|
}
|
||||||
setSenderValue('');
|
setSenderValue('');
|
||||||
@ -230,71 +231,77 @@ export const useSetChatBoxContext = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const switchAIEmployee = (aiEmployee: AIEmployee) => {
|
const switchAIEmployee = useCallback(
|
||||||
const greetingMsg = {
|
(aiEmployee: AIEmployee) => {
|
||||||
key: uid(),
|
const greetingMsg = {
|
||||||
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([
|
|
||||||
{
|
|
||||||
key: uid(),
|
key: uid(),
|
||||||
role: aiEmployee.username,
|
role: aiEmployee.username,
|
||||||
content: {
|
content: {
|
||||||
type: 'greeting',
|
type: 'greeting',
|
||||||
content: aiEmployee.greeting || t('Default greeting message', { nickname: aiEmployee.nickname }),
|
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();
|
senderRef.current?.focus();
|
||||||
infoForm.setValues(infoFormValues);
|
}, [infoForm]);
|
||||||
if (autoSend) {
|
|
||||||
send({
|
const triggerShortcut = useCallback(
|
||||||
aiEmployee,
|
(options: ShortcutOptions) => {
|
||||||
messages: [message],
|
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(() => {
|
useEffect(() => {
|
||||||
if (!aiEmployees) {
|
if (!aiEmployees) {
|
||||||
@ -343,6 +350,6 @@ export const useSetChatBoxContext = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useChatBoxContext = () => {
|
export const useChatBoxContext = (name: string) => {
|
||||||
return useContext(ChatBoxContext);
|
return useContextSelector(ChatBoxContext, (v) => v[name]);
|
||||||
};
|
};
|
||||||
|
@ -22,13 +22,11 @@ export const Conversations: React.FC = () => {
|
|||||||
const api = useAPIClient();
|
const api = useAPIClient();
|
||||||
const { modal, message } = App.useApp();
|
const { modal, message } = App.useApp();
|
||||||
const { token } = useToken();
|
const { token } = useToken();
|
||||||
const {
|
const conversationsService = useChatBoxContext('conversations');
|
||||||
conversations: conversationsService,
|
const currentConversation = useChatBoxContext('currentConversation');
|
||||||
currentConversation,
|
const setCurrentConversation = useChatBoxContext('setCurrentConversation');
|
||||||
setCurrentConversation,
|
const setMessages = useChatBoxContext('setMessages');
|
||||||
setMessages,
|
const startNewConversation = useChatBoxContext('startNewConversation');
|
||||||
startNewConversation,
|
|
||||||
} = useChatBoxContext();
|
|
||||||
const { loading: ConversationsLoading, data: conversationsRes } = conversationsService;
|
const { loading: ConversationsLoading, data: conversationsRes } = conversationsService;
|
||||||
const conversations: ConversationsProps['items'] = (conversationsRes || []).map((conversation) => ({
|
const conversations: ConversationsProps['items'] = (conversationsRes || []).map((conversation) => ({
|
||||||
key: conversation.sessionId,
|
key: conversation.sessionId,
|
||||||
|
@ -14,7 +14,10 @@ import { useChatBoxContext } from './ChatBoxContext';
|
|||||||
import { useAISelectionContext } from '../selector/AISelectorProvider';
|
import { useAISelectionContext } from '../selector/AISelectorProvider';
|
||||||
|
|
||||||
export const FieldSelector: React.FC = () => {
|
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 { startSelect } = useAISelectionContext();
|
||||||
|
|
||||||
const handleSelect = () => {
|
const handleSelect = () => {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
* 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 { AIEmployee } from '../types';
|
||||||
import { SchemaComponent } from '@nocobase/client';
|
import { SchemaComponent } from '@nocobase/client';
|
||||||
import { BlockSelector } from '../selector/BlockSelector';
|
import { BlockSelector } from '../selector/BlockSelector';
|
||||||
@ -87,8 +87,8 @@ export const ReadPrettyInfoForm: React.FC<{
|
|||||||
|
|
||||||
export const InfoFormMessage: React.FC<{
|
export const InfoFormMessage: React.FC<{
|
||||||
values: any;
|
values: any;
|
||||||
}> = ({ values }) => {
|
}> = memo(({ values }) => {
|
||||||
const { currentEmployee } = useChatBoxContext();
|
const currentEmployee = useChatBoxContext('currentEmployee');
|
||||||
const t = useT();
|
const t = useT();
|
||||||
const form = useMemo(
|
const form = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@ -122,4 +122,4 @@ export const InfoFormMessage: React.FC<{
|
|||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -13,7 +13,8 @@ import { useChatBoxContext } from './ChatBoxContext';
|
|||||||
import { ReactComponent as EmptyIcon } from '../empty-icon.svg';
|
import { ReactComponent as EmptyIcon } from '../empty-icon.svg';
|
||||||
|
|
||||||
export const Messages: React.FC = () => {
|
export const Messages: React.FC = () => {
|
||||||
const { messages, roles } = useChatBoxContext();
|
const messages = useChatBoxContext('messages');
|
||||||
|
const roles = useChatBoxContext('roles');
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{messages?.length ? (
|
{messages?.length ? (
|
||||||
|
@ -19,17 +19,15 @@ import { SenderFooter } from './SenderFooter';
|
|||||||
|
|
||||||
export const Sender: React.FC = memo(() => {
|
export const Sender: React.FC = memo(() => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
const {
|
const senderValue = useChatBoxContext('senderValue');
|
||||||
senderValue,
|
const setSenderValue = useChatBoxContext('setSenderValue');
|
||||||
setSenderValue,
|
const senderPlaceholder = useChatBoxContext('senderPlaceholder');
|
||||||
senderPlaceholder,
|
const send = useChatBoxContext('send');
|
||||||
send,
|
const currentConversation = useChatBoxContext('currentConversation');
|
||||||
currentConversation,
|
const currentEmployee = useChatBoxContext('currentEmployee');
|
||||||
currentEmployee,
|
const responseLoading = useChatBoxContext('responseLoading');
|
||||||
responseLoading,
|
const showInfoForm = useChatBoxContext('showInfoForm');
|
||||||
showInfoForm,
|
const senderRef = useChatBoxContext('senderRef');
|
||||||
senderRef,
|
|
||||||
} = useChatBoxContext();
|
|
||||||
return (
|
return (
|
||||||
<AntSender
|
<AntSender
|
||||||
value={senderValue}
|
value={senderValue}
|
||||||
|
@ -18,7 +18,7 @@ export const SenderFooter: React.FC<{
|
|||||||
}> = ({ components }) => {
|
}> = ({ components }) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
const { SendButton, LoadingButton } = components;
|
const { SendButton, LoadingButton } = components;
|
||||||
const { responseLoading: loading } = useChatBoxContext();
|
const { responseLoading: loading } = useChatBoxContext('responseLoading');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex justify="space-between" align="center">
|
<Flex justify="space-between" align="center">
|
||||||
|
@ -21,7 +21,10 @@ import { uid } from '@formily/shared';
|
|||||||
export const SenderHeader: React.FC = () => {
|
export const SenderHeader: React.FC = () => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
const { token } = useToken();
|
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 ? (
|
return currentEmployee ? (
|
||||||
showInfoForm ? (
|
showInfoForm ? (
|
||||||
<Sender.Header
|
<Sender.Header
|
||||||
|
@ -8,12 +8,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { ChatBoxContext } from './ChatBoxContext';
|
import { useChatBoxContext } from './ChatBoxContext';
|
||||||
import { avatars } from '../avatars';
|
import { avatars } from '../avatars';
|
||||||
import { Avatar } from 'antd';
|
import { Avatar } from 'antd';
|
||||||
|
|
||||||
export const SenderPrefix: React.FC = () => {
|
export const SenderPrefix: React.FC = () => {
|
||||||
const { currentEmployee } = useContext(ChatBoxContext);
|
const currentEmployee = useChatBoxContext('currentEmployee');
|
||||||
return currentEmployee ? (
|
return currentEmployee ? (
|
||||||
<Avatar
|
<Avatar
|
||||||
src={avatars(currentEmployee.avatar)}
|
src={avatars(currentEmployee.avatar)}
|
||||||
|
@ -67,7 +67,7 @@ export const AIEmployeeButton: React.FC<{
|
|||||||
};
|
};
|
||||||
infoForm: any;
|
infoForm: any;
|
||||||
}> = withDynamicSchemaProps(({ aiEmployee, taskDesc, message, infoForm: infoFormValues, autoSend }) => {
|
}> = withDynamicSchemaProps(({ aiEmployee, taskDesc, message, infoForm: infoFormValues, autoSend }) => {
|
||||||
const { triggerShortcut } = useChatBoxContext();
|
const triggerShortcut = useChatBoxContext('triggerShortcut');
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { render } = useSchemaToolbarRender(fieldSchema);
|
const { render } = useSchemaToolbarRender(fieldSchema);
|
||||||
const variables = useVariables();
|
const variables = useVariables();
|
||||||
|
@ -204,7 +204,6 @@ it('should convert ui schema to json schema', async () => {
|
|||||||
_isJSONSchemaObject: true,
|
_isJSONSchemaObject: true,
|
||||||
version: '2.0',
|
version: '2.0',
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-initializer': 'aiEmployees:configure',
|
|
||||||
'x-component': 'ActionBar',
|
'x-component': 'ActionBar',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
layout: 'one-column',
|
layout: 'one-column',
|
||||||
|
@ -127,99 +127,131 @@ export default {
|
|||||||
ctx.res.end();
|
ctx.res.end();
|
||||||
return next();
|
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;
|
let stream: any;
|
||||||
try {
|
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) {
|
} catch (err) {
|
||||||
ctx.log.error(err);
|
ctx.log.error(err);
|
||||||
ctx.res.write(`data: ${JSON.stringify({ type: 'error', body: 'Chat error warning' })}\n\n`);
|
ctx.res.write(`data: ${JSON.stringify({ type: 'error', body: 'Chat error warning' })}\n\n`);
|
||||||
@ -239,6 +271,7 @@ export default {
|
|||||||
ctx.res.end();
|
ctx.res.end();
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
console.log(message);
|
||||||
await ctx.db.getRepository('aiConversations.messages', sessionId).create({
|
await ctx.db.getRepository('aiConversations.messages', sessionId).create({
|
||||||
values: {
|
values: {
|
||||||
messageId: snowflake.generate(),
|
messageId: snowflake.generate(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user