diff --git a/client/public/imgs/loading.gif b/client/public/imgs/loading.gif deleted file mode 100644 index e5e62462d..000000000 Binary files a/client/public/imgs/loading.gif and /dev/null differ diff --git a/client/public/imgs/modelAvatar.png b/client/public/imgs/modelAvatar.png deleted file mode 100644 index 58cf2b218..000000000 Binary files a/client/public/imgs/modelAvatar.png and /dev/null differ diff --git a/client/public/imgs/module/AI.png b/client/public/imgs/module/AI.png new file mode 100644 index 000000000..800ee763c Binary files /dev/null and b/client/public/imgs/module/AI.png differ diff --git a/client/public/imgs/module/cq.png b/client/public/imgs/module/cq.png new file mode 100644 index 000000000..9101f3880 Binary files /dev/null and b/client/public/imgs/module/cq.png differ diff --git a/client/public/imgs/module/db.png b/client/public/imgs/module/db.png new file mode 100644 index 000000000..4c048f896 Binary files /dev/null and b/client/public/imgs/module/db.png differ diff --git a/client/public/imgs/module/history.png b/client/public/imgs/module/history.png new file mode 100644 index 000000000..3fd4b5140 Binary files /dev/null and b/client/public/imgs/module/history.png differ diff --git a/client/public/imgs/module/reply.png b/client/public/imgs/module/reply.png new file mode 100644 index 000000000..bb8ed28f8 Binary files /dev/null and b/client/public/imgs/module/reply.png differ diff --git a/client/public/imgs/module/userChatInput.png b/client/public/imgs/module/userChatInput.png new file mode 100644 index 000000000..8eaf9a66a Binary files /dev/null and b/client/public/imgs/module/userChatInput.png differ diff --git a/client/src/components/Icon/icons/minus.svg b/client/src/components/Icon/icons/minus.svg new file mode 100644 index 000000000..3dccbb1a0 --- /dev/null +++ b/client/src/components/Icon/icons/minus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/components/Icon/index.tsx b/client/src/components/Icon/index.tsx index 4ef827685..62d4b9c40 100644 --- a/client/src/components/Icon/index.tsx +++ b/client/src/components/Icon/index.tsx @@ -35,7 +35,8 @@ const map = { kbTest: require('./icons/kbTest.svg').default, date: require('./icons/date.svg').default, apikey: require('./icons/apikey.svg').default, - save: require('./icons/save.svg').default + save: require('./icons/save.svg').default, + minus: require('./icons/minus.svg').default }; export type IconName = keyof typeof map; diff --git a/client/src/components/Layout/navbar.tsx b/client/src/components/Layout/navbar.tsx index 45b335e75..f36764e4f 100644 --- a/client/src/components/Layout/navbar.tsx +++ b/client/src/components/Layout/navbar.tsx @@ -1,5 +1,5 @@ import React, { useMemo } from 'react'; -import { Box, Flex, Tooltip, Link } from '@chakra-ui/react'; +import { Box, Flex, Link } from '@chakra-ui/react'; import { useRouter } from 'next/router'; import MyIcon from '../Icon'; import { useUserStore } from '@/store/user'; diff --git a/client/src/components/Markdown/img/Loading.tsx b/client/src/components/Markdown/img/Loading.tsx deleted file mode 100644 index 4e454a1d9..000000000 --- a/client/src/components/Markdown/img/Loading.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React, { memo } from 'react'; -import { Box } from '@chakra-ui/react'; - -const Loading = ({ text }: { text?: string }) => { - return ( - - - {text && ( - - {text} - - )} - - ); -}; - -export default memo(Loading); diff --git a/client/src/components/MyTooltip/index.tsx b/client/src/components/MyTooltip/index.tsx new file mode 100644 index 000000000..d51261c56 --- /dev/null +++ b/client/src/components/MyTooltip/index.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { Tooltip, TooltipProps } from '@chakra-ui/react'; + +const MyTooltip = ({ children, ...props }: TooltipProps) => { + return ( + + {children} + + ); +}; + +export default MyTooltip; diff --git a/client/src/constants/app.ts b/client/src/constants/app.ts index 007d01c34..aed39f7bf 100644 --- a/client/src/constants/app.ts +++ b/client/src/constants/app.ts @@ -155,145 +155,145 @@ export const chatAppDemo: AppItemType = { modules: [chatModule({ id: 'chat' })] }; -export const kbChatAppDemo: AppItemType = { - id: 'kbchat', - name: 'kbchat', - // 标记字段 - modules: [ - { - moduleId: 'kbsearch', - flowType: FlowModuleTypeEnum.kbSearchNode, - type: AppModuleItemTypeEnum.http, - url: '/openapi/modules/kb/search', - position: { x: -500, y: 0 }, - inputs: [ - { - key: 'kb_ids', - type: FlowInputItemTypeEnum.custom, - label: '关联的知识库', - value: ['646627f4f7b896cfd8910e38'], - list: [] - }, +// export const kbChatAppDemo: AppItemType = { +// id: 'kbchat', +// name: 'kbchat', +// // 标记字段 +// modules: [ +// { +// moduleId: 'kbsearch', +// flowType: FlowModuleTypeEnum.kbSearchNode, +// type: AppModuleItemTypeEnum.http, +// url: '/openapi/modules/kb/search', +// position: { x: -500, y: 0 }, +// inputs: [ +// { +// key: 'kb_ids', +// type: FlowInputItemTypeEnum.custom, +// label: '关联的知识库', +// value: ['646627f4f7b896cfd8910e38'], +// list: [] +// }, - { - key: 'similarity', - type: FlowInputItemTypeEnum.slider, - label: '相似度', - value: 0.8, - min: 0, - max: 1, - step: 0.01, - markList: [ - { label: '0', value: 0 }, - { label: '1', value: 1 } - ] - }, - { - key: 'limit', - type: FlowInputItemTypeEnum.slider, - label: '单次搜索上限', - value: 5, - min: 1, - max: 20, - step: 1, - markList: [ - { label: '1', value: 1 }, - { label: '20', value: 20 } - ] - }, - { - key: SystemInputEnum.history, - type: FlowInputItemTypeEnum.hidden, - label: '引用复用数量', - value: 1 - }, - { - key: SystemInputEnum.userChatInput, - type: FlowInputItemTypeEnum.none, - label: '用户输入(系统自动填写)', - description: '' - } - ], - outputs: [ - { - key: 'rawSearch', - label: '源搜索数据', - type: FlowOutputItemTypeEnum.none, - response: true, - targets: [] - }, - { - key: 'isEmpty', - label: '无搜索结果', - type: FlowOutputItemTypeEnum.source, - targets: [ - { - moduleId: 'tfswitch', - key: SystemInputEnum.switch - } - ] - }, - { - key: 'quotePrompt', - label: '引用内容(字符串)', - type: FlowOutputItemTypeEnum.source, - targets: [ - { - moduleId: 'chat', - key: 'quotePrompt' - } - ] - } - ] - }, - { - moduleId: 'tfswitch', - type: AppModuleItemTypeEnum.switch, - flowType: FlowModuleTypeEnum.tfSwitchNode, - position: { x: 0, y: 510 }, - inputs: [ - { - key: SystemInputEnum.switch, - type: FlowInputItemTypeEnum.target, - label: '触发器', - connected: true - } - ], - outputs: [ - { - key: 'true', - label: '无搜索数据', - type: FlowOutputItemTypeEnum.source, - targets: [ - { - moduleId: 'answer', - key: SystemInputEnum.switch - } - ] - }, - { - key: 'false', - label: '有搜索数据', - type: FlowOutputItemTypeEnum.source, - targets: [ - { - moduleId: 'chat', - key: SystemInputEnum.switch - } - ] - } - ] - }, - { - ...chatModule({ id: 'chat', limitPrompt: '参考知识库内容进行回答', history: 5 }), - position: { x: 300, y: 240 } - }, - { - ...answerModule({ id: 'answer' }), - position: { x: 300, y: 0 } - } - ] -}; +// { +// key: 'similarity', +// type: FlowInputItemTypeEnum.slider, +// label: '相似度', +// value: 0.8, +// min: 0, +// max: 1, +// step: 0.01, +// markList: [ +// { label: '0', value: 0 }, +// { label: '1', value: 1 } +// ] +// }, +// { +// key: 'limit', +// type: FlowInputItemTypeEnum.slider, +// label: '单次搜索上限', +// value: 5, +// min: 1, +// max: 20, +// step: 1, +// markList: [ +// { label: '1', value: 1 }, +// { label: '20', value: 20 } +// ] +// }, +// { +// key: SystemInputEnum.history, +// type: FlowInputItemTypeEnum.hidden, +// label: '引用复用数量', +// value: 1 +// }, +// { +// key: SystemInputEnum.userChatInput, +// type: FlowInputItemTypeEnum.none, +// label: '用户输入(系统自动填写)', +// description: '' +// } +// ], +// outputs: [ +// { +// key: 'rawSearch', +// label: '源搜索数据', +// type: FlowOutputItemTypeEnum.none, +// response: true, +// targets: [] +// }, +// { +// key: 'isEmpty', +// label: '无搜索结果', +// type: FlowOutputItemTypeEnum.source, +// targets: [ +// { +// moduleId: 'tfswitch', +// key: SystemInputEnum.switch +// } +// ] +// }, +// { +// key: 'quotePrompt', +// label: '引用内容(字符串)', +// type: FlowOutputItemTypeEnum.source, +// targets: [ +// { +// moduleId: 'chat', +// key: 'quotePrompt' +// } +// ] +// } +// ] +// }, +// { +// moduleId: 'tfswitch', +// type: AppModuleItemTypeEnum.switch, +// flowType: FlowModuleTypeEnum.tfSwitchNode, +// position: { x: 0, y: 510 }, +// inputs: [ +// { +// key: SystemInputEnum.switch, +// type: FlowInputItemTypeEnum.target, +// label: '触发器', +// connected: true +// } +// ], +// outputs: [ +// { +// key: 'true', +// label: '无搜索数据', +// type: FlowOutputItemTypeEnum.source, +// targets: [ +// { +// moduleId: 'answer', +// key: SystemInputEnum.switch +// } +// ] +// }, +// { +// key: 'false', +// label: '有搜索数据', +// type: FlowOutputItemTypeEnum.source, +// targets: [ +// { +// moduleId: 'chat', +// key: SystemInputEnum.switch +// } +// ] +// } +// ] +// }, +// { +// ...chatModule({ id: 'chat', limitPrompt: '参考知识库内容进行回答', history: 5 }), +// position: { x: 300, y: 240 } +// }, +// { +// ...answerModule({ id: 'answer' }), +// position: { x: 300, y: 0 } +// } +// ] +// }; // export const classifyQuestionDemo: AppItemType = { // id: 'classifyQuestionDemo', diff --git a/client/src/constants/chat.ts b/client/src/constants/chat.ts index f51641db5..f1bc61234 100644 --- a/client/src/constants/chat.ts +++ b/client/src/constants/chat.ts @@ -25,4 +25,4 @@ export const ChatRoleMap = { }; export const HUMAN_ICON = `https://fastgpt.run/icon/human.png`; -export const LOGO_ICON = `https://fastgpt.run/imgs/modelAvatar.png`; +export const LOGO_ICON = `https://fastgpt.run/icon/logo.png`; diff --git a/client/src/constants/flow/ModuleTemplate.ts b/client/src/constants/flow/ModuleTemplate.ts index 42d5d70cd..ee102433b 100644 --- a/client/src/constants/flow/ModuleTemplate.ts +++ b/client/src/constants/flow/ModuleTemplate.ts @@ -1,4 +1,4 @@ -import { AppModuleItemTypeEnum, SystemInputEnum } from '../app'; +import { AppModuleItemTypeEnum, SystemInputEnum, SpecificInputEnum } from '../app'; import { FlowModuleTypeEnum, FlowInputItemTypeEnum, FlowOutputItemTypeEnum } from './index'; import type { AppModuleTemplateItemType } from '@/types/app'; import { chatModelList } from '../data'; @@ -9,7 +9,7 @@ import { } from './inputTemplate'; export const UserInputModule: AppModuleTemplateItemType = { - logo: '', + logo: '/imgs/module/userChatInput.png', name: '用户问题', intro: '用户输入的内容。该模块通常作为应用的入口,用户在发送消息后会首先执行该模块。', type: AppModuleItemTypeEnum.initInput, @@ -32,7 +32,7 @@ export const UserInputModule: AppModuleTemplateItemType = { ] }; export const HistoryModule: AppModuleTemplateItemType = { - logo: '', + logo: '/imgs/module/history.png', name: '聊天记录', intro: '用户输入的内容。该模块通常作为应用的入口,用户在发送消息后会首先执行该模块。', type: AppModuleItemTypeEnum.initInput, @@ -64,7 +64,7 @@ export const HistoryModule: AppModuleTemplateItemType = { }; export const ChatModule: AppModuleTemplateItemType = { - logo: '', + logo: '/imgs/module/AI.png', name: 'AI 对话', intro: 'OpenAI GPT 大模型对话。', flowType: FlowModuleTypeEnum.chatNode, @@ -135,7 +135,7 @@ export const ChatModule: AppModuleTemplateItemType = { ], outputs: [ { - key: 'answer', + key: SpecificInputEnum.answerText, label: '模型回复', description: '直接响应,无需配置', type: FlowOutputItemTypeEnum.hidden, @@ -145,7 +145,7 @@ export const ChatModule: AppModuleTemplateItemType = { }; export const KBSearchModule: AppModuleTemplateItemType = { - logo: '', + logo: '/imgs/module/db.png', name: '知识库搜索', intro: '去知识库中搜索对应的答案。可作为 AI 对话引用参考。', flowType: FlowModuleTypeEnum.kbSearchNode, @@ -205,7 +205,7 @@ export const KBSearchModule: AppModuleTemplateItemType = { { key: 'quotePrompt', label: '引用内容', - description: '搜索结果为空时不触发', + description: '搜索结果为空时不返回', type: FlowOutputItemTypeEnum.source, targets: [] } @@ -213,7 +213,7 @@ export const KBSearchModule: AppModuleTemplateItemType = { }; export const AnswerModule: AppModuleTemplateItemType = { - logo: '', + logo: '/imgs/module/reply.png', name: '指定回复', intro: '该模块可以直接回复一段指定的内容。常用于引导、提示。', type: AppModuleItemTypeEnum.answer, @@ -221,7 +221,7 @@ export const AnswerModule: AppModuleTemplateItemType = { inputs: [ Input_Template_TFSwitch, { - key: 'answerText', + key: SpecificInputEnum.answerText, value: '', type: FlowInputItemTypeEnum.input, label: '回复的内容' @@ -257,31 +257,52 @@ export const TFSwitchModule: AppModuleTemplateItemType = { } ] }; - export const ClassifyQuestionModule: AppModuleTemplateItemType = { - logo: '', + logo: '/imgs/module/cq.png', name: '意图识别', intro: '可以判断用户问题属于哪方面问题,从而执行不同的操作。', - type: AppModuleItemTypeEnum.switch, - flowType: FlowModuleTypeEnum.tfSwitchNode, + type: AppModuleItemTypeEnum.http, + url: '/openapi/modules/agent/classifyQuestion', + flowType: FlowModuleTypeEnum.classifyQuestionNode, inputs: [ { - key: SystemInputEnum.switch, - type: FlowInputItemTypeEnum.target, - label: '输入' + key: 'systemPrompt', + type: FlowInputItemTypeEnum.textarea, + label: '系统提示词', + description: + '你可以添加一些特定内容的介绍,从而更好的识别用户的问题类型。这个内容通常是给模型介绍一个它不知道的内容。', + placeholder: '例如: \n1. Laf 是一个云函数开发平台……\n2. Sealos 是一个集群操作系统', + value: '' + }, + Input_Template_History, + Input_Template_UserChatInput, + { + key: 'agents', + type: FlowInputItemTypeEnum.custom, + label: '', + value: [ + { + value: '', + key: 'a' + }, + { + value: '', + key: 'b' + } + ] } ], outputs: [ { - key: 'true', - label: 'True', - type: FlowOutputItemTypeEnum.source, + key: 'a', + label: '', + type: FlowOutputItemTypeEnum.hidden, targets: [] }, { - key: 'false', - label: 'False', - type: FlowOutputItemTypeEnum.source, + key: 'b', + label: '', + type: FlowOutputItemTypeEnum.hidden, targets: [] } ] @@ -302,7 +323,7 @@ export const ModuleTemplates = [ }, { label: '工具', - list: [AnswerModule, TFSwitchModule] + list: [AnswerModule] }, { label: 'Agent', diff --git a/client/src/constants/flow/index.ts b/client/src/constants/flow/index.ts index db6e6c6f8..5184e713f 100644 --- a/client/src/constants/flow/index.ts +++ b/client/src/constants/flow/index.ts @@ -24,7 +24,8 @@ export enum FlowModuleTypeEnum { chatNode = 'chatNode', kbSearchNode = 'kbSearchNode', tfSwitchNode = 'tfSwitchNode', - answerNode = 'answerNode' + answerNode = 'answerNode', + classifyQuestionNode = 'classifyQuestionNode' } export const edgeOptions = { diff --git a/client/src/constants/theme.ts b/client/src/constants/theme.ts index f98ae0026..99c06f554 100644 --- a/client/src/constants/theme.ts +++ b/client/src/constants/theme.ts @@ -202,6 +202,16 @@ const Select = selectMultiStyle({ } }); +const Tooltip = defineStyleConfig({ + baseStyle: { + p: 3, + bg: 'white', + color: 'blackAlpha.800', + borderRadius: '8px', + boxShadow: '1px 1px 10px rgba(0,0,0,0.2)' + } +}); + // 全局主题 export const theme = extendTheme({ styles: { @@ -297,6 +307,7 @@ export const theme = extendTheme({ Textarea, Switch, Select, + Tooltip, NumberInput } }); diff --git a/client/src/pages/api/openapi/modules/agent/classifyQuestion.ts b/client/src/pages/api/openapi/modules/agent/classifyQuestion.ts index 330bb1a30..9c5af1e8b 100644 --- a/client/src/pages/api/openapi/modules/agent/classifyQuestion.ts +++ b/client/src/pages/api/openapi/modules/agent/classifyQuestion.ts @@ -79,7 +79,7 @@ export async function classifyQuestion({ properties: { type: { type: 'string', - description: agents.map((item) => `${item.desc},返回: '${item.key}'`).join('; '), + description: agents.map((item) => `${item.value},返回: '${item.key}'`).join('; '), enum: agents.map((item) => item.key) } }, @@ -106,7 +106,10 @@ export async function classifyQuestion({ if (!arg.type) { throw new Error(''); } - console.log(arg.type); + console.log( + '意图结果', + agents.findIndex((item) => item.key === arg.type) + ); return { [arg.type]: 1 diff --git a/client/src/pages/api/openapi/modules/chat/gpt.ts b/client/src/pages/api/openapi/modules/chat/gpt.ts index eb5ccee70..3cc3eebb8 100644 --- a/client/src/pages/api/openapi/modules/chat/gpt.ts +++ b/client/src/pages/api/openapi/modules/chat/gpt.ts @@ -10,6 +10,7 @@ import type { ChatItemType } from '@/types/chat'; import { ChatRoleEnum, sseResponseEventEnum } from '@/constants/chat'; import { parseStreamChunk, textAdaptGptResponse } from '@/utils/adapt'; import { getOpenAIApi, axiosConfig } from '@/service/ai/openai'; +import { SpecificInputEnum } from '@/constants/app'; export type Props = { model: `${OpenAiChatEnum}`; @@ -22,7 +23,7 @@ export type Props = { systemPrompt?: string; limitPrompt?: string; }; -export type Response = { answer: string }; +export type Response = { [SpecificInputEnum.answerText]: string }; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { @@ -132,7 +133,8 @@ export async function chatCompletion({ const chatAPI = getOpenAIApi(); /* count response max token */ - const promptsToken = modelToolMap[model].countTokens({ + const promptsToken = modelToolMap.countTokens({ + model, messages: filterMessages }); maxToken = maxToken + promptsToken > modelTokenLimit ? modelTokenLimit - promptsToken : maxToken; @@ -143,8 +145,8 @@ export async function chatCompletion({ temperature: Number(temperature || 0), max_tokens: maxToken, messages: adaptMessages, - frequency_penalty: 0.5, // 越大,重复内容越少 - presence_penalty: -0.5, // 越大,越容易出现新内容 + // frequency_penalty: 0.5, // 越大,重复内容越少 + // presence_penalty: -0.5, // 越大,越容易出现新内容 stream }, { @@ -184,7 +186,7 @@ export async function chatCompletion({ })(); return { - answer + answerText: answer }; } diff --git a/client/src/pages/api/openapi/modules/kb/search.ts b/client/src/pages/api/openapi/modules/kb/search.ts index 983fa5758..21ed9cf5f 100644 --- a/client/src/pages/api/openapi/modules/kb/search.ts +++ b/client/src/pages/api/openapi/modules/kb/search.ts @@ -92,8 +92,9 @@ export async function kbSearch({ const searchRes: QuoteItemType[] = res?.[2]?.rows || []; // filter part quote by maxToken - const sliceResult = modelToolMap['gpt-3.5-turbo'] + const sliceResult = modelToolMap .tokenSlice({ + model: 'gpt-3.5-turbo', maxToken, messages: searchRes.map((item, i) => ({ obj: ChatRoleEnum.System, diff --git a/client/src/pages/api/openapi/v1/chat/completions2.ts b/client/src/pages/api/openapi/v1/chat/completions2.ts index 37a7daabb..e6b3703f5 100644 --- a/client/src/pages/api/openapi/v1/chat/completions2.ts +++ b/client/src/pages/api/openapi/v1/chat/completions2.ts @@ -10,12 +10,7 @@ import { getChatHistory } from './getHistory'; import { saveChat } from '@/pages/api/chat/saveChat'; import { sseResponse } from '@/service/utils/tools'; import { type ChatCompletionRequestMessage } from 'openai'; -import { - kbChatAppDemo, - chatAppDemo, - SpecificInputEnum, - AppModuleItemTypeEnum -} from '@/constants/app'; +import { SpecificInputEnum, AppModuleItemTypeEnum } from '@/constants/app'; import { model, Types } from 'mongoose'; import { moduleFetch } from '@/service/api/request'; import { AppModuleItemType, RunningModuleItemType } from '@/types/app'; @@ -42,7 +37,6 @@ export type ChatResponseType = { quoteLen?: number; }; -/* 发送提示词 */ export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse) { res.on('close', () => { res.end(); @@ -117,7 +111,6 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex }, stream }); - console.log(responseData, answerText); // save chat if (typeof chatId === 'string') { @@ -354,7 +347,7 @@ function loadModules(modules: AppModuleItemType[]): RunningModuleItemType[] { })), outputs: module.outputs.map((item) => ({ key: item.key, - answer: item.type === FlowOutputItemTypeEnum.answer, + answer: item.key === SpecificInputEnum.answerText, response: item.response, value: undefined, targets: item.targets diff --git a/client/src/pages/app/detail/components/Kb.tsx b/client/src/pages/app/detail/components/Kb.tsx deleted file mode 100644 index af27644f8..000000000 --- a/client/src/pages/app/detail/components/Kb.tsx +++ /dev/null @@ -1,394 +0,0 @@ -import React, { useState, useCallback } from 'react'; -import { useRouter } from 'next/router'; -import { - Card, - Flex, - Box, - Button, - useDisclosure, - Modal, - ModalOverlay, - ModalContent, - ModalBody, - ModalHeader, - ModalFooter, - ModalCloseButton, - Grid, - useTheme, - IconButton, - Tooltip, - Textarea -} from '@chakra-ui/react'; -import { useUserStore } from '@/store/user'; -import { useQuery } from '@tanstack/react-query'; -import Avatar from '@/components/Avatar'; -import { AddIcon, DeleteIcon, QuestionOutlineIcon } from '@chakra-ui/icons'; -import { putAppById } from '@/api/app'; -import { useToast } from '@/hooks/useToast'; -import { useLoading } from '@/hooks/useLoading'; -import { useForm } from 'react-hook-form'; -import MyIcon from '@/components/Icon'; -import MySlider from '@/components/Slider'; - -const Kb = ({ modelId }: { modelId: string }) => { - const theme = useTheme(); - const router = useRouter(); - const { toast } = useToast(); - const { appDetail, loadKbList, loadAppDetail } = useUserStore(); - const { Loading, setIsLoading } = useLoading(); - const [selectedIdList, setSelectedIdList] = useState([]); - const [refresh, setRefresh] = useState(false); - const { register, reset, getValues, setValue } = useForm({ - defaultValues: { - searchSimilarity: appDetail.chat.searchSimilarity, - searchLimit: appDetail.chat.searchLimit, - searchEmptyText: appDetail.chat.searchEmptyText - } - }); - - const { - isOpen: isOpenKbSelect, - onOpen: onOpenKbSelect, - onClose: onCloseKbSelect - } = useDisclosure(); - const { - isOpen: isOpenEditParams, - onOpen: onOpenEditParams, - onClose: onCloseEditParams - } = useDisclosure(); - - const onchangeKb = useCallback( - async ( - data: { - relatedKbs?: string[]; - searchSimilarity?: number; - searchLimit?: number; - searchEmptyText?: string; - } = {} - ) => { - setIsLoading(true); - try { - await putAppById(modelId, { - chat: { - ...appDetail.chat, - ...data - } - }); - loadAppDetail(modelId, true); - } catch (err: any) { - toast({ - title: err?.message || '更新失败', - status: 'error' - }); - } - setIsLoading(false); - }, - [setIsLoading, modelId, appDetail.chat, loadAppDetail, toast] - ); - - // init kb select list - const { isLoading, data: kbList = [] } = useQuery(['loadKbList'], () => loadKbList()); - - return ( - - 关联的知识库({appDetail.chat?.relatedKbs.length}) - {(() => { - const kbs = - appDetail.chat?.relatedKbs - ?.map((id) => kbList.find((kb) => kb._id === id)) - .filter((item) => item) || []; - return ( - - { - reset({ - searchSimilarity: appDetail.chat.searchSimilarity, - searchLimit: appDetail.chat.searchLimit, - searchEmptyText: appDetail.chat.searchEmptyText - }); - onOpenEditParams(); - }} - > - - } - aria-label={''} - variant={'base'} - /> - 调整搜索参数 - - - 相似度: {appDetail.chat.searchSimilarity}, 单次搜索数量:{' '} - {appDetail.chat.searchLimit}, 空搜索时拒绝回复:{' '} - {appDetail.chat.searchEmptyText !== '' ? 'true' : 'false'} - - - { - setSelectedIdList( - appDetail.chat?.relatedKbs ? [...appDetail.chat?.relatedKbs] : [] - ); - onOpenKbSelect(); - }} - > - - } - aria-label={''} - variant={'base'} - /> - 选择关联知识库 - - - 关联知识库,让 AI 应用回答你的特有内容。 - - - {kbs.map((item) => - item ? ( - - - - - {item.name} - - - - - } - variant={'outline'} - aria-label={'delete'} - size={'sm'} - _hover={{ color: 'red.600' }} - onClick={() => { - const ids = appDetail.chat?.relatedKbs - ? [...appDetail.chat.relatedKbs] - : []; - const i = ids.findIndex((id) => id === item._id); - ids.splice(i, 1); - onchangeKb({ relatedKbs: ids }); - }} - /> - - - ) : null - )} - - ); - })()} - {/* select kb modal */} - - - - 关联的知识库({selectedIdList.length}) - - - {kbList.map((item) => ( - { - let ids = [...selectedIdList]; - if (!selectedIdList.includes(item._id)) { - ids = ids.concat(item._id); - } else { - const i = ids.findIndex((id) => id === item._id); - ids.splice(i, 1); - } - - ids = ids.filter((id) => kbList.find((item) => item._id === id)); - setSelectedIdList(ids); - }} - > - - - - {item.name} - - - - ))} - - - - - - - - {/* edit mode */} - - - - 搜索参数调整 - - - - - 相似度 - - - - - { - setValue('searchSimilarity', val); - setRefresh(!refresh); - }} - /> - - - 单次搜索数量 - - { - setValue('searchLimit', val); - setRefresh(!refresh); - }} - /> - - - - 空搜索回复 - - - - - - - - - - - - - - ); -}; - -export default Kb; diff --git a/client/src/pages/app/detail/components/Share.tsx b/client/src/pages/app/detail/components/Share.tsx index ada868683..112e706c4 100644 --- a/client/src/pages/app/detail/components/Share.tsx +++ b/client/src/pages/app/detail/components/Share.tsx @@ -2,7 +2,6 @@ import React, { useCallback, useState } from 'react'; import { Flex, Box, - Tooltip, Button, TableContainer, Table, @@ -37,6 +36,7 @@ import { formatTimeToChatTime, useCopyData, getErrText } from '@/utils/tools'; import { useForm } from 'react-hook-form'; import { defaultShareChat } from '@/constants/model'; import type { ShareChatEditType } from '@/types/app'; +import MyTooltip from '@/components/MyTooltip'; const Share = ({ modelId }: { modelId: string }) => { const { toast } = useToast(); @@ -112,9 +112,9 @@ ${e.password ? `密码为: ${e.password}` : ''}`; 免登录聊天窗口 - + - + + + ) + }} + /> + + + ); +}; +export default React.memo(NodeCQNode); diff --git a/client/src/pages/app/detail/components/edit/components/NodeKbSearch.tsx b/client/src/pages/app/detail/components/edit/components/NodeKbSearch.tsx index fd1de5b5d..23e720aa5 100644 --- a/client/src/pages/app/detail/components/edit/components/NodeKbSearch.tsx +++ b/client/src/pages/app/detail/components/edit/components/NodeKbSearch.tsx @@ -26,7 +26,7 @@ const NodeKbSearch = ({ onChangeNode={onChangeNode} flowInputList={inputs} CustomComponent={{ - kb_ids: ({ key, value, onChangeNode }) => ( + kb_ids: ({ key, value }) => ( { diff --git a/client/src/pages/app/detail/components/edit/components/TemplateList.tsx b/client/src/pages/app/detail/components/edit/components/TemplateList.tsx index ae93b095a..11dd2ce8b 100644 --- a/client/src/pages/app/detail/components/edit/components/TemplateList.tsx +++ b/client/src/pages/app/detail/components/edit/components/TemplateList.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { Box, Flex } from '@chakra-ui/react'; +import React, { useRef } from 'react'; +import { Box, Flex, useOutsideClick } from '@chakra-ui/react'; import { ModuleTemplates } from '@/constants/flow/ModuleTemplate'; import type { AppModuleTemplateItemType } from '@/types/app'; import type { XYPosition } from 'reactflow'; @@ -7,62 +7,85 @@ import Avatar from '@/components/Avatar'; const ModuleStoreList = ({ isOpen, - onAddNode + onAddNode, + onClose }: { isOpen: boolean; onAddNode: (e: { template: AppModuleTemplateItemType; position: XYPosition }) => void; + onClose: () => void; }) => { + const ContextMenuRef = useRef(null); + + useOutsideClick({ + ref: ContextMenuRef, + handler: () => { + onClose(); + } + }); + return ( - - - 添加模块 - - - {ModuleTemplates.map((item) => - item.list.map((item) => ( - { - if (e.clientX < 400) return; - onAddNode({ - template: item, - position: { x: e.clientX, y: e.clientY } - }); - }} - > - - - {item.name} - - {item.intro} + <> + + + + 添加模块 + + + {ModuleTemplates.map((item) => + item.list.map((item) => ( + { + // if (e.clientX < 400) return; + onAddNode({ + template: item, + position: { x: e.clientX, y: e.clientY } + }); + }} + > + + + {item.name} + + {item.intro} + - - - )) - )} - - + + )) + )} + + + ); }; diff --git a/client/src/pages/app/detail/components/edit/components/modules/Label.tsx b/client/src/pages/app/detail/components/edit/components/modules/Label.tsx index f46d7f1a8..043af54f6 100644 --- a/client/src/pages/app/detail/components/edit/components/modules/Label.tsx +++ b/client/src/pages/app/detail/components/edit/components/modules/Label.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Box, Tooltip } from '@chakra-ui/react'; +import { Box } from '@chakra-ui/react'; import { QuestionOutlineIcon } from '@chakra-ui/icons'; +import MyTooltip from '@/components/MyTooltip'; const Label = ({ required = false, @@ -19,9 +20,9 @@ const Label = ({ )} {description && ( - + - + )} ); diff --git a/client/src/pages/app/detail/components/edit/components/render/RenderInput.tsx b/client/src/pages/app/detail/components/edit/components/render/RenderInput.tsx index 0095f3c58..81635078a 100644 --- a/client/src/pages/app/detail/components/edit/components/render/RenderInput.tsx +++ b/client/src/pages/app/detail/components/edit/components/render/RenderInput.tsx @@ -4,7 +4,6 @@ import { Box, Textarea, Input, - Tooltip, NumberInput, NumberInputField, NumberInputStepper, @@ -16,6 +15,7 @@ import { QuestionOutlineIcon } from '@chakra-ui/icons'; import { Handle, Position } from 'reactflow'; import MySelect from '@/components/Select'; import MySlider from '@/components/Slider'; +import MyTooltip from '@/components/MyTooltip'; const Label = ({ required = false, @@ -34,9 +34,9 @@ const Label = ({ )} {description && ( - + - + )} ); @@ -49,14 +49,7 @@ const RenderBody = ({ }: { flowInputList: FlowInputItemType[]; moduleId: string; - CustomComponent?: Record< - string, - (e: { - key: string; - value: any; - onChangeNode: FlowModuleItemType['onChangeNode']; - }) => React.ReactNode - >; + CustomComponent?: Record React.ReactNode>; onChangeNode: FlowModuleItemType['onChangeNode']; }) => { return ( @@ -65,9 +58,11 @@ const RenderBody = ({ (item) => item.type !== FlowInputItemTypeEnum.hidden && ( - + {!!item.label && ( + + )} {item.type === FlowInputItemTypeEnum.numberInput && ( )} {item.type === FlowInputItemTypeEnum.custom && CustomComponent[item.key] && ( - <> - {CustomComponent[item.key]({ key: item.key, value: item.value, onChangeNode })} - + <>{CustomComponent[item.key]({ ...item })} )} {item.type === FlowInputItemTypeEnum.target && ( ( {description && ( - + - + )} {children} diff --git a/client/src/pages/app/detail/components/edit/index.tsx b/client/src/pages/app/detail/components/edit/index.tsx index 15d6de586..b8a1b2897 100644 --- a/client/src/pages/app/detail/components/edit/index.tsx +++ b/client/src/pages/app/detail/components/edit/index.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect } from 'react'; +import React, { useCallback, useEffect, useRef } from 'react'; import ReactFlow, { Background, Controls, @@ -7,7 +7,8 @@ import ReactFlow, { useNodesState, useEdgesState, XYPosition, - Connection + Connection, + useViewport } from 'reactflow'; import { Box, Flex, IconButton, useTheme, useDisclosure } from '@chakra-ui/react'; import { SmallCloseIcon } from '@chakra-ui/icons'; @@ -47,6 +48,9 @@ const NodeQuestionInput = dynamic(() => import('./components/NodeQuestionInput') const TemplateList = dynamic(() => import('./components/TemplateList'), { ssr: false }); +const NodeCQNode = dynamic(() => import('./components/NodeCQNode'), { + ssr: false +}); import 'reactflow/dist/style.css'; import styles from './index.module.scss'; @@ -60,14 +64,18 @@ const nodeTypes = { [FlowModuleTypeEnum.chatNode]: NodeChat, [FlowModuleTypeEnum.kbSearchNode]: NodeKbSearch, [FlowModuleTypeEnum.tfSwitchNode]: NodeTFSwitch, - [FlowModuleTypeEnum.answerNode]: NodeAnswer + [FlowModuleTypeEnum.answerNode]: NodeAnswer, + [FlowModuleTypeEnum.classifyQuestionNode]: NodeCQNode }; const edgeTypes = { buttonedge: ButtonEdge }; +type Props = { app: AppSchema; onBack: () => void }; -const AppEdit = ({ app, onBack }: { app: AppSchema; onBack: () => void }) => { +const AppEdit = ({ app, onBack }: Props) => { + const reactFlowWrapper = useRef(null); const theme = useTheme(); + const { x, y, zoom } = useViewport(); const [nodes, setNodes, onNodesChange] = useNodesState([]); const [edges, setEdges, onEdgesChange] = useEdgesState([]); const { @@ -77,24 +85,33 @@ const AppEdit = ({ app, onBack }: { app: AppSchema; onBack: () => void }) => { } = useDisclosure(); const onChangeNode = useCallback( - ({ moduleId, key, value, valueKey = 'value' }: FlowModuleItemChangeProps) => { + ({ moduleId, key, type = 'inputs', value, valueKey = 'value' }: FlowModuleItemChangeProps) => { setNodes((nodes) => nodes.map((node) => { if (node.id !== moduleId) return node; + if (type === 'inputs') { + return { + ...node, + data: { + ...node.data, + inputs: node.data.inputs.map((item) => { + if (item.key === key) { + return { + ...item, + [valueKey]: value + }; + } + return item; + }) + } + }; + } return { ...node, data: { ...node.data, - inputs: node.data.inputs.map((item) => { - if (item.key === key) { - return { - ...item, - [valueKey]: value - }; - } - return item; - }) + outputs: value } }; }) @@ -111,12 +128,17 @@ const AppEdit = ({ app, onBack }: { app: AppSchema; onBack: () => void }) => { ); const onAddNode = useCallback( ({ template, position }: { template: AppModuleTemplateItemType; position: XYPosition }) => { + if (!reactFlowWrapper.current) return; + const reactFlowBounds = reactFlowWrapper.current.getBoundingClientRect(); + const mouseX = (position.x - reactFlowBounds.left - x) / zoom - 100; + const mouseY = (position.y - reactFlowBounds.top - y) / zoom; + setNodes((state) => state.concat( appModule2FlowNode({ item: { ...template, - position, + position: { x: mouseX, y: mouseY }, moduleId: nanoid() }, onChangeNode, @@ -125,7 +147,7 @@ const AppEdit = ({ app, onBack }: { app: AppSchema; onBack: () => void }) => { ) ); }, - [onChangeNode, onDelNode, setNodes] + [onChangeNode, onDelNode, setNodes, x, y, zoom] ); const onDelConnect = useCallback( @@ -245,6 +267,13 @@ const AppEdit = ({ app, onBack }: { app: AppSchema; onBack: () => void }) => { borderRadius={'lg'} isLoading={isLoading} aria-label={'save'} + bg={'myBlue.200'} + variant={'base'} + border={'none'} + color={'myGray.900'} + _hover={{ + bg: 'myBlue.300' + }} onClick={onclickSave} /> @@ -270,43 +299,50 @@ const AppEdit = ({ app, onBack }: { app: AppSchema; onBack: () => void }) => { transition={'0.2s ease'} aria-label={''} zIndex={1} - boxShadow={'1px 1px 6px #4e83fd'} - onClick={() => (isOpenTemplate ? onCloseTemplate() : onOpenTemplate())} + boxShadow={'2px 2px 6px #85b1ff'} + onClick={() => { + isOpenTemplate ? onCloseTemplate() : onOpenTemplate(); + }} /> - - { - connect.sourceHandle && - connect.targetHandle && - onConnect({ - connect - }); - }} - > - - - - - + { + connect.sourceHandle && + connect.targetHandle && + onConnect({ + connect + }); + }} + > + + + + ); }; -export default AppEdit; +const Flow = (data: Props) => ( + + + +); + +export default Flow; diff --git a/client/src/pages/app/list/component/CreateModal.tsx b/client/src/pages/app/list/component/CreateModal.tsx index 79750916a..3570569d5 100644 --- a/client/src/pages/app/list/component/CreateModal.tsx +++ b/client/src/pages/app/list/component/CreateModal.tsx @@ -173,7 +173,7 @@ const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: ( boxShadow={'sm'} {...(getValues('templateId') === item.id ? { - bg: 'myBlue.300' + bg: 'myWhite.600' } : { _hover: { diff --git a/client/src/pages/app/list/index.tsx b/client/src/pages/app/list/index.tsx index 22b0fd5b9..69964c6e7 100644 --- a/client/src/pages/app/list/index.tsx +++ b/client/src/pages/app/list/index.tsx @@ -120,7 +120,13 @@ const MyApps = () => { }} /> - + {app.intro || '这个应用还没写介绍~'} diff --git a/client/src/pages/appStore/components/list.tsx b/client/src/pages/appStore/components/list.tsx index f7e118bd3..ee42104bc 100644 --- a/client/src/pages/appStore/components/list.tsx +++ b/client/src/pages/appStore/components/list.tsx @@ -1,10 +1,11 @@ import React from 'react'; -import { Box, Flex, Button, Tooltip, Card } from '@chakra-ui/react'; +import { Box, Flex, Button, Card } from '@chakra-ui/react'; import type { ShareAppItem } from '@/types/app'; import { useRouter } from 'next/router'; import MyIcon from '@/components/Icon'; import styles from '../index.module.scss'; import Avatar from '@/components/Avatar'; +import MyTooltip from '@/components/MyTooltip'; const ShareModelList = ({ models = [], @@ -44,7 +45,7 @@ const ShareModelList = ({ {model.name} - + {model.intro || '这个应用还没有介绍~'} - + await import('@/components/Markdown')); const PhoneSliderBar = dynamic(() => import('./components/PhoneSliderBar'), { @@ -701,7 +701,7 @@ const Chat = () => { {item.obj === 'Human' && } {/* avatar */} - + { h={['20px', '34px']} /> - + {!isPc && } {/* message */} diff --git a/client/src/pages/chat/share.tsx b/client/src/pages/chat/share.tsx index 10b89cf33..5ec1f2a9e 100644 --- a/client/src/pages/chat/share.tsx +++ b/client/src/pages/chat/share.tsx @@ -22,7 +22,6 @@ import { DrawerOverlay, DrawerContent, Card, - Tooltip, useOutsideClick, useTheme, Input, @@ -49,6 +48,7 @@ import SideBar from '@/components/SideBar'; import Avatar from '@/components/Avatar'; import Empty from './components/Empty'; import { HUMAN_ICON } from '@/constants/chat'; +import MyTooltip from '@/components/MyTooltip'; const ShareHistory = dynamic(() => import('./components/ShareHistory'), { loading: () => , @@ -619,7 +619,7 @@ const Chat = () => { {item.obj === 'Human' && } {/* avatar */} - + { h={['20px', '34px']} /> - + {!isPc && } {/* message */} diff --git a/client/src/pages/kb/components/Info.tsx b/client/src/pages/kb/components/Info.tsx index 2cbf399a9..2920464ba 100644 --- a/client/src/pages/kb/components/Info.tsx +++ b/client/src/pages/kb/components/Info.tsx @@ -7,7 +7,7 @@ import React, { ForwardedRef } from 'react'; import { useRouter } from 'next/router'; -import { Box, Flex, Button, FormControl, IconButton, Tooltip, Input, Card } from '@chakra-ui/react'; +import { Box, Flex, Button, FormControl, IconButton, Input, Card } from '@chakra-ui/react'; import { QuestionOutlineIcon, DeleteIcon } from '@chakra-ui/icons'; import { delKbById, putKbById } from '@/api/plugins/kb'; import { useSelectFile } from '@/hooks/useSelectFile'; @@ -19,6 +19,7 @@ import { compressImg } from '@/utils/file'; import type { KbItemType } from '@/types/plugin'; import Avatar from '@/components/Avatar'; import Tag from '@/components/Tag'; +import MyTooltip from '@/components/MyTooltip'; export interface ComponentRef { initInput: (tags: string) => void; @@ -173,9 +174,9 @@ const Info = ( 分类标签 - + - + { const theme = useTheme(); @@ -78,7 +79,7 @@ const KbList = ({ kbId }: { kbId: string }) => { /> )} - + } @@ -86,7 +87,7 @@ const KbList = ({ kbId }: { kbId: string }) => { variant={'base'} onClick={handleCreateModel} /> - + {kbs.map((item) => ( diff --git a/client/src/pages/model/components/detail/components/Settings.tsx b/client/src/pages/model/components/detail/components/Settings.tsx deleted file mode 100644 index ec39c0cdb..000000000 --- a/client/src/pages/model/components/detail/components/Settings.tsx +++ /dev/null @@ -1,388 +0,0 @@ -import React, { useCallback, useState, useMemo } from 'react'; -import { - Box, - Flex, - Button, - FormControl, - Input, - Textarea, - Divider, - Tooltip -} from '@chakra-ui/react'; -import { QuestionOutlineIcon } from '@chakra-ui/icons'; -import { useQuery } from '@tanstack/react-query'; -import { useForm } from 'react-hook-form'; -import { useRouter } from 'next/router'; -import { useUserStore } from '@/store/user'; -import { useToast } from '@/hooks/useToast'; -import { useLoading } from '@/hooks/useLoading'; -import { delModelById, putAppById } from '@/api/app'; -import { useSelectFile } from '@/hooks/useSelectFile'; -import { compressImg } from '@/utils/file'; -import { getErrText } from '@/utils/tools'; -import { useConfirm } from '@/hooks/useConfirm'; -import { ChatModelMap, chatModelList } from '@/constants/model'; -import { formatPrice } from '@/utils/user'; - -import type { AppSchema } from '@/types/mongoSchema'; - -import Avatar from '@/components/Avatar'; -import MySelect from '@/components/Select'; -import MySlider from '@/components/Slider'; - -const systemPromptTip = - '模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。'; -const limitPromptTip = - '限定模型对话范围,会被放置在本次提问前,拥有强引导和限定性。例如:\n1. 知识库是关于 Laf 的介绍,参考知识库回答问题,与 "Laf" 无关内容,直接回复: "我不知道"。\n2. 你仅回答关于 "xxx" 的问题,其他问题回复: "xxxx"'; - -const Settings = ({ modelId }: { modelId: string }) => { - const { toast } = useToast(); - const router = useRouter(); - const { Loading, setIsLoading } = useLoading(); - const { userInfo, appDetail, myApps, loadAppDetail, refreshModel, setLastModelId } = - useUserStore(); - const { File, onOpen: onOpenSelectFile } = useSelectFile({ - fileType: '.jpg,.png', - multiple: false - }); - const { openConfirm, ConfirmChild } = useConfirm({ - content: '确认删除该应用?' - }); - - const [btnLoading, setBtnLoading] = useState(false); - const [refresh, setRefresh] = useState(false); - - const { - register, - setValue, - getValues, - formState: { errors }, - reset, - handleSubmit - } = useForm({ - defaultValues: appDetail - }); - - const isOwner = useMemo( - () => appDetail.userId === userInfo?._id, - [appDetail.userId, userInfo?._id] - ); - const tokenLimit = useMemo(() => { - const max = ChatModelMap[getValues('chat.chatModel')]?.contextMaxToken || 4000; - - if (max < getValues('chat.maxToken')) { - setValue('chat.maxToken', max); - } - - return max; - }, [getValues, setValue, refresh]); - - // 提交保存模型修改 - const saveSubmitSuccess = useCallback( - async (data: AppSchema) => { - setBtnLoading(true); - try { - await putAppById(data._id, { - name: data.name, - avatar: data.avatar, - intro: data.intro, - chat: data.chat, - share: data.share - }); - - refreshModel.updateModelDetail(data); - } catch (err: any) { - toast({ - title: err?.message || '更新失败', - status: 'error' - }); - } - setBtnLoading(false); - }, - [refreshModel, toast] - ); - // 提交保存表单失败 - const saveSubmitError = useCallback(() => { - // deep search message - const deepSearch = (obj: any): string => { - if (!obj) return '提交表单错误'; - if (!!obj.message) { - return obj.message; - } - return deepSearch(Object.values(obj)[0]); - }; - toast({ - title: deepSearch(errors), - status: 'error', - duration: 4000, - isClosable: true - }); - }, [errors, toast]); - - const saveUpdateModel = useCallback( - () => handleSubmit(saveSubmitSuccess, saveSubmitError)(), - [handleSubmit, saveSubmitError, saveSubmitSuccess] - ); - - /* 点击删除 */ - const handleDelModel = useCallback(async () => { - if (!appDetail) return; - setIsLoading(true); - try { - await delModelById(appDetail._id); - toast({ - title: '删除成功', - status: 'success' - }); - refreshModel.removeModelDetail(appDetail._id); - router.replace(`/model?modelId=${myApps[1]?._id}`); - } catch (err: any) { - toast({ - title: err?.message || '删除失败', - status: 'error' - }); - } - setIsLoading(false); - }, [appDetail, setIsLoading, toast, refreshModel, router, myApps]); - - const onSelectFile = useCallback( - async (e: File[]) => { - const file = e[0]; - if (!file) return; - try { - const src = await compressImg({ - file, - maxW: 100, - maxH: 100 - }); - setValue('avatar', src); - setRefresh((state) => !state); - } catch (err: any) { - toast({ - title: getErrText(err, '头像选择异常'), - status: 'warning' - }); - } - }, - [setValue, toast] - ); - - // load model data - const { isLoading } = useQuery([modelId], () => loadAppDetail(modelId, true), { - onSuccess(res) { - res && reset(res); - modelId && setLastModelId(modelId); - setRefresh(!refresh); - }, - onError(err: any) { - toast({ - title: err?.message || '获取应用异常', - status: 'error' - }); - setLastModelId(''); - refreshModel.freshMyModels(); - router.replace('/model'); - } - }); - - return ( - - - - 头像 - - isOwner && onOpenSelectFile()} - /> - - - - - 名称 - - - - - - - 介绍 - - - - - - - - - 对话模型 - - ({ - value: item.chatModel, - label: `${item.name} (${formatPrice( - ChatModelMap[item.chatModel]?.price, - 1000 - )} 元/1k tokens)` - }))} - onchange={(val: any) => { - setValue('chat.chatModel', val); - setRefresh(!refresh); - }} - /> - - - - 温度 - - - { - setValue('chat.temperature', val); - setRefresh(!refresh); - }} - /> - - - - - 回复上限 - - - { - setValue('chat.maxToken', val); - setRefresh(!refresh); - }} - /> - - - - - 提示词 - - - - - - - - - 限定词 - - - - - - - - - - - - {isOwner && ( - - )} - - - - - - - ); -}; - -export default Settings; diff --git a/client/src/types/app.d.ts b/client/src/types/app.d.ts index 217c442cd..1a50685f5 100644 --- a/client/src/types/app.d.ts +++ b/client/src/types/app.d.ts @@ -40,7 +40,7 @@ export type ShareChatEditType = { /* agent */ /* question classify */ export type ClassifyQuestionAgentItemType = { - desc: string; + value: string; key: string; }; diff --git a/client/src/types/flow.d.ts b/client/src/types/flow.d.ts index 40631d4a0..99e66540e 100644 --- a/client/src/types/flow.d.ts +++ b/client/src/types/flow.d.ts @@ -37,6 +37,7 @@ export type FlowOutputItemType = { export type FlowModuleItemChangeProps = { moduleId: string; + type?: 'inputs' | 'outputs'; key: string; value: any; valueKey?: keyof FlowInputItemType & keyof FlowBodyItemType; diff --git a/client/src/utils/adapt.ts b/client/src/utils/adapt.ts index 6819e1431..b0ae8d658 100644 --- a/client/src/utils/adapt.ts +++ b/client/src/utils/adapt.ts @@ -109,8 +109,6 @@ export const appModule2FlowEdge = ({ modules: AppModuleItemType[]; onDelete: (id: string) => void; }) => { - console.log(modules); - const edges: Edge[] = []; modules.forEach((module) => module.outputs.forEach((output) => diff --git a/client/src/utils/plugin/index.ts b/client/src/utils/plugin/index.ts index 96153f7d8..d70a066e7 100644 --- a/client/src/utils/plugin/index.ts +++ b/client/src/utils/plugin/index.ts @@ -1,6 +1,3 @@ -import { OpenAiChatEnum } from '@/constants/model'; -import type { ChatModelType } from '@/constants/model'; -import type { ChatItemType } from '@/types/chat'; import { countOpenAIToken, openAiSliceTextByToken } from './openai'; import { gpt_chatItemTokenSlice } from '@/pages/api/openapi/text/gptMessagesSlice';