Compare commits
12 Commits
v4.8.19-be
...
v4.8.19-al
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d82db01a9 | ||
|
|
80e670600b | ||
|
|
68f5afeba0 | ||
|
|
0d9f54cbf3 | ||
|
|
11cfe8a809 | ||
|
|
6f8c6b6ad1 | ||
|
|
f468ba2f30 | ||
|
|
19abfd1a3e | ||
|
|
ace304c619 | ||
|
|
923d0f85e9 | ||
|
|
62bcff2ff0 | ||
|
|
ec0cef09a2 |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 174 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 48 KiB |
@@ -29,43 +29,6 @@ images: []
|
||||
如图
|
||||

|
||||
|
||||
### 数据库3306端口被占用了,启动服务失败
|
||||

|
||||
|
||||
mysql 只有 oneAPI 用到,外面一般不需要调用,所以可以
|
||||
- 把 3306:3306 的映射去掉/或者直接改一个映射。
|
||||
|
||||
```yaml
|
||||
# 在 docker-compose.yaml 文件内
|
||||
# ...
|
||||
mysql:
|
||||
image: mysql:8.0.36
|
||||
ports:
|
||||
- 3306:3306 # 这个端口被占用了!
|
||||
# - 3307:3306 # 直接改一个。。和外面的不冲突
|
||||
# *empty* 或者直接删了,反正外面用不到
|
||||
oneapi:
|
||||
container_name: oneapi
|
||||
image: ghcr.io/songquanpeng/one-api:latest
|
||||
environment:
|
||||
- SQL_DSN=root:oneapimmysql@tcp(mysql:3306)/oneapi # 这不用改,容器内外网络是隔离的
|
||||
```
|
||||
- 另一种做法是可以直接连现有的 mysql, 要改 oneAPI 的环境变量。
|
||||
```yaml
|
||||
# 在 docker-compose.yaml 文件内
|
||||
# ...
|
||||
# mysql: # 要连外面的,这个玩意用不到了
|
||||
# image: mysql:8.0.36
|
||||
# ports:
|
||||
# - 3306:3306 # 这个端口被占用了!
|
||||
oneapi:
|
||||
container_name: oneapi
|
||||
image: ghcr.io/songquanpeng/one-api:latest
|
||||
environment:
|
||||
- SQL_DSN=root:oneapimmysql@tcp(mysql:3306)/oneapi # 改成外面的链接字符串
|
||||
```
|
||||
|
||||
|
||||
### 本地部署的限制
|
||||
|
||||
具体内容参考https://fael3z0zfze.feishu.cn/wiki/OFpAw8XzAi36Guk8dfucrCKUnjg。
|
||||
|
||||
@@ -11,12 +11,7 @@ weight: 806
|
||||
## 完整更新内容
|
||||
|
||||
1. 新增 - 工作流知识库检索支持按知识库权限进行过滤。
|
||||
2. 新增 - 飞书/语雀知识库查看原文。
|
||||
3. 新增 - 流程等待插件,可以等待 n 毫秒后继续执行流程。
|
||||
4. 优化 - 成员列表分页加载。
|
||||
5. 优化 - 统一分页加载代码。
|
||||
6. 优化 - 对话页面加载时,可配置是否为独立页面。
|
||||
7. 修复 - 语雀文件库导入时,嵌套文件内容无法展开的问题。
|
||||
8. 修复 - 工作流编排中,LLM 参数无法关闭问题。
|
||||
9. 修复 - 工作流编排中,代码运行节点还原模板问题。
|
||||
10. 修复 - HTTP 接口适配对象字符串解析。
|
||||
2. 优化 - 成员列表分页加载。
|
||||
3. 优化 - 统一分页加载代码。
|
||||
4. 修复 - 语雀文件库导入时,嵌套文件内容无法展开的问题。
|
||||
5. 修复 - 工作流编排中,LLM 参数无法关闭问题。
|
||||
|
||||
@@ -21,19 +21,6 @@ weight: 908
|
||||
|
||||
定时执行会在应用发布后生效,会在后台生效。
|
||||
|
||||
## V4.8.18-FIX2中提到“ 1. 修复 HTTP 节点, {{}} 格式引用变量兼容问题。建议尽快替换 / 模式取变量, {{}} 语法已弃用。”替换{{}}引用格式是仅仅只有在http节点,还是所有节点的都会有影响?
|
||||
|
||||
只有 http 节点用到这个语法。
|
||||
|
||||
## 工作流类型的应用在运行预览可以正常提问返回,但是发布免登录窗口之后有问题。
|
||||
|
||||
一般是没正确发布,在工作流右上角点击【保存并发布】。
|
||||
|
||||
## 如何解决猜你想问使用中文回答显示
|
||||
|
||||
注意需要更新到V4.8.17及以上,把猜你想问的提示词改成中文。
|
||||

|
||||
|
||||
## AI对话回答要求中的Markdown语法取消
|
||||
|
||||
修改知识库默认提示词, 默认用的是标准模板提示词,会要求按 Markdown 输出,可以去除该要求:
|
||||
|
||||
@@ -24,17 +24,6 @@ xlsx等都可以上传的,不止支持CSV。
|
||||
|
||||
统一按gpt3.5标准。
|
||||
|
||||
## 误删除重排模型后,重排模型怎么加入到fastgpt
|
||||
|
||||

|
||||
|
||||
config.json文件里面配置后就可以勾选重排模型
|
||||
|
||||
## 线上平台上创建了应用和知识库,到期之后如果短期内不续费,数据是否会被清理。
|
||||
|
||||
免费版是三十天不登录后清空知识库,应用不会动。其他付费套餐到期后自动切免费版。
|
||||

|
||||
|
||||
## 基于知识库的查询,但是问题相关的答案过多。ai回答到一半就不继续回答。
|
||||
|
||||
FastGPT回复长度计算公式:
|
||||
|
||||
@@ -8,14 +8,4 @@ weight: 918
|
||||
|
||||
## oneapi 官网是哪个
|
||||
|
||||
只有开源的 README,没官网,GitHub: https://github.com/songquanpeng/one-api
|
||||
|
||||
## 想做多用户和多chat key
|
||||
|
||||

|
||||

|
||||
|
||||
多用户问题:只能采取二开或者商业版
|
||||
|
||||
多chat key问题:1. 私有化部署情况下,oneapi解决。2. Saas或者商业版中,可以为每个团队设置单独的key。
|
||||

