Commit aef42cef by archer

perf: attribute

parent 23642af6
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1688783528309" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5845" xmlns:xlink="http://www.w3.org/1999/xlink" ><path d="M931.53 960H512C264.97 960 64 759.03 64 512S264.97 64 512 64s448 200.97 448 448v419.53c0 15.69-12.77 28.47-28.47 28.47zM512 116.71c-217.96 0-395.29 177.33-395.29 395.29 0 217.97 177.33 395.3 395.29 395.3h395.29V512c0-217.97-177.33-395.29-395.29-395.29z" fill="#333333" p-id="5846"></path><path d="M730.13 439.04H293.87c-14.55 0-26.35-11.8-26.35-26.35s11.8-26.35 26.35-26.35h436.26c14.55 0 26.35 11.8 26.35 26.35s-11.8 26.35-26.35 26.35zM730.13 637.67H293.87c-14.55 0-26.35-11.8-26.35-26.35s11.8-26.35 26.35-26.35h436.26c14.55 0 26.35 11.8 26.35 26.35s-11.8 26.35-26.35 26.35z" p-id="5847"></path></svg>
\ No newline at end of file
...@@ -36,7 +36,8 @@ const map = { ...@@ -36,7 +36,8 @@ const map = {
date: require('./icons/date.svg').default, date: require('./icons/date.svg').default,
apikey: require('./icons/apikey.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 minus: require('./icons/minus.svg').default,
chatLight: require('./icons/light/chat.svg').default
}; };
export type IconName = keyof typeof map; export type IconName = keyof typeof map;
......
...@@ -23,7 +23,7 @@ const Navbar = ({ unread }: { unread: number }) => { ...@@ -23,7 +23,7 @@ const Navbar = ({ unread }: { unread: number }) => {
{ {
label: '聊天', label: '聊天',
icon: 'chat', icon: 'chat',
link: `/chat?modelId=${lastChatModelId}&chatId=${lastChatId}`, link: `/chat?appId=${lastChatModelId}&chatId=${lastChatId}`,
activeLink: ['/chat'] activeLink: ['/chat']
}, },
{ {
......
...@@ -13,7 +13,7 @@ const NavbarPhone = ({ unread }: { unread: number }) => { ...@@ -13,7 +13,7 @@ const NavbarPhone = ({ unread }: { unread: number }) => {
{ {
label: '聊天', label: '聊天',
icon: 'tabbarChat', icon: 'tabbarChat',
link: `/chat?modelId=${lastChatModelId}&chatId=${lastChatId}`, link: `/chat?appId=${lastChatModelId}&chatId=${lastChatId}`,
activeLink: ['/chat'], activeLink: ['/chat'],
unread: 0 unread: 0
}, },
......
import type { AppItemType } from '@/types/app'; import type { AppItemType } from '@/types/app';
import { FlowInputItemTypeEnum, FlowModuleTypeEnum, FlowOutputItemTypeEnum } from './flow';
import { chatModelList } from './data';
/* app */ /* app */
export enum AppModuleItemTypeEnum { export enum AppModuleItemTypeEnum {
...@@ -18,282 +16,1110 @@ export enum SpecificInputEnum { ...@@ -18,282 +16,1110 @@ export enum SpecificInputEnum {
'answerText' = 'answerText' // answer module text key 'answerText' = 'answerText' // answer module text key
} }
export const answerModule = ({ id }: { id: string }) => ({ // template
moduleId: id, export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = [
type: AppModuleItemTypeEnum.answer, {
flowType: FlowModuleTypeEnum.answerNode, id: 'simpleChat',
inputs: [ avatar: '/imgs/module/AI.png',
{ name: '简单的对话',
key: SystemInputEnum.switch, intro: '一个极其简单的 AI 对话应用',
type: FlowInputItemTypeEnum.target, modules: [
label: '触发器',
connected: true
},
{
key: SpecificInputEnum.answerText,
value: '',
type: FlowInputItemTypeEnum.input,
label: '响应内容',
connected: true
}
],
outputs: []
});
export const chatModule = ({
id,
systemPrompt = '',
limitPrompt = '',
history = 10
}: {
id: string;
systemPrompt?: string;
limitPrompt?: string;
history?: number;
}) => {
return {
moduleId: id,
flowType: FlowModuleTypeEnum.chatNode,
type: AppModuleItemTypeEnum.http,
url: '/openapi/modules/chat/gpt',
inputs: [
{ {
key: 'model', logo: '/imgs/module/userChatInput.png',
type: FlowInputItemTypeEnum.select, name: '用户问题',
label: '对话模型', intro: '用户输入的内容。该模块通常作为应用的入口,用户在发送消息后会首先执行该模块。',
value: chatModelList[0].value, type: 'initInput',
list: chatModelList flowType: 'questionInput',
url: '/openapi/modules/init/userChatInput',
inputs: [
{
key: 'userChatInput',
type: 'systemInput',
label: '用户问题',
connected: false
}
],
outputs: [
{
key: 'userChatInput',
label: '用户问题',
type: 'source',
targets: [
{
moduleId: '3n49vn',
key: 'userChatInput'
}
]
}
],
position: {
x: 481.4684021933373,
y: 741.252592445572
},
moduleId: 'xzj0oo'
}, },
{ {
key: 'temperature', logo: '/imgs/module/history.png',
type: FlowInputItemTypeEnum.slider, name: '聊天记录',
label: '温度', intro: '用户输入的内容。该模块通常作为应用的入口,用户在发送消息后会首先执行该模块。',
value: 0, type: 'initInput',
min: 0, flowType: 'historyNode',
max: 10, url: '/openapi/modules/init/history',
step: 1, inputs: [
markList: [ {
{ label: '严谨', value: 0 }, key: 'maxContext',
{ label: '发散', value: 10 } type: 'numberInput',
] label: '最长记录数',
value: 4,
min: 0,
max: 50,
connected: false
},
{
key: 'history',
type: 'hidden',
label: '聊天记录',
connected: false
}
],
outputs: [
{
key: 'history',
label: '聊天记录',
type: 'source',
targets: [
{
moduleId: '3n49vn',
key: 'history'
}
]
}
],
position: {
x: 405.6002299937601,
y: 374.16606887857023
},
moduleId: 'hh6of9'
}, },
{ {
key: 'maxToken', logo: '/imgs/module/AI.png',
type: FlowInputItemTypeEnum.slider, name: 'AI 对话',
label: '回复上限', intro: 'OpenAI GPT 大模型对话。',
value: 3000, flowType: 'chatNode',
min: 0, type: 'http',
max: 4000, url: '/openapi/modules/chat/gpt',
step: 50, inputs: [
markList: [ {
{ label: '0', value: 0 }, key: 'model',
{ label: '4000', value: 4000 } type: 'select',
] label: '对话模型',
value: 'gpt-3.5-turbo-16k',
list: [
{
label: 'Gpt35-16k',
value: 'gpt-3.5-turbo-16k'
},
{
label: 'Gpt35-4k',
value: 'gpt-3.5-turbo'
},
{
label: 'Gpt4-8k',
value: 'gpt-4'
}
],
connected: false
},
{
key: 'temperature',
type: 'slider',
label: '温度',
value: 0,
min: 0,
max: 10,
step: 1,
markList: [
{
label: '严谨',
value: 0
},
{
label: '发散',
value: 10
}
],
connected: false
},
{
key: 'maxToken',
type: 'slider',
label: '回复上限',
value: 3000,
min: 0,
max: 4000,
step: 50,
markList: [
{
label: '0',
value: 0
},
{
label: '4000',
value: 4000
}
],
connected: false
},
{
key: 'systemPrompt',
type: 'textarea',
label: '系统提示词',
description:
'模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。',
placeholder:
'模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。',
value: '',
connected: false
},
{
key: 'limitPrompt',
type: 'textarea',
label: '限定词',
description:
'限定模型对话范围,会被放置在本次提问前,拥有强引导和限定性。例如:\n1. 知识库是关于 Laf 的介绍,参考知识库回答问题,与 "Laf" 无关内容,直接回复: "我不知道"。\n2. 你仅回答关于 "xxx" 的问题,其他问题回复: "xxxx"',
placeholder:
'限定模型对话范围,会被放置在本次提问前,拥有强引导和限定性。例如:\n1. 知识库是关于 Laf 的介绍,参考知识库回答问题,与 "Laf" 无关内容,直接回复: "我不知道"。\n2. 你仅回答关于 "xxx" 的问题,其他问题回复: "xxxx"',
value: '',
connected: false
},
{
key: 'switch',
type: 'target',
label: '触发器',
connected: false
},
{
key: 'quotePrompt',
type: 'target',
label: '引用内容',
connected: false
},
{
key: 'history',
type: 'target',
label: '聊天记录',
connected: true
},
{
key: 'userChatInput',
type: 'target',
label: '用户问题',
connected: true
}
],
outputs: [
{
key: 'answerText',
label: '模型回复',
description: '直接响应,无需配置',
type: 'hidden',
targets: []
}
],
position: {
x: 965.5863241865428,
y: -29.569293606933797
},
moduleId: '3n49vn'
}
]
},
{
id: 'simpleKbChat',
avatar: '/imgs/module/db.png',
name: '基础知识库',
intro: '每次提问时进行一次知识库搜索,将搜索结果注入 LLM 模型进行参考回答',
modules: [
{
logo: '/imgs/module/userChatInput.png',
name: '用户问题',
intro: '用户输入的内容。该模块通常作为应用的入口,用户在发送消息后会首先执行该模块。',
type: 'initInput',
flowType: 'questionInput',
url: '/openapi/modules/init/userChatInput',
inputs: [
{
key: 'userChatInput',
type: 'systemInput',
label: '用户问题',
connected: false
}
],
outputs: [
{
key: 'userChatInput',
label: '用户问题',
type: 'source',
targets: [
{
moduleId: '3n49vn',
key: 'userChatInput'
},
{
moduleId: 'zid0fj',
key: 'userChatInput'
}
]
}
],
position: {
x: 447.0165784462213,
y: 748.7421193471189
},
moduleId: 'xzj0oo'
},
{
logo: '/imgs/module/history.png',
name: '聊天记录',
intro: '用户输入的内容。该模块通常作为应用的入口,用户在发送消息后会首先执行该模块。',
type: 'initInput',
flowType: 'historyNode',
url: '/openapi/modules/init/history',
inputs: [
{
key: 'maxContext',
type: 'numberInput',
label: '最长记录数',
value: 4,
min: 0,
max: 50,
connected: false
},
{
key: 'history',
type: 'hidden',
label: '聊天记录',
connected: false
}
],
outputs: [
{
key: 'history',
label: '聊天记录',
type: 'source',
targets: [
{
moduleId: '3n49vn',
key: 'history'
}
]
}
],
position: {
x: 1182.3679138395933,
y: 882.21575235563
},
moduleId: 'hh6of9'
},
{
logo: '/imgs/module/AI.png',
name: 'AI 对话',
intro: 'OpenAI GPT 大模型对话。',
flowType: 'chatNode',
type: 'http',
url: '/openapi/modules/chat/gpt',
inputs: [
{
key: 'model',
type: 'select',
label: '对话模型',
value: 'gpt-3.5-turbo-16k',
list: [
{
label: 'Gpt35-16k',
value: 'gpt-3.5-turbo-16k'
},
{
label: 'Gpt35-4k',
value: 'gpt-3.5-turbo'
},
{
label: 'Gpt4-8k',
value: 'gpt-4'
}
],
connected: false
},
{
key: 'temperature',
type: 'slider',
label: '温度',
value: 0,
min: 0,
max: 10,
step: 1,
markList: [
{
label: '严谨',
value: 0
},
{
label: '发散',
value: 10
}
],
connected: false
},
{
key: 'maxToken',
type: 'slider',
label: '回复上限',
value: 3000,
min: 0,
max: 4000,
step: 50,
markList: [
{
label: '0',
value: 0
},
{
label: '4000',
value: 4000
}
],
connected: false
},
{
key: 'systemPrompt',
type: 'textarea',
label: '系统提示词',
description:
'模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。',
placeholder:
'模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。',
value: '',
connected: false
},
{
key: 'limitPrompt',
type: 'textarea',
label: '限定词',
description:
'限定模型对话范围,会被放置在本次提问前,拥有强引导和限定性。例如:\n1. 知识库是关于 Laf 的介绍,参考知识库回答问题,与 "Laf" 无关内容,直接回复: "我不知道"。\n2. 你仅回答关于 "xxx" 的问题,其他问题回复: "xxxx"',
placeholder:
'限定模型对话范围,会被放置在本次提问前,拥有强引导和限定性。例如:\n1. 知识库是关于 Laf 的介绍,参考知识库回答问题,与 "Laf" 无关内容,直接回复: "我不知道"。\n2. 你仅回答关于 "xxx" 的问题,其他问题回复: "xxxx"',
value: '',
connected: false
},
{
key: 'switch',
type: 'target',
label: '触发器',
connected: false
},
{
key: 'quotePrompt',
type: 'target',
label: '引用内容',
connected: true
},
{
key: 'history',
type: 'target',
label: '聊天记录',
connected: true
},
{
key: 'userChatInput',
type: 'target',
label: '用户问题',
connected: true
}
],
outputs: [
{
key: 'answerText',
label: '模型回复',
description: '直接响应,无需配置',
type: 'hidden',
targets: []
}
],
position: {
x: 1611.18354309989,
y: -56.531590452502826
},
moduleId: '3n49vn'
}, },
{ {
key: 'systemPrompt', logo: '/imgs/module/db.png',
type: FlowInputItemTypeEnum.textarea, name: '知识库搜索',
label: '系统提示词', intro: '去知识库中搜索对应的答案。可作为 AI 对话引用参考。',
description: flowType: 'kbSearchNode',
'模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。', type: 'http',
placeholder: url: '/openapi/modules/kb/search',
'模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。', inputs: [
value: systemPrompt {
key: 'kb_ids',
type: 'custom',
label: '关联的知识库',
value: [],
list: [],
connected: false
},
{
key: 'similarity',
type: 'slider',
label: '相似度',
value: 0.8,
min: 0,
max: 1,
step: 0.01,
markList: [
{
label: '0',
value: 0
},
{
label: '1',
value: 1
}
],
connected: false
},
{
key: 'limit',
type: 'slider',
label: '单次搜索上限',
value: 5,
min: 1,
max: 20,
step: 1,
markList: [
{
label: '1',
value: 1
},
{
label: '20',
value: 20
}
],
connected: false
},
{
key: 'switch',
type: 'target',
label: '触发器',
connected: false
},
{
key: 'userChatInput',
type: 'target',
label: '用户问题',
connected: true
}
],
outputs: [
{
key: 'rawSearch',
label: '源搜索数据',
type: 'hidden',
response: true,
targets: []
},
{
key: 'isEmpty',
label: '搜索结果为空',
type: 'source',
targets: [
{
moduleId: 'gbnzif',
key: 'switch'
}
]
},
{
key: 'quotePrompt',
label: '引用内容',
description: '搜索结果为空时不返回',
type: 'source',
targets: [
{
moduleId: '3n49vn',
key: 'quotePrompt'
}
]
}
],
position: {
x: 718.7528704477357,
y: 112.64438442321625
},
moduleId: 'zid0fj'
}, },
{ {
key: 'limitPrompt', logo: '/imgs/module/reply.png',
type: FlowInputItemTypeEnum.textarea, name: '指定回复',
label: '限定词', intro: '该模块可以直接回复一段指定的内容。常用于引导、提示。',
description: type: 'answer',
'限定模型对话范围,会被放置在本次提问前,拥有强引导和限定性。例如:\n1. 知识库是关于 Laf 的介绍,参考知识库回答问题,与 "Laf" 无关内容,直接回复: "我不知道"。\n2. 你仅回答关于 "xxx" 的问题,其他问题回复: "xxxx"', flowType: 'answerNode',
placeholder: inputs: [
'限定模型对话范围,会被放置在本次提问前,拥有强引导和限定性。例如:\n1. 知识库是关于 Laf 的介绍,参考知识库回答问题,与 "Laf" 无关内容,直接回复: "我不知道"。\n2. 你仅回答关于 "xxx" 的问题,其他问题回复: "xxxx"', {
value: limitPrompt key: 'switch',
type: 'target',
label: '触发器',
connected: true
},
{
key: 'answerText',
value: '对不起,你的问题不在知识库中。',
type: 'input',
label: '回复的内容',
connected: false
}
],
outputs: [],
position: {
x: 1171.1202953011716,
y: 213.00404490394536
},
moduleId: 'gbnzif'
}
]
},
{
id: 'chatGuide',
avatar: '/imgs/module/db.png',
name: '问答前引导',
intro: '可以在每次对话开始前提示用户填写一些内容,作为本次对话的永久内容',
modules: []
},
{
id: 'CQ',
avatar: '/imgs/module/cq.png',
name: '意图识别 + 知识库',
intro: '先对用户的问题进行分类,再根据不同类型问题,执行不同的操作',
modules: [
{
logo: '/imgs/module/userChatInput.png',
name: '用户问题',
intro: '用户输入的内容。该模块通常作为应用的入口,用户在发送消息后会首先执行该模块。',
type: 'initInput',
flowType: 'questionInput',
url: '/openapi/modules/init/userChatInput',
inputs: [
{
key: 'userChatInput',
type: 'systemInput',
label: '用户问题',
connected: false
}
],
outputs: [
{
key: 'userChatInput',
label: '用户问题',
type: 'source',
targets: [
{
moduleId: '3n49vn',
key: 'userChatInput'
},
{
moduleId: 'zid0fj',
key: 'userChatInput'
},
{
moduleId: 'gm15of',
key: 'userChatInput'
}
]
}
],
position: {
x: -33.86673792997432,
y: 874.685676808633
},
moduleId: 'xzj0oo'
}, },
{ {
key: SystemInputEnum.switch, logo: '/imgs/module/history.png',
type: FlowInputItemTypeEnum.target, name: '聊天记录',
label: '触发器', intro: '用户输入的内容。该模块通常作为应用的入口,用户在发送消息后会首先执行该模块。',
connected: true type: 'initInput',
flowType: 'historyNode',
url: '/openapi/modules/init/history',
inputs: [
{
key: 'maxContext',
type: 'numberInput',
label: '最长记录数',
value: 4,
min: 0,
max: 50,
connected: false
},
{
key: 'history',
type: 'hidden',
label: '聊天记录',
connected: false
}
],
outputs: [
{
key: 'history',
label: '聊天记录',
type: 'source',
targets: [
{
moduleId: '3n49vn',
key: 'history'
}
]
}
],
position: {
x: 1388.8842960266352,
y: 854.1553026226809
},
moduleId: 'hh6of9'
}, },
{ {
key: 'quotePrompt', logo: '/imgs/module/AI.png',
type: FlowInputItemTypeEnum.target, name: 'AI 对话',
label: '引用内容(字符串)', intro: 'OpenAI GPT 大模型对话。',
connected: true flowType: 'chatNode',
type: 'http',
url: '/openapi/modules/chat/gpt',
inputs: [
{
key: 'model',
type: 'select',
label: '对话模型',
value: 'gpt-3.5-turbo-16k',
list: [
{
label: 'Gpt35-16k',
value: 'gpt-3.5-turbo-16k'
},
{
label: 'Gpt35-4k',
value: 'gpt-3.5-turbo'
},
{
label: 'Gpt4-8k',
value: 'gpt-4'
}
],
connected: false
},
{
key: 'temperature',
type: 'slider',
label: '温度',
value: 0,
min: 0,
max: 10,
step: 1,
markList: [
{
label: '严谨',
value: 0
},
{
label: '发散',
value: 10
}
],
connected: false
},
{
key: 'maxToken',
type: 'slider',
label: '回复上限',
value: 3000,
min: 0,
max: 4000,
step: 50,
markList: [
{
label: '0',
value: 0
},
{
label: '4000',
value: 4000
}
],
connected: false
},
{
key: 'systemPrompt',
type: 'textarea',
label: '系统提示词',
description:
'模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。',
placeholder:
'模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。',
value: '知识库是关于 Laf 的介绍,根据知识库内容回答问题。',
connected: false
},
{
key: 'limitPrompt',
type: 'textarea',
label: '限定词',
description:
'限定模型对话范围,会被放置在本次提问前,拥有强引导和限定性。例如:\n1. 知识库是关于 Laf 的介绍,参考知识库回答问题,与 "Laf" 无关内容,直接回复: "我不知道"。\n2. 你仅回答关于 "xxx" 的问题,其他问题回复: "xxxx"',
placeholder:
'限定模型对话范围,会被放置在本次提问前,拥有强引导和限定性。例如:\n1. 知识库是关于 Laf 的介绍,参考知识库回答问题,与 "Laf" 无关内容,直接回复: "我不知道"。\n2. 你仅回答关于 "xxx" 的问题,其他问题回复: "xxxx"',
value: '',
connected: false
},
{
key: 'switch',
type: 'target',
label: '触发器',
connected: false
},
{
key: 'quotePrompt',
type: 'target',
label: '引用内容',
connected: true
},
{
key: 'history',
type: 'target',
label: '聊天记录',
connected: true
},
{
key: 'userChatInput',
type: 'target',
label: '用户问题',
connected: true
}
],
outputs: [
{
key: 'answerText',
label: '模型回复',
description: '直接响应,无需配置',
type: 'hidden',
targets: []
}
],
position: {
x: 1827.0428559231655,
y: 446.8058354748067
},
moduleId: '3n49vn'
}, },
{ {
key: SystemInputEnum.history, logo: '/imgs/module/db.png',
type: FlowInputItemTypeEnum.numberInput, name: '知识库搜索',
label: '最长上下文', intro: '去知识库中搜索对应的答案。可作为 AI 对话引用参考。',
description: '为 0 时,代表不需要上下文。', flowType: 'kbSearchNode',
value: history, type: 'http',
min: 0, url: '/openapi/modules/kb/search',
max: 50 inputs: [
{
key: 'kb_ids',
type: 'custom',
label: '关联的知识库',
value: [],
list: [],
connected: false
},
{
key: 'similarity',
type: 'slider',
label: '相似度',
value: 0.8,
min: 0,
max: 1,
step: 0.01,
markList: [
{
label: '0',
value: 0
},
{
label: '1',
value: 1
}
],
connected: false
},
{
key: 'limit',
type: 'slider',
label: '单次搜索上限',
value: 5,
min: 1,
max: 20,
step: 1,
markList: [
{
label: '1',
value: 1
},
{
label: '20',
value: 20
}
],
connected: false
},
{
key: 'switch',
type: 'target',
label: '触发器',
connected: true
},
{
key: 'userChatInput',
type: 'target',
label: '用户问题',
connected: true
}
],
outputs: [
{
key: 'rawSearch',
label: '源搜索数据',
type: 'hidden',
response: true,
targets: []
},
{
key: 'isEmpty',
label: '搜索结果为空',
type: 'source',
targets: [
{
moduleId: 'gbnzif',
key: 'switch'
}
]
},
{
key: 'quotePrompt',
label: '引用内容',
description: '搜索结果为空时不返回',
type: 'source',
targets: [
{
moduleId: '3n49vn',
key: 'quotePrompt'
}
]
}
],
position: {
x: 850.3203039824494,
y: 919.7043887997417
},
moduleId: 'zid0fj'
}, },
{ {
key: SystemInputEnum.userChatInput, logo: '/imgs/module/reply.png',
type: FlowInputItemTypeEnum.none, name: '指定回复',
label: '用户输入(系统自动填写)', intro: '该模块可以直接回复一段指定的内容。常用于引导、提示。',
description: '' type: 'answer',
} flowType: 'answerNode',
], inputs: [
outputs: [ {
key: 'switch',
type: 'target',
label: '触发器',
connected: true
},
{
key: 'answerText',
value: '对不起,我找不到你的问题。',
type: 'input',
label: '回复的内容',
connected: false
}
],
outputs: [],
position: {
x: 1392.0649222586217,
y: 553.0130337399224
},
moduleId: 'gbnzif'
},
{ {
key: 'answer', logo: '/imgs/module/cq.png',
label: '模型回复', name: '意图识别',
type: FlowOutputItemTypeEnum.answer, intro: '可以判断用户问题属于哪方面问题,从而执行不同的操作。',
targets: [] type: 'http',
url: '/openapi/modules/agent/classifyQuestion',
flowType: 'classifyQuestionNode',
inputs: [
{
key: 'systemPrompt',
type: 'textarea',
label: '系统提示词',
description:
'你可以添加一些特定内容的介绍,从而更好的识别用户的问题类型。这个内容通常是给模型介绍一个它不知道的内容。',
placeholder: '例如: \n1. Laf 是一个云函数开发平台……\n2. Sealos 是一个集群操作系统',
value:
'Laf 一个云函数开发平台,提供了基于 Node 的 serveless 的快速开发和部署。是一个集「函数计算」、「数据库」、「对象存储」等于一身的一站式开发平台。支持云函数、云数据库、在线编程 IDE、触发器、云存储和静态网站托管等功能。',
connected: false
},
{
key: 'history',
type: 'target',
label: '聊天记录',
connected: false
},
{
key: 'userChatInput',
type: 'target',
label: '用户问题',
connected: true
},
{
key: 'agents',
type: 'custom',
label: '',
value: [
{
value: '打招呼、问候、身份询问等问题',
key: 'a'
},
{
value: '商务类、联系方式问题',
key: 'b'
},
{
value: '其他问题',
key: 'ek3f'
},
{
value: '关于 Laf 云函数问题',
key: 'psau'
}
],
connected: false
}
],
outputs: [
{
key: 'a',
label: '',
type: 'hidden',
targets: [
{
moduleId: '6jnrp5',
key: 'switch'
}
]
},
{
key: 'b',
label: '',
type: 'hidden',
targets: [
{
moduleId: 'g13ipe',
key: 'switch'
}
]
},
{
key: 'ek3f',
label: '',
type: 'hidden',
targets: [
{
moduleId: 'gbnzif',
key: 'switch'
}
]
},
{
key: 'psau',
label: '',
type: 'hidden',
targets: [
{
moduleId: 'zid0fj',
key: 'switch'
}
]
}
],
position: {
x: 366.0894497581114,
y: 250.81741383805945
},
moduleId: 'gm15of'
},
{
logo: '/imgs/module/reply.png',
name: '指定回复',
intro: '该模块可以直接回复一段指定的内容。常用于引导、提示。',
type: 'answer',
flowType: 'answerNode',
inputs: [
{
key: 'switch',
type: 'target',
label: '触发器',
connected: true
},
{
key: 'answerText',
value: '你好,我是 Laf 助手,可以回答你 Laf 相关问题。',
type: 'input',
label: '回复的内容',
connected: false
}
],
outputs: [],
position: {
x: 855.9439119466947,
y: 15.463108315267931
},
moduleId: '6jnrp5'
},
{
logo: '/imgs/module/reply.png',
name: '指定回复',
intro: '该模块可以直接回复一段指定的内容。常用于引导、提示。',
type: 'answer',
flowType: 'answerNode',
inputs: [
{
key: 'switch',
type: 'target',
label: '触发器',
connected: true
},
{
key: 'answerText',
value: '联系方式:xxxxx',
type: 'input',
label: '回复的内容',
connected: false
}
],
outputs: [],
position: {
x: 854.0492662385566,
y: 320.5010673254856
},
moduleId: 'g13ipe'
} }
] ]
}; }
}; ];
export const chatAppDemo: AppItemType = {
id: 'chat',
name: '',
// 标记字段
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: []
// },
// {
// 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 = { // export const classifyQuestionDemo: AppItemType = {
// id: 'classifyQuestionDemo', // id: 'classifyQuestionDemo',
......
...@@ -72,6 +72,12 @@ export async function kbSearch({ ...@@ -72,6 +72,12 @@ export async function kbSearch({
maxToken = 2500, maxToken = 2500,
userChatInput userChatInput
}: Props): Promise<Response> { }: Props): Promise<Response> {
if (kb_ids.length === 0)
return {
isEmpty: true,
rawSearch: [],
quotePrompt: undefined
};
// get vector // get vector
const promptVector = await openaiEmbedding_system({ const promptVector = await openaiEmbedding_system({
input: [userChatInput] input: [userChatInput]
......
...@@ -238,7 +238,7 @@ const Settings = ({ modelId }: { modelId: string }) => { ...@@ -238,7 +238,7 @@ const Settings = ({ modelId }: { modelId: string }) => {
router.prefetch('/chat'); router.prefetch('/chat');
await saveUpdateModel(); await saveUpdateModel();
} catch (error) {} } catch (error) {}
router.push(`/chat?modelId=${modelId}`); router.push(`/chat?appId=${modelId}`);
}} }}
> >
对话 对话
......
...@@ -31,8 +31,8 @@ const ModuleStoreList = ({ ...@@ -31,8 +31,8 @@ const ModuleStoreList = ({
position={'fixed'} position={'fixed'}
top={0} top={0}
left={0} left={0}
right={0}
bottom={0} bottom={0}
w={'360px'}
></Box> ></Box>
<Flex <Flex
zIndex={3} zIndex={3}
...@@ -66,7 +66,7 @@ const ModuleStoreList = ({ ...@@ -66,7 +66,7 @@ const ModuleStoreList = ({
borderRadius={'md'} borderRadius={'md'}
draggable draggable
onDragEnd={(e) => { onDragEnd={(e) => {
// if (e.clientX < 400) return; if (e.clientX < 360) return;
onAddNode({ onAddNode({
template: item, template: item,
position: { x: e.clientX, y: e.clientY } position: { x: e.clientX, y: e.clientY }
......
...@@ -187,6 +187,7 @@ const AppEdit = ({ app, onBack }: Props) => { ...@@ -187,6 +187,7 @@ const AppEdit = ({ app, onBack }: Props) => {
targets: [] as FlowOutputTargetItemType[] targets: [] as FlowOutputTargetItemType[]
})) }))
})); }));
console.log(modules);
// update inputs and outputs // update inputs and outputs
modules.forEach((module) => { modules.forEach((module) => {
......
...@@ -83,7 +83,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => { ...@@ -83,7 +83,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
<Box display={['block', 'flex']} h={'100%'}> <Box display={['block', 'flex']} h={'100%'}>
{/* pc tab */} {/* pc tab */}
<Box display={['none', 'block']} p={4} w={'200px'} borderRight={theme.borders.base}> <Box display={['none', 'block']} p={4} w={'200px'} borderRight={theme.borders.base}>
<Flex mb={4}> <Flex mb={4} alignItems={'center'}>
<Avatar src={appDetail.avatar} w={'34px'} borderRadius={'lg'} /> <Avatar src={appDetail.avatar} w={'34px'} borderRadius={'lg'} />
<Box ml={2} fontWeight={'bold'}> <Box ml={2} fontWeight={'bold'}>
{appDetail.name} {appDetail.name}
...@@ -97,7 +97,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => { ...@@ -97,7 +97,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
activeId={currentTab} activeId={currentTab}
onChange={(e: any) => { onChange={(e: any) => {
if (e === 'startChat') { if (e === 'startChat') {
router.push(`/chat?modelId=${appId}`); router.push(`/chat?appId=${appId}`);
} else { } else {
setCurrentTab(e); setCurrentTab(e);
} }
...@@ -118,7 +118,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => { ...@@ -118,7 +118,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
activeId={currentTab} activeId={currentTab}
onChange={(e: any) => { onChange={(e: any) => {
if (e === 'startChat') { if (e === 'startChat') {
router.push(`/chat?modelId=${appId}`); router.push(`/chat?appId=${appId}`);
} else { } else {
setCurrentTab(e); setCurrentTab(e);
} }
......
...@@ -21,47 +21,16 @@ import { getErrText } from '@/utils/tools'; ...@@ -21,47 +21,16 @@ import { getErrText } from '@/utils/tools';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/hooks/useToast';
import { postCreateApp } from '@/api/app'; import { postCreateApp } from '@/api/app';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { chatAppDemo } from '@/constants/app'; import { appTemplates } from '@/constants/app';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
type FormType = { type FormType = {
avatar: string; avatar: string;
name: string; name: string;
templateId: number; templateId: string;
}; };
const templates = [
{
id: 0,
icon: 'settings',
name: '简单的对话',
intro: '一个极其简单的 AI 对话应用',
modules: chatAppDemo.modules
},
{
id: 1,
icon: 'settings',
name: '基础知识库',
intro: '每次提问时进行一次知识库搜索,将搜索结果注入 LLM 模型进行参考回答',
modules: chatAppDemo.modules
},
{
id: 2,
icon: 'settings',
name: '问答前引导',
intro: '可以在每次对话开始前提示用户填写一些内容,作为本次对话的永久内容',
modules: chatAppDemo.modules
},
{
id: 3,
icon: 'settings',
name: '意图识别 + 知识库',
intro: '先对用户的问题进行分类,再根据不同类型问题,执行不同的操作',
modules: chatAppDemo.modules
}
];
const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: () => void }) => { const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: () => void }) => {
const [refresh, setRefresh] = useState(false); const [refresh, setRefresh] = useState(false);
const [creating, setCreating] = useState(false); const [creating, setCreating] = useState(false);
...@@ -72,7 +41,7 @@ const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: ( ...@@ -72,7 +41,7 @@ const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: (
defaultValues: { defaultValues: {
avatar: '/icon/logo.png', avatar: '/icon/logo.png',
name: '', name: '',
templateId: 0 templateId: appTemplates[0].id
} }
}); });
...@@ -110,7 +79,7 @@ const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: ( ...@@ -110,7 +79,7 @@ const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: (
const id = await postCreateApp({ const id = await postCreateApp({
avatar: data.avatar, avatar: data.avatar,
name: data.name, name: data.name,
modules: templates.find((item) => item.id === data.templateId)?.modules || [] modules: appTemplates.find((item) => item.id === data.templateId)?.modules || []
}); });
toast({ toast({
title: '创建成功', title: '创建成功',
...@@ -163,7 +132,7 @@ const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: ( ...@@ -163,7 +132,7 @@ const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: (
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)']} gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)']}
gridGap={4} gridGap={4}
> >
{templates.map((item) => ( {appTemplates.map((item) => (
<Card <Card
key={item.id} key={item.id}
border={theme.borders.base} border={theme.borders.base}
...@@ -186,7 +155,7 @@ const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: ( ...@@ -186,7 +155,7 @@ const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: (
}} }}
> >
<Flex alignItems={'center'}> <Flex alignItems={'center'}>
<MyIcon name={'apikey'} w={'16px'} /> <Avatar src={item.avatar} borderRadius={'md'} w={'20px'} />
<Box ml={3} fontWeight={'bold'}> <Box ml={3} fontWeight={'bold'}>
{item.name} {item.name}
</Box> </Box>
......
...@@ -89,22 +89,27 @@ const MyApps = () => { ...@@ -89,22 +89,27 @@ const MyApps = () => {
border={theme.borders.md} border={theme.borders.md}
boxShadow={'none'} boxShadow={'none'}
userSelect={'none'} userSelect={'none'}
position={'relative'}
_hover={{ _hover={{
boxShadow: '1px 1px 10px rgba(0,0,0,0.2)', boxShadow: '1px 1px 10px rgba(0,0,0,0.2)',
borderColor: 'transparent', borderColor: 'transparent',
'& .delete': { '& .delete': {
display: 'block' display: 'block'
},
'& .chat': {
display: 'block'
} }
}} }}
onClick={() => router.push(`/app/detail?appId=${app._id}`)} onClick={() => router.push(`/app/detail?appId=${app._id}`)}
> >
<Flex alignItems={'center'} h={'38px'} position={'relative'}> <Flex alignItems={'center'} h={'38px'}>
<Avatar src={app.avatar} borderRadius={'md'} w={'28px'} /> <Avatar src={app.avatar} borderRadius={'md'} w={'28px'} />
<Box ml={3}>{app.name}</Box> <Box ml={3}>{app.name}</Box>
<IconButton <IconButton
className="delete" className="delete"
position={'absolute'} position={'absolute'}
right={0} top={4}
right={4}
size={'sm'} size={'sm'}
icon={<MyIcon name={'delete'} w={'14px'} />} icon={<MyIcon name={'delete'} w={'14px'} />}
variant={'base'} variant={'base'}
...@@ -129,6 +134,25 @@ const MyApps = () => { ...@@ -129,6 +134,25 @@ const MyApps = () => {
> >
{app.intro || '这个应用还没写介绍~'} {app.intro || '这个应用还没写介绍~'}
</Box> </Box>
<IconButton
className="chat"
position={'absolute'}
right={4}
bottom={4}
size={'sm'}
icon={<MyIcon name={'chatLight'} w={'14px'} />}
variant={'base'}
borderRadius={'md'}
aria-label={'delete'}
display={['', 'none']}
_hover={{
bg: 'myGray.100'
}}
onClick={(e) => {
e.stopPropagation();
router.push(`/chat?appId=${app._id}`);
}}
/>
</Card> </Card>
))} ))}
</Grid> </Grid>
......
...@@ -77,7 +77,7 @@ const ShareModelList = ({ ...@@ -77,7 +77,7 @@ const ShareModelList = ({
size={'sm'} size={'sm'}
variant={'base'} variant={'base'}
w={['60px', '70px']} w={['60px', '70px']}
onClick={() => router.push(`/chat?modelId=${model._id}`)} onClick={() => router.push(`/chat?appId=${model._id}`)}
> >
体验 体验
</Button> </Button>
......
...@@ -125,7 +125,7 @@ const PcSliderBar = ({ ...@@ -125,7 +125,7 @@ const PcSliderBar = ({
w={'100%'} w={'100%'}
h={'100%'} h={'100%'}
leftIcon={<AddIcon />} leftIcon={<AddIcon />}
onClick={() => router.replace(`/chat?modelId=${modelId}`)} onClick={() => router.replace(`/chat?appId=${modelId}`)}
> >
新对话 新对话
</Button> </Button>
...@@ -176,9 +176,9 @@ const PcSliderBar = ({ ...@@ -176,9 +176,9 @@ const PcSliderBar = ({
onClick={() => { onClick={() => {
if (item._id === chatId) return; if (item._id === chatId) return;
if (isPc) { if (isPc) {
router.replace(`/chat?modelId=${item.modelId}&chatId=${item._id}`); router.replace(`/chat?appId=${item.modelId}&chatId=${item._id}`);
} else { } else {
router.push(`/chat?modelId=${item.modelId}&chatId=${item._id}`); router.push(`/chat?appId=${item.modelId}&chatId=${item._id}`);
} }
}} }}
onContextMenu={(e) => onclickContextMenu(e, item)} onContextMenu={(e) => onclickContextMenu(e, item)}
...@@ -251,7 +251,7 @@ const PcSliderBar = ({ ...@@ -251,7 +251,7 @@ const PcSliderBar = ({
try { try {
await onclickDelHistory(contextMenuData.history._id); await onclickDelHistory(contextMenuData.history._id);
if (contextMenuData.history._id === chatId) { if (contextMenuData.history._id === chatId) {
router.replace(`/chat?modelId=${modelId}`); router.replace(`/chat?appId=${modelId}`);
} }
} catch (error) { } catch (error) {
console.log(error); console.log(error);
......
...@@ -30,7 +30,7 @@ const ModelList = ({ models, modelId }: { models: AppListItemType[]; modelId: st ...@@ -30,7 +30,7 @@ const ModelList = ({ models, modelId }: { models: AppListItemType[]; modelId: st
} }
: {})} : {})}
onClick={() => { onClick={() => {
router.replace(`/chat?modelId=${item._id}`); router.replace(`/chat?appId=${item._id}`);
}} }}
> >
<Avatar src={item.avatar} w={'34px'} h={'34px'} /> <Avatar src={item.avatar} w={'34px'} h={'34px'} />
......
...@@ -95,7 +95,7 @@ const PhoneSliderBar = ({ ...@@ -95,7 +95,7 @@ const PhoneSliderBar = ({
color={'white'} color={'white'}
leftIcon={<AddIcon />} leftIcon={<AddIcon />}
onClick={() => { onClick={() => {
router.replace(`/chat?modelId=${modelId}`); router.replace(`/chat?appId=${modelId}`);
onClose(); onClose();
}} }}
> >
...@@ -128,7 +128,7 @@ const PhoneSliderBar = ({ ...@@ -128,7 +128,7 @@ const PhoneSliderBar = ({
: {})} : {})}
onClick={async () => { onClick={async () => {
if (item._id === modelId) return; if (item._id === modelId) return;
router.replace(`/chat?modelId=${item._id}`); router.replace(`/chat?appId=${item._id}`);
onClose(); onClose();
}} }}
> >
...@@ -159,7 +159,7 @@ const PhoneSliderBar = ({ ...@@ -159,7 +159,7 @@ const PhoneSliderBar = ({
: {})} : {})}
onClick={() => { onClick={() => {
if (item._id === chatId) return; if (item._id === chatId) return;
router.replace(`/chat?modelId=${item.modelId}&chatId=${item._id}`); router.replace(`/chat?appId=${item.modelId}&chatId=${item._id}`);
onClose(); onClose();
}} }}
> >
...@@ -177,7 +177,7 @@ const PhoneSliderBar = ({ ...@@ -177,7 +177,7 @@ const PhoneSliderBar = ({
await delChatHistoryById(item._id); await delChatHistoryById(item._id);
loadHistory({ pageNum: 1, init: true }); loadHistory({ pageNum: 1, init: true });
if (item._id === chatId) { if (item._id === chatId) {
router.replace(`/chat?modelId=${modelId}`); router.replace(`/chat?appId=${modelId}`);
} }
}} }}
/> />
......
...@@ -65,7 +65,7 @@ const textareaMinH = '22px'; ...@@ -65,7 +65,7 @@ const textareaMinH = '22px';
const Chat = () => { const Chat = () => {
const router = useRouter(); const router = useRouter();
const { modelId = '', chatId = '' } = router.query as { modelId: string; chatId: string }; const { appId = '', chatId = '' } = router.query as { appId: string; chatId: string };
const theme = useTheme(); const theme = useTheme();
const ChatBox = useRef<HTMLDivElement>(null); const ChatBox = useRef<HTMLDivElement>(null);
...@@ -179,7 +179,7 @@ const Chat = () => { ...@@ -179,7 +179,7 @@ const Chat = () => {
data: { data: {
messages, messages,
chatId, chatId,
appId: modelId, appId,
model: '' model: ''
}, },
onMessage: (text: string) => { onMessage: (text: string) => {
...@@ -206,7 +206,7 @@ const Chat = () => { ...@@ -206,7 +206,7 @@ const Chat = () => {
// save chat // save chat
if (newChatId) { if (newChatId) {
setForbidLoadChatData(true); setForbidLoadChatData(true);
router.replace(`/chat?modelId=${modelId}&chatId=${newChatId}`); router.replace(`/chat?appId=${appId}&chatId=${newChatId}`);
} }
abortSignal.signal.aborted && (await delay(500)); abortSignal.signal.aborted && (await delay(500));
...@@ -243,7 +243,7 @@ const Chat = () => { ...@@ -243,7 +243,7 @@ const Chat = () => {
}, },
[ [
chatId, chatId,
modelId, appId,
setChatData, setChatData,
generatingMessage, generatingMessage,
setForbidLoadChatData, setForbidLoadChatData,
...@@ -474,17 +474,17 @@ const Chat = () => { ...@@ -474,17 +474,17 @@ const Chat = () => {
// 获取对话信息 // 获取对话信息
const loadChatInfo = useCallback( const loadChatInfo = useCallback(
async ({ async ({
modelId, appId,
chatId, chatId,
loading = false loading = false
}: { }: {
modelId: string; appId: string;
chatId: string; chatId: string;
loading?: boolean; loading?: boolean;
}) => { }) => {
try { try {
loading && setIsLoading(true); loading && setIsLoading(true);
const res = await getInitChatSiteInfo(modelId, chatId); const res = await getInitChatSiteInfo(appId, chatId);
setChatData({ setChatData({
...res, ...res,
...@@ -502,9 +502,9 @@ const Chat = () => { ...@@ -502,9 +502,9 @@ const Chat = () => {
} }
// 空 modelId 请求, 重定向到新的 model 聊天 // 空 modelId 请求, 重定向到新的 model 聊天
if (res.modelId !== modelId) { if (res.modelId !== appId) {
setForbidLoadChatData(true); setForbidLoadChatData(true);
router.replace(`/chat?modelId=${res.modelId}`); router.replace(`/chat?appId=${res.modelId}`);
} }
} catch (e: any) { } catch (e: any) {
// reset all chat tore // reset all chat tore
...@@ -529,15 +529,15 @@ const Chat = () => { ...@@ -529,15 +529,15 @@ const Chat = () => {
] ]
); );
// 初始化聊天框 // 初始化聊天框
useQuery(['init', modelId, chatId], () => { useQuery(['init', appId, chatId], () => {
// pc: redirect to latest model chat // pc: redirect to latest model chat
if (!modelId && lastChatModelId) { if (!appId && lastChatModelId) {
router.replace(`/chat?modelId=${lastChatModelId}&chatId=${lastChatId}`); router.replace(`/chat?appId=${lastChatModelId}&chatId=${lastChatId}`);
return null; return null;
} }
// store id // store id
modelId && setLastChatModelId(modelId); appId && setLastChatModelId(appId);
setLastChatId(chatId); setLastChatId(chatId);
if (forbidLoadChatData) { if (forbidLoadChatData) {
...@@ -546,7 +546,7 @@ const Chat = () => { ...@@ -546,7 +546,7 @@ const Chat = () => {
} }
return loadChatInfo({ return loadChatInfo({
modelId, appId,
chatId, chatId,
loading: true loading: true
}); });
...@@ -559,7 +559,7 @@ const Chat = () => { ...@@ -559,7 +559,7 @@ const Chat = () => {
isLeavePage.current = true; isLeavePage.current = true;
controller.current?.abort(); controller.current?.abort();
}; };
}, [modelId, chatId]); }, [appId, chatId]);
// context menu component // context menu component
const RenderContextMenu = useCallback( const RenderContextMenu = useCallback(
...@@ -611,14 +611,14 @@ const Chat = () => { ...@@ -611,14 +611,14 @@ const Chat = () => {
backgroundColor={useColorModeValue('#fdfdfd', '')} backgroundColor={useColorModeValue('#fdfdfd', '')}
> >
{/* pc always show history. */} {/* pc always show history. */}
{(isPc || !modelId) && ( {(isPc || !appId) && (
<SideBar> <SideBar>
<History onclickDelHistory={onclickDelHistory} onclickExportChat={onclickExportChat} /> <History onclickDelHistory={onclickDelHistory} onclickExportChat={onclickExportChat} />
</SideBar> </SideBar>
)} )}
{/* 聊天内容 */} {/* 聊天内容 */}
{modelId && ( {appId && (
<Flex <Flex
position={'relative'} position={'relative'}
h={[0, '100%']} h={[0, '100%']}
...@@ -667,15 +667,13 @@ const Chat = () => { ...@@ -667,15 +667,13 @@ const Chat = () => {
/> />
</MenuButton> </MenuButton>
<MenuList minW={`90px !important`}> <MenuList minW={`90px !important`}>
<MenuItem onClick={() => router.replace(`/chat?modelId=${modelId}`)}> <MenuItem onClick={() => router.replace(`/chat?appId=${appId}`)}>新对话</MenuItem>
新对话
</MenuItem>
<MenuItem <MenuItem
onClick={async () => { onClick={async () => {
try { try {
setIsLoading(true); setIsLoading(true);
await onclickDelHistory(chatData.chatId); await onclickDelHistory(chatData.chatId);
router.replace(`/chat?modelId=${modelId}`); router.replace(`/chat?appId=${appId}`);
} catch (err) { } catch (err) {
console.log(err); console.log(err);
} }
...@@ -901,7 +899,7 @@ const Chat = () => { ...@@ -901,7 +899,7 @@ const Chat = () => {
<Drawer isOpen={isOpenSlider} placement="left" size={'xs'} onClose={onCloseSlider}> <Drawer isOpen={isOpenSlider} placement="left" size={'xs'} onClose={onCloseSlider}>
<DrawerOverlay backgroundColor={'rgba(255,255,255,0.5)'} /> <DrawerOverlay backgroundColor={'rgba(255,255,255,0.5)'} />
<DrawerContent maxW={'70%'}> <DrawerContent maxW={'70%'}>
<PhoneSliderBar chatId={chatId} modelId={modelId} onClose={onCloseSlider} /> <PhoneSliderBar chatId={chatId} modelId={appId} onClose={onCloseSlider} />
</DrawerContent> </DrawerContent>
</Drawer> </Drawer>
)} )}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment