4.6.8-production (#822)
* Json completion (#16) * json-completion * fix duplicate * fix * fix: config json * feat: query extension * perf: i18n * 468 doc * json editor * perf: doc * perf: default extension model * docker file * doc * perf: token count * perf: search extension * format * perf: some constants data --------- Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
This commit is contained in:
@@ -48,7 +48,7 @@
|
||||
"model": "gpt-4-0125-preview",
|
||||
"name": "gpt-4-turbo",
|
||||
"maxContext": 125000,
|
||||
"maxResponse": 125000,
|
||||
"maxResponse": 4000,
|
||||
"quoteMaxToken": 100000,
|
||||
"maxTemperature": 1.2,
|
||||
"inputPrice": 0,
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
"quoteTemplate": false,
|
||||
"quotePrompt": false
|
||||
},
|
||||
"cfr": {
|
||||
"background": true
|
||||
},
|
||||
"dataset": {
|
||||
"datasets": true,
|
||||
"similarity": false,
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
"Finish": "Finish",
|
||||
"Input": "Input",
|
||||
"Intro": "Intro",
|
||||
"Invalid Json": "Invalid Json",
|
||||
"Last Step": "Last",
|
||||
"Last use time": "Last use time",
|
||||
"Load Failed": "Load Failed",
|
||||
@@ -274,13 +275,12 @@
|
||||
"deterministic": "Deterministic",
|
||||
"edit": {
|
||||
"Confirm Save App Tip": "The application may be in advanced orchestration mode, and the advanced orchestration configuration will be overwritten after saving, please confirm!",
|
||||
"Open cfr": "Open Cfr",
|
||||
"Out Ad Edit": "You are about to exit the Advanced orchestration page, please confirm",
|
||||
"Prompt Editor": "Prompt Editor",
|
||||
"Query extension background prompt": "Chat background description",
|
||||
"Query extension background tip": "Describing the scope of the current conversation makes it easier for AI to complete first or vague questions, thereby enhancing the knowledge base's ability to continue conversations.\nIf the value is empty, the question completion function is not used for [first question].",
|
||||
"Save and out": "Save out",
|
||||
"UnSave": "UnSave",
|
||||
"cfr background prompt": "Chat background description",
|
||||
"cfr background tip": "Describing the scope of the current conversation makes it easier for AI to complete first or vague questions, thereby enhancing the knowledge base's ability to continue conversations.\nIf the value is empty, the problem completion function is not used for the \"first problem\".\nIf the value is none, the problem completion function is not used."
|
||||
"UnSave": "UnSave"
|
||||
},
|
||||
"error": {
|
||||
"App name can not be empty": "App name can not be empty",
|
||||
@@ -432,6 +432,7 @@
|
||||
},
|
||||
"response": {
|
||||
"Complete Response": "Complete Response",
|
||||
"Extension model": "Extension model",
|
||||
"Plugin Resonse Detail": "Plugin Detail",
|
||||
"Read complete response": "Read Detail",
|
||||
"Read complete response tips": "Click to see the detailed process",
|
||||
@@ -649,10 +650,13 @@
|
||||
},
|
||||
"link": "Link",
|
||||
"search": {
|
||||
"Dataset Search Params": "Dataset Search Params",
|
||||
"Basic params": "Basic settings",
|
||||
"Dataset Search Params": "Dataset search configuration",
|
||||
"Embedding score": "Embedding score",
|
||||
"Empty result response": "Empty Response",
|
||||
"Empty result response Tips": "If you fill in the content, if no suitable content is found, you will directly reply to the content.",
|
||||
"Filter": "Search filter",
|
||||
"Limit": "Search limit",
|
||||
"Max Tokens": "Max Tokens",
|
||||
"Max Tokens Tips": "The maximum number of Tokens in a single search, about 1 word in Chinese =1.7Tokens, about 1 word in English =1 tokens",
|
||||
"Min Similarity": "Min Similarity",
|
||||
@@ -670,6 +674,8 @@
|
||||
"Source id": "Source ID",
|
||||
"Source name": "Source",
|
||||
"Top K": "Top K",
|
||||
"Using cfr": "Open query extension",
|
||||
"Using query extension": "",
|
||||
"mode": {
|
||||
"embedding": "Vector recall",
|
||||
"embedding desc": "Use vectors for text correlation queries",
|
||||
@@ -694,6 +700,9 @@
|
||||
},
|
||||
"search mode": "Search Mode"
|
||||
},
|
||||
"settings": {
|
||||
"Search basic params": ""
|
||||
},
|
||||
"status": {
|
||||
"active": "Ready",
|
||||
"syncing": "Syncing"
|
||||
@@ -752,6 +761,10 @@
|
||||
"Field key": "Key",
|
||||
"Input Type": "Input Type",
|
||||
"Plugin output must connect": "Custom outputs must all be connected",
|
||||
"QueryExtension": {
|
||||
"placeholder": "Questions about python introduction and usage, etc. The current conversation is related to the game GTA5.",
|
||||
"tip": "Describes the scope of the current conversation, making it easier for the AI to complete first or vague questions, thereby enhancing the knowledge base's ability to continue conversations.If \n is empty, the question completion function is not used in the first conversation. "
|
||||
},
|
||||
"Unlink tip": "[{{name}}] An unfilled or unconnected parameter exists",
|
||||
"Variable": "Variables",
|
||||
"Variable Setting": "Variable Setting",
|
||||
@@ -777,7 +790,6 @@
|
||||
"TFSwitch textarea": "Allows you to define a number of strings to achieve false matching, one per line, and supports regular expressions.",
|
||||
"Trigger": "Most of the time, you don't need to concatenate this property. You can connect this property when you need to delay execution, or precisely control the timing of execution.",
|
||||
"anyInput": "Can pass anything ",
|
||||
"cfr background": "Describes the scope of the current conversation, making it easier for the AI to complete first or vague questions, thereby enhancing the knowledge base's ability to continue conversations. If\nis empty, the question completion function is not used in the first conversation. ",
|
||||
"dynamic input": "Receives parameters dynamically added by the user and will be tiled in at run time ",
|
||||
"textEditor textarea": "The passed variable can be referenced by {{key}}. Variables support only strings or numbers."
|
||||
},
|
||||
@@ -794,15 +806,13 @@
|
||||
"TFSwitch textarea": "Custom False matching rule ",
|
||||
"aiModel": "AI model ",
|
||||
"anyInput": "Any input ",
|
||||
"cfr background": "Background",
|
||||
"chat history": "chat history",
|
||||
"switch": "Trigger",
|
||||
"textEditor textarea": "Text edit",
|
||||
"user question": "User question"
|
||||
},
|
||||
"placeholder": {
|
||||
"Classify background": "For example:\n1.AIGC (Artificial Intelligence Generates content) refers to the automatic or semi-automatic generation of digital content, such as text, images, music, videos, and so on, using artificial intelligence technologies. AIGC technologies include, but are not limited to, natural language processing, computer vision, machine learning, and deep learning. These technologies can create new content or modify existing content to meet specific creative, educational, entertainment or information needs.",
|
||||
"cfr background": "Questions about the introduction and use of python. \nThe current dialogue is related to the game GTA5."
|
||||
"Classify background": "For example:\n1.AIGC (Artificial Intelligence Generates content) refers to the automatic or semi-automatic generation of digital content, such as text, images, music, videos, and so on, using artificial intelligence technologies. AIGC technologies include, but are not limited to, natural language processing, computer vision, machine learning, and deep learning. These technologies can create new content or modify existing content to meet specific creative, educational, entertainment or information needs."
|
||||
}
|
||||
},
|
||||
"inputType": {
|
||||
@@ -858,6 +868,8 @@
|
||||
"Http request": "Http request",
|
||||
"Http request intro": " Can issue an HTTP request to implement more complex operations (Internet search, database query, etc.)",
|
||||
"My plugin module": "Personal plugins",
|
||||
"Query extension": "Query extension",
|
||||
"Query extension intro": "If the problem completion function is enabled, the accuracy of knowledge base search can be improved in continuous conversations. After this function is enabled, when searching the knowledge base, AI will be used to complete the missing information of the problem according to the conversation records.",
|
||||
"Response module": "Text output",
|
||||
"Running app": "Running app",
|
||||
"Running app intro": "You can select a different app to run",
|
||||
@@ -867,8 +879,6 @@
|
||||
"Tool module": "Tools",
|
||||
"UnKnow Module": "UnKnow Module",
|
||||
"User guide": "User guide",
|
||||
"cfr": "Coreference resolution",
|
||||
"cfr intro": "Refine the current issue based on history, making it more conducive to knowledge base search, while improving continuous conversation capabilities.",
|
||||
"textEditor": "Text Editor",
|
||||
"textEditor intro": "Output of fixed or incoming text after edit"
|
||||
},
|
||||
@@ -1342,6 +1352,9 @@
|
||||
"Data Length": "Data length",
|
||||
"Dataset store": "",
|
||||
"Duration": "Duration(s)",
|
||||
"Extension Input Token Length": "Extension input tokens",
|
||||
"Extension Output Token Length": "Extension output tokens",
|
||||
"Extension result": "Extension result",
|
||||
"Input Token Length": "Input tokens",
|
||||
"Module name": "Module name",
|
||||
"Next Step Guide": "",
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
"Finish": "完成",
|
||||
"Input": "输入",
|
||||
"Intro": "介绍",
|
||||
"Invalid Json": "无效的JSON格式,请注意检查。",
|
||||
"Last Step": "上一步",
|
||||
"Last use time": "最后使用时间",
|
||||
"Load Failed": "加载失败",
|
||||
@@ -274,13 +275,12 @@
|
||||
"deterministic": "严谨",
|
||||
"edit": {
|
||||
"Confirm Save App Tip": "该应用可能为高级编排模式,保存后将会覆盖高级编排配置,请确认!",
|
||||
"Open cfr": "开启自动补全",
|
||||
"Out Ad Edit": "您即将退出高级编排页面,请确认",
|
||||
"Prompt Editor": "提示词编辑",
|
||||
"Query extension background prompt": "对话背景描述",
|
||||
"Query extension background tip": "描述当前对话的范围,便于AI为当前问题进行补全和扩展。填写的内容,通常为该助手",
|
||||
"Save and out": "保存并退出",
|
||||
"UnSave": "不保存",
|
||||
"cfr background prompt": "对话背景描述",
|
||||
"cfr background tip": "描述当前对话的范围,便于AI补全首次问题或模糊的问题,从而增强知识库连续对话的能力。\n值为空时,表示【首个问题】不使用问题补全功能。\n值为 none 时,表示不使用问题补全功能。"
|
||||
"UnSave": "不保存"
|
||||
},
|
||||
"error": {
|
||||
"App name can not be empty": "应用名不能为空",
|
||||
@@ -432,6 +432,7 @@
|
||||
},
|
||||
"response": {
|
||||
"Complete Response": "完整响应",
|
||||
"Extension model": "问题补全模型",
|
||||
"Plugin Resonse Detail": "插件详情",
|
||||
"Read complete response": "查看详情",
|
||||
"Read complete response tips": "点击查看详细流程",
|
||||
@@ -445,7 +446,7 @@
|
||||
"module http result": "响应体",
|
||||
"module http url": "请求地址",
|
||||
"module limit": "单次搜索上限",
|
||||
"module maxToken": "最大 Tokens",
|
||||
"module maxToken": "最大响应 Tokens",
|
||||
"module model": "模型",
|
||||
"module name": "模型名",
|
||||
"module price": "计费",
|
||||
@@ -548,7 +549,8 @@
|
||||
"success": "开始同步"
|
||||
}
|
||||
},
|
||||
"training": {}
|
||||
"training": {
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"Auxiliary Data": "辅助数据",
|
||||
@@ -650,10 +652,13 @@
|
||||
},
|
||||
"link": "链接",
|
||||
"search": {
|
||||
"Dataset Search Params": "搜索参数",
|
||||
"Basic params": "基础参数",
|
||||
"Dataset Search Params": "知识库搜索配置",
|
||||
"Embedding score": "语意检索得分",
|
||||
"Empty result response": "空搜索回复",
|
||||
"Empty result response Tips": "若填写该内容,没有搜索到合适内容时,将直接回复填写的内容。",
|
||||
"Filter": "搜索过滤",
|
||||
"Limit": "",
|
||||
"Max Tokens": "引用上限",
|
||||
"Max Tokens Tips": "单次搜索最大的 Tokens 数量,中文约1字=1.7Tokens,英文约1字=1Tokens",
|
||||
"Min Similarity": "最低相关度",
|
||||
@@ -671,6 +676,8 @@
|
||||
"Source id": "来源ID",
|
||||
"Source name": "引用来源名",
|
||||
"Top K": "单次搜索上限",
|
||||
"Using cfr": "",
|
||||
"Using query extension": "使用问题补全",
|
||||
"mode": {
|
||||
"embedding": "语义检索",
|
||||
"embedding desc": "使用向量进行文本相关性查询",
|
||||
@@ -695,6 +702,9 @@
|
||||
},
|
||||
"search mode": "搜索模式"
|
||||
},
|
||||
"settings": {
|
||||
"Search basic params": "检索参数"
|
||||
},
|
||||
"status": {
|
||||
"active": "已就绪",
|
||||
"syncing": "同步中"
|
||||
@@ -753,6 +763,10 @@
|
||||
"Field key": "字段 Key",
|
||||
"Input Type": "输入类型",
|
||||
"Plugin output must connect": "自定义输出必须全部连接",
|
||||
"QueryExtension": {
|
||||
"placeholder": "例如:\n关于 python 的介绍和使用等问题。\n当前对话与游戏《GTA5》有关。",
|
||||
"tip": "描述当前对话的范围,便于AI补全首次问题或模糊的问题,从而增强知识库连续对话的能力。建议开启该功能后,都简单的描述在对话的背景,否则容易造成补全对象不准确。"
|
||||
},
|
||||
"Unlink tip": "【{{name}}】存在未填或未连接参数",
|
||||
"Variable": "全局变量",
|
||||
"Variable Setting": "变量设置",
|
||||
@@ -778,7 +792,6 @@
|
||||
"TFSwitch textarea": "允许定义一些字符串来实现 false 匹配,每行一个,支持正则表达式。",
|
||||
"Trigger": "大部分时候,你不需要连接该属性。\n当你需要延迟执行,或精确控制执行时机时,可以连接该属性。",
|
||||
"anyInput": "可传入任意内容",
|
||||
"cfr background": "描述当前对话的范围,便于AI补全首次问题或模糊的问题,从而增强知识库连续对话的能力。\n为空时,表示【首次对话】不使用问题补全功能。",
|
||||
"dynamic input": "接收用户动态添加的参数,会在运行时将这些参数平铺传入",
|
||||
"textEditor textarea": "可以通过 {{key}} 的方式引用传入的变量。变量仅支持字符串或数字。"
|
||||
},
|
||||
@@ -795,15 +808,13 @@
|
||||
"TFSwitch textarea": "自定义 False 匹配规则",
|
||||
"aiModel": "AI 模型",
|
||||
"anyInput": "任意内容输入",
|
||||
"cfr background": "背景知识",
|
||||
"chat history": "聊天记录",
|
||||
"switch": "触发器",
|
||||
"textEditor textarea": "文本编辑",
|
||||
"user question": "用户问题"
|
||||
},
|
||||
"placeholder": {
|
||||
"Classify background": "例如: \n1. AIGC(人工智能生成内容)是指使用人工智能技术自动或半自动地生成数字内容,如文本、图像、音乐、视频等。\n2. AIGC技术包括但不限于自然语言处理、计算机视觉、机器学习和深度学习。这些技术可以创建新内容或修改现有内容,以满足特定的创意、教育、娱乐或信息需求。",
|
||||
"cfr background": "关于 python 的介绍和使用等问题。\n当前对话与游戏《GTA5》有关。"
|
||||
"Classify background": "例如: \n1. AIGC(人工智能生成内容)是指使用人工智能技术自动或半自动地生成数字内容,如文本、图像、音乐、视频等。\n2. AIGC技术包括但不限于自然语言处理、计算机视觉、机器学习和深度学习。这些技术可以创建新内容或修改现有内容,以满足特定的创意、教育、娱乐或信息需求。"
|
||||
}
|
||||
},
|
||||
"inputType": {
|
||||
@@ -859,6 +870,8 @@
|
||||
"Http request": "Http 请求",
|
||||
"Http request intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
|
||||
"My plugin module": "个人插件",
|
||||
"Query extension": "问题补全",
|
||||
"Query extension intro": "开启问题补全功能,可以提高提高连续对话时,知识库搜索的精度。开启该功能后,在进行知识库搜索时,会根据对话记录,利用 AI 补全问题缺失的信息。",
|
||||
"Response module": "文本输出",
|
||||
"Running app": "应用调用",
|
||||
"Running app intro": "可以选择一个其他应用进行调用",
|
||||
@@ -868,8 +881,6 @@
|
||||
"Tool module": "工具",
|
||||
"UnKnow Module": "未知模块",
|
||||
"User guide": "用户引导",
|
||||
"cfr": "问题补全",
|
||||
"cfr intro": "根据历史记录,完善当前问题,使其更利于知识库搜索,同时提高连续对话能力。",
|
||||
"textEditor": "文本加工",
|
||||
"textEditor intro": "可对固定或传入的文本进行加工后输出"
|
||||
},
|
||||
@@ -1343,6 +1354,9 @@
|
||||
"Data Length": "数据长度",
|
||||
"Dataset store": "知识库存储",
|
||||
"Duration": "时长(秒)",
|
||||
"Extension Input Token Length": "问题补全输入Tokens",
|
||||
"Extension Output Token Length": "问题补全输出Tokens",
|
||||
"Extension result": "问题补全结果",
|
||||
"Input Token Length": "输入 Tokens",
|
||||
"Module name": "模块名",
|
||||
"Next Step Guide": "下一步指引",
|
||||
|
||||
@@ -39,8 +39,8 @@ function Row({
|
||||
{...(isCodeBlock
|
||||
? { transform: 'translateY(-3px)' }
|
||||
: value
|
||||
? { px: 3, py: 1, border: theme.borders.base }
|
||||
: {})}
|
||||
? { px: 3, py: 1, border: theme.borders.base }
|
||||
: {})}
|
||||
>
|
||||
{value && <Markdown source={strValue} />}
|
||||
{rawDom}
|
||||
@@ -129,126 +129,154 @@ const ResponseBox = React.memo(function ResponseBox({
|
||||
<Tabs list={list} activeId={currentTab} onChange={setCurrentTab} />
|
||||
</Box>
|
||||
<Box py={2} px={4} flex={'1 0 0'} overflow={'auto'}>
|
||||
<Row label={t('core.chat.response.module name')} value={t(activeModule.moduleName)} />
|
||||
{activeModule?.price !== undefined && (
|
||||
<>
|
||||
<Row label={t('core.chat.response.module name')} value={t(activeModule.moduleName)} />
|
||||
{activeModule?.price !== undefined && (
|
||||
<Row
|
||||
label={t('core.chat.response.module price')}
|
||||
value={`¥${formatStorePrice2Read(activeModule?.price)}`}
|
||||
/>
|
||||
)}
|
||||
<Row
|
||||
label={t('core.chat.response.module price')}
|
||||
value={`¥${formatStorePrice2Read(activeModule?.price)}`}
|
||||
label={t('core.chat.response.module time')}
|
||||
value={`${activeModule?.runningTime || 0}s`}
|
||||
/>
|
||||
)}
|
||||
<Row
|
||||
label={t('core.chat.response.module time')}
|
||||
value={`${activeModule?.runningTime || 0}s`}
|
||||
/>
|
||||
<Row label={t('core.chat.response.module model')} value={activeModule?.model} />
|
||||
<Row label={t('wallet.bill.Chars length')} value={`${activeModule?.charsLength}`} />
|
||||
<Row label={t('wallet.bill.Input Token Length')} value={`${activeModule?.inputTokens}`} />
|
||||
<Row label={t('wallet.bill.Output Token Length')} value={`${activeModule?.outputTokens}`} />
|
||||
<Row label={t('core.chat.response.module query')} value={activeModule?.query} />
|
||||
<Row
|
||||
label={t('core.chat.response.context total length')}
|
||||
value={activeModule?.contextTotalLen}
|
||||
/>
|
||||
<Row label={t('core.chat.response.module model')} value={activeModule?.model} />
|
||||
<Row label={t('wallet.bill.Chars length')} value={`${activeModule?.charsLength}`} />
|
||||
<Row label={t('wallet.bill.Input Token Length')} value={`${activeModule?.inputTokens}`} />
|
||||
<Row
|
||||
label={t('wallet.bill.Output Token Length')}
|
||||
value={`${activeModule?.outputTokens}`}
|
||||
/>
|
||||
<Row label={t('core.chat.response.module query')} value={activeModule?.query} />
|
||||
<Row
|
||||
label={t('core.chat.response.context total length')}
|
||||
value={activeModule?.contextTotalLen}
|
||||
/>
|
||||
</>
|
||||
|
||||
{/* ai chat */}
|
||||
<Row label={t('core.chat.response.module temperature')} value={activeModule?.temperature} />
|
||||
<Row label={t('core.chat.response.module maxToken')} value={activeModule?.maxToken} />
|
||||
<Row
|
||||
label={t('core.chat.response.module historyPreview')}
|
||||
rawDom={
|
||||
activeModule.historyPreview ? (
|
||||
<Box px={3} py={2} border={theme.borders.base} borderRadius={'md'}>
|
||||
{activeModule.historyPreview?.map((item, i) => (
|
||||
<Box
|
||||
key={i}
|
||||
_notLast={{
|
||||
borderBottom: '1px solid',
|
||||
borderBottomColor: 'myWhite.700',
|
||||
mb: 2
|
||||
}}
|
||||
pb={2}
|
||||
>
|
||||
<Box fontWeight={'bold'}>{item.obj}</Box>
|
||||
<Box whiteSpace={'pre-wrap'}>{item.value}</Box>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
) : (
|
||||
''
|
||||
)
|
||||
}
|
||||
/>
|
||||
{activeModule.quoteList && activeModule.quoteList.length > 0 && (
|
||||
<>
|
||||
<Row
|
||||
label={t('core.chat.response.module quoteList')}
|
||||
rawDom={<QuoteList isShare={isShare} rawSearch={activeModule.quoteList} />}
|
||||
label={t('core.chat.response.module temperature')}
|
||||
value={activeModule?.temperature}
|
||||
/>
|
||||
)}
|
||||
<Row label={t('core.chat.response.module maxToken')} value={activeModule?.maxToken} />
|
||||
<Row
|
||||
label={t('core.chat.response.module historyPreview')}
|
||||
rawDom={
|
||||
activeModule.historyPreview ? (
|
||||
<Box px={3} py={2} border={theme.borders.base} borderRadius={'md'}>
|
||||
{activeModule.historyPreview?.map((item, i) => (
|
||||
<Box
|
||||
key={i}
|
||||
_notLast={{
|
||||
borderBottom: '1px solid',
|
||||
borderBottomColor: 'myWhite.700',
|
||||
mb: 2
|
||||
}}
|
||||
pb={2}
|
||||
>
|
||||
<Box fontWeight={'bold'}>{item.obj}</Box>
|
||||
<Box whiteSpace={'pre-wrap'}>{item.value}</Box>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
) : (
|
||||
''
|
||||
)
|
||||
}
|
||||
/>
|
||||
{activeModule.quoteList && activeModule.quoteList.length > 0 && (
|
||||
<Row
|
||||
label={t('core.chat.response.module quoteList')}
|
||||
rawDom={<QuoteList isShare={isShare} rawSearch={activeModule.quoteList} />}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
{/* dataset search */}
|
||||
{activeModule?.searchMode && (
|
||||
<>
|
||||
{activeModule?.searchMode && (
|
||||
<Row
|
||||
label={t('core.dataset.search.search mode')}
|
||||
// @ts-ignore
|
||||
value={t(DatasetSearchModeMap[activeModule.searchMode]?.title)}
|
||||
/>
|
||||
)}
|
||||
<Row label={t('core.chat.response.module similarity')} value={activeModule?.similarity} />
|
||||
<Row label={t('core.chat.response.module limit')} value={activeModule?.limit} />
|
||||
<Row
|
||||
label={t('core.dataset.search.search mode')}
|
||||
// @ts-ignore
|
||||
value={t(DatasetSearchModeMap[activeModule.searchMode]?.title)}
|
||||
label={t('core.chat.response.search using reRank')}
|
||||
value={activeModule?.searchUsingReRank}
|
||||
/>
|
||||
)}
|
||||
<Row label={t('core.chat.response.module similarity')} value={activeModule?.similarity} />
|
||||
<Row label={t('core.chat.response.module limit')} value={activeModule?.limit} />
|
||||
<Row
|
||||
label={t('core.chat.response.search using reRank')}
|
||||
value={activeModule?.searchUsingReRank}
|
||||
/>
|
||||
<Row
|
||||
label={t('core.chat.response.Extension model')}
|
||||
value={activeModule?.extensionModel}
|
||||
/>
|
||||
<Row
|
||||
label={t('wallet.bill.Extension result')}
|
||||
value={`${activeModule?.extensionResult}`}
|
||||
/>
|
||||
</>
|
||||
|
||||
{/* classify question */}
|
||||
<Row
|
||||
label={t('core.chat.response.module cq')}
|
||||
value={(() => {
|
||||
if (!activeModule?.cqList) return '';
|
||||
return activeModule.cqList.map((item) => `* ${item.value}`).join('\n');
|
||||
})()}
|
||||
/>
|
||||
<Row label={t('core.chat.response.module cq result')} value={activeModule?.cqResult} />
|
||||
<>
|
||||
<Row
|
||||
label={t('core.chat.response.module cq')}
|
||||
value={(() => {
|
||||
if (!activeModule?.cqList) return '';
|
||||
return activeModule.cqList.map((item) => `* ${item.value}`).join('\n');
|
||||
})()}
|
||||
/>
|
||||
<Row label={t('core.chat.response.module cq result')} value={activeModule?.cqResult} />
|
||||
</>
|
||||
|
||||
{/* extract */}
|
||||
<Row
|
||||
label={t('core.chat.response.module extract description')}
|
||||
value={activeModule?.extractDescription}
|
||||
/>
|
||||
{activeModule?.extractResult && (
|
||||
<>
|
||||
<Row
|
||||
label={t('core.chat.response.module extract result')}
|
||||
value={`~~~json\n${JSON.stringify(activeModule?.extractResult, null, 2)}`}
|
||||
label={t('core.chat.response.module extract description')}
|
||||
value={activeModule?.extractDescription}
|
||||
/>
|
||||
)}
|
||||
{activeModule?.extractResult && (
|
||||
<Row
|
||||
label={t('core.chat.response.module extract result')}
|
||||
value={`~~~json\n${JSON.stringify(activeModule?.extractResult, null, 2)}`}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
{/* http */}
|
||||
{activeModule?.body && (
|
||||
<Row
|
||||
label={t('core.chat.response.module http body')}
|
||||
value={`~~~json\n${JSON.stringify(activeModule?.body, null, 2)}`}
|
||||
/>
|
||||
)}
|
||||
{activeModule?.httpResult && (
|
||||
<Row
|
||||
label={t('core.chat.response.module http result')}
|
||||
value={`~~~json\n${JSON.stringify(activeModule?.httpResult, null, 2)}`}
|
||||
/>
|
||||
)}
|
||||
<>
|
||||
{activeModule?.body && (
|
||||
<Row
|
||||
label={t('core.chat.response.module http body')}
|
||||
value={`~~~json\n${JSON.stringify(activeModule?.body, null, 2)}`}
|
||||
/>
|
||||
)}
|
||||
{activeModule?.httpResult && (
|
||||
<Row
|
||||
label={t('core.chat.response.module http result')}
|
||||
value={`~~~json\n${JSON.stringify(activeModule?.httpResult, null, 2)}`}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
{/* plugin */}
|
||||
{activeModule?.pluginDetail && activeModule?.pluginDetail.length > 0 && (
|
||||
<Row
|
||||
label={t('core.chat.response.Plugin Resonse Detail')}
|
||||
rawDom={<ResponseBox response={activeModule.pluginDetail} isShare={isShare} />}
|
||||
/>
|
||||
)}
|
||||
{activeModule?.pluginOutput && (
|
||||
<Row
|
||||
label={t('core.chat.response.plugin output')}
|
||||
value={`~~~json\n${JSON.stringify(activeModule?.pluginOutput, null, 2)}`}
|
||||
/>
|
||||
)}
|
||||
<>
|
||||
{activeModule?.pluginDetail && activeModule?.pluginDetail.length > 0 && (
|
||||
<Row
|
||||
label={t('core.chat.response.Plugin Resonse Detail')}
|
||||
rawDom={<ResponseBox response={activeModule.pluginDetail} isShare={isShare} />}
|
||||
/>
|
||||
)}
|
||||
{activeModule?.pluginOutput && (
|
||||
<Row
|
||||
label={t('core.chat.response.plugin output')}
|
||||
value={`~~~json\n${JSON.stringify(activeModule?.pluginOutput, null, 2)}`}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
{/* text output */}
|
||||
<Row label={t('core.chat.response.text output')} value={activeModule?.textOutput} />
|
||||
|
||||
@@ -1011,8 +1011,9 @@ export const useChatBox = () => {
|
||||
const historyDom = document.getElementById('history');
|
||||
if (!historyDom) return;
|
||||
const dom = Array.from(historyDom.children).map((child, i) => {
|
||||
const avatar = `<img src="${child.querySelector<HTMLImageElement>('.avatar')
|
||||
?.src}" alt="" />`;
|
||||
const avatar = `<img src="${
|
||||
child.querySelector<HTMLImageElement>('.avatar')?.src
|
||||
}" alt="" />`;
|
||||
|
||||
const chatContent = child.querySelector<HTMLDivElement>('.markdown');
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ const MySlider = ({
|
||||
borderRadius={'md'}
|
||||
transform={'translate(-50%, -155%)'}
|
||||
fontSize={'11px'}
|
||||
display={'none'}
|
||||
display={['block', 'none']}
|
||||
>
|
||||
<Box transform={'scale(0.9)'}>{value}</Box>
|
||||
</SliderMark>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Box, Grid } from '@chakra-ui/react';
|
||||
import { Box, Flex, Grid, Image } from '@chakra-ui/react';
|
||||
import type { GridProps } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
|
||||
// @ts-ignore
|
||||
interface Props extends GridProps {
|
||||
list: { id: string; label: string | React.ReactNode }[];
|
||||
list: { id: string; icon?: string; label: string | React.ReactNode }[];
|
||||
activeId: string;
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
onChange: (id: string) => void;
|
||||
@@ -46,10 +47,11 @@ const Tabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => {
|
||||
{...props}
|
||||
>
|
||||
{list.map((item) => (
|
||||
<Box
|
||||
<Flex
|
||||
key={item.id}
|
||||
py={sizeMap.inlineP}
|
||||
textAlign={'center'}
|
||||
alignItems={'center'}
|
||||
justifyContent={'center'}
|
||||
borderBottom={'2px solid transparent'}
|
||||
px={3}
|
||||
whiteSpace={'nowrap'}
|
||||
@@ -68,8 +70,17 @@ const Tabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => {
|
||||
onChange(item.id);
|
||||
}}
|
||||
>
|
||||
{item.icon && (
|
||||
<>
|
||||
{item.icon.startsWith('/') ? (
|
||||
<Image mr={1} src={item.icon} alt={''} w={'16px'} />
|
||||
) : (
|
||||
<MyIcon mr={1} name={item.icon as any} w={'16px'} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{typeof item.label === 'string' ? t(item.label) : item.label}
|
||||
</Box>
|
||||
</Flex>
|
||||
))}
|
||||
</Grid>
|
||||
);
|
||||
|
||||
@@ -34,14 +34,12 @@ const AIChatSettingsModal = ({
|
||||
onClose,
|
||||
onSuccess,
|
||||
defaultData,
|
||||
simpleModeTemplate = SimpleModeTemplate_FastGPT_Universal,
|
||||
pickerMenu = []
|
||||
}: {
|
||||
isAdEdit?: boolean;
|
||||
onClose: () => void;
|
||||
onSuccess: (e: AIChatModuleProps) => void;
|
||||
defaultData: AIChatModuleProps;
|
||||
simpleModeTemplate?: AppSimpleEditConfigTemplateType;
|
||||
pickerMenu?: EditorVariablePickerType[];
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -160,119 +158,112 @@ const AIChatSettingsModal = ({
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
{simpleModeTemplate?.systemForm?.aiSettings?.temperature && (
|
||||
<Flex mb={10} mt={isAdEdit ? 8 : 6}>
|
||||
<Box {...LabelStyles} mr={2} w={'80px'}>
|
||||
{t('core.app.Temperature')}
|
||||
</Box>
|
||||
<Box flex={1} ml={'10px'}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: t('core.app.deterministic'), value: 0 },
|
||||
{ label: t('core.app.Random'), value: 10 }
|
||||
]}
|
||||
width={'95%'}
|
||||
min={0}
|
||||
max={10}
|
||||
value={getValues(ModuleInputKeyEnum.aiChatTemperature)}
|
||||
onChange={(e) => {
|
||||
setValue(ModuleInputKeyEnum.aiChatTemperature, e);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
{simpleModeTemplate?.systemForm?.aiSettings?.maxToken && (
|
||||
<Flex mt={5} mb={5}>
|
||||
<Box {...LabelStyles} mr={2} w={'80px'}>
|
||||
{t('core.app.Max tokens')}
|
||||
</Box>
|
||||
<Box flex={1} ml={'10px'}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '100', value: 100 },
|
||||
{ label: `${tokenLimit}`, value: tokenLimit }
|
||||
]}
|
||||
width={'95%'}
|
||||
min={100}
|
||||
max={tokenLimit}
|
||||
step={50}
|
||||
value={getValues(ModuleInputKeyEnum.aiChatMaxToken)}
|
||||
onChange={(val) => {
|
||||
setValue(ModuleInputKeyEnum.aiChatMaxToken, val);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
<Flex mb={10} mt={isAdEdit ? 8 : 6}>
|
||||
<Box {...LabelStyles} mr={2} w={'80px'}>
|
||||
{t('core.app.Temperature')}
|
||||
</Box>
|
||||
<Box flex={1} ml={'10px'}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: t('core.app.deterministic'), value: 0 },
|
||||
{ label: t('core.app.Random'), value: 10 }
|
||||
]}
|
||||
width={'95%'}
|
||||
min={0}
|
||||
max={10}
|
||||
value={getValues(ModuleInputKeyEnum.aiChatTemperature)}
|
||||
onChange={(e) => {
|
||||
setValue(ModuleInputKeyEnum.aiChatTemperature, e);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex mt={5} mb={5}>
|
||||
<Box {...LabelStyles} mr={2} w={'80px'}>
|
||||
{t('core.app.Max tokens')}
|
||||
</Box>
|
||||
<Box flex={1} ml={'10px'}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '100', value: 100 },
|
||||
{ label: `${tokenLimit}`, value: tokenLimit }
|
||||
]}
|
||||
width={'95%'}
|
||||
min={100}
|
||||
max={tokenLimit}
|
||||
step={50}
|
||||
value={getValues(ModuleInputKeyEnum.aiChatMaxToken)}
|
||||
onChange={(val) => {
|
||||
setValue(ModuleInputKeyEnum.aiChatMaxToken, val);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
{simpleModeTemplate?.systemForm?.aiSettings?.quoteTemplate && (
|
||||
<Box>
|
||||
<Flex {...LabelStyles} mb={1}>
|
||||
{t('core.app.Quote templates')}
|
||||
<MyTooltip
|
||||
label={t('template.Quote Content Tip', {
|
||||
default: Prompt_QuoteTemplateList[0].value
|
||||
})}
|
||||
forceShow
|
||||
>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
<Box flex={1} />
|
||||
<Box
|
||||
{...selectTemplateBtn}
|
||||
onClick={() =>
|
||||
setSelectTemplateData({
|
||||
title: t('core.app.Select quote template'),
|
||||
templates: Prompt_QuoteTemplateList
|
||||
})
|
||||
}
|
||||
>
|
||||
{t('common.Select template')}
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
<PromptEditor
|
||||
variables={quoteTemplateVariables}
|
||||
title={t('core.app.Quote templates')}
|
||||
placeholder={t('template.Quote Content Tip', {
|
||||
<Box>
|
||||
<Flex {...LabelStyles} mb={1}>
|
||||
{t('core.app.Quote templates')}
|
||||
<MyTooltip
|
||||
label={t('template.Quote Content Tip', {
|
||||
default: Prompt_QuoteTemplateList[0].value
|
||||
})}
|
||||
value={aiChatQuoteTemplate}
|
||||
onChange={(e) => {
|
||||
setValue(ModuleInputKeyEnum.aiChatQuoteTemplate, e);
|
||||
// setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
{simpleModeTemplate?.systemForm?.aiSettings?.quotePrompt && (
|
||||
<Box mt={4}>
|
||||
<Flex {...LabelStyles} mb={1}>
|
||||
{t('core.app.Quote prompt')}
|
||||
<MyTooltip
|
||||
label={t('template.Quote Prompt Tip', { default: Prompt_QuotePromptList[0].value })}
|
||||
forceShow
|
||||
>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
<PromptEditor
|
||||
variables={quotePromptVariables}
|
||||
title={t('core.app.Quote prompt')}
|
||||
h={220}
|
||||
placeholder={t('template.Quote Prompt Tip', {
|
||||
default: Prompt_QuotePromptList[0].value
|
||||
})}
|
||||
value={aiChatQuotePrompt}
|
||||
onChange={(e) => {
|
||||
setValue(ModuleInputKeyEnum.aiChatQuotePrompt, e);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
forceShow
|
||||
>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
<Box flex={1} />
|
||||
<Box
|
||||
{...selectTemplateBtn}
|
||||
onClick={() =>
|
||||
setSelectTemplateData({
|
||||
title: t('core.app.Select quote template'),
|
||||
templates: Prompt_QuoteTemplateList
|
||||
})
|
||||
}
|
||||
>
|
||||
{t('common.Select template')}
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
<PromptEditor
|
||||
variables={quoteTemplateVariables}
|
||||
h={160}
|
||||
title={t('core.app.Quote templates')}
|
||||
placeholder={t('template.Quote Content Tip', {
|
||||
default: Prompt_QuoteTemplateList[0].value
|
||||
})}
|
||||
value={aiChatQuoteTemplate}
|
||||
onChange={(e) => {
|
||||
setValue(ModuleInputKeyEnum.aiChatQuoteTemplate, e);
|
||||
// setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Box mt={4}>
|
||||
<Flex {...LabelStyles} mb={1}>
|
||||
{t('core.app.Quote prompt')}
|
||||
<MyTooltip
|
||||
label={t('template.Quote Prompt Tip', { default: Prompt_QuotePromptList[0].value })}
|
||||
forceShow
|
||||
>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
<PromptEditor
|
||||
variables={quotePromptVariables}
|
||||
title={t('core.app.Quote prompt')}
|
||||
h={230}
|
||||
placeholder={t('template.Quote Prompt Tip', {
|
||||
default: Prompt_QuotePromptList[0].value
|
||||
})}
|
||||
value={aiChatQuotePrompt}
|
||||
onChange={(e) => {
|
||||
setValue(ModuleInputKeyEnum.aiChatQuotePrompt, e);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button variant={'whiteBase'} onClick={onClose}>
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
Flex,
|
||||
ModalBody,
|
||||
ModalFooter,
|
||||
Switch,
|
||||
Textarea,
|
||||
useTheme
|
||||
} from '@chakra-ui/react';
|
||||
@@ -23,15 +24,27 @@ import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import { DatasetSearchModeMap } from '@fastgpt/global/core/dataset/constants';
|
||||
import MyRadio from '@/components/common/MyRadio';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import Tabs from '@/components/Tabs';
|
||||
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
|
||||
import SelectAiModel from '@/components/Select/SelectAiModel';
|
||||
|
||||
type DatasetParamsProps = {
|
||||
export type DatasetParamsProps = {
|
||||
searchMode: `${DatasetSearchModeEnum}`;
|
||||
searchEmptyText?: string;
|
||||
limit?: number;
|
||||
similarity?: number;
|
||||
usingReRank?: boolean;
|
||||
datasetSearchUsingExtensionQuery?: boolean;
|
||||
datasetSearchExtensionModel?: string;
|
||||
datasetSearchExtensionBg?: string;
|
||||
|
||||
maxTokens?: number;
|
||||
searchEmptyText?: string;
|
||||
};
|
||||
enum SearchSettingTabEnum {
|
||||
searchMode = 'searchMode',
|
||||
limit = 'limit',
|
||||
queryExtension = 'queryExtension'
|
||||
}
|
||||
|
||||
const DatasetParamsModal = ({
|
||||
searchMode = DatasetSearchModeEnum.embedding,
|
||||
@@ -40,22 +53,39 @@ const DatasetParamsModal = ({
|
||||
similarity,
|
||||
usingReRank,
|
||||
maxTokens = 3000,
|
||||
datasetSearchUsingExtensionQuery,
|
||||
datasetSearchExtensionModel,
|
||||
datasetSearchExtensionBg,
|
||||
onClose,
|
||||
onSuccess
|
||||
}: DatasetParamsProps & { onClose: () => void; onSuccess: (e: DatasetParamsProps) => void }) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const { reRankModelList } = useSystemStore();
|
||||
const { reRankModelList, llmModelList } = useSystemStore();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
const { register, setValue, getValues, handleSubmit } = useForm<DatasetParamsProps>({
|
||||
const [currentTabType, setCurrentTabType] = useState(SearchSettingTabEnum.searchMode);
|
||||
|
||||
const { register, setValue, getValues, handleSubmit, watch } = useForm<DatasetParamsProps>({
|
||||
defaultValues: {
|
||||
searchEmptyText,
|
||||
limit,
|
||||
similarity,
|
||||
searchMode,
|
||||
usingReRank
|
||||
usingReRank,
|
||||
datasetSearchUsingExtensionQuery,
|
||||
datasetSearchExtensionModel: datasetSearchExtensionModel ?? llmModelList[0]?.model,
|
||||
datasetSearchExtensionBg
|
||||
}
|
||||
});
|
||||
const datasetSearchUsingCfrForm = watch('datasetSearchUsingExtensionQuery');
|
||||
const queryExtensionModel = watch('datasetSearchExtensionModel');
|
||||
const cfbBgDesc = watch('datasetSearchExtensionBg');
|
||||
|
||||
const chatModelSelectList = (() =>
|
||||
llmModelList.map((item) => ({
|
||||
value: item.model,
|
||||
label: item.name
|
||||
})))();
|
||||
|
||||
const searchModeList = useMemo(() => {
|
||||
const list = Object.values(DatasetSearchModeMap);
|
||||
@@ -82,125 +112,209 @@ const DatasetParamsModal = ({
|
||||
iconSrc="/imgs/modal/params.svg"
|
||||
title={t('core.dataset.search.Dataset Search Params')}
|
||||
w={['90vw', '550px']}
|
||||
h={['90vh', 'auto']}
|
||||
isCentered={searchEmptyText !== undefined}
|
||||
>
|
||||
<ModalBody flex={['1 0 0', 'auto']} overflow={'auto'}>
|
||||
<MyRadio
|
||||
gridGap={2}
|
||||
gridTemplateColumns={'repeat(1,1fr)'}
|
||||
list={searchModeList}
|
||||
value={getValues('searchMode')}
|
||||
onChange={(e) => {
|
||||
setValue('searchMode', e as `${DatasetSearchModeEnum}`);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
<ModalBody flex={'auto'} overflow={'auto'}>
|
||||
<Tabs
|
||||
mb={3}
|
||||
list={[
|
||||
{
|
||||
icon: 'modal/setting',
|
||||
label: t('core.dataset.search.search mode'),
|
||||
id: SearchSettingTabEnum.searchMode
|
||||
},
|
||||
{
|
||||
icon: 'support/outlink/apikeyFill',
|
||||
label: t('core.dataset.search.Filter'),
|
||||
id: SearchSettingTabEnum.limit
|
||||
},
|
||||
{
|
||||
label: t('core.module.template.Query extension'),
|
||||
id: SearchSettingTabEnum.queryExtension,
|
||||
icon: '/imgs/module/cfr.svg'
|
||||
}
|
||||
]}
|
||||
activeId={currentTabType}
|
||||
onChange={(e) => setCurrentTabType(e as any)}
|
||||
/>
|
||||
{usingReRank !== undefined && reRankModelList.length > 0 && (
|
||||
{currentTabType === SearchSettingTabEnum.searchMode && (
|
||||
<>
|
||||
<Divider my={4} />
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
cursor={'pointer'}
|
||||
userSelect={'none'}
|
||||
py={3}
|
||||
pl={'14px'}
|
||||
pr={'16px'}
|
||||
border={theme.borders.sm}
|
||||
borderWidth={'1.5px'}
|
||||
borderRadius={'md'}
|
||||
position={'relative'}
|
||||
{...(getValues('usingReRank')
|
||||
? {
|
||||
borderColor: 'primary.400'
|
||||
}
|
||||
: {})}
|
||||
onClick={(e) => {
|
||||
setValue('usingReRank', !getValues('usingReRank'));
|
||||
setRefresh((state) => !state);
|
||||
<MyRadio
|
||||
gridGap={2}
|
||||
gridTemplateColumns={'repeat(1,1fr)'}
|
||||
list={searchModeList}
|
||||
value={getValues('searchMode')}
|
||||
onChange={(e) => {
|
||||
setValue('searchMode', e as `${DatasetSearchModeEnum}`);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
>
|
||||
<MyIcon name="core/dataset/rerank" w={'18px'} mr={'14px'} />
|
||||
<Box pr={2} color={'myGray.800'} flex={'1 0 0'}>
|
||||
<Box>{t('core.dataset.search.ReRank')}</Box>
|
||||
<Box fontSize={['xs', 'sm']} color={'myGray.500'}>
|
||||
{t('core.dataset.search.ReRank desc')}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box position={'relative'} w={'18px'} h={'18px'}>
|
||||
<Checkbox colorScheme="primary" isChecked={getValues('usingReRank')} size="lg" />
|
||||
<Box position={'absolute'} top={0} right={0} bottom={0} left={0} zIndex={1}></Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
/>
|
||||
{usingReRank !== undefined && reRankModelList.length > 0 && (
|
||||
<>
|
||||
<Divider my={4} />
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
cursor={'pointer'}
|
||||
userSelect={'none'}
|
||||
py={3}
|
||||
pl={'14px'}
|
||||
pr={'16px'}
|
||||
border={theme.borders.sm}
|
||||
borderWidth={'1.5px'}
|
||||
borderRadius={'md'}
|
||||
position={'relative'}
|
||||
{...(getValues('usingReRank')
|
||||
? {
|
||||
borderColor: 'primary.400'
|
||||
}
|
||||
: {})}
|
||||
onClick={(e) => {
|
||||
setValue('usingReRank', !getValues('usingReRank'));
|
||||
setRefresh((state) => !state);
|
||||
}}
|
||||
>
|
||||
<MyIcon name="core/dataset/rerank" w={'18px'} mr={'14px'} />
|
||||
<Box pr={2} color={'myGray.800'} flex={'1 0 0'}>
|
||||
<Box>{t('core.dataset.search.ReRank')}</Box>
|
||||
<Box fontSize={['xs', 'sm']} color={'myGray.500'}>
|
||||
{t('core.dataset.search.ReRank desc')}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box position={'relative'} w={'18px'} h={'18px'}>
|
||||
<Checkbox
|
||||
colorScheme="primary"
|
||||
isChecked={getValues('usingReRank')}
|
||||
size="lg"
|
||||
/>
|
||||
<Box
|
||||
position={'absolute'}
|
||||
top={0}
|
||||
right={0}
|
||||
bottom={0}
|
||||
left={0}
|
||||
zIndex={1}
|
||||
></Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{limit !== undefined && (
|
||||
<Box display={['block', 'flex']} mt={5}>
|
||||
<Box flex={'0 0 120px'} mb={[8, 0]}>
|
||||
{t('core.dataset.search.Max Tokens')}
|
||||
<MyTooltip label={t('core.dataset.search.Max Tokens Tips')} forceShow>
|
||||
<QuestionOutlineIcon ml={1} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
<Box flex={1} mx={4}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '100', value: 100 },
|
||||
{ label: maxTokens, value: maxTokens }
|
||||
]}
|
||||
min={100}
|
||||
max={maxTokens}
|
||||
step={50}
|
||||
value={getValues(ModuleInputKeyEnum.datasetMaxTokens) ?? 1000}
|
||||
onChange={(val) => {
|
||||
setValue(ModuleInputKeyEnum.datasetMaxTokens, val);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
{currentTabType === SearchSettingTabEnum.limit && (
|
||||
<Box pt={5}>
|
||||
{limit !== undefined && (
|
||||
<Box display={['block', 'flex']}>
|
||||
<Box flex={'0 0 120px'} mb={[8, 0]}>
|
||||
{t('core.dataset.search.Max Tokens')}
|
||||
<MyTooltip label={t('core.dataset.search.Max Tokens Tips')} forceShow>
|
||||
<QuestionOutlineIcon ml={1} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
<Box flex={1} mx={4}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '100', value: 100 },
|
||||
{ label: maxTokens, value: maxTokens }
|
||||
]}
|
||||
min={100}
|
||||
max={maxTokens}
|
||||
step={50}
|
||||
value={getValues(ModuleInputKeyEnum.datasetMaxTokens) ?? 1000}
|
||||
onChange={(val) => {
|
||||
setValue(ModuleInputKeyEnum.datasetMaxTokens, val);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
{showSimilarity && (
|
||||
<Box display={['block', 'flex']} mt={10}>
|
||||
<Box flex={'0 0 120px'} mb={[8, 0]}>
|
||||
{t('core.dataset.search.Min Similarity')}
|
||||
<MyTooltip label={t('core.dataset.search.Min Similarity Tips')} forceShow>
|
||||
<QuestionOutlineIcon ml={1} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
<Box flex={1} mx={4}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '0', value: 0 },
|
||||
{ label: '1', value: 1 }
|
||||
]}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
value={getValues(ModuleInputKeyEnum.datasetSimilarity) ?? 0.5}
|
||||
onChange={(val) => {
|
||||
setValue(ModuleInputKeyEnum.datasetSimilarity, val);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
{searchEmptyText !== undefined && (
|
||||
<Box display={['block', 'flex']} pt={3}>
|
||||
<Box flex={'0 0 120px'} mb={[2, 0]}>
|
||||
{t('core.dataset.search.Empty result response')}
|
||||
</Box>
|
||||
<Box flex={1}>
|
||||
<Textarea
|
||||
rows={5}
|
||||
maxLength={500}
|
||||
placeholder={t('core.dataset.search.Empty result response Tips')}
|
||||
{...register('searchEmptyText')}
|
||||
></Textarea>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
{showSimilarity && (
|
||||
<Box display={['block', 'flex']} mt={5}>
|
||||
<Box flex={'0 0 120px'} mb={[8, 0]}>
|
||||
{t('core.dataset.search.Min Similarity')}
|
||||
<MyTooltip label={t('core.dataset.search.Min Similarity Tips')} forceShow>
|
||||
<QuestionOutlineIcon ml={1} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
<Box flex={1} mx={4}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '0', value: 0 },
|
||||
{ label: '1', value: 1 }
|
||||
]}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
value={getValues(ModuleInputKeyEnum.datasetSimilarity) ?? 0.5}
|
||||
onChange={(val) => {
|
||||
setValue(ModuleInputKeyEnum.datasetSimilarity, val);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{searchEmptyText !== undefined && (
|
||||
<Box display={['block', 'flex']} pt={3}>
|
||||
<Box flex={'0 0 120px'} mb={[2, 0]}>
|
||||
{t('core.dataset.search.Empty result response')}
|
||||
</Box>
|
||||
<Box flex={1}>
|
||||
<Textarea
|
||||
rows={5}
|
||||
maxLength={500}
|
||||
placeholder={t('core.dataset.search.Empty result response Tips')}
|
||||
{...register('searchEmptyText')}
|
||||
></Textarea>
|
||||
{currentTabType === SearchSettingTabEnum.queryExtension && (
|
||||
<Box>
|
||||
<Box fontSize={'xs'} color={'myGray.500'}>
|
||||
{t('core.module.template.Query extension intro')}
|
||||
</Box>
|
||||
<Flex mt={3} alignItems={'center'}>
|
||||
<Box flex={'1 0 0'}>{t('core.dataset.search.Using query extension')}</Box>
|
||||
<Switch {...register('datasetSearchUsingExtensionQuery')} />
|
||||
</Flex>
|
||||
{datasetSearchUsingCfrForm === true && (
|
||||
<>
|
||||
<Flex mt={4} alignItems={'center'}>
|
||||
<Box flex={'0 0 100px'}>{t('core.ai.Model')}</Box>
|
||||
<Box flex={'1 0 0'}>
|
||||
<SelectAiModel
|
||||
width={'100%'}
|
||||
value={queryExtensionModel}
|
||||
list={chatModelSelectList}
|
||||
onchange={(val: any) => {
|
||||
setValue('datasetSearchExtensionModel', val);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Box mt={3}>
|
||||
<Flex alignItems={'center'}>
|
||||
{t('core.app.edit.Query extension background prompt')}
|
||||
<MyTooltip label={t('core.app.edit.Query extension background tip')} forceShow>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
<Box mt={1}>
|
||||
<PromptEditor
|
||||
h={200}
|
||||
showOpenModal={false}
|
||||
placeholder={t('core.module.QueryExtension.placeholder')}
|
||||
value={cfbBgDesc}
|
||||
onChange={(e) => {
|
||||
setValue('datasetSearchExtensionBg', e);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</ModalBody>
|
||||
|
||||
@@ -53,8 +53,8 @@ const TTSSelect = ({
|
||||
if (e === TTSTypeEnum.none || e === TTSTypeEnum.web) {
|
||||
onChange({ type: e as `${TTSTypeEnum}` });
|
||||
} else {
|
||||
const audioModel = audioSpeechModelList.find(
|
||||
(item) => item.voices?.find((voice) => voice.value === e)
|
||||
const audioModel = audioSpeechModelList.find((item) =>
|
||||
item.voices?.find((voice) => voice.value === e)
|
||||
);
|
||||
if (!audioModel) {
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import NodeCard from '../render/NodeCard';
|
||||
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
|
||||
import Divider from '../modules/Divider';
|
||||
import Container from '../modules/Container';
|
||||
import RenderInput from '../render/RenderInput';
|
||||
import RenderOutput from '../render/RenderOutput';
|
||||
|
||||
const NodeHttp = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
|
||||
const { moduleId, inputs, outputs } = data;
|
||||
|
||||
return (
|
||||
<NodeCard minW={'350px'} selected={selected} {...data}>
|
||||
<Divider text="Input" />
|
||||
<Container>
|
||||
<RenderInput moduleId={moduleId} flowInputList={inputs} />
|
||||
</Container>
|
||||
<Divider text="Output" />
|
||||
<Container>
|
||||
<RenderOutput moduleId={moduleId} flowOutputList={outputs} />
|
||||
</Container>
|
||||
</NodeCard>
|
||||
);
|
||||
};
|
||||
export default React.memo(NodeHttp);
|
||||
@@ -61,8 +61,9 @@ const NodeCard = (props: Props) => {
|
||||
icon: 'common/refreshLight',
|
||||
label: t('plugin.Synchronous version'),
|
||||
onClick: () => {
|
||||
const pluginId = inputs.find((item) => item.key === ModuleInputKeyEnum.pluginId)
|
||||
?.value;
|
||||
const pluginId = inputs.find(
|
||||
(item) => item.key === ModuleInputKeyEnum.pluginId
|
||||
)?.value;
|
||||
if (!pluginId) return;
|
||||
openConfirm(async () => {
|
||||
try {
|
||||
|
||||
@@ -1,11 +1,34 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import type { RenderInputProps } from '../type';
|
||||
import { onChangeNode } from '../../../../FlowProvider';
|
||||
import { onChangeNode, useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import JSONEditor from '@fastgpt/web/components/common/Textarea/JsonEditor';
|
||||
import {
|
||||
formatEditorVariablePickerIcon,
|
||||
getGuideModule,
|
||||
splitGuideModule
|
||||
} from '@fastgpt/global/core/module/utils';
|
||||
|
||||
const JsonEditor = ({ item, moduleId }: RenderInputProps) => {
|
||||
const JsonEditor = ({ inputs = [], item, moduleId }: RenderInputProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { nodes } = useFlowProviderStore();
|
||||
|
||||
// get variable
|
||||
const variables = useMemo(() => {
|
||||
const globalVariables = formatEditorVariablePickerIcon(
|
||||
splitGuideModule(getGuideModule(nodes.map((node) => node.data)))?.variableModules || []
|
||||
);
|
||||
const moduleVariables = formatEditorVariablePickerIcon(
|
||||
inputs
|
||||
.filter((input) => input.edit)
|
||||
.map((item) => ({
|
||||
key: item.key,
|
||||
label: item.label
|
||||
}))
|
||||
);
|
||||
|
||||
return [...globalVariables, ...moduleVariables];
|
||||
}, [inputs, nodes]);
|
||||
|
||||
const update = useCallback(
|
||||
(value: string) => {
|
||||
@@ -28,10 +51,11 @@ const JsonEditor = ({ item, moduleId }: RenderInputProps) => {
|
||||
bg={'myWhite.400'}
|
||||
placeholder={t(item.placeholder || '')}
|
||||
resize
|
||||
defaultValue={item.value}
|
||||
value={item.value}
|
||||
onChange={(e) => {
|
||||
update(e);
|
||||
}}
|
||||
variables={variables}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -7,19 +7,24 @@ import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import DatasetParamsModal from '@/components/core/module/DatasetParamsModal';
|
||||
import DatasetParamsModal, {
|
||||
DatasetParamsProps
|
||||
} from '@/components/core/module/DatasetParamsModal';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
|
||||
const SelectDatasetParam = ({ inputs = [], moduleId }: RenderInputProps) => {
|
||||
const { nodes } = useFlowProviderStore();
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { llmModelList } = useSystemStore();
|
||||
const [data, setData] = useState({
|
||||
|
||||
const [data, setData] = useState<DatasetParamsProps>({
|
||||
searchMode: DatasetSearchModeEnum.embedding,
|
||||
limit: 5,
|
||||
similarity: 0.5,
|
||||
usingReRank: false
|
||||
usingReRank: false,
|
||||
datasetSearchUsingExtensionQuery: true,
|
||||
datasetSearchExtensionModel: llmModelList[0]?.model,
|
||||
datasetSearchExtensionBg: ''
|
||||
});
|
||||
|
||||
const tokenLimit = useMemo(() => {
|
||||
@@ -69,6 +74,7 @@ const SelectDatasetParam = ({ inputs = [], moduleId }: RenderInputProps) => {
|
||||
maxTokens={tokenLimit}
|
||||
onClose={onClose}
|
||||
onSuccess={(e) => {
|
||||
setData(e);
|
||||
for (let key in e) {
|
||||
const item = inputs.find((input) => input.key === key);
|
||||
if (!item) continue;
|
||||
|
||||
@@ -25,7 +25,7 @@ const nodeTypes: Record<`${FlowNodeTypeEnum}`, any> = {
|
||||
[FlowNodeTypeEnum.answerNode]: dynamic(() => import('./components/nodes/NodeAnswer')),
|
||||
[FlowNodeTypeEnum.classifyQuestion]: dynamic(() => import('./components/nodes/NodeCQNode')),
|
||||
[FlowNodeTypeEnum.contentExtract]: dynamic(() => import('./components/nodes/NodeExtract')),
|
||||
[FlowNodeTypeEnum.httpRequest]: NodeSimple,
|
||||
[FlowNodeTypeEnum.httpRequest]: dynamic(() => import('./components/nodes/NodeHttp')),
|
||||
[FlowNodeTypeEnum.runApp]: NodeSimple,
|
||||
[FlowNodeTypeEnum.pluginInput]: dynamic(() => import('./components/nodes/NodePluginInput')),
|
||||
[FlowNodeTypeEnum.pluginOutput]: dynamic(() => import('./components/nodes/NodePluginOutput')),
|
||||
|
||||
@@ -14,9 +14,6 @@ export const SimpleModeTemplate_FastGPT_Universal: AppSimpleEditConfigTemplateTy
|
||||
quoteTemplate: true,
|
||||
quotePrompt: true
|
||||
},
|
||||
cfr: {
|
||||
background: true
|
||||
},
|
||||
dataset: {
|
||||
datasets: true,
|
||||
similarity: true,
|
||||
|
||||
12
projects/app/src/global/core/dataset/api.d.ts
vendored
12
projects/app/src/global/core/dataset/api.d.ts
vendored
@@ -8,6 +8,7 @@ import {
|
||||
DatasetDataIndexItemType,
|
||||
SearchDataResponseItemType
|
||||
} from '@fastgpt/global/core/dataset/type';
|
||||
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
|
||||
/* ================= dataset ===================== */
|
||||
export type CreateDatasetParams = {
|
||||
@@ -50,10 +51,13 @@ export type GetTrainingQueueResponse = {
|
||||
export type SearchTestProps = {
|
||||
datasetId: string;
|
||||
text: string;
|
||||
limit?: number;
|
||||
searchMode?: `${DatasetSearchModeEnum}`;
|
||||
usingReRank: boolean;
|
||||
similarity?: number;
|
||||
[ModuleInputKeyEnum.datasetSimilarity]?: number;
|
||||
[ModuleInputKeyEnum.datasetMaxTokens]?: number;
|
||||
[ModuleInputKeyEnum.datasetSearchMode]?: `${DatasetSearchModeEnum}`;
|
||||
[ModuleInputKeyEnum.datasetSearchUsingReRank]?: boolean;
|
||||
[ModuleInputKeyEnum.datasetSearchUsingExtensionQuery]?: boolean;
|
||||
[ModuleInputKeyEnum.datasetSearchExtensionModel]?: string;
|
||||
[ModuleInputKeyEnum.datasetSearchExtensionBg]?: string;
|
||||
};
|
||||
export type SearchTestResponse = {
|
||||
list: SearchDataResponseItemType[];
|
||||
|
||||
@@ -58,7 +58,7 @@ export const Prompt_QuotePromptList: PromptTemplateItem[] = [
|
||||
- 使用 Markdown 语法优化回答格式。
|
||||
- 使用与问题相同的语言回答。
|
||||
|
||||
问题:"{{question}}"`
|
||||
问题:"""{{question}}"""`
|
||||
},
|
||||
{
|
||||
title: '问答模板',
|
||||
@@ -73,7 +73,7 @@ export const Prompt_QuotePromptList: PromptTemplateItem[] = [
|
||||
- 如果没有相关的问答对,你需要澄清。
|
||||
- 避免提及你是从 QA 获取的知识,只需要回复答案。
|
||||
|
||||
问题:"{{question}}"`
|
||||
问题:"""{{question}}"""`
|
||||
},
|
||||
{
|
||||
title: '标准严格模板',
|
||||
@@ -93,7 +93,7 @@ export const Prompt_QuotePromptList: PromptTemplateItem[] = [
|
||||
- 使用 Markdown 语法优化回答格式。
|
||||
- 使用与问题相同的语言回答。
|
||||
|
||||
问题:"{{question}}"`
|
||||
问题:"""{{question}}"""`
|
||||
},
|
||||
{
|
||||
title: '严格问答模板',
|
||||
@@ -111,6 +111,6 @@ export const Prompt_QuotePromptList: PromptTemplateItem[] = [
|
||||
|
||||
最后,避免提及你是从 QA 获取的知识,只需要回复答案。
|
||||
|
||||
问题:"{{question}}"`
|
||||
问题:"""{{question}}"""`
|
||||
}
|
||||
];
|
||||
|
||||
@@ -66,13 +66,13 @@ export async function getInitConfig() {
|
||||
await Promise.all([
|
||||
initGlobal(),
|
||||
initSystemConfig(),
|
||||
getSimpleModeTemplates(),
|
||||
// getSimpleModeTemplates(),
|
||||
getSystemVersion(),
|
||||
getSystemPlugin()
|
||||
]);
|
||||
|
||||
console.log({
|
||||
simpleModeTemplates: global.simpleModeTemplates,
|
||||
// simpleModeTemplates: global.simpleModeTemplates,
|
||||
communityPlugins: global.communityPlugins
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -165,38 +165,38 @@ export function getSystemVersion() {
|
||||
}
|
||||
}
|
||||
|
||||
async function getSimpleModeTemplates() {
|
||||
if (global.simpleModeTemplates && global.simpleModeTemplates.length > 0) return;
|
||||
// async function getSimpleModeTemplates() {
|
||||
// if (global.simpleModeTemplates && global.simpleModeTemplates.length > 0) return;
|
||||
|
||||
try {
|
||||
const basePath =
|
||||
process.env.NODE_ENV === 'development' ? 'data/simpleTemplates' : '/app/data/simpleTemplates';
|
||||
// read data/simpleTemplates directory, get all json file
|
||||
const files = readdirSync(basePath);
|
||||
// filter json file
|
||||
const filterFiles = files.filter((item) => item.endsWith('.json'));
|
||||
// try {
|
||||
// const basePath =
|
||||
// process.env.NODE_ENV === 'development' ? 'data/simpleTemplates' : '/app/data/simpleTemplates';
|
||||
// // read data/simpleTemplates directory, get all json file
|
||||
// const files = readdirSync(basePath);
|
||||
// // filter json file
|
||||
// const filterFiles = files.filter((item) => item.endsWith('.json'));
|
||||
|
||||
// read json file
|
||||
const fileTemplates = filterFiles.map((item) => {
|
||||
const content = readFileSync(`${basePath}/${item}`, 'utf-8');
|
||||
return {
|
||||
id: item.replace('.json', ''),
|
||||
...JSON.parse(content)
|
||||
};
|
||||
});
|
||||
// // read json file
|
||||
// const fileTemplates = filterFiles.map((item) => {
|
||||
// const content = readFileSync(`${basePath}/${item}`, 'utf-8');
|
||||
// return {
|
||||
// id: item.replace('.json', ''),
|
||||
// ...JSON.parse(content)
|
||||
// };
|
||||
// });
|
||||
|
||||
// fetch templates from plus
|
||||
const plusTemplates = await getSimpleTemplatesFromPlus();
|
||||
// // fetch templates from plus
|
||||
// const plusTemplates = await getSimpleTemplatesFromPlus();
|
||||
|
||||
global.simpleModeTemplates = [
|
||||
SimpleModeTemplate_FastGPT_Universal,
|
||||
...plusTemplates,
|
||||
...fileTemplates
|
||||
];
|
||||
} catch (error) {
|
||||
global.simpleModeTemplates = [SimpleModeTemplate_FastGPT_Universal];
|
||||
}
|
||||
}
|
||||
// global.simpleModeTemplates = [
|
||||
// SimpleModeTemplate_FastGPT_Universal,
|
||||
// ...plusTemplates,
|
||||
// ...fileTemplates
|
||||
// ];
|
||||
// } catch (error) {
|
||||
// global.simpleModeTemplates = [SimpleModeTemplate_FastGPT_Universal];
|
||||
// }
|
||||
// }
|
||||
|
||||
function getSystemPlugin() {
|
||||
if (global.communityPlugins && global.communityPlugins.length > 0) return;
|
||||
|
||||
@@ -294,7 +294,7 @@ function datasetTemplate({ formData, maxToken }: Props): ModuleItemType[] {
|
||||
valueType: 'string',
|
||||
targets: [
|
||||
{
|
||||
moduleId: 'vuc92c',
|
||||
moduleId: 'datasetSearch',
|
||||
key: 'userChatInput'
|
||||
}
|
||||
]
|
||||
@@ -387,15 +387,6 @@ function datasetTemplate({ formData, maxToken }: Props): ModuleItemType[] {
|
||||
value: true,
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'datasetParamsModal',
|
||||
type: 'selectDatasetParamsModal',
|
||||
label: '',
|
||||
valueType: 'any',
|
||||
showTargetInApp: false,
|
||||
showTargetInPlugin: false,
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'userChatInput',
|
||||
type: 'target',
|
||||
@@ -495,19 +486,6 @@ function datasetTemplate({ formData, maxToken }: Props): ModuleItemType[] {
|
||||
label: '温度',
|
||||
value: 0,
|
||||
valueType: 'number',
|
||||
min: 0,
|
||||
max: 10,
|
||||
step: 1,
|
||||
markList: [
|
||||
{
|
||||
label: '严谨',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
label: '发散',
|
||||
value: 10
|
||||
}
|
||||
],
|
||||
showTargetInApp: false,
|
||||
showTargetInPlugin: false,
|
||||
connected: false
|
||||
@@ -518,19 +496,6 @@ function datasetTemplate({ formData, maxToken }: Props): ModuleItemType[] {
|
||||
label: '回复上限',
|
||||
value: maxToken,
|
||||
valueType: 'number',
|
||||
min: 100,
|
||||
max: 4000,
|
||||
step: 50,
|
||||
markList: [
|
||||
{
|
||||
label: '100',
|
||||
value: 100
|
||||
},
|
||||
{
|
||||
label: '4000',
|
||||
value: 4000
|
||||
}
|
||||
],
|
||||
showTargetInApp: false,
|
||||
showTargetInPlugin: false,
|
||||
connected: false
|
||||
@@ -649,89 +614,6 @@ function datasetTemplate({ formData, maxToken }: Props): ModuleItemType[] {
|
||||
targets: []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'vuc92c',
|
||||
name: 'core.module.template.cfr',
|
||||
avatar: '/imgs/module/cfr.svg',
|
||||
flowType: 'cfr',
|
||||
showStatus: true,
|
||||
position: {
|
||||
x: 758.2985382279098,
|
||||
y: 1124.6527309337314
|
||||
},
|
||||
inputs: [
|
||||
{
|
||||
key: 'switch',
|
||||
type: 'target',
|
||||
label: 'core.module.input.label.switch',
|
||||
valueType: 'any',
|
||||
showTargetInApp: true,
|
||||
showTargetInPlugin: true,
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'model',
|
||||
type: 'selectExtractModel',
|
||||
label: 'core.module.input.label.aiModel',
|
||||
required: true,
|
||||
valueType: 'string',
|
||||
value: getLLMModel().model,
|
||||
showTargetInApp: false,
|
||||
showTargetInPlugin: false,
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'systemPrompt',
|
||||
type: 'textarea',
|
||||
label: 'core.module.input.label.cfr background',
|
||||
max: 300,
|
||||
value: formData.cfr.background,
|
||||
valueType: 'string',
|
||||
description: 'core.module.input.description.cfr background',
|
||||
placeholder: 'core.module.input.placeholder.cfr background',
|
||||
showTargetInApp: true,
|
||||
showTargetInPlugin: true,
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'history',
|
||||
type: 'numberInput',
|
||||
label: 'core.module.input.label.chat history',
|
||||
required: true,
|
||||
min: 0,
|
||||
max: 30,
|
||||
valueType: 'chatHistory',
|
||||
value: 6,
|
||||
showTargetInApp: true,
|
||||
showTargetInPlugin: true,
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'userChatInput',
|
||||
type: 'target',
|
||||
label: 'core.module.input.label.user question',
|
||||
required: true,
|
||||
valueType: 'string',
|
||||
showTargetInApp: true,
|
||||
showTargetInPlugin: true,
|
||||
connected: true
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
key: 'system_text',
|
||||
label: 'core.module.output.label.cfr result',
|
||||
valueType: 'string',
|
||||
type: 'source',
|
||||
targets: [
|
||||
{
|
||||
moduleId: 'datasetSearch',
|
||||
key: 'userChatInput'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -290,7 +290,7 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
|
||||
valueType: 'string',
|
||||
targets: [
|
||||
{
|
||||
moduleId: 'vuc92c',
|
||||
moduleId: 'datasetSearch',
|
||||
key: 'userChatInput'
|
||||
}
|
||||
]
|
||||
@@ -335,19 +335,6 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
|
||||
label: '最低相关性',
|
||||
value: formData.dataset.similarity,
|
||||
valueType: 'number',
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.01,
|
||||
markList: [
|
||||
{
|
||||
label: '0',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
label: '1',
|
||||
value: 1
|
||||
}
|
||||
],
|
||||
showTargetInApp: false,
|
||||
showTargetInPlugin: false,
|
||||
connected: false
|
||||
@@ -384,12 +371,33 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'datasetParamsModal',
|
||||
type: 'selectDatasetParamsModal',
|
||||
key: 'datasetSearchUsingExtensionQuery',
|
||||
type: 'hidden',
|
||||
label: '',
|
||||
valueType: 'any',
|
||||
valueType: 'boolean',
|
||||
showTargetInApp: false,
|
||||
showTargetInPlugin: false,
|
||||
value: formData.dataset.datasetSearchUsingExtensionQuery,
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'datasetSearchExtensionBg',
|
||||
type: 'hidden',
|
||||
label: '',
|
||||
valueType: 'string',
|
||||
showTargetInApp: false,
|
||||
showTargetInPlugin: false,
|
||||
value: formData.dataset.datasetSearchExtensionBg,
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'datasetSearchExtensionModel',
|
||||
type: 'hidden',
|
||||
label: '',
|
||||
valueType: 'string',
|
||||
showTargetInApp: false,
|
||||
showTargetInPlugin: false,
|
||||
value: formData.dataset.datasetSearchExtensionModel,
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
@@ -659,89 +667,6 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
|
||||
targets: []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'vuc92c',
|
||||
name: 'core.module.template.cfr',
|
||||
avatar: '/imgs/module/cfr.svg',
|
||||
flowType: 'cfr',
|
||||
showStatus: true,
|
||||
position: {
|
||||
x: 758.2985382279098,
|
||||
y: 1124.6527309337314
|
||||
},
|
||||
inputs: [
|
||||
{
|
||||
key: 'switch',
|
||||
type: 'target',
|
||||
label: 'core.module.input.label.switch',
|
||||
valueType: 'any',
|
||||
showTargetInApp: true,
|
||||
showTargetInPlugin: true,
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'model',
|
||||
type: 'selectExtractModel',
|
||||
label: 'core.module.input.label.aiModel',
|
||||
required: true,
|
||||
valueType: 'string',
|
||||
value: getLLMModel().model,
|
||||
showTargetInApp: false,
|
||||
showTargetInPlugin: false,
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'systemPrompt',
|
||||
type: 'textarea',
|
||||
label: 'core.module.input.label.cfr background',
|
||||
max: 300,
|
||||
value: formData.cfr.background,
|
||||
valueType: 'string',
|
||||
description: 'core.module.input.description.cfr background',
|
||||
placeholder: 'core.module.input.placeholder.cfr background',
|
||||
showTargetInApp: true,
|
||||
showTargetInPlugin: true,
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'history',
|
||||
type: 'numberInput',
|
||||
label: 'core.module.input.label.chat history',
|
||||
required: true,
|
||||
min: 0,
|
||||
max: 30,
|
||||
valueType: 'chatHistory',
|
||||
value: 6,
|
||||
showTargetInApp: true,
|
||||
showTargetInPlugin: true,
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'userChatInput',
|
||||
type: 'target',
|
||||
label: 'core.module.input.label.user question',
|
||||
required: true,
|
||||
valueType: 'string',
|
||||
showTargetInApp: true,
|
||||
showTargetInPlugin: true,
|
||||
connected: true
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
key: 'system_text',
|
||||
label: 'core.module.output.label.cfr result',
|
||||
valueType: 'string',
|
||||
type: 'source',
|
||||
targets: [
|
||||
{
|
||||
moduleId: 'datasetSearch',
|
||||
key: 'userChatInput'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -9,7 +9,9 @@ import { pushGenerateVectorBill } from '@/service/support/wallet/bill/push';
|
||||
import { searchDatasetData } from '@/service/core/dataset/data/controller';
|
||||
import { updateApiKeyUsage } from '@fastgpt/service/support/openapi/tools';
|
||||
import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
|
||||
import { searchQueryExtension } from '@fastgpt/service/core/ai/functions/queryExtension';
|
||||
import { getLLMModel } from '@/service/core/ai/model';
|
||||
import { queryExtension } from '@fastgpt/service/core/ai/functions/queryExtension';
|
||||
import { datasetSearchQueryExtension } from '@fastgpt/service/core/dataset/search/utils';
|
||||
|
||||
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
@@ -20,13 +22,16 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
limit = 1500,
|
||||
similarity,
|
||||
searchMode,
|
||||
usingReRank
|
||||
usingReRank,
|
||||
|
||||
datasetSearchUsingExtensionQuery = false,
|
||||
datasetSearchExtensionModel,
|
||||
datasetSearchExtensionBg = ''
|
||||
} = req.body as SearchTestProps;
|
||||
|
||||
if (!datasetId || !text) {
|
||||
throw new Error('缺少参数');
|
||||
}
|
||||
|
||||
const start = Date.now();
|
||||
|
||||
// auth dataset role
|
||||
@@ -37,20 +42,24 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
datasetId,
|
||||
per: 'r'
|
||||
});
|
||||
|
||||
// auth balance
|
||||
await authTeamBalance(teamId);
|
||||
|
||||
// query extension
|
||||
// const { queries } = await searchQueryExtension({
|
||||
// query: text,
|
||||
// model: global.llmModel[0].model
|
||||
// });
|
||||
const extensionModel =
|
||||
datasetSearchUsingExtensionQuery && datasetSearchExtensionModel
|
||||
? getLLMModel(datasetSearchExtensionModel)
|
||||
: undefined;
|
||||
const { concatQueries, rewriteQuery, aiExtensionResult } = await datasetSearchQueryExtension({
|
||||
query: text,
|
||||
extensionModel,
|
||||
extensionBg: datasetSearchExtensionBg
|
||||
});
|
||||
|
||||
const { searchRes, charsLength, ...result } = await searchDatasetData({
|
||||
teamId,
|
||||
rawQuery: text,
|
||||
queries: [text],
|
||||
reRankQuery: rewriteQuery,
|
||||
queries: concatQueries,
|
||||
model: dataset.vectorModel,
|
||||
limit: Math.min(limit, 20000),
|
||||
similarity,
|
||||
@@ -65,7 +74,14 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
tmbId,
|
||||
charsLength,
|
||||
model: dataset.vectorModel,
|
||||
source: apikey ? BillSourceEnum.api : BillSourceEnum.fastgpt
|
||||
source: apikey ? BillSourceEnum.api : BillSourceEnum.fastgpt,
|
||||
|
||||
...(aiExtensionResult &&
|
||||
extensionModel && {
|
||||
extensionModel: extensionModel.name,
|
||||
extensionInputTokens: aiExtensionResult.inputTokens,
|
||||
extensionOutputTokens: aiExtensionResult.outputTokens
|
||||
})
|
||||
});
|
||||
if (apikey) {
|
||||
updateApiKeyUsage({
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import React, { useCallback, useState, useTransition } from 'react';
|
||||
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { Box, Button, ModalBody, ModalFooter } from '@chakra-ui/react';
|
||||
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
|
||||
const CfrEditModal = ({
|
||||
defaultValue = '',
|
||||
onClose,
|
||||
onFinish
|
||||
}: {
|
||||
defaultValue?: string;
|
||||
onClose: () => void;
|
||||
onFinish: (value: string) => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [value, setValue] = useState(defaultValue);
|
||||
|
||||
return (
|
||||
<MyModal
|
||||
isOpen
|
||||
onClose={onClose}
|
||||
iconSrc="/imgs/module/cfr.svg"
|
||||
w={'500px'}
|
||||
title={t('core.module.template.cfr')}
|
||||
>
|
||||
<ModalBody>
|
||||
{t('core.app.edit.cfr background prompt')}
|
||||
<MyTooltip label={t('core.app.edit.cfr background tip')} forceShow>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
<Box mt={1} flex={1}>
|
||||
<PromptEditor
|
||||
h={200}
|
||||
showOpenModal={false}
|
||||
placeholder={t('core.module.input.placeholder.cfr background')}
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
setValue(e);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onFinish(value);
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{t('common.Done')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</MyModal>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(CfrEditModal);
|
||||
@@ -30,7 +30,6 @@ import MySelect from '@/components/Select';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { SimpleModeTemplate_FastGPT_Universal } from '@/global/core/app/constants';
|
||||
import VariableEdit from '@/components/core/module/Flow/components/modules/VariableEdit';
|
||||
import MyTextarea from '@/components/common/Textarea/MyTextarea/index';
|
||||
import { DatasetSearchModeMap } from '@fastgpt/global/core/dataset/constants';
|
||||
@@ -45,7 +44,6 @@ const TTSSelect = dynamic(
|
||||
() => import('@/components/core/module/Flow/components/modules/TTSSelect')
|
||||
);
|
||||
const QGSwitch = dynamic(() => import('@/components/core/module/Flow/components/modules/QGSwitch'));
|
||||
const CfrEditModal = dynamic(() => import('./CfrEditModal'));
|
||||
|
||||
const EditForm = ({
|
||||
divRef,
|
||||
@@ -59,7 +57,7 @@ const EditForm = ({
|
||||
const { t } = useTranslation();
|
||||
const { appDetail, updateAppDetail } = useAppStore();
|
||||
const { loadAllDatasets, allDatasets } = useDatasetStore();
|
||||
const { isPc, llmModelList, reRankModelList, simpleModeTemplates } = useSystemStore();
|
||||
const { isPc, llmModelList, reRankModelList } = useSystemStore();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
const [, startTst] = useTransition();
|
||||
|
||||
@@ -88,19 +86,16 @@ const EditForm = ({
|
||||
onOpen: onOpenDatasetParams,
|
||||
onClose: onCloseDatasetParams
|
||||
} = useDisclosure();
|
||||
const {
|
||||
isOpen: isOpenCfrModal,
|
||||
onOpen: onOpenCfrModal,
|
||||
onClose: onCloseCfrModal
|
||||
} = useDisclosure();
|
||||
|
||||
const { openConfirm: openConfirmSave, ConfirmModal: ConfirmSaveModal } = useConfirm({
|
||||
content: t('core.app.edit.Confirm Save App Tip')
|
||||
});
|
||||
|
||||
const aiSystemPrompt = watch('aiSettings.systemPrompt');
|
||||
const selectLLMModel = watch('aiSettings.model');
|
||||
const datasetSearchSetting = watch('dataset');
|
||||
const variables = watch('userGuide.variables');
|
||||
const formatVariables = useMemo(() => formatEditorVariablePickerIcon(variables), [variables]);
|
||||
const aiSystemPrompt = watch('aiSettings.systemPrompt');
|
||||
const searchMode = watch('dataset.searchMode');
|
||||
|
||||
const chatModelSelectList = (() =>
|
||||
@@ -114,16 +109,9 @@ const EditForm = ({
|
||||
[allDatasets, datasets]
|
||||
);
|
||||
|
||||
const selectSimpleTemplate = (() =>
|
||||
simpleModeTemplates?.find((item) => item.id === getValues('templateId')) ||
|
||||
SimpleModeTemplate_FastGPT_Universal)();
|
||||
|
||||
const tokenLimit = useMemo(() => {
|
||||
return (
|
||||
llmModelList.find((item) => item.model === getValues('aiSettings.model'))?.quoteMaxToken ||
|
||||
3000
|
||||
);
|
||||
}, [getValues, llmModelList]);
|
||||
return llmModelList.find((item) => item.model === selectLLMModel)?.quoteMaxToken || 3000;
|
||||
}, [selectLLMModel, llmModelList]);
|
||||
|
||||
const datasetSearchMode = useMemo(() => {
|
||||
if (!searchMode) return '';
|
||||
@@ -132,12 +120,11 @@ const EditForm = ({
|
||||
|
||||
const { mutate: onSubmitSave, isLoading: isSaving } = useRequest({
|
||||
mutationFn: async (data: AppSimpleEditFormType) => {
|
||||
const modules = await postForm2Modules(data, data.templateId);
|
||||
const modules = await postForm2Modules(data);
|
||||
|
||||
await updateAppDetail(appDetail._id, {
|
||||
modules,
|
||||
type: AppTypeEnum.simple,
|
||||
simpleTemplateId: data.templateId,
|
||||
permission: undefined
|
||||
});
|
||||
},
|
||||
@@ -149,7 +136,6 @@ const EditForm = ({
|
||||
['init', appDetail],
|
||||
() => {
|
||||
const formatVal = appModules2Form({
|
||||
templateId: appDetail.simpleTemplateId,
|
||||
modules: appDetail.modules
|
||||
});
|
||||
reset(formatVal);
|
||||
@@ -228,7 +214,7 @@ const EditForm = ({
|
||||
<Box px={4}>
|
||||
<Box bg={'white'} borderRadius={'md'} borderWidth={'1px'} borderColor={'borderColor.base'}>
|
||||
{/* simple mode select */}
|
||||
<Flex {...BoxStyles}>
|
||||
{/* <Flex {...BoxStyles}>
|
||||
<Flex alignItems={'center'} flex={'1 0 0'}>
|
||||
<MyIcon name={'core/app/simpleMode/template'} w={'20px'} />
|
||||
<Box mx={2}>{t('core.app.simple.mode template select')}</Box>
|
||||
@@ -248,237 +234,187 @@ const EditForm = ({
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
</Flex> */}
|
||||
|
||||
{/* ai */}
|
||||
{selectSimpleTemplate?.systemForm?.aiSettings && (
|
||||
<Box {...BoxStyles}>
|
||||
<Flex alignItems={'center'}>
|
||||
<MyIcon name={'core/app/simpleMode/ai'} w={'20px'} />
|
||||
<Box ml={2} flex={1}>
|
||||
{t('app.AI Settings')}
|
||||
</Box>
|
||||
{(selectSimpleTemplate.systemForm.aiSettings.maxToken ||
|
||||
selectSimpleTemplate.systemForm.aiSettings.temperature ||
|
||||
selectSimpleTemplate.systemForm.aiSettings.quoteTemplate ||
|
||||
selectSimpleTemplate.systemForm.aiSettings.quotePrompt) && (
|
||||
<Flex {...BoxBtnStyles} onClick={onOpenAIChatSetting}>
|
||||
<MyIcon mr={1} name={'common/settingLight'} w={'14px'} />
|
||||
{t('common.More settings')}
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
{selectSimpleTemplate.systemForm.aiSettings?.model && (
|
||||
<Flex alignItems={'center'} mt={5}>
|
||||
<Box {...LabelStyles}>{t('core.ai.Model')}</Box>
|
||||
<Box flex={'1 0 0'}>
|
||||
<SelectAiModel
|
||||
width={'100%'}
|
||||
value={getValues(`aiSettings.model`)}
|
||||
list={chatModelSelectList}
|
||||
onchange={(val: any) => {
|
||||
setValue('aiSettings.model', val);
|
||||
const maxToken =
|
||||
llmModelList.find((item) => item.model === getValues('aiSettings.model'))
|
||||
?.maxResponse || 4000;
|
||||
const token = maxToken / 2;
|
||||
setValue('aiSettings.maxToken', token);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{selectSimpleTemplate.systemForm.aiSettings?.systemPrompt && (
|
||||
<Flex mt={10} alignItems={'flex-start'}>
|
||||
<Box {...LabelStyles}>
|
||||
{t('core.ai.Prompt')}
|
||||
<MyTooltip label={t(chatNodeSystemPromptTip)} forceShow>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
{isInitd && (
|
||||
<PromptEditor
|
||||
value={aiSystemPrompt}
|
||||
onChange={(text) => {
|
||||
startTst(() => {
|
||||
setValue('aiSettings.systemPrompt', text);
|
||||
});
|
||||
}}
|
||||
variables={formatVariables}
|
||||
placeholder={t('core.app.tip.chatNodeSystemPromptTip')}
|
||||
title={t('core.ai.Prompt')}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* dataset */}
|
||||
{selectSimpleTemplate?.systemForm?.dataset && (
|
||||
<Box {...BoxStyles}>
|
||||
<Flex alignItems={'center'}>
|
||||
<Flex alignItems={'center'} flex={1}>
|
||||
<MyIcon name={'core/app/simpleMode/dataset'} w={'20px'} />
|
||||
<Box ml={2}>{t('core.dataset.Choose Dataset')}</Box>
|
||||
</Flex>
|
||||
{selectSimpleTemplate.systemForm.dataset.datasets && (
|
||||
<Flex alignItems={'center'} {...BoxBtnStyles} onClick={onOpenKbSelect}>
|
||||
<SmallAddIcon />
|
||||
{t('common.Choose')}
|
||||
</Flex>
|
||||
)}
|
||||
{(selectSimpleTemplate.systemForm.dataset.limit ||
|
||||
selectSimpleTemplate.systemForm.dataset.searchMode ||
|
||||
selectSimpleTemplate.systemForm.dataset.searchEmptyText ||
|
||||
selectSimpleTemplate.systemForm.dataset.similarity) && (
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
ml={3}
|
||||
{...BoxBtnStyles}
|
||||
onClick={onOpenDatasetParams}
|
||||
>
|
||||
<MyIcon name={'edit'} w={'14px'} mr={1} />
|
||||
{t('common.Params')}
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
{getValues('dataset.datasets').length > 0 && (
|
||||
<Flex mt={1} color={'myGray.600'} fontSize={'sm'} mb={2}>
|
||||
{t('core.dataset.search.search mode')}: {datasetSearchMode}
|
||||
{', '}
|
||||
{reRankModelList.length > 0 && (
|
||||
<>
|
||||
{t('core.dataset.search.ReRank')}:{' '}
|
||||
{getValues('dataset.usingReRank') ? '✅' : '✖'}
|
||||
</>
|
||||
)}
|
||||
{', '}
|
||||
{t('core.dataset.search.Min Similarity')}: {getValues('dataset.similarity')}
|
||||
{', '}
|
||||
{t('core.dataset.search.Max Tokens')}: {getValues('dataset.limit')}
|
||||
{getValues('dataset.searchEmptyText') === ''
|
||||
? ''
|
||||
: t('core.dataset.Set Empty Result Tip')}
|
||||
</Flex>
|
||||
)}
|
||||
<Grid
|
||||
gridTemplateColumns={['repeat(2, minmax(0, 1fr))', 'repeat(3, minmax(0, 1fr))']}
|
||||
gridGap={[2, 4]}
|
||||
>
|
||||
{selectDatasets.map((item) => (
|
||||
<MyTooltip key={item._id} label={t('core.dataset.Read Dataset')}>
|
||||
<Flex
|
||||
overflow={'hidden'}
|
||||
alignItems={'center'}
|
||||
p={2}
|
||||
bg={'white'}
|
||||
boxShadow={
|
||||
'0 4px 8px -2px rgba(16,24,40,.1),0 2px 4px -2px rgba(16,24,40,.06)'
|
||||
}
|
||||
borderRadius={'md'}
|
||||
border={theme.borders.base}
|
||||
cursor={'pointer'}
|
||||
onClick={() =>
|
||||
router.push({
|
||||
pathname: '/dataset/detail',
|
||||
query: {
|
||||
datasetId: item._id
|
||||
}
|
||||
})
|
||||
}
|
||||
>
|
||||
<Avatar src={item.avatar} w={'18px'} mr={1} />
|
||||
<Box flex={'1 0 0'} w={0} className={'textEllipsis'} fontSize={'sm'}>
|
||||
{item.name}
|
||||
</Box>
|
||||
</Flex>
|
||||
</MyTooltip>
|
||||
))}
|
||||
</Grid>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* cfr */}
|
||||
{selectSimpleTemplate?.systemForm?.cfr && getValues('dataset.datasets').length > 0 && (
|
||||
<Flex {...BoxStyles} alignItems={'center'}>
|
||||
<Image src={'/imgs/module/cfr.svg'} alt={''} w={'18px'} />
|
||||
<Box ml={2}>{t('core.module.template.cfr')}</Box>
|
||||
<MyTooltip label={t('core.module.template.cfr intro')} forceShow>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
<Box flex={1} />
|
||||
<Flex {...BoxBtnStyles} onClick={onOpenCfrModal}>
|
||||
{getValues('cfr.background') === 'none' ? t('common.Not open') : t('common.Opened')}
|
||||
<Box {...BoxStyles}>
|
||||
<Flex alignItems={'center'}>
|
||||
<MyIcon name={'core/app/simpleMode/ai'} w={'20px'} />
|
||||
<Box ml={2} flex={1}>
|
||||
{t('app.AI Settings')}
|
||||
</Box>
|
||||
<Flex {...BoxBtnStyles} onClick={onOpenAIChatSetting}>
|
||||
<MyIcon mr={1} name={'common/settingLight'} w={'14px'} />
|
||||
{t('common.More settings')}
|
||||
</Flex>
|
||||
</Flex>
|
||||
)}
|
||||
<Flex alignItems={'center'} mt={5}>
|
||||
<Box {...LabelStyles}>{t('core.ai.Model')}</Box>
|
||||
<Box flex={'1 0 0'}>
|
||||
<SelectAiModel
|
||||
width={'100%'}
|
||||
value={getValues(`aiSettings.model`)}
|
||||
list={chatModelSelectList}
|
||||
onchange={(val: any) => {
|
||||
setValue('aiSettings.model', val);
|
||||
const maxToken =
|
||||
llmModelList.find((item) => item.model === getValues('aiSettings.model'))
|
||||
?.maxResponse || 4000;
|
||||
const token = maxToken / 2;
|
||||
setValue('aiSettings.maxToken', token);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
<Flex mt={10} alignItems={'flex-start'}>
|
||||
<Box {...LabelStyles}>
|
||||
{t('core.ai.Prompt')}
|
||||
<MyTooltip label={t(chatNodeSystemPromptTip)} forceShow>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
{isInitd && (
|
||||
<PromptEditor
|
||||
value={aiSystemPrompt}
|
||||
onChange={(text) => {
|
||||
startTst(() => {
|
||||
setValue('aiSettings.systemPrompt', text);
|
||||
});
|
||||
}}
|
||||
variables={formatVariables}
|
||||
placeholder={t('core.app.tip.chatNodeSystemPromptTip')}
|
||||
title={t('core.ai.Prompt')}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
</Box>
|
||||
|
||||
{/* dataset */}
|
||||
<Box {...BoxStyles}>
|
||||
<Flex alignItems={'center'}>
|
||||
<Flex alignItems={'center'} flex={1}>
|
||||
<MyIcon name={'core/app/simpleMode/dataset'} w={'20px'} />
|
||||
<Box ml={2}>{t('core.dataset.Choose Dataset')}</Box>
|
||||
</Flex>
|
||||
<Flex alignItems={'center'} {...BoxBtnStyles} onClick={onOpenKbSelect}>
|
||||
<SmallAddIcon />
|
||||
{t('common.Choose')}
|
||||
</Flex>
|
||||
<Flex alignItems={'center'} ml={3} {...BoxBtnStyles} onClick={onOpenDatasetParams}>
|
||||
<MyIcon name={'edit'} w={'14px'} mr={1} />
|
||||
{t('common.Params')}
|
||||
</Flex>
|
||||
</Flex>
|
||||
{getValues('dataset.datasets').length > 0 && (
|
||||
<Flex mt={1} color={'myGray.600'} fontSize={'sm'} mb={2}>
|
||||
{t('core.dataset.search.search mode')}: {datasetSearchMode}
|
||||
{', '}
|
||||
{reRankModelList.length > 0 && (
|
||||
<>
|
||||
{t('core.dataset.search.ReRank')}:{' '}
|
||||
{getValues('dataset.usingReRank') ? '✅' : '✖'}
|
||||
</>
|
||||
)}
|
||||
{', '}
|
||||
{t('core.dataset.search.Min Similarity')}: {getValues('dataset.similarity')}
|
||||
{', '}
|
||||
{t('core.dataset.search.Max Tokens')}: {getValues('dataset.limit')}
|
||||
{getValues('dataset.searchEmptyText') === ''
|
||||
? ''
|
||||
: t('core.dataset.Set Empty Result Tip')}
|
||||
</Flex>
|
||||
)}
|
||||
<Grid
|
||||
gridTemplateColumns={['repeat(2, minmax(0, 1fr))', 'repeat(3, minmax(0, 1fr))']}
|
||||
gridGap={[2, 4]}
|
||||
>
|
||||
{selectDatasets.map((item) => (
|
||||
<MyTooltip key={item._id} label={t('core.dataset.Read Dataset')}>
|
||||
<Flex
|
||||
overflow={'hidden'}
|
||||
alignItems={'center'}
|
||||
p={2}
|
||||
bg={'white'}
|
||||
boxShadow={'0 4px 8px -2px rgba(16,24,40,.1),0 2px 4px -2px rgba(16,24,40,.06)'}
|
||||
borderRadius={'md'}
|
||||
border={theme.borders.base}
|
||||
cursor={'pointer'}
|
||||
onClick={() =>
|
||||
router.push({
|
||||
pathname: '/dataset/detail',
|
||||
query: {
|
||||
datasetId: item._id
|
||||
}
|
||||
})
|
||||
}
|
||||
>
|
||||
<Avatar src={item.avatar} w={'18px'} mr={1} />
|
||||
<Box flex={'1 0 0'} w={0} className={'textEllipsis'} fontSize={'sm'}>
|
||||
{item.name}
|
||||
</Box>
|
||||
</Flex>
|
||||
</MyTooltip>
|
||||
))}
|
||||
</Grid>
|
||||
</Box>
|
||||
|
||||
{/* variable */}
|
||||
{selectSimpleTemplate?.systemForm?.userGuide?.variables && (
|
||||
<Box {...BoxStyles}>
|
||||
<VariableEdit
|
||||
variables={variables}
|
||||
onChange={(e) => {
|
||||
setValue('userGuide.variables', e);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
<Box {...BoxStyles}>
|
||||
<VariableEdit
|
||||
variables={variables}
|
||||
onChange={(e) => {
|
||||
setValue('userGuide.variables', e);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* welcome */}
|
||||
{selectSimpleTemplate?.systemForm?.userGuide?.welcomeText && (
|
||||
<Box {...BoxStyles}>
|
||||
<Flex alignItems={'center'}>
|
||||
<MyIcon name={'core/app/simpleMode/chat'} w={'20px'} />
|
||||
<Box mx={2}>{t('core.app.Welcome Text')}</Box>
|
||||
<MyTooltip label={t(welcomeTextTip)} forceShow>
|
||||
<QuestionOutlineIcon />
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
<MyTextarea
|
||||
mt={2}
|
||||
bg={'myWhite.400'}
|
||||
rows={5}
|
||||
placeholder={t(welcomeTextTip)}
|
||||
defaultValue={getValues('userGuide.welcomeText')}
|
||||
onBlur={(e) => {
|
||||
setValue('userGuide.welcomeText', e.target.value || '');
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
<Box {...BoxStyles}>
|
||||
<Flex alignItems={'center'}>
|
||||
<MyIcon name={'core/app/simpleMode/chat'} w={'20px'} />
|
||||
<Box mx={2}>{t('core.app.Welcome Text')}</Box>
|
||||
<MyTooltip label={t(welcomeTextTip)} forceShow>
|
||||
<QuestionOutlineIcon />
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
<MyTextarea
|
||||
mt={2}
|
||||
bg={'myWhite.400'}
|
||||
rows={5}
|
||||
placeholder={t(welcomeTextTip)}
|
||||
defaultValue={getValues('userGuide.welcomeText')}
|
||||
onBlur={(e) => {
|
||||
setValue('userGuide.welcomeText', e.target.value || '');
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* tts */}
|
||||
{selectSimpleTemplate?.systemForm?.userGuide?.tts && (
|
||||
<Box {...BoxStyles}>
|
||||
<TTSSelect
|
||||
value={getValues('userGuide.tts')}
|
||||
onChange={(e) => {
|
||||
setValue('userGuide.tts', e);
|
||||
setRefresh((state) => !state);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
<Box {...BoxStyles}>
|
||||
<TTSSelect
|
||||
value={getValues('userGuide.tts')}
|
||||
onChange={(e) => {
|
||||
setValue('userGuide.tts', e);
|
||||
setRefresh((state) => !state);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* question guide */}
|
||||
{selectSimpleTemplate?.systemForm?.userGuide?.questionGuide && (
|
||||
<Box {...BoxStyles} borderBottom={'none'}>
|
||||
<QGSwitch
|
||||
isChecked={getValues('userGuide.questionGuide')}
|
||||
size={'lg'}
|
||||
onChange={(e) => {
|
||||
const value = e.target.checked;
|
||||
setValue('userGuide.questionGuide', value);
|
||||
setRefresh((state) => !state);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
<Box {...BoxStyles} borderBottom={'none'}>
|
||||
<QGSwitch
|
||||
isChecked={getValues('userGuide.questionGuide')}
|
||||
size={'lg'}
|
||||
onChange={(e) => {
|
||||
const value = e.target.checked;
|
||||
setValue('userGuide.questionGuide', value);
|
||||
setRefresh((state) => !state);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -491,7 +427,6 @@ const EditForm = ({
|
||||
onCloseAIChatSetting();
|
||||
}}
|
||||
defaultData={getValues('aiSettings')}
|
||||
simpleModeTemplate={selectSimpleTemplate}
|
||||
pickerMenu={formatVariables}
|
||||
/>
|
||||
)}
|
||||
@@ -508,28 +443,7 @@ const EditForm = ({
|
||||
)}
|
||||
{isOpenDatasetParams && (
|
||||
<DatasetParamsModal
|
||||
// {...getValues('dataset')}
|
||||
searchMode={getValues('dataset.searchMode')}
|
||||
searchEmptyText={
|
||||
selectSimpleTemplate?.systemForm?.dataset?.searchEmptyText
|
||||
? getValues('dataset.searchEmptyText')
|
||||
: undefined
|
||||
}
|
||||
limit={
|
||||
selectSimpleTemplate?.systemForm?.dataset?.limit
|
||||
? getValues('dataset.limit')
|
||||
: undefined
|
||||
}
|
||||
similarity={
|
||||
selectSimpleTemplate?.systemForm?.dataset?.similarity
|
||||
? getValues('dataset.similarity')
|
||||
: undefined
|
||||
}
|
||||
usingReRank={
|
||||
selectSimpleTemplate?.systemForm?.dataset?.usingReRank
|
||||
? getValues('dataset.usingReRank')
|
||||
: undefined
|
||||
}
|
||||
{...datasetSearchSetting}
|
||||
maxTokens={tokenLimit}
|
||||
onClose={onCloseDatasetParams}
|
||||
onSuccess={(e) => {
|
||||
@@ -542,15 +456,6 @@ const EditForm = ({
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{isOpenCfrModal && (
|
||||
<CfrEditModal
|
||||
onClose={onCloseCfrModal}
|
||||
defaultValue={getValues('cfr.background')}
|
||||
onFinish={(e) => {
|
||||
setValue('cfr.background', e);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -39,6 +39,8 @@ import { fileDownload } from '@/web/common/file/utils';
|
||||
import { readCsvContent } from '@fastgpt/web/common/file/read/csv';
|
||||
import { delay } from '@fastgpt/global/common/system/utils';
|
||||
import QuoteItem from '@/components/core/dataset/QuoteItem';
|
||||
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
|
||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
|
||||
|
||||
@@ -48,9 +50,13 @@ type FormType = {
|
||||
inputText: string;
|
||||
searchParams: {
|
||||
searchMode: `${DatasetSearchModeEnum}`;
|
||||
usingReRank: boolean;
|
||||
limit: number;
|
||||
similarity: number;
|
||||
similarity?: number;
|
||||
limit?: number;
|
||||
usingReRank?: boolean;
|
||||
searchEmptyText?: string;
|
||||
datasetSearchUsingExtensionQuery?: boolean;
|
||||
datasetSearchExtensionModel?: string;
|
||||
datasetSearchExtensionBg?: string;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -58,6 +64,7 @@ const Test = ({ datasetId }: { datasetId: string }) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const { toast } = useToast();
|
||||
const { llmModelList } = useSystemStore();
|
||||
const { datasetDetail } = useDatasetStore();
|
||||
const { pushDatasetTestItem } = useSearchTestStore();
|
||||
const [inputType, setInputType] = useState<'text' | 'file'>('text');
|
||||
@@ -77,12 +84,15 @@ const Test = ({ datasetId }: { datasetId: string }) => {
|
||||
searchMode: DatasetSearchModeEnum.embedding,
|
||||
usingReRank: false,
|
||||
limit: 5000,
|
||||
similarity: 0
|
||||
similarity: 0,
|
||||
datasetSearchUsingExtensionQuery: false,
|
||||
datasetSearchExtensionModel: llmModelList[0].model,
|
||||
datasetSearchExtensionBg: ''
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const searchModeData = DatasetSearchModeMap[getValues('searchParams.searchMode')];
|
||||
const searchModeData = DatasetSearchModeMap[getValues(`searchParams.searchMode`)];
|
||||
|
||||
const {
|
||||
isOpen: isOpenSelectMode,
|
||||
@@ -123,34 +133,34 @@ const Test = ({ datasetId }: { datasetId: string }) => {
|
||||
});
|
||||
}
|
||||
});
|
||||
const { mutate: onFileTest, isLoading: fileTestIsLoading } = useRequest({
|
||||
mutationFn: async ({ searchParams }: FormType) => {
|
||||
if (!selectFile) return Promise.reject('File is not selected');
|
||||
const { data } = await readCsvContent({ file: selectFile });
|
||||
const testList = data.slice(0, 100);
|
||||
const results: SearchTestResponse[] = [];
|
||||
// const { mutate: onFileTest, isLoading: fileTestIsLoading } = useRequest({
|
||||
// mutationFn: async ({ searchParams }: FormType) => {
|
||||
// if (!selectFile) return Promise.reject('File is not selected');
|
||||
// const { data } = await readCsvContent({ file: selectFile });
|
||||
// const testList = data.slice(0, 100);
|
||||
// const results: SearchTestResponse[] = [];
|
||||
|
||||
for await (const item of testList) {
|
||||
try {
|
||||
const result = await postSearchText({ datasetId, text: item[0].trim(), ...searchParams });
|
||||
results.push(result);
|
||||
} catch (error) {
|
||||
await delay(500);
|
||||
}
|
||||
}
|
||||
// for await (const item of testList) {
|
||||
// try {
|
||||
// const result = await postSearchText({ datasetId, text: item[0].trim(), ...searchParams });
|
||||
// results.push(result);
|
||||
// } catch (error) {
|
||||
// await delay(500);
|
||||
// }
|
||||
// }
|
||||
|
||||
return results;
|
||||
},
|
||||
onSuccess(res: SearchTestResponse[]) {
|
||||
console.log(res);
|
||||
},
|
||||
onError(err) {
|
||||
toast({
|
||||
title: getErrText(err),
|
||||
status: 'error'
|
||||
});
|
||||
}
|
||||
});
|
||||
// return results;
|
||||
// },
|
||||
// onSuccess(res: SearchTestResponse[]) {
|
||||
// console.log(res);
|
||||
// },
|
||||
// onError(err) {
|
||||
// toast({
|
||||
// title: getErrText(err),
|
||||
// status: 'error'
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
|
||||
const onSelectFile = async (files: File[]) => {
|
||||
const file = files[0];
|
||||
@@ -295,13 +305,13 @@ const Test = ({ datasetId }: { datasetId: string }) => {
|
||||
<Flex justifyContent={'flex-end'}>
|
||||
<Button
|
||||
size={'sm'}
|
||||
isLoading={textTestIsLoading || fileTestIsLoading}
|
||||
isLoading={textTestIsLoading}
|
||||
isDisabled={inputType === 'file' && !selectFile}
|
||||
onClick={() => {
|
||||
if (inputType === 'text') {
|
||||
handleSubmit((data) => onTextTest(data))();
|
||||
} else {
|
||||
handleSubmit((data) => onFileTest(data))();
|
||||
// handleSubmit((data) => onFileTest(data))();
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -35,6 +35,7 @@ import type {
|
||||
} from '@fastgpt/global/core/dataset/api.d';
|
||||
import { pushDataListToTrainingQueue } from '@fastgpt/service/core/dataset/training/controller';
|
||||
import { getVectorModel } from '../../ai/model';
|
||||
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
|
||||
export async function pushDataToTrainingQueue(
|
||||
props: {
|
||||
@@ -272,7 +273,7 @@ export async function updateData2Dataset({
|
||||
};
|
||||
}
|
||||
|
||||
export async function searchDatasetData(props: {
|
||||
type SearchDatasetDataProps = {
|
||||
teamId: string;
|
||||
model: string;
|
||||
similarity?: number; // min distance
|
||||
@@ -280,12 +281,14 @@ export async function searchDatasetData(props: {
|
||||
datasetIds: string[];
|
||||
searchMode?: `${DatasetSearchModeEnum}`;
|
||||
usingReRank?: boolean;
|
||||
rawQuery: string;
|
||||
reRankQuery: string;
|
||||
queries: string[];
|
||||
}) {
|
||||
};
|
||||
|
||||
export async function searchDatasetData(props: SearchDatasetDataProps) {
|
||||
let {
|
||||
teamId,
|
||||
rawQuery,
|
||||
reRankQuery,
|
||||
queries,
|
||||
model,
|
||||
similarity = 0,
|
||||
@@ -307,27 +310,6 @@ export async function searchDatasetData(props: {
|
||||
let usingSimilarityFilter = false;
|
||||
|
||||
/* function */
|
||||
const countRecallLimit = () => {
|
||||
const oneChunkToken = 50;
|
||||
const estimatedLen = Math.max(20, Math.ceil(maxTokens / oneChunkToken));
|
||||
|
||||
if (searchMode === DatasetSearchModeEnum.embedding) {
|
||||
return {
|
||||
embeddingLimit: Math.min(estimatedLen, 80),
|
||||
fullTextLimit: 0
|
||||
};
|
||||
}
|
||||
if (searchMode === DatasetSearchModeEnum.fullTextRecall) {
|
||||
return {
|
||||
embeddingLimit: 0,
|
||||
fullTextLimit: Math.min(estimatedLen, 50)
|
||||
};
|
||||
}
|
||||
return {
|
||||
embeddingLimit: Math.min(estimatedLen, 60),
|
||||
fullTextLimit: Math.min(estimatedLen, 40)
|
||||
};
|
||||
};
|
||||
const embeddingRecall = async ({ query, limit }: { query: string; limit: number }) => {
|
||||
const { vectors, charsLength } = await getVectorsByText({
|
||||
model: getVectorModel(model),
|
||||
@@ -531,69 +513,50 @@ export async function searchDatasetData(props: {
|
||||
embeddingLimit: number;
|
||||
fullTextLimit: number;
|
||||
}) => {
|
||||
// In a group n recall, as long as one of the data appears minAmount of times, it is retained
|
||||
const getIntersection = (resultList: SearchDataResponseItemType[][], minAmount = 1) => {
|
||||
minAmount = Math.min(resultList.length, minAmount);
|
||||
|
||||
const map: Record<
|
||||
string,
|
||||
{
|
||||
amount: number;
|
||||
data: SearchDataResponseItemType;
|
||||
}
|
||||
> = {};
|
||||
|
||||
for (const list of resultList) {
|
||||
for (const item of list) {
|
||||
map[item.id] = map[item.id]
|
||||
? {
|
||||
amount: map[item.id].amount + 1,
|
||||
data: item
|
||||
}
|
||||
: {
|
||||
amount: 1,
|
||||
data: item
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return Object.values(map)
|
||||
.filter((item) => item.amount >= minAmount)
|
||||
.map((item) => item.data);
|
||||
};
|
||||
|
||||
// multi query recall
|
||||
const embeddingRecallResList: SearchDataResponseItemType[][] = [];
|
||||
const fullTextRecallResList: SearchDataResponseItemType[][] = [];
|
||||
let totalCharsLength = 0;
|
||||
for await (const query of queries) {
|
||||
const [{ charsLength, embeddingRecallResults }, { fullTextRecallResults }] =
|
||||
await Promise.all([
|
||||
embeddingRecall({
|
||||
query,
|
||||
limit: embeddingLimit
|
||||
}),
|
||||
fullTextRecall({
|
||||
query,
|
||||
limit: fullTextLimit
|
||||
})
|
||||
]);
|
||||
totalCharsLength += charsLength;
|
||||
|
||||
embeddingRecallResList.push(embeddingRecallResults);
|
||||
fullTextRecallResList.push(fullTextRecallResults);
|
||||
}
|
||||
await Promise.all(
|
||||
queries.map(async (query) => {
|
||||
const [{ charsLength, embeddingRecallResults }, { fullTextRecallResults }] =
|
||||
await Promise.all([
|
||||
embeddingRecall({
|
||||
query,
|
||||
limit: embeddingLimit
|
||||
}),
|
||||
fullTextRecall({
|
||||
query,
|
||||
limit: fullTextLimit
|
||||
})
|
||||
]);
|
||||
totalCharsLength += charsLength;
|
||||
|
||||
embeddingRecallResList.push(embeddingRecallResults);
|
||||
fullTextRecallResList.push(fullTextRecallResults);
|
||||
})
|
||||
);
|
||||
|
||||
// rrf concat
|
||||
const rrfEmbRecall = datasetSearchResultConcat(
|
||||
embeddingRecallResList.map((list) => ({ k: 60, list }))
|
||||
).slice(0, embeddingLimit);
|
||||
const rrfFTRecall = datasetSearchResultConcat(
|
||||
fullTextRecallResList.map((list) => ({ k: 60, list }))
|
||||
).slice(0, fullTextLimit);
|
||||
|
||||
return {
|
||||
charsLength: totalCharsLength,
|
||||
embeddingRecallResults: embeddingRecallResList[0],
|
||||
fullTextRecallResults: fullTextRecallResList[0]
|
||||
embeddingRecallResults: rrfEmbRecall,
|
||||
fullTextRecallResults: rrfFTRecall
|
||||
};
|
||||
};
|
||||
|
||||
/* main step */
|
||||
// count limit
|
||||
const { embeddingLimit, fullTextLimit } = countRecallLimit();
|
||||
const embeddingLimit = 60;
|
||||
const fullTextLimit = 40;
|
||||
|
||||
// recall
|
||||
const { embeddingRecallResults, fullTextRecallResults, charsLength } = await multiQueryRecall({
|
||||
@@ -620,7 +583,7 @@ export async function searchDatasetData(props: {
|
||||
return true;
|
||||
});
|
||||
return reRankSearchResult({
|
||||
query: rawQuery,
|
||||
query: reRankQuery,
|
||||
data: filterSameDataResults
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -3,10 +3,13 @@ import { formatModelPrice2Store } from '@/service/support/wallet/bill/utils';
|
||||
import type { SelectedDatasetType } from '@fastgpt/global/core/module/api.d';
|
||||
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/module/type.d';
|
||||
import { ModelTypeEnum, getVectorModel } from '@/service/core/ai/model';
|
||||
import { ModelTypeEnum, getLLMModel, getVectorModel } from '@/service/core/ai/model';
|
||||
import { searchDatasetData } from '@/service/core/dataset/data/controller';
|
||||
import { ModuleInputKeyEnum, ModuleOutputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { queryExtension } from '@fastgpt/service/core/ai/functions/queryExtension';
|
||||
import { getHistories } from '../utils';
|
||||
import { datasetSearchQueryExtension } from '@fastgpt/service/core/dataset/search/utils';
|
||||
|
||||
type DatasetSearchProps = ModuleDispatchProps<{
|
||||
[ModuleInputKeyEnum.datasetSelectList]: SelectedDatasetType;
|
||||
@@ -15,6 +18,9 @@ type DatasetSearchProps = ModuleDispatchProps<{
|
||||
[ModuleInputKeyEnum.datasetSearchMode]: `${DatasetSearchModeEnum}`;
|
||||
[ModuleInputKeyEnum.userChatInput]: string;
|
||||
[ModuleInputKeyEnum.datasetSearchUsingReRank]: boolean;
|
||||
[ModuleInputKeyEnum.datasetSearchUsingExtensionQuery]: boolean;
|
||||
[ModuleInputKeyEnum.datasetSearchExtensionModel]: string;
|
||||
[ModuleInputKeyEnum.datasetSearchExtensionBg]: string;
|
||||
}>;
|
||||
export type DatasetSearchResponse = {
|
||||
[ModuleOutputKeyEnum.responseData]: moduleDispatchResType;
|
||||
@@ -28,7 +34,19 @@ export async function dispatchDatasetSearch(
|
||||
): Promise<DatasetSearchResponse> {
|
||||
const {
|
||||
teamId,
|
||||
params: { datasets = [], similarity, limit = 1500, usingReRank, searchMode, userChatInput }
|
||||
histories,
|
||||
params: {
|
||||
datasets = [],
|
||||
similarity,
|
||||
limit = 1500,
|
||||
usingReRank,
|
||||
searchMode,
|
||||
userChatInput,
|
||||
|
||||
datasetSearchUsingExtensionQuery,
|
||||
datasetSearchExtensionModel,
|
||||
datasetSearchExtensionBg
|
||||
}
|
||||
} = props as DatasetSearchProps;
|
||||
|
||||
if (!Array.isArray(datasets)) {
|
||||
@@ -43,15 +61,21 @@ export async function dispatchDatasetSearch(
|
||||
return Promise.reject('core.chat.error.User input empty');
|
||||
}
|
||||
|
||||
// query extension
|
||||
const extensionModel =
|
||||
datasetSearchUsingExtensionQuery && datasetSearchExtensionModel
|
||||
? getLLMModel(datasetSearchExtensionModel)
|
||||
: undefined;
|
||||
const { concatQueries, rewriteQuery, aiExtensionResult } = await datasetSearchQueryExtension({
|
||||
query: userChatInput,
|
||||
extensionModel,
|
||||
extensionBg: datasetSearchExtensionBg,
|
||||
histories: getHistories(6, histories)
|
||||
});
|
||||
|
||||
// get vector
|
||||
const vectorModel = getVectorModel(datasets[0]?.vectorModel?.model);
|
||||
|
||||
// const { queries: extensionQueries } = await searchQueryExtension({
|
||||
// query: userChatInput,
|
||||
// model: global.llmModels[0].model
|
||||
// });
|
||||
const concatQueries = [userChatInput];
|
||||
|
||||
// start search
|
||||
const {
|
||||
searchRes,
|
||||
@@ -60,7 +84,7 @@ export async function dispatchDatasetSearch(
|
||||
usingReRank: searchUsingReRank
|
||||
} = await searchDatasetData({
|
||||
teamId,
|
||||
rawQuery: `${userChatInput}`,
|
||||
reRankQuery: `${rewriteQuery}`,
|
||||
queries: concatQueries,
|
||||
model: vectorModel.model,
|
||||
similarity,
|
||||
@@ -70,25 +94,45 @@ export async function dispatchDatasetSearch(
|
||||
usingReRank
|
||||
});
|
||||
|
||||
// count bill results
|
||||
// vector
|
||||
const { total, modelName } = formatModelPrice2Store({
|
||||
model: vectorModel.model,
|
||||
inputLen: charsLength,
|
||||
type: ModelTypeEnum.vector
|
||||
});
|
||||
const responseData: moduleDispatchResType & { price: number } = {
|
||||
price: total,
|
||||
query: concatQueries.join('\n'),
|
||||
model: modelName,
|
||||
charsLength,
|
||||
similarity: usingSimilarityFilter ? similarity : undefined,
|
||||
limit,
|
||||
searchMode,
|
||||
searchUsingReRank: searchUsingReRank
|
||||
};
|
||||
|
||||
if (aiExtensionResult) {
|
||||
const { total, modelName } = formatModelPrice2Store({
|
||||
model: aiExtensionResult.model,
|
||||
inputLen: aiExtensionResult.inputTokens,
|
||||
outputLen: aiExtensionResult.outputTokens,
|
||||
type: ModelTypeEnum.llm
|
||||
});
|
||||
|
||||
responseData.price += total;
|
||||
responseData.inputTokens = aiExtensionResult.inputTokens;
|
||||
responseData.outputTokens = aiExtensionResult.outputTokens;
|
||||
responseData.extensionModel = modelName;
|
||||
responseData.extensionResult =
|
||||
aiExtensionResult.extensionQueries?.join('\n') ||
|
||||
JSON.stringify(aiExtensionResult.extensionQueries);
|
||||
}
|
||||
|
||||
return {
|
||||
isEmpty: searchRes.length === 0 ? true : undefined,
|
||||
unEmpty: searchRes.length > 0 ? true : undefined,
|
||||
quoteQA: searchRes,
|
||||
responseData: {
|
||||
price: total,
|
||||
query: concatQueries.join('\n'),
|
||||
model: modelName,
|
||||
charsLength,
|
||||
similarity: usingSimilarityFilter ? similarity : undefined,
|
||||
limit,
|
||||
searchMode,
|
||||
searchUsingReRank: searchUsingReRank
|
||||
}
|
||||
responseData
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import type { ChatItemType, moduleDispatchResType } from '@fastgpt/global/core/chat/type.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/module/type.d';
|
||||
import { ModuleInputKeyEnum, ModuleOutputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import { getHistories } from '../utils';
|
||||
import { getAIApi } from '@fastgpt/service/core/ai/config';
|
||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||
import { ModelTypeEnum, getLLMModel } from '@/service/core/ai/model';
|
||||
import { formatModelPrice2Store } from '@/service/support/wallet/bill/utils';
|
||||
import { queryCfr } from '@fastgpt/service/core/ai/functions/cfr';
|
||||
import { getHistories } from '../utils';
|
||||
|
||||
type Props = ModuleDispatchProps<{
|
||||
[ModuleInputKeyEnum.aiModel]: string;
|
||||
@@ -34,57 +33,18 @@ export const dispatchCFR = async ({
|
||||
};
|
||||
}
|
||||
|
||||
const extractModel = getLLMModel(model);
|
||||
const cfrModel = getLLMModel(model);
|
||||
const chatHistories = getHistories(history, histories);
|
||||
|
||||
const systemFewShot = systemPrompt
|
||||
? `Q: 对话背景。
|
||||
A: ${systemPrompt}
|
||||
`
|
||||
: '';
|
||||
const historyFewShot = chatHistories
|
||||
.map((item) => {
|
||||
const role = item.obj === 'Human' ? 'Q' : 'A';
|
||||
return `${role}: ${item.value}`;
|
||||
})
|
||||
.join('\n');
|
||||
|
||||
const concatFewShot = `${systemFewShot}${historyFewShot}`.trim();
|
||||
|
||||
const ai = getAIApi({
|
||||
timeout: 480000
|
||||
const { cfrQuery, inputTokens, outputTokens } = await queryCfr({
|
||||
chatBg: systemPrompt,
|
||||
query: userChatInput,
|
||||
histories: chatHistories,
|
||||
model: cfrModel.model
|
||||
});
|
||||
|
||||
const result = await ai.chat.completions.create({
|
||||
model: extractModel.model,
|
||||
temperature: 0,
|
||||
max_tokens: 150,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: replaceVariable(defaultPrompt, {
|
||||
query: `${userChatInput}`,
|
||||
histories: concatFewShot
|
||||
})
|
||||
}
|
||||
],
|
||||
stream: false
|
||||
});
|
||||
|
||||
let answer = result.choices?.[0]?.message?.content || '';
|
||||
// console.log(
|
||||
// replaceVariable(defaultPrompt, {
|
||||
// query: userChatInput,
|
||||
// histories: concatFewShot
|
||||
// })
|
||||
// );
|
||||
// console.log(answer);
|
||||
|
||||
const inputTokens = result.usage?.prompt_tokens || 0;
|
||||
const outputTokens = result.usage?.completion_tokens || 0;
|
||||
|
||||
const { total, modelName } = formatModelPrice2Store({
|
||||
model: extractModel.model,
|
||||
model: cfrModel.model,
|
||||
inputLen: inputTokens,
|
||||
outputLen: outputTokens,
|
||||
type: ModelTypeEnum.llm
|
||||
@@ -97,85 +57,8 @@ A: ${systemPrompt}
|
||||
inputTokens,
|
||||
outputTokens,
|
||||
query: userChatInput,
|
||||
textOutput: answer
|
||||
textOutput: cfrQuery
|
||||
},
|
||||
[ModuleOutputKeyEnum.text]: answer
|
||||
[ModuleOutputKeyEnum.text]: cfrQuery
|
||||
};
|
||||
};
|
||||
|
||||
const defaultPrompt = `请不要回答任何问题。
|
||||
你的任务是结合上下文,为当前问题,实现代词替换,确保问题描述的对象清晰明确。例如:
|
||||
历史记录:
|
||||
"""
|
||||
Q: 对话背景。
|
||||
A: 关于 FatGPT 的介绍和使用等问题。
|
||||
"""
|
||||
当前问题: 怎么下载
|
||||
输出: FastGPT 怎么下载?
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: 报错 "no connection"
|
||||
A: FastGPT 报错"no connection"可能是因为……
|
||||
"""
|
||||
当前问题: 怎么解决
|
||||
输出: FastGPT 报错"no connection"如何解决?
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: 作者是谁?
|
||||
A: FastGPT 的作者是 labring。
|
||||
"""
|
||||
当前问题: 介绍下他
|
||||
输出: 介绍下 FastGPT 的作者 labring。
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: 作者是谁?
|
||||
A: FastGPT 的作者是 labring。
|
||||
"""
|
||||
当前问题: 我想购买商业版。
|
||||
输出: FastGPT 商业版如何购买?
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: 对话背景。
|
||||
A: 关于 FatGPT 的介绍和使用等问题。
|
||||
"""
|
||||
当前问题: nh
|
||||
输出: nh
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: FastGPT 如何收费?
|
||||
A: FastGPT 收费可以参考……
|
||||
"""
|
||||
当前问题: 你知道 laf 么?
|
||||
输出: 你知道 laf 么?
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: FastGPT 的优势
|
||||
A: 1. 开源
|
||||
2. 简便
|
||||
3. 扩展性强
|
||||
"""
|
||||
当前问题: 介绍下第2点。
|
||||
输出: 介绍下 FastGPT 简便的优势。
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: 什么是 FastGPT?
|
||||
A: FastGPT 是一个 RAG 平台。
|
||||
Q: 什么是 Sealos?
|
||||
A: Sealos 是一个云操作系统。
|
||||
"""
|
||||
当前问题: 它们有什么关系?
|
||||
输出: FastGPT 和 Sealos 有什么关系?
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
{{histories}}
|
||||
"""
|
||||
当前问题: {{query}}
|
||||
输出: `;
|
||||
|
||||
@@ -26,63 +26,40 @@ export const dispatchHttpRequest = async (props: HttpRequestProps): Promise<Http
|
||||
variables,
|
||||
outputs,
|
||||
params: {
|
||||
system_httpMethod: httpMethod,
|
||||
url: abandonUrl,
|
||||
system_httpMethod: httpMethod = 'POST',
|
||||
system_httpReqUrl: httpReqUrl,
|
||||
system_httpHeader: httpHeader,
|
||||
...body
|
||||
}
|
||||
} = props;
|
||||
|
||||
if (!httpReqUrl) {
|
||||
return Promise.reject('Http url is empty');
|
||||
}
|
||||
|
||||
body = flatDynamicParams(body);
|
||||
|
||||
const { requestMethod, requestUrl, requestHeader, requestBody, requestQuery } = await (() => {
|
||||
// 2024-2-12 clear
|
||||
if (abandonUrl) {
|
||||
return {
|
||||
requestMethod: 'POST',
|
||||
requestUrl: abandonUrl,
|
||||
requestHeader: httpHeader,
|
||||
requestBody: {
|
||||
...body,
|
||||
appId,
|
||||
chatId,
|
||||
variables
|
||||
},
|
||||
requestQuery: {}
|
||||
};
|
||||
}
|
||||
if (httpReqUrl) {
|
||||
return {
|
||||
requestMethod: httpMethod,
|
||||
requestUrl: httpReqUrl,
|
||||
requestHeader: httpHeader,
|
||||
requestBody: {
|
||||
appId,
|
||||
chatId,
|
||||
responseChatItemId,
|
||||
variables,
|
||||
data: body
|
||||
},
|
||||
requestQuery: {
|
||||
appId,
|
||||
chatId,
|
||||
...variables,
|
||||
...body
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return Promise.reject('url is empty');
|
||||
})();
|
||||
const requestBody = {
|
||||
appId,
|
||||
chatId,
|
||||
responseChatItemId,
|
||||
variables,
|
||||
data: body
|
||||
};
|
||||
const requestQuery = {
|
||||
appId,
|
||||
chatId,
|
||||
...variables,
|
||||
...body
|
||||
};
|
||||
|
||||
const formatBody = transformFlatJson({ ...requestBody });
|
||||
|
||||
// parse header
|
||||
const headers = await (() => {
|
||||
try {
|
||||
if (!requestHeader) return {};
|
||||
return JSON.parse(requestHeader);
|
||||
if (!httpHeader) return {};
|
||||
return JSON.parse(httpHeader);
|
||||
} catch (error) {
|
||||
return Promise.reject('Header 为非法 JSON 格式');
|
||||
}
|
||||
@@ -90,8 +67,8 @@ export const dispatchHttpRequest = async (props: HttpRequestProps): Promise<Http
|
||||
|
||||
try {
|
||||
const response = await fetchData({
|
||||
method: requestMethod,
|
||||
url: requestUrl,
|
||||
method: httpMethod,
|
||||
url: httpReqUrl,
|
||||
headers,
|
||||
body: formatBody,
|
||||
query: requestQuery
|
||||
|
||||
@@ -87,7 +87,10 @@ export const pushGenerateVectorBill = ({
|
||||
tmbId,
|
||||
charsLength,
|
||||
model,
|
||||
source = BillSourceEnum.fastgpt
|
||||
source = BillSourceEnum.fastgpt,
|
||||
extensionModel,
|
||||
extensionInputTokens,
|
||||
extensionOutputTokens
|
||||
}: {
|
||||
billId?: string;
|
||||
teamId: string;
|
||||
@@ -95,19 +98,43 @@ export const pushGenerateVectorBill = ({
|
||||
charsLength: number;
|
||||
model: string;
|
||||
source?: `${BillSourceEnum}`;
|
||||
|
||||
extensionModel?: string;
|
||||
extensionInputTokens?: number;
|
||||
extensionOutputTokens?: number;
|
||||
}) => {
|
||||
let { total, modelName } = formatModelPrice2Store({
|
||||
const { total: totalVector, modelName: vectorModelName } = formatModelPrice2Store({
|
||||
model,
|
||||
inputLen: charsLength,
|
||||
type: ModelTypeEnum.vector
|
||||
});
|
||||
|
||||
const { extensionTotal, extensionModelName } = (() => {
|
||||
if (!extensionModel || !extensionInputTokens || !extensionOutputTokens)
|
||||
return {
|
||||
extensionTotal: 0,
|
||||
extensionModelName: ''
|
||||
};
|
||||
const { total, modelName } = formatModelPrice2Store({
|
||||
model: extensionModel,
|
||||
inputLen: extensionInputTokens,
|
||||
outputLen: extensionOutputTokens,
|
||||
type: ModelTypeEnum.llm
|
||||
});
|
||||
return {
|
||||
extensionTotal: total,
|
||||
extensionModelName: modelName
|
||||
};
|
||||
})();
|
||||
|
||||
const total = totalVector + extensionTotal;
|
||||
|
||||
// 插入 Bill 记录
|
||||
if (billId) {
|
||||
concatBill({
|
||||
teamId,
|
||||
tmbId,
|
||||
total,
|
||||
total: totalVector,
|
||||
billId,
|
||||
charsLength,
|
||||
listIndex: 0
|
||||
@@ -123,9 +150,20 @@ export const pushGenerateVectorBill = ({
|
||||
{
|
||||
moduleName: 'wallet.moduleName.index',
|
||||
amount: total,
|
||||
model: modelName,
|
||||
model: vectorModelName,
|
||||
charsLength
|
||||
}
|
||||
},
|
||||
...(extensionModel !== undefined
|
||||
? [
|
||||
{
|
||||
moduleName: extensionModelName,
|
||||
amount: extensionTotal,
|
||||
model: extensionModelName,
|
||||
inputTokens: extensionInputTokens,
|
||||
outputTokens: extensionOutputTokens
|
||||
}
|
||||
]
|
||||
: [])
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,10 +6,7 @@ import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import type { FormatForm2ModulesProps } from '@fastgpt/global/core/app/api.d';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
|
||||
export async function postForm2Modules(
|
||||
data: AppSimpleEditFormType,
|
||||
templateId = 'fastgpt-universal'
|
||||
) {
|
||||
export async function postForm2Modules(data: AppSimpleEditFormType) {
|
||||
const llmModelList = useSystemStore.getState().llmModelList;
|
||||
function userGuideTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
|
||||
return [
|
||||
@@ -60,7 +57,7 @@ export async function postForm2Modules(
|
||||
llmModelList
|
||||
};
|
||||
|
||||
const modules = await POST<ModuleItemType[]>(`/core/app/form2Modules/${templateId}`, props);
|
||||
const modules = await POST<ModuleItemType[]>(`/core/app/form2Modules/fastgpt-universal`, props);
|
||||
|
||||
return [...userGuideTemplate(data), ...modules];
|
||||
}
|
||||
|
||||
@@ -128,8 +128,8 @@ const SelectCollections = ({
|
||||
{title
|
||||
? title
|
||||
: type === 'folder'
|
||||
? t('common.Root folder')
|
||||
: t('dataset.collections.Select Collection')}
|
||||
? t('common.Root folder')
|
||||
: t('dataset.collections.Select Collection')}
|
||||
</Box>
|
||||
{!!tip && (
|
||||
<Box fontSize={'sm'} color={'myGray.500'}>
|
||||
|
||||
@@ -29,8 +29,7 @@ export const appSystemModuleTemplates: FlowModuleTemplateType[] = [
|
||||
RunAppModule,
|
||||
ClassifyQuestionModule,
|
||||
ContextExtractModule,
|
||||
HttpModule,
|
||||
AiCFR
|
||||
HttpModule
|
||||
];
|
||||
export const pluginSystemModuleTemplates: FlowModuleTemplateType[] = [
|
||||
PluginInputModule,
|
||||
@@ -42,8 +41,7 @@ export const pluginSystemModuleTemplates: FlowModuleTemplateType[] = [
|
||||
RunAppModule,
|
||||
ClassifyQuestionModule,
|
||||
ContextExtractModule,
|
||||
HttpModule,
|
||||
AiCFR
|
||||
HttpModule
|
||||
];
|
||||
|
||||
export const moduleTemplatesFlat: FlowModuleTemplateType[] = [
|
||||
|
||||
@@ -329,11 +329,16 @@ const Switch = switchMultiStyle({
|
||||
baseStyle: switchPart({
|
||||
track: {
|
||||
bg: 'myGray.100',
|
||||
borderWidth: '1px',
|
||||
borderColor: 'borders.base',
|
||||
_checked: {
|
||||
bg: 'primary.600'
|
||||
}
|
||||
}
|
||||
})
|
||||
}),
|
||||
defaultProps: {
|
||||
size: 'md'
|
||||
}
|
||||
});
|
||||
|
||||
const Select = selectMultiStyle({
|
||||
|
||||
Reference in New Issue
Block a user