|
||||
只有开源的 README,没官网,GitHub: https://github.com/songquanpeng/one-api
|
||||
@@ -22,11 +22,10 @@ FastGPT v4.8.16 版本开始,商业版用户支持飞书知识库导入,用
|
||||
|
||||
## 2. 配置应用权限
|
||||
|
||||
创建应用后,进入应用可以配置相关权限,这里需要增加**3个权限**:
|
||||
创建应用后,进入应用可以配置相关权限,这里需要增加两个权限:
|
||||
|
||||
1. 获取云空间文件夹下的云文档清单
|
||||
2. 查看新版文档
|
||||
3. 查看、评论、编辑和管理云空间中所有文件
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: "批量运行"
|
||||
description: "FastGPT 批量运行节点介绍和使用"
|
||||
title: "循环执行"
|
||||
description: "FastGPT 循环运行节点介绍和使用"
|
||||
icon: "input"
|
||||
draft: false
|
||||
toc: true
|
||||
@@ -9,15 +9,15 @@ weight: 260
|
||||
|
||||
## 节点概述
|
||||
|
||||
【**批量运行**】节点是 FastGPT V4.8.11 版本新增的一个重要功能模块。它允许工作流对数组类型的输入数据进行迭代处理,每次处理数组中的一个元素,并自动执行后续节点,直到完成整个数组的处理。
|
||||
【**循环运行**】节点是 FastGPT V4.8.11 版本新增的一个重要功能模块。它允许工作流对数组类型的输入数据进行迭代处理,每次处理数组中的一个元素,并自动执行后续节点,直到完成整个数组的处理。
|
||||
|
||||
这个节点的设计灵感来自编程语言中的循环结构,但以可视化的方式呈现。
|
||||
|
||||

|
||||

|
||||
|
||||
> 在程序中,节点可以理解为一个个 Function 或者接口。可以理解为它就是一个**步骤**。将多个节点一个个拼接起来,即可一步步的去实现最终的 AI 输出。
|
||||
|
||||
【**批量运行**】节点本质上也是一个 Function,它的主要职责是自动化地重复执行特定的工作流程。
|
||||
【**循环运行**】节点本质上也是一个 Function,它的主要职责是自动化地重复执行特定的工作流程。
|
||||
|
||||
## 核心特性
|
||||
|
||||
@@ -41,9 +41,9 @@ weight: 260
|
||||
|
||||
## 应用场景
|
||||
|
||||
【**批量运行**】节点的主要作用是通过自动化的方式扩展工作流的处理能力,使 FastGPT 能够更好地处理批量任务和复杂的数据处理流程。特别是在处理大规模数据或需要多轮迭代的场景下,批量运行节点能显著提升工作流的效率和自动化程度。
|
||||
【**循环运行**】节点的主要作用是通过自动化的方式扩展工作流的处理能力,使 FastGPT 能够更好地处理批量任务和复杂的数据处理流程。特别是在处理大规模数据或需要多轮迭代的场景下,循环运行节点能显著提升工作流的效率和自动化程度。
|
||||
|
||||
【**批量运行**】节点特别适合以下场景:
|
||||
【**循环运行**】节点特别适合以下场景:
|
||||
|
||||
1. **批量数据处理**
|
||||
- 批量翻译文本
|
||||
@@ -64,7 +64,7 @@ weight: 260
|
||||
|
||||
### 输入参数设置
|
||||
|
||||
【**批量运行**】节点需要配置两个核心输入参数:
|
||||
【**循环运行**】节点需要配置两个核心输入参数:
|
||||
|
||||
1. **数组 (必填)**:接收一个数组类型的输入,可以是:
|
||||
- 字符串数组 (`Array<string>`)
|
||||
@@ -95,7 +95,7 @@ weight: 260
|
||||
|
||||
### 批量处理数组
|
||||
|
||||
假设我们有一个包含多个文本的数组,需要对每个文本进行 AI 处理。这是批量运行节点最基础也最常见的应用场景。
|
||||
假设我们有一个包含多个文本的数组,需要对每个文本进行 AI 处理。这是循环运行节点最基础也最常见的应用场景。
|
||||
|
||||
#### 实现步骤
|
||||
|
||||
@@ -114,9 +114,9 @@ weight: 260
|
||||
return { textArray: texts };
|
||||
```
|
||||
|
||||
2. 配置批量运行节点
|
||||
2. 配置循环运行节点
|
||||
|
||||

|
||||

|
||||
|
||||
- 数组输入:选择上一步代码运行节点的输出变量 `textArray`。
|
||||
- 循环体内添加一个【AI 对话】节点,用于处理每个文本。这里我们输入的 prompt 为:`请将这段文本翻译成英文`。
|
||||
@@ -128,7 +128,7 @@ weight: 260
|
||||

|
||||
|
||||
1. 【代码运行】节点执行,生成测试数组
|
||||
2. 【批量运行】节点接收数组,开始遍历
|
||||
2. 【循环运行】节点接收数组,开始遍历
|
||||
3. 对每个数组元素:
|
||||
- 【AI 对话】节点处理当前元素
|
||||
- 【指定回复】节点输出翻译后的文本
|
||||
@@ -144,7 +144,7 @@ weight: 260
|
||||
- 需要维护上下文的连贯性
|
||||
- 翻译质量需要多轮优化
|
||||
|
||||
【**批量运行**】节点可以很好地解决这些问题。
|
||||
【**循环运行**】节点可以很好地解决这些问题。
|
||||
|
||||
#### 实现步骤
|
||||
|
||||
@@ -281,9 +281,9 @@ weight: 260
|
||||
|
||||
这里我们用到了 [Jina AI 开源的一个强大的正则表达式](https://x.com/JinaAI_/status/1823756993108304135),它能利用所有可能的边界线索和启发式方法来精确切分文本。
|
||||
|
||||
2. 配置批量运行节点
|
||||
2. 配置循环运行节点
|
||||
|
||||

|
||||

|
||||
|
||||
- 数组输入:选择上一步代码运行节点的输出变量 `chunks`。
|
||||
- 循环体内添加一个【代码运行】节点,对源文本进行格式化。
|
||||
|
||||
@@ -212,7 +212,7 @@ export default async function (ctx: FunctionContext): Promise<IResponse>{
|
||||
|
||||

|
||||
|
||||
## 批量运行
|
||||
## 循环执行
|
||||
|
||||
长文反思翻译比较关键的一个部分,就是对多个文本块进行循环反思翻译
|
||||
|
||||
|
||||
@@ -91,9 +91,9 @@ weight: 604
|
||||
|
||||
这个过程不仅提高了效率,还最大限度地减少了人为错误的可能性。
|
||||
|
||||
## 批量运行
|
||||
## 循环执行
|
||||
|
||||
为了处理整个长字幕文件,我们需要一个批量运行机制。这是通过一个简单但有效的判断模块实现的:
|
||||
为了处理整个长字幕文件,我们需要一个循环执行机制。这是通过一个简单但有效的判断模块实现的:
|
||||
|
||||
1. 检查当前翻译的文本块是否为最后一个。
|
||||
2. 如果不是,则将工作流重定向到格式化原文本块节点。
|
||||
|
||||
@@ -33,7 +33,7 @@ export const defaultWhisperConfig: AppWhisperConfigType = {
|
||||
export const defaultQGConfig: AppQGConfigType = {
|
||||
open: false,
|
||||
model: 'gpt-4o-mini',
|
||||
customPrompt: ''
|
||||
customPrompt: PROMPT_QUESTION_GUIDE
|
||||
};
|
||||
|
||||
export const defaultChatInputGuideConfig = {
|
||||
|
||||
@@ -34,7 +34,7 @@ export function getSourceNameIcon({
|
||||
}
|
||||
} catch (error) {}
|
||||
|
||||
return 'file/fill/file';
|
||||
return 'file/fill/manual';
|
||||
}
|
||||
|
||||
/* get dataset data default index */
|
||||
|
||||
@@ -12,8 +12,7 @@ const staticPluginList = [
|
||||
'DingTalkWebhook',
|
||||
'WeWorkWebhook',
|
||||
'google',
|
||||
'bing',
|
||||
'delay'
|
||||
'bing'
|
||||
];
|
||||
// Run in worker thread (Have npm packages)
|
||||
const packagePluginList = [
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { delay } from '@fastgpt/global/common/system/utils';
|
||||
|
||||
type Props = {
|
||||
ms: number;
|
||||
};
|
||||
type Response = Promise<Number>;
|
||||
|
||||
const main = async ({ ms }: Props): Response => {
|
||||
if (typeof ms !== 'number' || ms <= 0 || ms > 300000) {
|
||||
return ms;
|
||||
}
|
||||
|
||||
await delay(ms);
|
||||
|
||||
return ms;
|
||||
};
|
||||
|
||||
export default main;
|
||||
@@ -1,318 +0,0 @@
|
||||
{
|
||||
"author": "collin",
|
||||
"version": "4817",
|
||||
"name": "流程等待",
|
||||
"avatar": "core/workflow/template/sleep",
|
||||
"intro": "让工作流等待指定时间后运行",
|
||||
"showStatus": true,
|
||||
"weight": 1,
|
||||
|
||||
"isTool": true,
|
||||
"templateType": "tools",
|
||||
|
||||
"workflow": {
|
||||
"nodes": [
|
||||
{
|
||||
"nodeId": "pluginInput",
|
||||
"name": "workflow:template.plugin_start",
|
||||
"intro": "workflow:intro_plugin_input",
|
||||
"avatar": "core/workflow/template/workflowStart",
|
||||
"flowNodeType": "pluginInput",
|
||||
"showStatus": false,
|
||||
"position": {
|
||||
"x": 627.6352390819724,
|
||||
"y": -165.05298493910118
|
||||
},
|
||||
"version": "481",
|
||||
"inputs": [
|
||||
{
|
||||
"renderTypeList": ["numberInput", "reference"],
|
||||
"selectedTypeIndex": 0,
|
||||
"valueType": "number",
|
||||
"canEdit": true,
|
||||
"key": "延迟时长",
|
||||
"label": "延迟时长",
|
||||
"description": "需要暂停的时间,单位毫秒",
|
||||
"defaultValue": 1000,
|
||||
"list": [
|
||||
{
|
||||
"label": "",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"maxFiles": 5,
|
||||
"canSelectFile": true,
|
||||
"canSelectImg": true,
|
||||
"required": true,
|
||||
"toolDescription": "需要暂停的时间,单位毫秒",
|
||||
"max": 300000,
|
||||
"min": 1
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"id": "ms",
|
||||
"valueType": "number",
|
||||
"key": "延迟时长",
|
||||
"label": "延迟时长",
|
||||
"type": "hidden"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeId": "pluginOutput",
|
||||
"name": "common:core.module.template.self_output",
|
||||
"intro": "workflow:intro_custom_plugin_output",
|
||||
"avatar": "core/workflow/template/pluginOutput",
|
||||
"flowNodeType": "pluginOutput",
|
||||
"showStatus": false,
|
||||
"position": {
|
||||
"x": 1921.839722563351,
|
||||
"y": -160.05298493910115
|
||||
},
|
||||
"version": "481",
|
||||
"inputs": [
|
||||
{
|
||||
"renderTypeList": ["reference"],
|
||||
"valueType": "any",
|
||||
"canEdit": true,
|
||||
"key": "result",
|
||||
"label": "result",
|
||||
"isToolOutput": true,
|
||||
"description": "",
|
||||
"required": true,
|
||||
"value": ["zCJC6zw7c14i", "httpRawResponse"]
|
||||
}
|
||||
],
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"nodeId": "pluginConfig",
|
||||
"name": "common:core.module.template.system_config",
|
||||
"intro": "",
|
||||
"avatar": "core/workflow/template/systemConfig",
|
||||
"flowNodeType": "pluginConfig",
|
||||
"position": {
|
||||
"x": 184.66337662472682,
|
||||
"y": -216.05298493910115
|
||||
},
|
||||
"version": "4811",
|
||||
"inputs": [],
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"nodeId": "zCJC6zw7c14i",
|
||||
"name": "HTTP 请求",
|
||||
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
|
||||
"avatar": "core/workflow/template/httpRequest",
|
||||
"flowNodeType": "httpRequest468",
|
||||
"showStatus": true,
|
||||
"position": {
|
||||
"x": 1154.4041630064592,
|
||||
"y": -455.0529849391012
|
||||
},
|
||||
"version": "481",
|
||||
"inputs": [
|
||||
{
|
||||
"key": "system_addInputParam",
|
||||
"renderTypeList": ["addInputParam"],
|
||||
"valueType": "dynamic",
|
||||
"label": "",
|
||||
"required": false,
|
||||
"description": "common:core.module.input.description.HTTP Dynamic Input",
|
||||
"customInputConfig": {
|
||||
"selectValueTypeList": [
|
||||
"string",
|
||||
"number",
|
||||
"boolean",
|
||||
"object",
|
||||
"arrayString",
|
||||
"arrayNumber",
|
||||
"arrayBoolean",
|
||||
"arrayObject",
|
||||
"arrayAny",
|
||||
"any",
|
||||
"chatHistory",
|
||||
"datasetQuote",
|
||||
"dynamic",
|
||||
"selectApp",
|
||||
"selectDataset"
|
||||
],
|
||||
"showDescription": false,
|
||||
"showDefaultValue": true
|
||||
},
|
||||
"valueDesc": "",
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
},
|
||||
{
|
||||
"key": "system_httpMethod",
|
||||
"renderTypeList": ["custom"],
|
||||
"valueType": "string",
|
||||
"label": "",
|
||||
"value": "POST",
|
||||
"required": true,
|
||||
"valueDesc": "",
|
||||
"description": "",
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
},
|
||||
{
|
||||
"key": "system_httpTimeout",
|
||||
"renderTypeList": ["custom"],
|
||||
"valueType": "number",
|
||||
"label": "",
|
||||
"value": 30,
|
||||
"min": 5,
|
||||
"max": 600,
|
||||
"required": true,
|
||||
"valueDesc": "",
|
||||
"description": "",
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
},
|
||||
{
|
||||
"key": "system_httpReqUrl",
|
||||
"renderTypeList": ["hidden"],
|
||||
"valueType": "string",
|
||||
"label": "",
|
||||
"description": "common:core.module.input.description.Http Request Url",
|
||||
"placeholder": "https://api.ai.com/getInventory",
|
||||
"required": false,
|
||||
"value": "delay",
|
||||
"valueDesc": "",
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
},
|
||||
{
|
||||
"key": "system_httpHeader",
|
||||
"renderTypeList": ["custom"],
|
||||
"valueType": "any",
|
||||
"value": [],
|
||||
"label": "",
|
||||
"description": "common:core.module.input.description.Http Request Header",
|
||||
"placeholder": "common:core.module.input.description.Http Request Header",
|
||||
"required": false,
|
||||
"valueDesc": "",
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
},
|
||||
{
|
||||
"key": "system_httpParams",
|
||||
"renderTypeList": ["hidden"],
|
||||
"valueType": "any",
|
||||
"value": [],
|
||||
"label": "",
|
||||
"required": false,
|
||||
"valueDesc": "",
|
||||
"description": "",
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
},
|
||||
{
|
||||
"key": "system_httpJsonBody",
|
||||
"renderTypeList": ["hidden"],
|
||||
"valueType": "any",
|
||||
"value": "{\n\"ms\": {{$pluginInput.ms$}}\n}",
|
||||
"label": "",
|
||||
"required": false,
|
||||
"valueDesc": "",
|
||||
"description": "",
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
},
|
||||
{
|
||||
"key": "system_httpFormBody",
|
||||
"renderTypeList": ["hidden"],
|
||||
"valueType": "any",
|
||||
"value": [],
|
||||
"label": "",
|
||||
"required": false,
|
||||
"valueDesc": "",
|
||||
"description": "",
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
},
|
||||
{
|
||||
"key": "system_httpContentType",
|
||||
"renderTypeList": ["hidden"],
|
||||
"valueType": "string",
|
||||
"value": "json",
|
||||
"label": "",
|
||||
"required": false,
|
||||
"valueDesc": "",
|
||||
"description": "",
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"id": "error",
|
||||
"key": "error",
|
||||
"label": "workflow:request_error",
|
||||
"description": "HTTP请求错误信息,成功时返回空",
|
||||
"valueType": "object",
|
||||
"type": "static"
|
||||
},
|
||||
{
|
||||
"id": "httpRawResponse",
|
||||
"key": "httpRawResponse",
|
||||
"required": true,
|
||||
"label": "workflow:raw_response",
|
||||
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
|
||||
"valueType": "any",
|
||||
"type": "static"
|
||||
},
|
||||
{
|
||||
"id": "system_addOutputParam",
|
||||
"key": "system_addOutputParam",
|
||||
"type": "dynamic",
|
||||
"valueType": "dynamic",
|
||||
"label": "输出字段提取",
|
||||
"customFieldConfig": {
|
||||
"selectValueTypeList": [
|
||||
"string",
|
||||
"number",
|
||||
"boolean",
|
||||
"object",
|
||||
"arrayString",
|
||||
"arrayNumber",
|
||||
"arrayBoolean",
|
||||
"arrayObject",
|
||||
"arrayAny",
|
||||
"any",
|
||||
"chatHistory",
|
||||
"datasetQuote",
|
||||
"dynamic",
|
||||
"selectApp",
|
||||
"selectDataset"
|
||||
],
|
||||
"showDescription": false,
|
||||
"showDefaultValue": false
|
||||
},
|
||||
"description": "可以通过 JSONPath 语法来提取响应值中的指定字段",
|
||||
"valueDesc": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"source": "pluginInput",
|
||||
"target": "zCJC6zw7c14i",
|
||||
"sourceHandle": "pluginInput-source-right",
|
||||
"targetHandle": "zCJC6zw7c14i-target-left"
|
||||
},
|
||||
{
|
||||
"source": "zCJC6zw7c14i",
|
||||
"target": "pluginOutput",
|
||||
"sourceHandle": "zCJC6zw7c14i-source-right",
|
||||
"targetHandle": "pluginOutput-target-left"
|
||||
}
|
||||
],
|
||||
"chatConfig": {
|
||||
"welcomeText": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,6 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
|
||||
showStatus: false
|
||||
};
|
||||
});
|
||||
|
||||
const runtimeVariables = {
|
||||
...filterSystemVariables(props.variables),
|
||||
appId: String(plugin.id)
|
||||
|
||||
@@ -127,16 +127,8 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
||||
if (typeof val === 'object') return JSON.stringify(val);
|
||||
|
||||
if (typeof val === 'string') {
|
||||
try {
|
||||
const parsed = JSON.parse(val);
|
||||
if (typeof parsed === 'object') {
|
||||
return JSON.stringify(parsed);
|
||||
}
|
||||
return val;
|
||||
} catch (error) {
|
||||
const str = JSON.stringify(val);
|
||||
return str.startsWith('"') && str.endsWith('"') ? str.slice(1, -1) : str;
|
||||
}
|
||||
const str = JSON.stringify(val);
|
||||
return str.startsWith('"') && str.endsWith('"') ? str.slice(1, -1) : str;
|
||||
}
|
||||
|
||||
return String(val);
|
||||
@@ -243,9 +235,7 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
||||
}
|
||||
if (!httpJsonBody) return {};
|
||||
if (httpContentType === ContentTypes.json) {
|
||||
httpJsonBody = replaceJsonBodyString(httpJsonBody);
|
||||
console.log(httpJsonBody);
|
||||
return json5.parse(httpJsonBody);
|
||||
return json5.parse(replaceJsonBodyString(httpJsonBody));
|
||||
}
|
||||
|
||||
// Raw text, xml
|
||||
|
||||
@@ -270,7 +270,6 @@ export const iconPaths = {
|
||||
import('./icons/core/workflow/template/datasource.svg'),
|
||||
'core/workflow/template/duckduckgo': () =>
|
||||
import('./icons/core/workflow/template/duckduckgo.svg'),
|
||||
'core/workflow/template/sleep': () => import('./icons/core/workflow/template/sleep.svg'),
|
||||
'core/workflow/template/extractJson': () =>
|
||||
import('./icons/core/workflow/template/extractJson.svg'),
|
||||
'core/workflow/template/fetchUrl': () => import('./icons/core/workflow/template/fetchUrl.svg'),
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||
width="200" height="200">
|
||||
<path d="M-70.54222222-70.54222222m582.54222222 0l0 0q582.54222222 0 582.54222222 582.54222222l0 0q0 582.54222222-582.54222222 582.54222222l0 0q-582.54222222 0-582.54222222-582.54222222l0 0q0-582.54222222 582.54222222-582.54222222Z"
|
||||
fill="#1296db"/>
|
||||
<path d="M422.64477924 243.86730561H243.86730561v536.26538878h178.77747363V243.86730561zM780.13269439 243.86730561h-178.77747363v536.26538878H780.13269439V243.86730561z"
|
||||
fill="#ffffff"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 593 B |
@@ -135,7 +135,7 @@ const MySelect = <T = any,>(
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}, [list, value]);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Box
|
||||
|
||||
@@ -29,6 +29,8 @@ export type ChatProviderProps = {
|
||||
outLinkAuthData?: OutLinkChatAuthProps;
|
||||
|
||||
chatType: 'log' | 'chat' | 'share' | 'team';
|
||||
showRawSource: boolean;
|
||||
showNodeStatus: boolean;
|
||||
};
|
||||
|
||||
type useChatStoreType = ChatProviderProps & {
|
||||
@@ -130,6 +132,8 @@ const Provider = ({
|
||||
chatId,
|
||||
outLinkAuthData = {},
|
||||
chatType = 'chat',
|
||||
showRawSource,
|
||||
showNodeStatus,
|
||||
children,
|
||||
...props
|
||||
}: ChatProviderProps & {
|
||||
@@ -245,7 +249,9 @@ const Provider = ({
|
||||
chatId,
|
||||
outLinkAuthData,
|
||||
getHistoryResponseData,
|
||||
chatType
|
||||
chatType,
|
||||
showRawSource,
|
||||
showNodeStatus
|
||||
};
|
||||
|
||||
return <ChatBoxContext.Provider value={value}>{children}</ChatBoxContext.Provider>;
|
||||
|
||||
@@ -25,7 +25,6 @@ import { isEqual } from 'lodash';
|
||||
import { useSystem } from '@fastgpt/web/hooks/useSystem';
|
||||
import { formatTimeToChatItemTime } from '@fastgpt/global/common/string/time';
|
||||
import dayjs from 'dayjs';
|
||||
import { ChatItemContext } from '@/web/core/chat/context/chatItemContext';
|
||||
|
||||
const colorMap = {
|
||||
[ChatStatusEnum.loading]: {
|
||||
@@ -140,7 +139,7 @@ const ChatItem = (props: Props) => {
|
||||
|
||||
const isChatting = useContextSelector(ChatBoxContext, (v) => v.isChatting);
|
||||
const chatType = useContextSelector(ChatBoxContext, (v) => v.chatType);
|
||||
const showNodeStatus = useContextSelector(ChatItemContext, (v) => v.showNodeStatus);
|
||||
const showNodeStatus = useContextSelector(ChatBoxContext, (v) => v.showNodeStatus);
|
||||
const isChatLog = chatType === 'log';
|
||||
|
||||
const { copyData } = useCopyData();
|
||||
|
||||
@@ -9,16 +9,19 @@ import RawSourceBox from '@/components/core/dataset/RawSourceBox';
|
||||
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { ChatBoxContext } from '../Provider';
|
||||
import { ChatItemContext } from '@/web/core/chat/context/chatItemContext';
|
||||
|
||||
const QuoteModal = ({
|
||||
rawSearch = [],
|
||||
onClose,
|
||||
canEditDataset,
|
||||
showRawSource,
|
||||
chatItemId,
|
||||
metadata
|
||||
}: {
|
||||
rawSearch: SearchDataResponseItemType[];
|
||||
onClose: () => void;
|
||||
canEditDataset: boolean;
|
||||
showRawSource: boolean;
|
||||
chatItemId: string;
|
||||
metadata?: {
|
||||
collectionId: string;
|
||||
@@ -44,11 +47,6 @@ const QuoteModal = ({
|
||||
chatItemId,
|
||||
...(v.outLinkAuthData || {})
|
||||
}));
|
||||
const showRawSource = useContextSelector(ChatItemContext, (v) => v.isShowReadRawSource);
|
||||
const showRouteToDatasetDetail = useContextSelector(
|
||||
ChatItemContext,
|
||||
(v) => v.showRouteToDatasetDetail
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -73,7 +71,12 @@ const QuoteModal = ({
|
||||
}
|
||||
>
|
||||
<ModalBody>
|
||||
<QuoteList rawSearch={filterResults} chatItemId={chatItemId} />
|
||||
<QuoteList
|
||||
rawSearch={filterResults}
|
||||
canEditDataset={canEditDataset}
|
||||
canViewSource={showRawSource}
|
||||
chatItemId={chatItemId}
|
||||
/>
|
||||
</ModalBody>
|
||||
</MyModal>
|
||||
</>
|
||||
@@ -84,10 +87,14 @@ export default QuoteModal;
|
||||
|
||||
export const QuoteList = React.memo(function QuoteList({
|
||||
chatItemId,
|
||||
rawSearch = []
|
||||
rawSearch = [],
|
||||
canEditDataset,
|
||||
canViewSource
|
||||
}: {
|
||||
chatItemId?: string;
|
||||
rawSearch: SearchDataResponseItemType[];
|
||||
canEditDataset: boolean;
|
||||
canViewSource: boolean;
|
||||
}) {
|
||||
const theme = useTheme();
|
||||
|
||||
@@ -97,11 +104,6 @@ export const QuoteList = React.memo(function QuoteList({
|
||||
chatId: v.chatId,
|
||||
...(v.outLinkAuthData || {})
|
||||
}));
|
||||
const showRawSource = useContextSelector(ChatItemContext, (v) => v.isShowReadRawSource);
|
||||
const showRouteToDatasetDetail = useContextSelector(
|
||||
ChatItemContext,
|
||||
(v) => v.showRouteToDatasetDetail
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -118,8 +120,8 @@ export const QuoteList = React.memo(function QuoteList({
|
||||
>
|
||||
<QuoteItem
|
||||
quoteItem={item}
|
||||
canViewSource={showRawSource}
|
||||
canEditDataset={showRouteToDatasetDetail}
|
||||
canViewSource={canViewSource}
|
||||
canEditDataset={canEditDataset}
|
||||
{...RawSourceBoxProps}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@@ -49,6 +49,7 @@ const ResponseTags = ({
|
||||
const [quoteFolded, setQuoteFolded] = useState<boolean>(true);
|
||||
|
||||
const chatType = useContextSelector(ChatBoxContext, (v) => v.chatType);
|
||||
const showRawSource = useContextSelector(ChatBoxContext, (v) => v.showRawSource);
|
||||
const notSharePage = useMemo(() => chatType !== 'share', [chatType]);
|
||||
|
||||
const {
|
||||
@@ -250,6 +251,8 @@ const ResponseTags = ({
|
||||
<QuoteModal
|
||||
{...quoteModalData}
|
||||
chatItemId={historyItem.dataId}
|
||||
canEditDataset={notSharePage}
|
||||
showRawSource={showRawSource}
|
||||
onClose={() => setQuoteModalData(undefined)}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -18,6 +18,7 @@ import { Box, Checkbox } from '@chakra-ui/react';
|
||||
import { EventNameEnum, eventBus } from '@/web/common/utils/eventbus';
|
||||
import { chats2GPTMessages } from '@fastgpt/global/core/chat/adapt';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import {
|
||||
|
||||
@@ -249,7 +249,14 @@ export const WholeResponseContent = ({
|
||||
{activeModule.quoteList && activeModule.quoteList.length > 0 && (
|
||||
<Row
|
||||
label={t('common:core.chat.response.module quoteList')}
|
||||
rawDom={<QuoteList chatItemId={dataId} rawSearch={activeModule.quoteList} />}
|
||||
rawDom={
|
||||
<QuoteList
|
||||
canEditDataset
|
||||
canViewSource
|
||||
chatItemId={dataId}
|
||||
rawSearch={activeModule.quoteList}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -164,6 +164,8 @@ const DetailLogsModal = ({ appId, chatId, onClose }: Props) => {
|
||||
showMarkIcon
|
||||
showVoiceIcon={false}
|
||||
chatType="log"
|
||||
showRawSource
|
||||
showNodeStatus
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
@@ -185,12 +187,7 @@ const Render = (props: Props) => {
|
||||
}, [appId, chatId]);
|
||||
|
||||
return (
|
||||
<ChatItemContextProvider
|
||||
showRouteToAppDetail={true}
|
||||
showRouteToDatasetDetail={true}
|
||||
isShowReadRawSource={true}
|
||||
showNodeStatus
|
||||
>
|
||||
<ChatItemContextProvider>
|
||||
<ChatRecordContextProvider params={params}>
|
||||
<DetailLogsModal {...props} />
|
||||
</ChatRecordContextProvider>
|
||||
|
||||
@@ -91,12 +91,7 @@ const Render = ({ appForm }: Props) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<ChatItemContextProvider
|
||||
showRouteToAppDetail={true}
|
||||
showRouteToDatasetDetail={true}
|
||||
isShowReadRawSource={true}
|
||||
showNodeStatus
|
||||
>
|
||||
<ChatItemContextProvider>
|
||||
<ChatRecordContextProvider params={chatRecordProviderParams}>
|
||||
<ChatTest appForm={appForm} />
|
||||
</ChatRecordContextProvider>
|
||||
|
||||
@@ -158,12 +158,7 @@ const Render = (Props: Props) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<ChatItemContextProvider
|
||||
showRouteToAppDetail={true}
|
||||
showRouteToDatasetDetail={true}
|
||||
isShowReadRawSource={true}
|
||||
showNodeStatus
|
||||
>
|
||||
<ChatItemContextProvider>
|
||||
<ChatRecordContextProvider params={chatRecordProviderParams}>
|
||||
<ChatTest {...Props} />
|
||||
</ChatRecordContextProvider>
|
||||
|
||||
@@ -14,18 +14,22 @@ import RenderToolInput from './render/RenderToolInput';
|
||||
import RenderOutput from './render/RenderOutput';
|
||||
import CodeEditor from '@fastgpt/web/components/common/Textarea/CodeEditor';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { JS_TEMPLATE } from '@fastgpt/global/core/workflow/template/system/sandbox/constants';
|
||||
import { getLatestNodeTemplate } from '@/web/core/workflow/utils';
|
||||
import { CodeNode } from '@fastgpt/global/core/workflow/template/system/sandbox';
|
||||
|
||||
const NodeCode = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
const { workflowT } = useI18n();
|
||||
const { nodeId, inputs, outputs } = data;
|
||||
|
||||
const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs);
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (ctx) => ctx.onChangeNode);
|
||||
const { splitToolInputs, onChangeNode, onResetNode } = useContextSelector(
|
||||
WorkflowContext,
|
||||
(ctx) => ctx
|
||||
);
|
||||
|
||||
const { ConfirmModal, openConfirm } = useConfirm({
|
||||
content: t('workflow:code.Reset template confirm')
|
||||
content: workflowT('code.Reset template confirm')
|
||||
});
|
||||
|
||||
const CustomComponent = useMemo(() => {
|
||||
@@ -34,24 +38,19 @@ const NodeCode = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
return (
|
||||
<Box mt={-3}>
|
||||
<Flex mb={2} alignItems={'flex-end'}>
|
||||
<Box flex={'1'}>{'Javascript ' + t('workflow:Code')}</Box>
|
||||
<Box flex={'1'}>{'Javascript ' + workflowT('Code')}</Box>
|
||||
<Box
|
||||
cursor={'pointer'}
|
||||
color={'primary.500'}
|
||||
fontSize={'xs'}
|
||||
onClick={openConfirm(() => {
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'updateInput',
|
||||
key: item.key,
|
||||
value: {
|
||||
...item,
|
||||
value: JS_TEMPLATE
|
||||
}
|
||||
onResetNode({
|
||||
id: nodeId,
|
||||
node: getLatestNodeTemplate(data, CodeNode)
|
||||
});
|
||||
})}
|
||||
>
|
||||
{t('workflow:code.Reset template')}
|
||||
{workflowT('code.Reset template')}
|
||||
</Box>
|
||||
</Flex>
|
||||
<CodeEditor
|
||||
@@ -74,33 +73,37 @@ const NodeCode = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
);
|
||||
}
|
||||
};
|
||||
}, [nodeId, onChangeNode, openConfirm, t]);
|
||||
}, [data, nodeId, onChangeNode, onResetNode, openConfirm, workflowT]);
|
||||
|
||||
const { isTool, commonInputs } = splitToolInputs(inputs, nodeId);
|
||||
const Render = useMemo(() => {
|
||||
const { isTool, commonInputs } = splitToolInputs(inputs, nodeId);
|
||||
|
||||
return (
|
||||
<NodeCard minW={'400px'} selected={selected} {...data}>
|
||||
{isTool && (
|
||||
<>
|
||||
<Container>
|
||||
<RenderToolInput nodeId={nodeId} inputs={inputs} />
|
||||
</Container>
|
||||
</>
|
||||
)}
|
||||
<Container>
|
||||
<IOTitle text={t('common:common.Input')} mb={-1} />
|
||||
<RenderInput
|
||||
nodeId={nodeId}
|
||||
flowInputList={commonInputs}
|
||||
CustomComponent={CustomComponent}
|
||||
/>
|
||||
</Container>
|
||||
<Container>
|
||||
<IOTitle text={t('common:common.Output')} />
|
||||
<RenderOutput nodeId={nodeId} flowOutputList={outputs} />
|
||||
</Container>
|
||||
<ConfirmModal />
|
||||
</NodeCard>
|
||||
);
|
||||
return (
|
||||
<NodeCard minW={'400px'} selected={selected} {...data}>
|
||||
{isTool && (
|
||||
<>
|
||||
<Container>
|
||||
<RenderToolInput nodeId={nodeId} inputs={inputs} />
|
||||
</Container>
|
||||
</>
|
||||
)}
|
||||
<Container>
|
||||
<IOTitle text={t('common:common.Input')} mb={-1} />
|
||||
<RenderInput
|
||||
nodeId={nodeId}
|
||||
flowInputList={commonInputs}
|
||||
CustomComponent={CustomComponent}
|
||||
/>
|
||||
</Container>
|
||||
<Container>
|
||||
<IOTitle text={t('common:common.Output')} />
|
||||
<RenderOutput nodeId={nodeId} flowOutputList={outputs} />
|
||||
</Container>
|
||||
<ConfirmModal />
|
||||
</NodeCard>
|
||||
);
|
||||
}, [ConfirmModal, CustomComponent, data, inputs, nodeId, outputs, selected, splitToolInputs, t]);
|
||||
|
||||
return Render;
|
||||
};
|
||||
export default React.memo(NodeCode);
|
||||
|
||||
@@ -141,6 +141,8 @@ export const useChatTest = ({
|
||||
chatId={chatId}
|
||||
showMarkIcon
|
||||
chatType="chat"
|
||||
showRawSource
|
||||
showNodeStatus
|
||||
onStartChat={startChat}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -27,11 +27,13 @@ const ChatHeader = ({
|
||||
history,
|
||||
showHistory,
|
||||
apps,
|
||||
onRouteToAppDetail,
|
||||
totalRecordsCount
|
||||
}: {
|
||||
history: ChatItemType[];
|
||||
showHistory?: boolean;
|
||||
apps?: AppListItemType[];
|
||||
onRouteToAppDetail?: () => void;
|
||||
totalRecordsCount: number;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -69,7 +71,7 @@ const ChatHeader = ({
|
||||
)}
|
||||
|
||||
{/* control */}
|
||||
{!isPlugin && <ToolMenu history={history} />}
|
||||
{!isPlugin && <ToolMenu history={history} onRouteToAppDetail={onRouteToAppDetail} />}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@ type HistoryItemType = {
|
||||
const ChatHistorySlider = ({ confirmClearText }: { confirmClearText: string }) => {
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const isUserChatPage = router.pathname === '/chat';
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -45,7 +46,6 @@ const ChatHistorySlider = ({ confirmClearText }: { confirmClearText: string }) =
|
||||
|
||||
const appName = useContextSelector(ChatItemContext, (v) => v.chatBoxData?.app.name);
|
||||
const appAvatar = useContextSelector(ChatItemContext, (v) => v.chatBoxData?.app.avatar);
|
||||
const showRouteToAppDetail = useContextSelector(ChatItemContext, (v) => v.showRouteToAppDetail);
|
||||
|
||||
const concatHistory = useMemo(() => {
|
||||
const formatHistories: HistoryItemType[] = histories.map((item) => {
|
||||
@@ -77,8 +77,8 @@ const ChatHistorySlider = ({ confirmClearText }: { confirmClearText: string }) =
|
||||
});
|
||||
|
||||
const canRouteToDetail = useMemo(
|
||||
() => appId && userInfo?.team.permission.hasWritePer && showRouteToAppDetail,
|
||||
[appId, userInfo?.team.permission.hasWritePer, showRouteToAppDetail]
|
||||
() => appId && userInfo?.team.permission.hasWritePer,
|
||||
[appId, userInfo?.team.permission.hasWritePer]
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -287,7 +287,7 @@ const ChatHistorySlider = ({ confirmClearText }: { confirmClearText: string }) =
|
||||
</ScrollData>
|
||||
|
||||
{/* exec */}
|
||||
{!isPc && !!canRouteToDetail && (
|
||||
{!isPc && isUserChatPage && (
|
||||
<Flex
|
||||
mt={2}
|
||||
borderTop={theme.borders.base}
|
||||
|
||||
@@ -14,8 +14,6 @@ import {
|
||||
} from '@fastgpt/global/common/parentFolder/type';
|
||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { ChatItemContext } from '@/web/core/chat/context/chatItemContext';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
|
||||
const SelectOneResource = dynamic(() => import('@/components/common/folder/SelectOneResource'));
|
||||
|
||||
@@ -24,8 +22,6 @@ const SliderApps = ({ apps, activeAppId }: { apps: AppListItemType[]; activeAppI
|
||||
const router = useRouter();
|
||||
const isTeamChat = router.pathname === '/chat/team';
|
||||
|
||||
const showRouteToAppDetail = useContextSelector(ChatItemContext, (v) => v.showRouteToAppDetail);
|
||||
|
||||
const getAppList = useCallback(async ({ parentId }: GetResourceFolderListProps) => {
|
||||
return getMyApps({
|
||||
parentId,
|
||||
@@ -54,36 +50,34 @@ const SliderApps = ({ apps, activeAppId }: { apps: AppListItemType[]; activeAppI
|
||||
|
||||
return (
|
||||
<Flex flexDirection={'column'} h={'100%'}>
|
||||
{showRouteToAppDetail && (
|
||||
<>
|
||||
<Box mt={4} px={4}>
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
cursor={'pointer'}
|
||||
py={2}
|
||||
px={3}
|
||||
borderRadius={'md'}
|
||||
_hover={{ bg: 'myGray.200' }}
|
||||
onClick={() => router.push('/app/list')}
|
||||
>
|
||||
<IconButton
|
||||
mr={3}
|
||||
icon={<MyIcon name={'common/backFill'} w={'1rem'} color={'primary.500'} />}
|
||||
bg={'white'}
|
||||
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
|
||||
size={'smSquare'}
|
||||
borderRadius={'50%'}
|
||||
aria-label={''}
|
||||
/>
|
||||
{t('common:core.chat.Exit Chat')}
|
||||
</Flex>
|
||||
</Box>
|
||||
<MyDivider h={2} my={1} />
|
||||
</>
|
||||
)}
|
||||
<Box mt={4} px={4}>
|
||||
{!isTeamChat && (
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
cursor={'pointer'}
|
||||
py={2}
|
||||
px={3}
|
||||
borderRadius={'md'}
|
||||
_hover={{ bg: 'myGray.200' }}
|
||||
onClick={() => router.push('/app/list')}
|
||||
>
|
||||
<IconButton
|
||||
mr={3}
|
||||
icon={<MyIcon name={'common/backFill'} w={'1rem'} color={'primary.500'} />}
|
||||
bg={'white'}
|
||||
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
|
||||
size={'smSquare'}
|
||||
borderRadius={'50%'}
|
||||
aria-label={''}
|
||||
/>
|
||||
{t('common:core.chat.Exit Chat')}
|
||||
</Flex>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{!isTeamChat && (
|
||||
<>
|
||||
<MyDivider h={2} my={1} />
|
||||
<HStack
|
||||
px={4}
|
||||
my={2}
|
||||
|
||||
@@ -7,19 +7,20 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import MyMenu from '@fastgpt/web/components/common/MyMenu';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { ChatContext } from '@/web/core/chat/context/chatContext';
|
||||
import { ChatItemContext } from '@/web/core/chat/context/chatItemContext';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
|
||||
const router = useRouter();
|
||||
const ToolMenu = ({
|
||||
history,
|
||||
onRouteToAppDetail
|
||||
}: {
|
||||
history: ChatItemType[];
|
||||
onRouteToAppDetail?: () => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { onExportChat } = useChatBox();
|
||||
|
||||
const onChangeChatId = useContextSelector(ChatContext, (v) => v.onChangeChatId);
|
||||
const chatData = useContextSelector(ChatItemContext, (v) => v.chatBoxData);
|
||||
const showRouteToAppDetail = useContextSelector(ChatItemContext, (v) => v.showRouteToAppDetail);
|
||||
|
||||
return (
|
||||
return history.length > 0 ? (
|
||||
<MyMenu
|
||||
Button={
|
||||
<IconButton
|
||||
@@ -60,14 +61,14 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
|
||||
// }
|
||||
]
|
||||
},
|
||||
...(showRouteToAppDetail
|
||||
...(onRouteToAppDetail
|
||||
? [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
icon: 'core/app/aiLight',
|
||||
label: t('app:app_detail'),
|
||||
onClick: () => router.push(`/app/detail?appId=${chatData.appId}`)
|
||||
onClick: onRouteToAppDetail
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -75,6 +76,8 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
|
||||
: [])
|
||||
]}
|
||||
/>
|
||||
) : (
|
||||
<Box w={'28px'} h={'28px'} />
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const { isPc } = useSystem();
|
||||
|
||||
const { userInfo } = useUserStore();
|
||||
const { setLastChatAppId, chatId, appId, outLinkAuthData } = useChatStore();
|
||||
|
||||
@@ -187,6 +186,7 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
|
||||
apps={myApps}
|
||||
history={chatRecords}
|
||||
showHistory
|
||||
onRouteToAppDetail={() => router.push(`/app/detail?appId=${appId}`)}
|
||||
/>
|
||||
|
||||
{/* chat box */}
|
||||
@@ -208,6 +208,8 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
|
||||
feedbackType={'user'}
|
||||
onStartChat={onStartChat}
|
||||
chatType={'chat'}
|
||||
showRawSource
|
||||
showNodeStatus
|
||||
isReady={!loading}
|
||||
/>
|
||||
)}
|
||||
@@ -219,8 +221,8 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const Render = (props: { appId: string; isStandalone?: string }) => {
|
||||
const { appId, isStandalone } = props;
|
||||
const Render = (props: { appId: string }) => {
|
||||
const { appId } = props;
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
const router = useRouter();
|
||||
@@ -274,12 +276,7 @@ const Render = (props: { appId: string; isStandalone?: string }) => {
|
||||
|
||||
return source === ChatSourceEnum.online ? (
|
||||
<ChatContextProvider params={chatHistoryProviderParams}>
|
||||
<ChatItemContextProvider
|
||||
showRouteToAppDetail={isStandalone !== '1'}
|
||||
showRouteToDatasetDetail={isStandalone !== '1'}
|
||||
isShowReadRawSource={true}
|
||||
showNodeStatus
|
||||
>
|
||||
<ChatItemContextProvider>
|
||||
<ChatRecordContextProvider params={chatRecordProviderParams}>
|
||||
<Chat myApps={myApps} />
|
||||
</ChatRecordContextProvider>
|
||||
@@ -292,7 +289,6 @@ export async function getServerSideProps(context: any) {
|
||||
return {
|
||||
props: {
|
||||
appId: context?.query?.appId || '',
|
||||
isStandalone: context?.query?.isStandalone || '',
|
||||
...(await serviceSideProps(context, ['file', 'app', 'chat', 'workflow']))
|
||||
}
|
||||
};
|
||||
|
||||
@@ -55,6 +55,7 @@ type Props = {
|
||||
const OutLink = (props: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const router = useRouter();
|
||||
const { showRawSource, showNodeStatus } = props;
|
||||
const {
|
||||
shareId = '',
|
||||
showHistory = '1',
|
||||
@@ -286,6 +287,8 @@ const OutLink = (props: Props) => {
|
||||
feedbackType={'user'}
|
||||
onStartChat={startChat}
|
||||
chatType="share"
|
||||
showRawSource={showRawSource}
|
||||
showNodeStatus={showNodeStatus}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
@@ -337,12 +340,7 @@ const Render = (props: Props) => {
|
||||
|
||||
return source === ChatSourceEnum.share ? (
|
||||
<ChatContextProvider params={chatHistoryProviderParams}>
|
||||
<ChatItemContextProvider
|
||||
showRouteToAppDetail={false}
|
||||
showRouteToDatasetDetail={false}
|
||||
isShowReadRawSource={props.showRawSource}
|
||||
showNodeStatus={props.showNodeStatus}
|
||||
>
|
||||
<ChatItemContextProvider>
|
||||
<ChatRecordContextProvider params={chatRecordProviderParams}>
|
||||
<OutLink {...props} />
|
||||
</ChatRecordContextProvider>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import NextHead from '@/components/common/NextHead';
|
||||
import { getTeamChatInfo } from '@/web/core/chat/api';
|
||||
import { useRouter } from 'next/router';
|
||||
@@ -20,7 +20,8 @@ import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import ChatContextProvider, { ChatContext } from '@/web/core/chat/context/chatContext';
|
||||
import { AppListItemType } from '@fastgpt/global/core/app/type';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { GetChatTypeEnum } from '@/global/core/chat/constants';
|
||||
import { InitChatResponse } from '@/global/core/chat/api';
|
||||
import { defaultChatData, GetChatTypeEnum } from '@/global/core/chat/constants';
|
||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
|
||||
@@ -225,6 +226,8 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
|
||||
feedbackType={'user'}
|
||||
onStartChat={startChat}
|
||||
chatType="team"
|
||||
showRawSource
|
||||
showNodeStatus
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
@@ -296,12 +299,7 @@ const Render = (props: Props) => {
|
||||
|
||||
return source === ChatSourceEnum.team ? (
|
||||
<ChatContextProvider params={contextParams}>
|
||||
<ChatItemContextProvider
|
||||
showRouteToAppDetail={false}
|
||||
showRouteToDatasetDetail={false}
|
||||
isShowReadRawSource={true}
|
||||
showNodeStatus
|
||||
>
|
||||
<ChatItemContextProvider>
|
||||
<ChatRecordContextProvider params={chatRecordProviderParams}>
|
||||
<Chat {...props} myApps={myApps} />
|
||||
</ChatRecordContextProvider>
|
||||
|
||||
@@ -9,12 +9,6 @@ import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
import { AppChatConfigType, VariableItemType } from '@fastgpt/global/core/app/type';
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io';
|
||||
|
||||
type ContextProps = {
|
||||
showRouteToAppDetail: boolean;
|
||||
showRouteToDatasetDetail: boolean;
|
||||
isShowReadRawSource: boolean;
|
||||
showNodeStatus: boolean;
|
||||
};
|
||||
type ChatBoxDataType = {
|
||||
appId: string;
|
||||
title?: string;
|
||||
@@ -43,7 +37,7 @@ type ChatItemContextType = {
|
||||
chatBoxData: ChatBoxDataType;
|
||||
setChatBoxData: React.Dispatch<React.SetStateAction<ChatBoxDataType>>;
|
||||
isPlugin: boolean;
|
||||
} & ContextProps;
|
||||
};
|
||||
|
||||
export const ChatItemContext = createContext<ChatItemContextType>({
|
||||
ChatBoxRef: null,
|
||||
@@ -67,15 +61,7 @@ export const ChatItemContext = createContext<ChatItemContextType>({
|
||||
/*
|
||||
Chat 对象的上下文
|
||||
*/
|
||||
const ChatItemContextProvider = ({
|
||||
children,
|
||||
showRouteToAppDetail,
|
||||
showRouteToDatasetDetail,
|
||||
isShowReadRawSource,
|
||||
showNodeStatus
|
||||
}: {
|
||||
children: ReactNode;
|
||||
} & ContextProps) => {
|
||||
const ChatItemContextProvider = ({ children }: { children: ReactNode }) => {
|
||||
const ChatBoxRef = useRef<ChatComponentRef>(null);
|
||||
const variablesForm = useForm<ChatBoxInputFormType>();
|
||||
|
||||
@@ -127,23 +113,16 @@ const ChatItemContextProvider = ({
|
||||
pluginRunTab,
|
||||
setPluginRunTab,
|
||||
resetVariables,
|
||||
clearChatRecords,
|
||||
showRouteToAppDetail,
|
||||
showRouteToDatasetDetail,
|
||||
isShowReadRawSource,
|
||||
showNodeStatus
|
||||
clearChatRecords
|
||||
};
|
||||
}, [
|
||||
chatBoxData,
|
||||
setChatBoxData,
|
||||
clearChatRecords,
|
||||
isPlugin,
|
||||
variablesForm,
|
||||
pluginRunTab,
|
||||
resetVariables,
|
||||
clearChatRecords,
|
||||
showRouteToAppDetail,
|
||||
showRouteToDatasetDetail,
|
||||
isShowReadRawSource,
|
||||
showNodeStatus
|
||||
variablesForm
|
||||
]);
|
||||
|
||||
return <ChatItemContext.Provider value={contextValue}>{children}</ChatItemContext.Provider>;
|
||||
|
||||