Compare commits
17 Commits
v4.8.15-al
...
v4.8.15-fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
048f5a2d53 | ||
|
|
096afef629 | ||
|
|
f832d32c62 | ||
|
|
d7c6204e62 | ||
|
|
806109b748 | ||
|
|
b327e487a5 | ||
|
|
c98224dda3 | ||
|
|
5cea6015c0 | ||
|
|
fd47f73086 | ||
|
|
fc8f73fc55 | ||
|
|
1b8b11239c | ||
|
|
15dc7b220e | ||
|
|
c64d629a6a | ||
|
|
1a294c1fd3 | ||
|
|
a4f6128a89 | ||
|
|
021ec0595d | ||
|
|
6ceee7cb5e |
@@ -27,9 +27,6 @@ FastGPT 是一个基于 LLM 大语言模型的知识库问答系统,提供开
|
||||
<a href="/#-%E7%9B%B8%E5%85%B3%E9%A1%B9%E7%9B%AE">
|
||||
<img height="21" src="https://img.shields.io/badge/相关项目-7d09f1?style=flat-square" alt="project">
|
||||
</a>
|
||||
<a href="https://github.com/labring/FastGPT/blob/main/LICENSE">
|
||||
<img height="21" src="https://img.shields.io/badge/License-Apache--2.0-ffffff?style=flat-square&labelColor=d4eaf7&color=7d09f1" alt="license">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
https://github.com/labring/FastGPT/assets/15308462/7d3a38df-eb0e-4388-9250-2409bd33f6d4
|
||||
|
||||
@@ -21,9 +21,11 @@ PDF 是一个相对复杂的文件格式,在 FastGPT 内置的 pdf 解析器
|
||||
|
||||
参考文档 [Marker 安装教程](https://github.com/labring/FastGPT/tree/main/python/pdf-marker),安装 Marker 模型。封装的 API 已经适配了 FastGPT 自定义解析服务。
|
||||
|
||||
这里介绍快速 Docker 按照的方法:
|
||||
这里介绍快速 Docker 安装的方法:
|
||||
|
||||
```
|
||||
```dockerfile
|
||||
docker pull crpi-h3snc261q1dosroc.cn-hangzhou.personal.cr.aliyuncs.com/marker11/marker_images:latest
|
||||
docker run --gpus all -itd -p 7231:7231 --name model_pdf_v1 crpi-h3snc261q1dosroc.cn-hangzhou.personal.cr.aliyuncs.com/marker11/marker_images:latest
|
||||
```
|
||||
|
||||
### 2. 添加 FastGPT 环境变量
|
||||
|
||||
@@ -126,17 +126,40 @@ OneAPI 的 API Key 配置错误,需要修改`OPENAI_API_KEY`环境变量,并
|
||||
|
||||
## 四、常见模型问题
|
||||
|
||||
### 报错 - 模型响应为空
|
||||
### 报错 - 模型响应为空/模型报错
|
||||
|
||||
该错误是由于 stream 模式下,oneapi 直接结束了流请求,并且未返回任何内容导致。
|
||||
|
||||
4.8.10 版本新增了错误日志,报错时,会在日志中打印出实际发送的 Body 参数,可以复制该参数后,通过 curl 向 oneapi 发起请求测试。
|
||||
|
||||
由于 oneapi 在 stream 模式下,无法正确捕获错误,可以设置成 `stream=false` 后进行测试。可能的问题:
|
||||
由于 oneapi 在 stream 模式下,无法正确捕获错误,有时候可以设置成 `stream=false` 来获取到精确的错误。
|
||||
|
||||
可能的报错问题:
|
||||
|
||||
1. 国内模型命中风控
|
||||
2. 不支持的模型参数:只保留 messages 和必要参数来测试,删除其他参数测试。
|
||||
3. 参数不符合模型要求:例如有的模型 temperature 不支持 0,有些不支持两位小数。max_tokens 超出,上下文超长等。
|
||||
4. 模型部署有问题,stream 模式不兼容。
|
||||
|
||||
测试示例如下,可复制报错日志中的请求体进行测试:
|
||||
|
||||
```bash
|
||||
curl --location --request POST 'https://api.openai.com/v1/chat/completions' \
|
||||
--header 'Authorization: Bearer sk-xxxx' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"model": "xxx",
|
||||
"temperature": 0.01,
|
||||
"max_tokens": 1000,
|
||||
"stream": true,
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": " 你是饿"
|
||||
}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
### 如何测试模型是否支持工具调用
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ milvus版本使用:v4.8.14-milvus-fix 镜像。
|
||||
2. 新增 - 重写 chatContext,对话测试也会有日志,并且刷新后不会丢失对话。
|
||||
3. 新增 - 分享链接支持配置是否允许查看原文。
|
||||
4. 新增 - 新的 doc2x 插件。
|
||||
5. 新增 - 繁体中文-台湾。
|
||||
5. 新增 - 繁体中文。
|
||||
6. 新增 - 分析链接和 chat api 支持传入自定义 uid。
|
||||
7. 商业版新增 - 微软 oauth 登录
|
||||
8. 优化 - 工作流 ui 细节。
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: 'V4.8.15(进行中)'
|
||||
title: 'V4.8.15(初始化)'
|
||||
description: 'FastGPT V4.8.15 更新说明'
|
||||
icon: 'upgrade'
|
||||
draft: false
|
||||
@@ -23,11 +23,24 @@ weight: 809
|
||||
|
||||
## 升级指南
|
||||
|
||||
- 更新 FastGPT 镜像 tag: v4.8.15-alpha
|
||||
- 更新 FastGPT 商业版镜像 tag: v4.8.15-alpha (fastgpt-pro镜像)
|
||||
- 更新 FastGPT 镜像 tag: v4.8.15
|
||||
- 更新 FastGPT 商业版镜像 tag: v4.8.15 (fastgpt-pro镜像)
|
||||
- Sandbox 镜像,可以不更新
|
||||
|
||||
|
||||
## 运行初始化脚本
|
||||
|
||||
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 `rootkey`;{{host}} 替换成**FastGPT 域名**。
|
||||
|
||||
```bash
|
||||
curl --location --request POST 'https://{{host}}/admin/initv4815' \
|
||||
--header 'rootkey: {{rootkey}}' \
|
||||
--header 'Content-Type: application/json'
|
||||
```
|
||||
|
||||
会重置应用定时执行的字段,把 null 去掉,减少索引大小。
|
||||
|
||||
|
||||
## 完整更新内容
|
||||
|
||||
1. 新增 - API 知识库, 见 [API 知识库介绍](/docs/guide/knowledge_base/api_dataset/),外部文件库会被弃用。
|
||||
@@ -41,8 +54,11 @@ weight: 809
|
||||
9. 优化 - 支持 Markdown 文本分割时,只有标题,无内容。
|
||||
10. 优化 - 字符串变量替换,未赋值的变量会转成 undefined,而不是保留原来 id 串。
|
||||
11. 优化 - 全局变量默认值在 API 生效,并且自定义变量支持默认值。
|
||||
12. 修复 - 分享链接点赞鉴权问题。
|
||||
13. 修复 - 对话页面切换自动执行应用时,会误触发非自动执行应用。
|
||||
14. 修复 - 语言播放鉴权问题。
|
||||
15. 修复 - 插件应用知识库引用上限始终为 3000
|
||||
16. 修复 - 工作流编辑记录存储上限,去掉本地存储,增加异常离开时,强制自动保存。
|
||||
12. 优化 - 增加 HTTP Body 的 JSON 解析,正则将 undefined 转 null,减少 Body 解析错误。
|
||||
13. 优化 - 定时执行增加运行日志,增加重试,减少报错概率。
|
||||
14. 修复 - 分享链接点赞鉴权问题。
|
||||
15. 修复 - 对话页面切换自动执行应用时,会误触发非自动执行应用。
|
||||
16. 修复 - 语言播放鉴权问题。
|
||||
17. 修复 - 插件应用知识库引用上限始终为 3000
|
||||
18. 修复 - 工作流编辑记录存储上限,去掉本地存储,增加异常离开时,强制自动保存。
|
||||
19. 修复 - 工作流特殊变量替换问题。($开头的字符串无法替换)
|
||||
@@ -114,15 +114,15 @@ services:
|
||||
# fastgpt
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.8.14 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.8.14 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.8.15 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.8.15 # 阿里云
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.8.14-milvus-fix # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.14-milvus-fix # 阿里云
|
||||
image: ghcr.io/labring/fastgpt:v4.8.15 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.15 # 阿里云
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
||||
@@ -72,15 +72,15 @@ services:
|
||||
# fastgpt
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.8.13 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.8.13 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.8.15 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.8.15 # 阿里云
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.8.14 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.14 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt:v4.8.15 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.15 # 阿里云
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
||||
@@ -53,15 +53,15 @@ services:
|
||||
wait $$!
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.8.14 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.8.14 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.8.15 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.8.15 # 阿里云
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.8.14-milvus-fix # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.14-milvus-fix # 阿里云
|
||||
image: ghcr.io/labring/fastgpt:v4.8.15 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.15 # 阿里云
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
||||
@@ -4,3 +4,15 @@ export const delay = (ms: number) =>
|
||||
resolve('');
|
||||
}, ms);
|
||||
});
|
||||
|
||||
export const retryFn = async <T>(fn: () => Promise<T>, retryTimes = 3): Promise<T> => {
|
||||
try {
|
||||
return fn();
|
||||
} catch (error) {
|
||||
if (retryTimes > 0) {
|
||||
await delay(500);
|
||||
return retryFn(fn, retryTimes - 1);
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -33,6 +33,7 @@ export enum ChatSourceEnum {
|
||||
online = 'online',
|
||||
share = 'share',
|
||||
api = 'api',
|
||||
cronJob = 'cronJob',
|
||||
team = 'team',
|
||||
feishu = 'feishu',
|
||||
official_account = 'official_account',
|
||||
@@ -52,6 +53,9 @@ export const ChatSourceMap = {
|
||||
[ChatSourceEnum.api]: {
|
||||
name: i18nT('common:core.chat.logs.api')
|
||||
},
|
||||
[ChatSourceEnum.cronJob]: {
|
||||
name: i18nT('chat:source_cronJob')
|
||||
},
|
||||
[ChatSourceEnum.team]: {
|
||||
name: i18nT('common:core.chat.logs.team')
|
||||
},
|
||||
|
||||
3
packages/global/core/dataset/type.d.ts
vendored
3
packages/global/core/dataset/type.d.ts
vendored
@@ -34,6 +34,9 @@ export type DatasetSchemaType = {
|
||||
inheritPermission: boolean;
|
||||
apiServer?: APIFileServer;
|
||||
|
||||
syncSchedule?: { cronString: string; timezone: string };
|
||||
syncNextTime?: Date;
|
||||
|
||||
// abandon
|
||||
externalReadUrl?: string;
|
||||
defaultPermission?: number;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ChatCompletionRequestMessageRoleEnum } from '../../ai/constants';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '../constants';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum, WorkflowIOValueTypeEnum } from '../constants';
|
||||
import { FlowNodeTypeEnum } from '../node/constant';
|
||||
import { StoreNodeItemType } from '../type/node';
|
||||
import { StoreEdgeItemType } from '../type/edge';
|
||||
@@ -279,6 +279,27 @@ export const getReferenceVariableValue = ({
|
||||
return value;
|
||||
};
|
||||
|
||||
export const formatVariableValByType = (val: any, valueType?: WorkflowIOValueTypeEnum) => {
|
||||
if (!valueType) return val;
|
||||
// Value type check, If valueType invalid, return undefined
|
||||
if (valueType.startsWith('array') && !Array.isArray(val)) return undefined;
|
||||
if (valueType === WorkflowIOValueTypeEnum.boolean && typeof val !== 'boolean') return undefined;
|
||||
if (valueType === WorkflowIOValueTypeEnum.number && typeof val !== 'number') return undefined;
|
||||
if (valueType === WorkflowIOValueTypeEnum.string && typeof val !== 'string') return undefined;
|
||||
if (
|
||||
[
|
||||
WorkflowIOValueTypeEnum.object,
|
||||
WorkflowIOValueTypeEnum.chatHistory,
|
||||
WorkflowIOValueTypeEnum.datasetQuote,
|
||||
WorkflowIOValueTypeEnum.selectApp,
|
||||
WorkflowIOValueTypeEnum.selectDataset
|
||||
].includes(valueType) &&
|
||||
typeof val !== 'object'
|
||||
)
|
||||
return undefined;
|
||||
|
||||
return val;
|
||||
};
|
||||
// replace {{$xx.xx$}} variables for text
|
||||
export function replaceEditorVariable({
|
||||
text,
|
||||
@@ -308,7 +329,7 @@ export function replaceEditorVariable({
|
||||
if (!node) return;
|
||||
|
||||
const output = node.outputs.find((output) => output.id === id);
|
||||
if (output) return output.value;
|
||||
if (output) return formatVariableValByType(output.value, output.valueType);
|
||||
|
||||
const input = node.inputs.find((input) => input.key === id);
|
||||
if (input) return getReferenceVariableValue({ value: input.value, nodes, variables });
|
||||
@@ -321,7 +342,7 @@ export function replaceEditorVariable({
|
||||
})();
|
||||
|
||||
const regex = new RegExp(`\\{\\{\\$(${nodeId}\\.${id})\\$\\}\\}`, 'g');
|
||||
text = text.replace(regex, formatVal);
|
||||
text = text.replace(regex, () => formatVal);
|
||||
});
|
||||
|
||||
return text || '';
|
||||
|
||||
@@ -10,8 +10,7 @@ const SystemPluginSchema = new Schema({
|
||||
required: true
|
||||
},
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
type: Boolean
|
||||
},
|
||||
inputConfig: {
|
||||
type: Array,
|
||||
|
||||
2
packages/service/core/app/plugin/type.d.ts
vendored
2
packages/service/core/app/plugin/type.d.ts
vendored
@@ -13,7 +13,7 @@ export type SystemPluginConfigSchemaType = {
|
||||
hasTokenFee: boolean;
|
||||
isActive: boolean;
|
||||
pluginOrder: number;
|
||||
inputConfig: SystemPluginTemplateItemType['inputConfig'];
|
||||
inputConfig?: SystemPluginTemplateItemType['inputConfig'];
|
||||
|
||||
customConfig?: {
|
||||
name: string;
|
||||
|
||||
@@ -121,6 +121,13 @@ const AppSchema = new Schema({
|
||||
|
||||
AppSchema.index({ teamId: 1, updateTime: -1 });
|
||||
AppSchema.index({ teamId: 1, type: 1 });
|
||||
AppSchema.index({ scheduledTriggerConfig: 1, intervalNextTime: -1 });
|
||||
AppSchema.index(
|
||||
{ scheduledTriggerConfig: 1, scheduledTriggerNextTime: -1 },
|
||||
{
|
||||
partialFilterExpression: {
|
||||
scheduledTriggerConfig: { $exists: true }
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const MongoApp = getMongoModel<AppType>(AppCollectionName, AppSchema);
|
||||
|
||||
@@ -91,6 +91,18 @@ const DatasetSchema = new Schema({
|
||||
type: Object
|
||||
},
|
||||
|
||||
syncSchedule: {
|
||||
cronString: {
|
||||
type: String
|
||||
},
|
||||
timezone: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
syncNextTime: {
|
||||
type: Date
|
||||
},
|
||||
|
||||
// abandoned
|
||||
externalReadUrl: {
|
||||
type: String
|
||||
@@ -100,6 +112,7 @@ const DatasetSchema = new Schema({
|
||||
|
||||
try {
|
||||
DatasetSchema.index({ teamId: 1 });
|
||||
DatasetSchema.index({ syncSchedule: 1, syncNextTime: -1 });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
|
||||
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
||||
import { loadRequestMessages } from '../../../chat/utils';
|
||||
import { llmCompletionsBodyFormat } from '../../../ai/utils';
|
||||
import { addLog } from '../../../../common/system/log';
|
||||
|
||||
type Props = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.aiModel]: string;
|
||||
@@ -65,7 +66,7 @@ export const dispatchClassifyQuestion = async (props: Props): Promise<CQResponse
|
||||
return {
|
||||
[NodeOutputKeyEnum.cqResult]: result.value,
|
||||
[DispatchNodeResponseKeyEnum.skipHandleId]: agents
|
||||
.filter((item) => item.key !== arg?.type)
|
||||
.filter((item) => item.key !== result.key)
|
||||
.map((item) => getHandleId(nodeId, 'source', item.key)),
|
||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||
totalPoints: user.openaiAccount?.key ? 0 : totalPoints,
|
||||
@@ -142,6 +143,10 @@ const completions = async ({
|
||||
agents.find((item) => answer.includes(item.value))?.key ||
|
||||
'';
|
||||
|
||||
if (!id) {
|
||||
addLog.warn('Classify error', { answer });
|
||||
}
|
||||
|
||||
return {
|
||||
tokens: await countMessagesTokens(messages),
|
||||
arg: { type: id }
|
||||
|
||||
@@ -42,7 +42,8 @@ import {
|
||||
filterWorkflowEdges,
|
||||
checkNodeRunStatus,
|
||||
textAdaptGptResponse,
|
||||
replaceEditorVariable
|
||||
replaceEditorVariable,
|
||||
formatVariableValByType
|
||||
} from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
||||
import { dispatchRunTools } from './agent/runTool/index';
|
||||
@@ -72,6 +73,7 @@ import { dispatchLoopEnd } from './loop/runLoopEnd';
|
||||
import { dispatchLoopStart } from './loop/runLoopStart';
|
||||
import { dispatchFormInput } from './interactive/formInput';
|
||||
import { dispatchToolParams } from './agent/runTool/toolParams';
|
||||
import { AppChatConfigType } from '@fastgpt/global/core/app/type';
|
||||
|
||||
const callbackMap: Record<FlowNodeTypeEnum, Function> = {
|
||||
[FlowNodeTypeEnum.workflowStart]: dispatchWorkflowStart,
|
||||
@@ -685,7 +687,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
}
|
||||
|
||||
/* get system variable */
|
||||
export function getSystemVariable({
|
||||
const getSystemVariable = ({
|
||||
user,
|
||||
runningAppInfo,
|
||||
chatId,
|
||||
@@ -693,7 +695,7 @@ export function getSystemVariable({
|
||||
histories = [],
|
||||
uid,
|
||||
chatConfig
|
||||
}: Props): SystemVariablesType {
|
||||
}: Props): SystemVariablesType => {
|
||||
const variables = chatConfig?.variables || [];
|
||||
const variablesMap = variables.reduce<Record<string, any>>((acc, item) => {
|
||||
acc[item.key] = valueTypeFormat(item.defaultValue, item.valueType);
|
||||
@@ -709,10 +711,10 @@ export function getSystemVariable({
|
||||
histories,
|
||||
cTime: getSystemTime(user.timezone)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/* Merge consecutive text messages into one */
|
||||
export const mergeAssistantResponseAnswerText = (response: AIChatItemValueItemType[]) => {
|
||||
const mergeAssistantResponseAnswerText = (response: AIChatItemValueItemType[]) => {
|
||||
const result: AIChatItemValueItemType[] = [];
|
||||
// 合并连续的text
|
||||
for (let i = 0; i < response.length; i++) {
|
||||
|
||||
@@ -24,6 +24,7 @@ import { ReadFileBaseUrl } from '@fastgpt/global/common/file/constants';
|
||||
import { createFileToken } from '../../../../support/permission/controller';
|
||||
import { JSONPath } from 'jsonpath-plus';
|
||||
import type { SystemPluginSpecialResponse } from '../../../../../plugins/type';
|
||||
import json5 from 'json5';
|
||||
|
||||
type PropsArrType = {
|
||||
key: string;
|
||||
@@ -103,8 +104,6 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
||||
[NodeInputKeyEnum.addInputParam]: concatVariables,
|
||||
...concatVariables
|
||||
};
|
||||
httpReqUrl = replaceVariable(httpReqUrl, allVariables);
|
||||
|
||||
const replaceStringVariables = (text: string) => {
|
||||
return replaceVariable(
|
||||
replaceEditorVariable({
|
||||
@@ -116,6 +115,8 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
||||
);
|
||||
};
|
||||
|
||||
httpReqUrl = replaceStringVariables(httpReqUrl);
|
||||
|
||||
// parse header
|
||||
const headers = await (() => {
|
||||
try {
|
||||
@@ -175,9 +176,11 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
||||
}
|
||||
if (!httpJsonBody) return {};
|
||||
if (httpContentType === ContentTypes.json) {
|
||||
httpJsonBody = replaceVariable(httpJsonBody, allVariables);
|
||||
httpJsonBody = replaceStringVariables(httpJsonBody);
|
||||
// Json body, parse and return
|
||||
const jsonParse = JSON.parse(httpJsonBody);
|
||||
const jsonParse = json5.parse(
|
||||
httpJsonBody.replace(/(".*?")\s*:\s*undefined\b/g, '$1: null')
|
||||
);
|
||||
const removeSignJson = removeUndefinedSign(jsonParse);
|
||||
return removeSignJson;
|
||||
}
|
||||
@@ -195,7 +198,7 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
||||
return Object.fromEntries(requestBody);
|
||||
} else if (typeof requestBody === 'string') {
|
||||
try {
|
||||
return JSON.parse(requestBody);
|
||||
return json5.parse(requestBody);
|
||||
} catch {
|
||||
return { content: requestBody };
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ export const iconPaths = {
|
||||
check: () => import('./icons/check.svg'),
|
||||
checkCircle: () => import('./icons/checkCircle.svg'),
|
||||
closeSolid: () => import('./icons/closeSolid.svg'),
|
||||
code: () => import('./icons/code.svg'),
|
||||
collectionLight: () => import('./icons/collectionLight.svg'),
|
||||
collectionSolid: () => import('./icons/collectionSolid.svg'),
|
||||
comment: () => import('./icons/comment.svg'),
|
||||
@@ -58,8 +59,6 @@ export const iconPaths = {
|
||||
'common/monitor': () => import('./icons/common/monitor.svg'),
|
||||
'common/more': () => import('./icons/common/more.svg'),
|
||||
'common/moreFill': () => import('./icons/common/moreFill.svg'),
|
||||
'common/navbar/pluginFill': () => import('./icons/common/navbar/pluginFill.svg'),
|
||||
'common/navbar/pluginLight': () => import('./icons/common/navbar/pluginLight.svg'),
|
||||
'common/openai': () => import('./icons/common/openai.svg'),
|
||||
'common/overviewLight': () => import('./icons/common/overviewLight.svg'),
|
||||
'common/paramsLight': () => import('./icons/common/paramsLight.svg'),
|
||||
@@ -94,9 +93,6 @@ export const iconPaths = {
|
||||
'common/wechatFill': () => import('./icons/common/wechatFill.svg'),
|
||||
configmap: () => import('./icons/configmap.svg'),
|
||||
copy: () => import('./icons/copy.svg'),
|
||||
code: () => import('./icons/code.svg'),
|
||||
preview: () => import('./icons/preview.svg'),
|
||||
fullScreen: () => import('./icons/fullScreen.svg'),
|
||||
'core/app/aiFill': () => import('./icons/core/app/aiFill.svg'),
|
||||
'core/app/aiLight': () => import('./icons/core/app/aiLight.svg'),
|
||||
'core/app/aiLightSmall': () => import('./icons/core/app/aiLightSmall.svg'),
|
||||
@@ -128,7 +124,9 @@ export const iconPaths = {
|
||||
'core/app/type/httpPluginFill': () => import('./icons/core/app/type/httpPluginFill.svg'),
|
||||
'core/app/type/plugin': () => import('./icons/core/app/type/plugin.svg'),
|
||||
'core/app/type/pluginFill': () => import('./icons/core/app/type/pluginFill.svg'),
|
||||
'core/app/type/pluginLight': () => import('./icons/core/app/type/pluginLight.svg'),
|
||||
'core/app/type/simple': () => import('./icons/core/app/type/simple.svg'),
|
||||
'core/app/type/simpleFill': () => import('./icons/core/app/type/simpleFill.svg'),
|
||||
'core/app/type/workflow': () => import('./icons/core/app/type/workflow.svg'),
|
||||
'core/app/type/workflowFill': () => import('./icons/core/app/type/workflowFill.svg'),
|
||||
'core/app/variable/external': () => import('./icons/core/app/variable/external.svg'),
|
||||
@@ -320,6 +318,7 @@ export const iconPaths = {
|
||||
'file/pdf': () => import('./icons/file/pdf.svg'),
|
||||
'file/qaImport': () => import('./icons/file/qaImport.svg'),
|
||||
'file/uploadFile': () => import('./icons/file/uploadFile.svg'),
|
||||
fullScreen: () => import('./icons/fullScreen.svg'),
|
||||
help: () => import('./icons/help.svg'),
|
||||
history: () => import('./icons/history.svg'),
|
||||
infoRounded: () => import('./icons/infoRounded.svg'),
|
||||
@@ -345,6 +344,7 @@ export const iconPaths = {
|
||||
'plugins/doc2x': () => import('./icons/plugins/doc2x.svg'),
|
||||
'plugins/textEditor': () => import('./icons/plugins/textEditor.svg'),
|
||||
point: () => import('./icons/point.svg'),
|
||||
preview: () => import('./icons/preview.svg'),
|
||||
'price/bg': () => import('./icons/price/bg.svg'),
|
||||
'price/right': () => import('./icons/price/right.svg'),
|
||||
save: () => import('./icons/save.svg'),
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="none">
|
||||
<path
|
||||
d="M13.9765 20H9.99764V17.9556C9.99764 17.8624 9.98917 17.7693 9.97224 17.6762C9.95531 17.5831 9.92568 17.4942 9.88759 17.4053C9.84949 17.3164 9.80716 17.236 9.75214 17.1598C9.69711 17.0836 9.63785 17.0116 9.57013 16.9439C9.22727 16.6053 8.7278 16.4148 8.20716 16.4233C8.09288 16.4233 7.97859 16.436 7.86431 16.4571C7.75002 16.4783 7.63997 16.5079 7.52991 16.5503C7.41986 16.5926 7.31827 16.6392 7.21669 16.6984C7.1151 16.7577 7.02198 16.8254 6.93732 16.9016C6.70452 17.109 6.42939 17.4603 6.42939 17.9937V20H2.48018C2.39976 20 2.31933 19.9958 2.23891 19.9873C2.15849 19.9788 2.07806 19.9661 1.99764 19.9534C1.91722 19.9365 1.84103 19.9196 1.7606 19.8942C1.68441 19.8688 1.60822 19.8434 1.53203 19.8138C1.45584 19.7841 1.38388 19.746 1.31193 19.7079C1.23997 19.6698 1.17224 19.6275 1.10452 19.581C1.03679 19.5344 0.973301 19.4878 0.909809 19.437C0.846317 19.3862 0.787057 19.3312 0.727798 19.272C0.668539 19.2127 0.617745 19.1534 0.562719 19.0899C0.511925 19.0265 0.461132 18.963 0.418804 18.8952C0.372243 18.8275 0.329915 18.7598 0.291819 18.6878C0.253724 18.6159 0.219862 18.5439 0.185999 18.4677C0.15637 18.3915 0.12674 18.3153 0.105576 18.2392C0.0801791 18.163 0.0632479 18.0825 0.0463167 18.0021C0.0293855 17.9217 0.0166871 17.8413 0.0124543 17.7608C0.00398871 17.6804 -0.000244141 17.6 -0.000244141 17.5196V13.5746H2.03997C2.45055 13.5746 2.84843 13.4011 3.16166 13.0836C3.25055 12.9947 3.32674 12.9016 3.39446 12.7958C3.46219 12.6942 3.52145 12.5841 3.56801 12.4698C3.61457 12.3556 3.64843 12.237 3.67383 12.1143C3.69923 11.9915 3.70769 11.8688 3.70769 11.746C3.69076 10.7979 2.91193 9.99788 2.00187 9.99788H-0.000244141V6.01058C-0.000244141 5.84974 0.0166871 5.68889 0.0463167 5.52804C0.0801792 5.3672 0.12674 5.21481 0.190232 5.06667C0.253724 4.91852 0.329915 4.7746 0.423036 4.64339C0.516158 4.50794 0.621978 4.38519 0.736264 4.27513C0.85055 4.16508 0.977534 4.06349 1.11298 3.9746C1.24843 3.88571 1.39235 3.81376 1.5405 3.7545C1.68864 3.69524 1.84526 3.64868 2.00187 3.61905C2.15849 3.58942 2.31933 3.57249 2.48018 3.57672H5.30346V2.92487C5.30346 2.87831 5.30346 2.82751 5.30769 2.78095C5.31192 2.73439 5.31192 2.6836 5.32039 2.63704C5.32462 2.59048 5.33309 2.53968 5.33732 2.49312C5.34579 2.44656 5.35425 2.39577 5.36272 2.34921C5.37118 2.30265 5.38388 2.25608 5.39658 2.20952L5.43468 2.06984C5.44737 2.02328 5.46431 1.97672 5.48124 1.93016C5.49817 1.8836 5.5151 1.84127 5.53203 1.79471C5.54896 1.74815 5.57013 1.70582 5.59129 1.66349C5.61245 1.62116 5.63362 1.5746 5.65901 1.53228C5.68018 1.48995 5.70558 1.44762 5.73097 1.40529C5.75637 1.36296 5.78177 1.32487 5.8114 1.28254C5.83679 1.24444 5.86642 1.20212 5.89605 1.16402L5.98494 1.04974C6.01457 1.01164 6.04843 0.977778 6.0823 0.939683C6.11616 0.90582 6.15002 0.867725 6.18388 0.833862C6.21774 0.8 6.25584 0.766138 6.2897 0.736508C6.3278 0.702646 6.36166 0.673016 6.39976 0.643386L6.51404 0.554497C6.55214 0.524868 6.59446 0.499471 6.63256 0.474074C6.67065 0.448677 6.71298 0.42328 6.75531 0.397884C6.79764 0.372487 6.83997 0.351323 6.8823 0.325926C6.92462 0.304762 6.96695 0.283598 7.01351 0.262434C7.05584 0.24127 7.1024 0.224339 7.14896 0.207407C7.19552 0.190476 7.23785 0.173545 7.28441 0.156614C7.33097 0.139683 7.37753 0.126984 7.42409 0.114286L7.56378 0.0761905C7.61034 0.0634921 7.6569 0.0550265 7.70769 0.0465609C7.75849 0.0380953 7.80505 0.0296296 7.85161 0.0253968C7.89817 0.021164 7.94896 0.0126984 7.99552 0.00846564C8.04208 0.00423284 8.09288 0 8.13944 0H8.28335C9.86642 0.0296296 11.1574 1.3545 11.1574 2.96296V3.57249H13.9765C14.0569 3.57249 14.1373 3.57672 14.2177 3.58095C14.2982 3.58942 14.3786 3.59788 14.4548 3.61481C14.5352 3.63175 14.6114 3.64868 14.6876 3.66984C14.7638 3.691 14.84 3.72064 14.9162 3.75026C14.9923 3.77989 15.0643 3.81376 15.1363 3.85185C15.2082 3.88995 15.2759 3.93227 15.3437 3.9746C15.4114 4.01693 15.4749 4.06772 15.5384 4.11852C15.6019 4.16931 15.6611 4.22434 15.7162 4.27937C15.7712 4.33439 15.8262 4.39788 15.877 4.45714C15.9278 4.52064 15.9744 4.58413 16.0209 4.65185C16.0675 4.71958 16.1056 4.7873 16.1437 4.85926C16.1818 4.93122 16.2156 5.00317 16.2453 5.07936C16.2749 5.15556 16.3003 5.23175 16.3257 5.30794C16.3468 5.38413 16.368 5.46455 16.3807 5.54074C16.3976 5.62116 16.4061 5.69735 16.4146 5.77778C16.423 5.8582 16.423 5.93862 16.423 6.01905V8.84233H17.0326C18.6664 8.84233 19.9955 10.1376 19.9955 11.7291C19.9955 13.363 18.6834 14.6921 17.0707 14.6921H16.423V17.5153C16.4273 18.8825 15.3267 20 13.9765 20Z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,12 @@
|
||||
<svg viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="20" height="20" transform="translate(0.5 0.5)" fill="url(#paint0_linear_5846_2933)"/>
|
||||
<path d="M9.96659 4.38986C10.2456 4.22877 10.6979 4.22877 10.9769 4.38986L15.2403 6.85129C15.7983 7.17346 15.7983 7.6958 15.2403 8.01796L11.0331 10.447C10.7541 10.6081 10.3017 10.6081 10.0227 10.447L5.75936 7.98557C5.20135 7.6634 5.20135 7.14107 5.75935 6.8189L9.96659 4.38986Z" fill="white"/>
|
||||
<path d="M4.9906 9.46161C4.9906 9.01057 5.30725 8.82776 5.69785 9.05327L9.6388 11.3286C9.862 11.4574 10.0429 11.7708 10.0429 12.0286V16.1949C10.0429 16.6459 9.7263 16.8287 9.33569 16.6032L5.39475 14.3279C5.17154 14.1991 4.9906 13.8857 4.9906 13.6279V9.46161Z" fill="white"/>
|
||||
<path d="M10.9563 12.06C10.9563 11.8023 11.1372 11.4889 11.3604 11.36L15.302 9.08435C15.6926 8.85883 16.0093 9.04165 16.0093 9.49268V13.6585C16.0093 13.9162 15.8283 14.2296 15.6051 14.3585L11.6635 16.6342C11.2729 16.8597 10.9563 16.6769 10.9563 16.2258V12.06Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_5846_2933" x1="10" y1="0" x2="3.05556" y2="18.3333" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#67BFFF"/>
|
||||
<stop offset="1" stop-color="#5BA6FF"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -104,7 +104,7 @@ export const MultipleRowSelect = ({
|
||||
);
|
||||
|
||||
const onOpenSelect = useCallback(() => {
|
||||
setCloneValue(value);
|
||||
setCloneValue(Array.isArray(value) ? value : []);
|
||||
onOpen();
|
||||
}, [value, onOpen]);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { i18nT } from '../../i18n/utils';
|
||||
import type { PluginGroupSchemaType, TGroupType } from '../../../service/core/app/plugin/type';
|
||||
|
||||
export const workflowNodeTemplateList = [
|
||||
{
|
||||
@@ -49,10 +50,7 @@ export const workflowNodeTemplateList = [
|
||||
}
|
||||
];
|
||||
|
||||
export const systemPluginTemplateList: {
|
||||
typeId: string;
|
||||
typeName: string;
|
||||
}[] = [
|
||||
export const systemPluginTemplateList: TGroupType[] = [
|
||||
{
|
||||
typeId: FlowNodeTemplateTypeEnum.tools,
|
||||
typeName: i18nT('common:navbar.Tools')
|
||||
@@ -74,9 +72,9 @@ export const systemPluginTemplateList: {
|
||||
typeName: i18nT('common:common.Other')
|
||||
}
|
||||
];
|
||||
export const defaultGroup = {
|
||||
export const defaultGroup: PluginGroupSchemaType = {
|
||||
groupId: 'systemPlugin',
|
||||
groupAvatar: 'common/navbar/pluginLight',
|
||||
groupAvatar: 'core/app/type/pluginLight',
|
||||
groupName: i18nT('common:core.module.template.System Plugin'),
|
||||
groupOrder: 0,
|
||||
groupTypes: systemPluginTemplateList
|
||||
|
||||
@@ -1,15 +1,27 @@
|
||||
import Cookies, { CookieAttributes } from 'js-cookie';
|
||||
import Cookies from 'js-cookie';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { LangEnum } from '../../../projects/app/src/web/common/utils/i18n';
|
||||
|
||||
const setCookie = (key: string, value: string, options?: CookieAttributes) => {
|
||||
Cookies.set(key, value, options);
|
||||
};
|
||||
const getCookie = (key: string) => {
|
||||
return Cookies.get(key);
|
||||
};
|
||||
|
||||
const LANG_KEY = 'NEXT_LOCALE';
|
||||
const isInIframe = () => {
|
||||
try {
|
||||
return window.self !== window.top;
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
const setLang = (value: string) => {
|
||||
if (isInIframe()) {
|
||||
localStorage.setItem(LANG_KEY, value);
|
||||
} else {
|
||||
// 不在 iframe 中,同时使用 Cookie 和 localStorage
|
||||
Cookies.set(LANG_KEY, value, { expires: 30 });
|
||||
localStorage.setItem(LANG_KEY, value);
|
||||
}
|
||||
};
|
||||
const getLang = () => {
|
||||
return localStorage.getItem(LANG_KEY) || Cookies.get(LANG_KEY);
|
||||
};
|
||||
|
||||
export const useI18nLng = () => {
|
||||
const { i18n } = useTranslation();
|
||||
@@ -26,22 +38,19 @@ export const useI18nLng = () => {
|
||||
|
||||
const onChangeLng = async (lng: string) => {
|
||||
const lang = languageMap[lng] || 'en';
|
||||
const prevLang = getLang();
|
||||
|
||||
setCookie(LANG_KEY, lang, {
|
||||
expires: 30
|
||||
});
|
||||
setLang(lang);
|
||||
|
||||
const currentLng = i18n?.language;
|
||||
await i18n?.changeLanguage?.(lang);
|
||||
|
||||
if (currentLng !== lang) {
|
||||
if (prevLang && prevLang !== lang) {
|
||||
window?.location?.reload?.();
|
||||
}
|
||||
};
|
||||
|
||||
const setUserDefaultLng = () => {
|
||||
if (!navigator || !localStorage) return;
|
||||
if (getCookie(LANG_KEY)) return onChangeLng(getCookie(LANG_KEY) as string);
|
||||
if (getLang()) return onChangeLng(getLang() as string);
|
||||
|
||||
const lang = languageMap[navigator.language] || 'en';
|
||||
|
||||
|
||||
@@ -43,9 +43,10 @@
|
||||
"select_file": "Upload File",
|
||||
"select_file_img": "Upload file / image",
|
||||
"select_img": "Upload Image",
|
||||
"source_cronJob": "Scheduled execution",
|
||||
"stream_output": "Stream Output",
|
||||
"unsupported_file_type": "Unsupported file types",
|
||||
"upload": "Upload",
|
||||
"view_citations": "View References",
|
||||
"web_site_sync": "Web Site Sync"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -751,7 +751,6 @@
|
||||
"core.module.template.config_params": "Can configure application system parameters",
|
||||
"core.module.template.empty_plugin": "Blank plugin",
|
||||
"core.module.template.empty_workflow": "Blank workflow",
|
||||
"core.module.template.http body placeholder": "Same syntax as Apifox",
|
||||
"core.module.template.self_input": "Plug-in input",
|
||||
"core.module.template.self_output": "Custom plug-in output",
|
||||
"core.module.template.system_config": "System configuration",
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
"full_response_data": "Full Response Data",
|
||||
"greater_than": "Greater Than",
|
||||
"greater_than_or_equal_to": "Greater Than or Equal To",
|
||||
"http_body_placeholder": "Similar syntax to APIFox, variable selection can be activated via /. \nString variables need to be enclosed in double quotes, other types of variables do not need to be enclosed in double quotes. \nPlease strictly check whether it conforms to JSON format.",
|
||||
"http_extract_output": "Output field extraction",
|
||||
"http_extract_output_description": "Specified fields in the response value can be extracted through JSONPath syntax",
|
||||
"http_raw_response_description": "Raw HTTP response. Only accepts string or JSON type response data.",
|
||||
@@ -193,4 +194,4 @@
|
||||
"workflow.Switch_success": "Switch Successful",
|
||||
"workflow.Team cloud": "Team Cloud",
|
||||
"workflow.exit_tips": "Your changes have not been saved. 'Exit directly' will not save your edits."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,9 +43,10 @@
|
||||
"select_file": "上传文件",
|
||||
"select_file_img": "上传文件/图片",
|
||||
"select_img": "上传图片",
|
||||
"source_cronJob": "定时执行",
|
||||
"stream_output": "流输出",
|
||||
"unsupported_file_type": "不支持的文件类型",
|
||||
"upload": "上传",
|
||||
"view_citations": "查看引用",
|
||||
"web_site_sync": "Web站点同步"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -750,7 +750,6 @@
|
||||
"core.module.template.config_params": "可以配置应用的系统参数",
|
||||
"core.module.template.empty_plugin": "空白插件",
|
||||
"core.module.template.empty_workflow": "空白工作流",
|
||||
"core.module.template.http body placeholder": "与 Apifox 相同的语法",
|
||||
"core.module.template.self_input": "插件输入",
|
||||
"core.module.template.self_output": "插件输出",
|
||||
"core.module.template.system_config": "系统配置",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"Variable_name": "变量名",
|
||||
"add_new_input": "新增输入",
|
||||
"add_new_output": "新增输出",
|
||||
"http_body_placeholder": "与 APIFox 类似的语法,可通过 / 来激活变量选择。字符串变量均需加双引号,其他类型变量无需加双引号。请严格检查是否符合 JSON 格式。",
|
||||
"append_application_reply_to_history_as_new_context": "将该应用回复内容拼接到历史记录中,作为新的上下文返回",
|
||||
"application_call": "应用调用",
|
||||
"assigned_reply": "指定回复",
|
||||
@@ -193,4 +194,4 @@
|
||||
"workflow.Switch_success": "切换成功",
|
||||
"workflow.Team cloud": "团队云端",
|
||||
"workflow.exit_tips": "您的更改尚未保存,「直接退出」将不会保存您的编辑记录。"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,9 +43,10 @@
|
||||
"select_file": "上傳檔案",
|
||||
"select_file_img": "上傳檔案 / 圖片",
|
||||
"select_img": "上傳圖片",
|
||||
"source_cronJob": "定時執行",
|
||||
"stream_output": "串流輸出",
|
||||
"unsupported_file_type": "不支援的檔案類型",
|
||||
"upload": "上傳",
|
||||
"view_citations": "檢視引用",
|
||||
"web_site_sync": "網站同步"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -751,7 +751,6 @@
|
||||
"core.module.template.config_params": "可以設定應用程式的系統參數",
|
||||
"core.module.template.empty_plugin": "空白外掛程式",
|
||||
"core.module.template.empty_workflow": "空白工作流程",
|
||||
"core.module.template.http body placeholder": "與 Apifox 相同的語法",
|
||||
"core.module.template.self_input": "外掛程式輸入",
|
||||
"core.module.template.self_output": "外掛程式輸出",
|
||||
"core.module.template.system_config": "系統設定",
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
"full_response_data": "完整回應資料",
|
||||
"greater_than": "大於",
|
||||
"greater_than_or_equal_to": "大於或等於",
|
||||
"http_body_placeholder": "與 APIFox 類似的語法,可透過 / 來啟動變數選擇。\n字串變數均需加雙引號,其他類型變數無需加雙引號。\n請嚴格檢查是否符合 JSON 格式。",
|
||||
"http_extract_output": "輸出欄位擷取",
|
||||
"http_extract_output_description": "可以透過 JSONPath 語法來擷取回應值中的指定欄位",
|
||||
"http_raw_response_description": "HTTP 請求的原始回應。僅接受字串或 JSON 類型回應資料。",
|
||||
@@ -193,4 +194,4 @@
|
||||
"workflow.Switch_success": "切換成功",
|
||||
"workflow.Team cloud": "團隊雲端",
|
||||
"workflow.exit_tips": "您的變更尚未儲存,「直接結束」將不會儲存您的編輯紀錄。"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "app",
|
||||
"version": "4.8.14",
|
||||
"version": "4.8.15",
|
||||
"private": false,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
||||
@@ -115,7 +115,7 @@ const Navbar = ({ unread }: { unread: number }) => {
|
||||
borderRadius={'50%'}
|
||||
overflow={'hidden'}
|
||||
cursor={'pointer'}
|
||||
onClick={() => router.push('/account')}
|
||||
onClick={() => router.push('/account/info')}
|
||||
>
|
||||
<Avatar w={'2rem'} h={'2rem'} src={userInfo?.avatar} borderRadius={'50%'} />
|
||||
</Box>
|
||||
|
||||
@@ -48,7 +48,7 @@ const NavbarPhone = ({ unread }: { unread: number }) => {
|
||||
label: t('common:navbar.Account'),
|
||||
icon: 'support/user/userLight',
|
||||
activeIcon: 'support/user/userFill',
|
||||
link: '/account',
|
||||
link: '/account/info',
|
||||
activeLink: [
|
||||
'/account/bill',
|
||||
'/account/info',
|
||||
|
||||
@@ -58,7 +58,7 @@ import dynamic from 'next/dynamic';
|
||||
import type { StreamResponseType } from '@/web/common/api/fetch';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { useSystem } from '@fastgpt/web/hooks/useSystem';
|
||||
import { useCreation, useMemoizedFn, useThrottleFn } from 'ahooks';
|
||||
import { useCreation, useDebounceEffect, useMemoizedFn, useThrottleFn } from 'ahooks';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { mergeChatResponseData } from '@fastgpt/global/core/chat/utils';
|
||||
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
|
||||
@@ -380,10 +380,11 @@ const ChatBox = ({
|
||||
async ({ variables = {} }) => {
|
||||
if (!onStartChat) return;
|
||||
if (isChatting) {
|
||||
toast({
|
||||
title: t('chat:is_chatting'),
|
||||
status: 'warning'
|
||||
});
|
||||
!hideInUI &&
|
||||
toast({
|
||||
title: t('chat:is_chatting'),
|
||||
status: 'warning'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -834,27 +835,33 @@ const ChatBox = ({
|
||||
}, [isReady, resetInputVal, sendPrompt]);
|
||||
|
||||
// Auto send prompt
|
||||
useEffect(() => {
|
||||
if (
|
||||
isReady &&
|
||||
chatBoxData?.app?.chatConfig?.autoExecute?.open &&
|
||||
chatStarted &&
|
||||
chatRecords.length === 0 &&
|
||||
isChatRecordsLoaded
|
||||
) {
|
||||
sendPrompt({
|
||||
text: chatBoxData?.app?.chatConfig?.autoExecute?.defaultPrompt || 'AUTO_EXECUTE',
|
||||
hideInUI: true
|
||||
});
|
||||
useDebounceEffect(
|
||||
() => {
|
||||
if (
|
||||
isReady &&
|
||||
chatBoxData?.app?.chatConfig?.autoExecute?.open &&
|
||||
chatStarted &&
|
||||
chatRecords.length === 0 &&
|
||||
isChatRecordsLoaded
|
||||
) {
|
||||
sendPrompt({
|
||||
text: chatBoxData?.app?.chatConfig?.autoExecute?.defaultPrompt || 'AUTO_EXECUTE',
|
||||
hideInUI: true
|
||||
});
|
||||
}
|
||||
},
|
||||
[
|
||||
isReady,
|
||||
chatStarted,
|
||||
chatRecords.length,
|
||||
isChatRecordsLoaded,
|
||||
sendPrompt,
|
||||
chatBoxData?.app?.chatConfig?.autoExecute
|
||||
],
|
||||
{
|
||||
wait: 500
|
||||
}
|
||||
}, [
|
||||
isReady,
|
||||
chatStarted,
|
||||
chatRecords.length,
|
||||
isChatRecordsLoaded,
|
||||
sendPrompt,
|
||||
chatBoxData?.app?.chatConfig?.autoExecute
|
||||
]);
|
||||
);
|
||||
|
||||
// output data
|
||||
useImperativeHandle(ChatBoxRef, () => ({
|
||||
|
||||
@@ -161,6 +161,7 @@ const AccountContainer = ({
|
||||
<Box mb={3}>
|
||||
<LightRowTabs<TabEnum>
|
||||
m={'auto'}
|
||||
w={'100%'}
|
||||
size={isPc ? 'md' : 'sm'}
|
||||
list={tabList.map((item) => ({
|
||||
value: item.value,
|
||||
|
||||
@@ -61,10 +61,9 @@ const AiPointsModal = dynamic(() =>
|
||||
|
||||
const Info = () => {
|
||||
const { isPc } = useSystem();
|
||||
const { teamPlanStatus } = useUserStore();
|
||||
const { teamPlanStatus, initUserInfo } = useUserStore();
|
||||
const standardPlan = teamPlanStatus?.standardConstants;
|
||||
const { isOpen: isOpenContact, onClose: onCloseContact, onOpen: onOpenContact } = useDisclosure();
|
||||
const { initUserInfo } = useUserStore();
|
||||
|
||||
useQuery(['init'], initUserInfo);
|
||||
|
||||
@@ -112,15 +111,13 @@ const MyInfo = ({ onOpenContact }: { onOpenContact: () => void }) => {
|
||||
const theme = useTheme();
|
||||
const { feConfigs } = useSystemStore();
|
||||
const { t } = useTranslation();
|
||||
const { userInfo, updateUserInfo } = useUserStore();
|
||||
const { userInfo, updateUserInfo, teamPlanStatus } = useUserStore();
|
||||
const { reset } = useForm<UserUpdateParams>({
|
||||
defaultValues: userInfo as UserType
|
||||
});
|
||||
const { teamPlanStatus } = useUserStore();
|
||||
const standardPlan = teamPlanStatus?.standardConstants;
|
||||
const { isPc } = useSystem();
|
||||
const { toast } = useToast();
|
||||
const router = useRouter();
|
||||
|
||||
const {
|
||||
isOpen: isOpenConversionModal,
|
||||
@@ -305,12 +302,14 @@ const MyInfo = ({ onOpenContact }: { onOpenContact: () => void }) => {
|
||||
)}
|
||||
</Flex>
|
||||
)}
|
||||
<Flex mt={6} alignItems={'center'}>
|
||||
<Box {...labelStyles}>{t('account_info:user_team_team_name')}: </Box>
|
||||
<Flex flex={'1 0 0'} w={0} align={'center'}>
|
||||
<TeamSelector height={'28px'} w={'100%'} showManage />
|
||||
{feConfigs.isPlus && (
|
||||
<Flex mt={6} alignItems={'center'}>
|
||||
<Box {...labelStyles}>{t('account_info:user_team_team_name')}: </Box>
|
||||
<Flex flex={'1 0 0'} w={0} align={'center'}>
|
||||
<TeamSelector height={'28px'} w={'100%'} showManage />
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
)}
|
||||
{feConfigs?.isPlus && (userInfo?.team?.balance ?? 0) > 0 && (
|
||||
<Box mt={6} whiteSpace={'nowrap'}>
|
||||
<Flex alignItems={'center'}>
|
||||
|
||||
27
projects/app/src/pages/api/admin/initv4815.ts
Normal file
27
projects/app/src/pages/api/admin/initv4815.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { MongoApp } from '@fastgpt/service/core/app/schema';
|
||||
|
||||
/* 初始化发布的版本 */
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
await authCert({ req, authRoot: true });
|
||||
|
||||
// scheduledTriggerConfig为 null 的,都转成 unExist
|
||||
return MongoApp.updateMany(
|
||||
{
|
||||
$or: [
|
||||
{ scheduledTriggerConfig: { $eq: null } },
|
||||
{ 'scheduledTriggerConfig.cronString': { $eq: '' } }
|
||||
]
|
||||
},
|
||||
{
|
||||
$unset: {
|
||||
scheduledTriggerConfig: '',
|
||||
scheduledTriggerNextTime: ''
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default NextAPI(handler);
|
||||
@@ -130,7 +130,8 @@ export const onCreateApp = async ({
|
||||
chatConfig,
|
||||
versionName: name,
|
||||
username,
|
||||
avatar: userAvatar
|
||||
avatar: userAvatar,
|
||||
isPublish: true
|
||||
}
|
||||
],
|
||||
{ session }
|
||||
|
||||
@@ -10,6 +10,7 @@ import { PostPublishAppProps } from '@/global/core/app/api';
|
||||
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { ApiRequestProps } from '@fastgpt/service/type/next';
|
||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
import { getScheduleTriggerApp } from '@/service/core/app/utils';
|
||||
|
||||
async function handler(
|
||||
req: ApiRequestProps<PostPublishAppProps>,
|
||||
@@ -52,12 +53,17 @@ async function handler(
|
||||
updateTime: new Date(),
|
||||
version: 'v2',
|
||||
// 只有发布才会更新定时器
|
||||
...(isPublish && {
|
||||
scheduledTriggerConfig: chatConfig?.scheduledTriggerConfig,
|
||||
scheduledTriggerNextTime: chatConfig?.scheduledTriggerConfig?.cronString
|
||||
? getNextTimeByCronStringAndTimezone(chatConfig.scheduledTriggerConfig)
|
||||
: null
|
||||
}),
|
||||
...(isPublish &&
|
||||
(chatConfig?.scheduledTriggerConfig?.cronString
|
||||
? {
|
||||
$set: {
|
||||
scheduledTriggerConfig: chatConfig.scheduledTriggerConfig,
|
||||
scheduledTriggerNextTime: getNextTimeByCronStringAndTimezone(
|
||||
chatConfig.scheduledTriggerConfig
|
||||
)
|
||||
}
|
||||
}
|
||||
: { $unset: { scheduledTriggerConfig: '', scheduledTriggerNextTime: '' } })),
|
||||
'pluginData.nodeVersion': _id
|
||||
},
|
||||
{
|
||||
|
||||
@@ -8,16 +8,17 @@ import { authChatCrud } from '@/service/support/permission/auth/chat';
|
||||
import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { aiTranscriptions } from '@fastgpt/service/core/ai/audio/transcriptions';
|
||||
import { useReqFrequencyLimit } from '@fastgpt/service/common/middle/reqFrequencyLimit';
|
||||
|
||||
const upload = getUploadModel({
|
||||
maxSize: 20
|
||||
maxSize: 5
|
||||
});
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
let filePaths: string[] = [];
|
||||
|
||||
try {
|
||||
const {
|
||||
let {
|
||||
file,
|
||||
data: { appId, duration, shareId, outLinkUid, teamId: spaceTeamId, teamToken }
|
||||
} = await upload.doUpload<
|
||||
@@ -42,9 +43,17 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
if (!file) {
|
||||
throw new Error('file not found');
|
||||
}
|
||||
if (duration === undefined) {
|
||||
throw new Error('duration not found');
|
||||
}
|
||||
duration = duration < 1 ? 1 : duration;
|
||||
|
||||
// auth role
|
||||
const { teamId, tmbId } = await authChatCrud({ req, authToken: true, ...req.body });
|
||||
const { teamId, tmbId } = await authChatCrud({
|
||||
req,
|
||||
authToken: true,
|
||||
...req.body
|
||||
});
|
||||
|
||||
// auth app
|
||||
// const app = await MongoApp.findById(appId, 'modules').lean();
|
||||
@@ -80,7 +89,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
removeFilesByPaths(filePaths);
|
||||
}
|
||||
|
||||
export default NextAPI(handler);
|
||||
export default NextAPI(useReqFrequencyLimit(1, 2), handler);
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
|
||||
@@ -97,9 +97,10 @@ const AppCard = ({ showSaveStatus, isSaved }: { showSaveStatus: boolean; isSaved
|
||||
appName: appDetail.name
|
||||
})}
|
||||
</MyBox>
|
||||
<Box w={'full'} h={'1px'} bg={'myGray.200'} my={1} />
|
||||
{appDetail.permission.hasWritePer && feConfigs?.show_team_chat && (
|
||||
<>
|
||||
<Box w={'full'} h={'1px'} bg={'myGray.200'} my={1} />
|
||||
|
||||
<MyBox
|
||||
display={'flex'}
|
||||
size={'md'}
|
||||
@@ -113,25 +114,28 @@ const AppCard = ({ showSaveStatus, isSaved }: { showSaveStatus: boolean; isSaved
|
||||
<MyIcon name={'core/dataset/tag'} w={'16px'} mr={2} />
|
||||
<Box fontSize={'sm'}>{t('app:Team_Tags')}</Box>
|
||||
</MyBox>
|
||||
<Box w={'full'} h={'1px'} bg={'myGray.200'} my={1} />
|
||||
</>
|
||||
)}
|
||||
|
||||
{appDetail.permission.isOwner && (
|
||||
<MyBox
|
||||
display={'flex'}
|
||||
size={'md'}
|
||||
px={1}
|
||||
py={1.5}
|
||||
rounded={'4px'}
|
||||
color={'red.600'}
|
||||
_hover={{ bg: 'rgba(17, 24, 36, 0.05)' }}
|
||||
cursor={'pointer'}
|
||||
onClick={onDelApp}
|
||||
>
|
||||
<MyIcon name={'delete'} w={'16px'} mr={2} />
|
||||
<Box fontSize={'sm'}>{t('common:common.Delete')}</Box>
|
||||
</MyBox>
|
||||
<>
|
||||
<Box w={'full'} h={'1px'} bg={'myGray.200'} my={1} />
|
||||
|
||||
<MyBox
|
||||
display={'flex'}
|
||||
size={'md'}
|
||||
px={1}
|
||||
py={1.5}
|
||||
rounded={'4px'}
|
||||
color={'red.600'}
|
||||
_hover={{ bg: 'rgba(17, 24, 36, 0.05)' }}
|
||||
cursor={'pointer'}
|
||||
onClick={onDelApp}
|
||||
>
|
||||
<MyIcon name={'delete'} w={'16px'} mr={2} />
|
||||
<Box fontSize={'sm'}>{t('common:common.Delete')}</Box>
|
||||
</MyBox>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
@@ -292,63 +292,7 @@ export const useWorkflow = () => {
|
||||
const { getIntersectingNodes } = useReactFlow();
|
||||
const { isDowningCtrl } = useKeyboard();
|
||||
|
||||
// Loop node size and position
|
||||
const resetParentNodeSizeAndPosition = useMemoizedFn((parentId: string) => {
|
||||
const { childNodes, loopNode } = nodes.reduce(
|
||||
(acc, node) => {
|
||||
if (node.data.parentNodeId === parentId) {
|
||||
acc.childNodes.push(node);
|
||||
}
|
||||
if (node.id === parentId) {
|
||||
acc.loopNode = node;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{ childNodes: [] as Node[], loopNode: undefined as Node<FlowNodeItemType> | undefined }
|
||||
);
|
||||
|
||||
if (!loopNode) return;
|
||||
|
||||
const rect = getNodesBounds(childNodes);
|
||||
// Calculate parent node size with minimum width/height constraints
|
||||
const width = Math.max(rect.width + 80, 840);
|
||||
const height = Math.max(rect.height + 80, 600);
|
||||
|
||||
const offsetHeight =
|
||||
loopNode.data.inputs.find((input) => input.key === NodeInputKeyEnum.loopNodeInputHeight)
|
||||
?.value ?? 83;
|
||||
|
||||
// Update parentNode size and position
|
||||
onChangeNode({
|
||||
nodeId: parentId,
|
||||
type: 'updateInput',
|
||||
key: NodeInputKeyEnum.nodeWidth,
|
||||
value: {
|
||||
...Input_Template_Node_Width,
|
||||
value: width
|
||||
}
|
||||
});
|
||||
onChangeNode({
|
||||
nodeId: parentId,
|
||||
type: 'updateInput',
|
||||
key: NodeInputKeyEnum.nodeHeight,
|
||||
value: {
|
||||
...Input_Template_Node_Height,
|
||||
value: height
|
||||
}
|
||||
});
|
||||
// Update parentNode position
|
||||
onNodesChange([
|
||||
{
|
||||
id: parentId,
|
||||
type: 'position',
|
||||
position: {
|
||||
x: rect.x - 70,
|
||||
y: rect.y - offsetHeight - 240
|
||||
}
|
||||
}
|
||||
]);
|
||||
});
|
||||
const { resetParentNodeSizeAndPosition } = useLoopNode();
|
||||
|
||||
/* helper line */
|
||||
const [helperLineHorizontal, setHelperLineHorizontal] = useState<THelperLine>();
|
||||
@@ -704,7 +648,7 @@ export const useWorkflow = () => {
|
||||
chatConfig: appDetail.chatConfig
|
||||
});
|
||||
},
|
||||
[nodes, edges, appDetail.chatConfig, pushPastSnapshot],
|
||||
[nodes, edges, appDetail.chatConfig],
|
||||
{ wait: 500 }
|
||||
);
|
||||
|
||||
@@ -721,7 +665,73 @@ export const useWorkflow = () => {
|
||||
helperLineVertical,
|
||||
onNodeDragStop,
|
||||
onPaneContextMenu,
|
||||
onPaneClick,
|
||||
onPaneClick
|
||||
};
|
||||
};
|
||||
|
||||
export const useLoopNode = () => {
|
||||
const nodes = useContextSelector(WorkflowInitContext, (state) => state.nodes);
|
||||
const onNodesChange = useContextSelector(WorkflowNodeEdgeContext, (state) => state.onNodesChange);
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const resetParentNodeSizeAndPosition = useMemoizedFn((parentId: string) => {
|
||||
const { childNodes, loopNode } = nodes.reduce(
|
||||
(acc, node) => {
|
||||
if (node.data.parentNodeId === parentId) {
|
||||
acc.childNodes.push(node);
|
||||
}
|
||||
if (node.id === parentId) {
|
||||
acc.loopNode = node;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{ childNodes: [] as Node[], loopNode: undefined as Node<FlowNodeItemType> | undefined }
|
||||
);
|
||||
|
||||
if (!loopNode) return;
|
||||
|
||||
const rect = getNodesBounds(childNodes);
|
||||
// Calculate parent node size with minimum width/height constraints
|
||||
const width = Math.max(rect.width + 80, 840);
|
||||
const height = Math.max(rect.height + 80, 600);
|
||||
|
||||
const offsetHeight =
|
||||
loopNode.data.inputs.find((input) => input.key === NodeInputKeyEnum.loopNodeInputHeight)
|
||||
?.value ?? 83;
|
||||
|
||||
// Update parentNode size and position
|
||||
onChangeNode({
|
||||
nodeId: parentId,
|
||||
type: 'updateInput',
|
||||
key: NodeInputKeyEnum.nodeWidth,
|
||||
value: {
|
||||
...Input_Template_Node_Width,
|
||||
value: width
|
||||
}
|
||||
});
|
||||
onChangeNode({
|
||||
nodeId: parentId,
|
||||
type: 'updateInput',
|
||||
key: NodeInputKeyEnum.nodeHeight,
|
||||
value: {
|
||||
...Input_Template_Node_Height,
|
||||
value: height
|
||||
}
|
||||
});
|
||||
// Update parentNode position
|
||||
onNodesChange([
|
||||
{
|
||||
id: parentId,
|
||||
type: 'position',
|
||||
position: {
|
||||
x: rect.x - 70,
|
||||
y: rect.y - offsetHeight - 240
|
||||
}
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
return {
|
||||
resetParentNodeSizeAndPosition
|
||||
};
|
||||
};
|
||||
|
||||
@@ -31,7 +31,7 @@ import { getWorkflowGlobalVariables } from '@/web/core/workflow/utils';
|
||||
import { AppContext } from '../../../../context';
|
||||
import { isValidArrayReferenceValue } from '@fastgpt/global/core/workflow/utils';
|
||||
import { ReferenceArrayValueType } from '@fastgpt/global/core/workflow/type/io';
|
||||
import { useWorkflow } from '../../hooks/useWorkflow';
|
||||
import { useLoopNode } from '../../hooks/useWorkflow';
|
||||
import { useSize } from 'ahooks';
|
||||
|
||||
const NodeLoop = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
@@ -41,7 +41,7 @@ const NodeLoop = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
const appDetail = useContextSelector(AppContext, (v) => v.appDetail);
|
||||
|
||||
const { resetParentNodeSizeAndPosition } = useWorkflow();
|
||||
const { resetParentNodeSizeAndPosition } = useLoopNode();
|
||||
|
||||
const {
|
||||
nodeWidth,
|
||||
@@ -50,8 +50,12 @@ const NodeLoop = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
loopNodeInputHeight = Input_Template_LOOP_NODE_OFFSET
|
||||
} = useMemo(() => {
|
||||
return {
|
||||
nodeWidth: inputs.find((input) => input.key === NodeInputKeyEnum.nodeWidth)?.value,
|
||||
nodeHeight: inputs.find((input) => input.key === NodeInputKeyEnum.nodeHeight)?.value,
|
||||
nodeWidth: Number(
|
||||
inputs.find((input) => input.key === NodeInputKeyEnum.nodeWidth)?.value?.toFixed(0)
|
||||
),
|
||||
nodeHeight: Number(
|
||||
inputs.find((input) => input.key === NodeInputKeyEnum.nodeHeight)?.value?.toFixed(0)
|
||||
),
|
||||
loopInputArray: inputs.find((input) => input.key === NodeInputKeyEnum.loopInputArray),
|
||||
loopNodeInputHeight: inputs.find(
|
||||
(input) => input.key === NodeInputKeyEnum.loopNodeInputHeight
|
||||
|
||||
@@ -687,26 +687,24 @@ const RenderBody = ({
|
||||
<RenderForm nodeId={nodeId} input={formBody} variables={variables} />
|
||||
)}
|
||||
{typeInput?.value === ContentTypes.json && (
|
||||
<JSONEditor
|
||||
<PromptEditor
|
||||
bg={'white'}
|
||||
defaultHeight={200}
|
||||
resize
|
||||
showOpenModal={false}
|
||||
variableLabels={variables}
|
||||
minH={200}
|
||||
value={jsonBody.value}
|
||||
placeholder={t('common:core.module.template.http body placeholder')}
|
||||
placeholder={t('workflow:http_body_placeholder')}
|
||||
onChange={(e) => {
|
||||
startSts(() => {
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'updateInput',
|
||||
key: jsonBody.key,
|
||||
value: {
|
||||
...jsonBody,
|
||||
value: e
|
||||
}
|
||||
});
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'updateInput',
|
||||
key: jsonBody.key,
|
||||
value: {
|
||||
...jsonBody,
|
||||
value: e
|
||||
}
|
||||
});
|
||||
}}
|
||||
variables={variables}
|
||||
/>
|
||||
)}
|
||||
{(typeInput?.value === ContentTypes.xml || typeInput?.value === ContentTypes.raw) && (
|
||||
@@ -714,16 +712,14 @@ const RenderBody = ({
|
||||
value={jsonBody.value}
|
||||
placeholder={t('common:textarea_variable_picker_tip')}
|
||||
onChange={(e) => {
|
||||
startSts(() => {
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'updateInput',
|
||||
key: jsonBody.key,
|
||||
value: {
|
||||
...jsonBody,
|
||||
value: e
|
||||
}
|
||||
});
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'updateInput',
|
||||
key: jsonBody.key,
|
||||
value: {
|
||||
...jsonBody,
|
||||
value: e
|
||||
}
|
||||
});
|
||||
}}
|
||||
showOpenModal={false}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { postWorkflowDebug } from '@/web/core/workflow/api';
|
||||
import {
|
||||
checkWorkflowNodeAndConnection,
|
||||
compareSnapshot,
|
||||
simplifyWorkflowNodes,
|
||||
storeEdgesRenderEdge,
|
||||
storeNode2FlowNode
|
||||
} from '@/web/core/workflow/utils';
|
||||
@@ -832,11 +831,11 @@ const WorkflowContextProvider = ({
|
||||
const undo = useMemoizedFn(() => {
|
||||
if (past.length > 1) {
|
||||
forbiddenSaveSnapshot.current = true;
|
||||
|
||||
const firstPast = past[0];
|
||||
// Current version is the first one, so we need to reset the second one
|
||||
const firstPast = past[1];
|
||||
resetSnapshot(firstPast);
|
||||
|
||||
setFuture((future) => [firstPast, ...future]);
|
||||
setFuture((future) => [past[0], ...future]);
|
||||
setPast((past) => past.slice(1));
|
||||
}
|
||||
});
|
||||
@@ -937,10 +936,10 @@ const WorkflowContextProvider = ({
|
||||
if (isInit && past.length === 0) {
|
||||
setPast([
|
||||
{
|
||||
nodes: nodes,
|
||||
edges: edges,
|
||||
title: t(`app:app.version_initial`),
|
||||
isSaved: true,
|
||||
nodes: simplifyWorkflowNodes(nodes),
|
||||
edges,
|
||||
chatConfig: e.chatConfig || appDetail.chatConfig
|
||||
}
|
||||
]);
|
||||
|
||||
@@ -3,7 +3,6 @@ import { Box, Flex, Button, useDisclosure, Input, InputGroup } from '@chakra-ui/
|
||||
import { AddIcon } from '@chakra-ui/icons';
|
||||
import { serviceSideProps } from '@/web/common/utils/i18n';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import dynamic from 'next/dynamic';
|
||||
import MyMenu from '@fastgpt/web/components/common/MyMenu';
|
||||
@@ -41,7 +40,6 @@ const List = dynamic(() => import('./components/List'));
|
||||
|
||||
const MyApps = () => {
|
||||
const { t } = useTranslation();
|
||||
const { appT } = useI18n();
|
||||
const router = useRouter();
|
||||
const { isPc } = useSystem();
|
||||
const {
|
||||
@@ -102,14 +100,14 @@ const MyApps = () => {
|
||||
<Input
|
||||
value={searchKey}
|
||||
onChange={(e) => setSearchKey(e.target.value)}
|
||||
placeholder={appT('search_app')}
|
||||
placeholder={t('app:search_app')}
|
||||
maxLength={30}
|
||||
pl={8}
|
||||
bg={'white'}
|
||||
/>
|
||||
</InputGroup>
|
||||
),
|
||||
[searchKey, setSearchKey, appT]
|
||||
[searchKey, setSearchKey, t]
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -300,7 +298,7 @@ const MyApps = () => {
|
||||
});
|
||||
}}
|
||||
onMove={() => setMoveAppId(folderDetail._id)}
|
||||
deleteTip={appT('confirm_delete_folder_tip')}
|
||||
deleteTip={t('app:confirm_delete_folder_tip')}
|
||||
onDelete={() => onDeleFolder(folderDetail._id)}
|
||||
managePer={{
|
||||
mode: 'all',
|
||||
|
||||
@@ -141,7 +141,7 @@ export const AiPointsTable = () => {
|
||||
<Box flex={'1 0 0'}>
|
||||
{whisperModel?.charsPointsPrice +
|
||||
t('common:support.wallet.subscription.point') +
|
||||
' / 1000' +
|
||||
' / 60' +
|
||||
t('common:unit.minute')}
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
@@ -12,12 +12,14 @@ import { TimerIdEnum } from '@fastgpt/service/common/system/timerLock/constants'
|
||||
import { addHours } from 'date-fns';
|
||||
import { getScheduleTriggerApp } from '@/service/core/app/utils';
|
||||
|
||||
// Try to run train every minute
|
||||
const setTrainingQueueCron = () => {
|
||||
setCron('*/1 * * * *', () => {
|
||||
startTrainingQueue();
|
||||
});
|
||||
};
|
||||
|
||||
// Clear tmp upload files every ten minutes
|
||||
const setClearTmpUploadFilesCron = () => {
|
||||
// Clear tmp upload files every ten minutes
|
||||
setCron('*/10 * * * *', () => {
|
||||
@@ -61,6 +63,7 @@ const clearInvalidDataCron = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// Run app timer trigger every hour
|
||||
const scheduleTriggerAppCron = () => {
|
||||
setCron('0 */1 * * *', async () => {
|
||||
if (
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team';
|
||||
import { pushChatUsage } from '@/service/support/wallet/usage/push';
|
||||
import { defaultApp } from '@/web/core/app/constants';
|
||||
import { getNextTimeByCronStringAndTimezone } from '@fastgpt/global/common/string/time';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { delay } from '@fastgpt/global/common/system/utils';
|
||||
import { ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import { delay, retryFn } from '@fastgpt/global/common/system/utils';
|
||||
import {
|
||||
ChatItemValueTypeEnum,
|
||||
ChatRoleEnum,
|
||||
ChatSourceEnum
|
||||
} from '@fastgpt/global/core/chat/constants';
|
||||
import {
|
||||
getWorkflowEntryNodeIds,
|
||||
initWorkflowEdgeStatus,
|
||||
@@ -15,48 +18,87 @@ import { addLog } from '@fastgpt/service/common/system/log';
|
||||
import { MongoApp } from '@fastgpt/service/core/app/schema';
|
||||
import { WORKFLOW_MAX_RUN_TIMES } from '@fastgpt/service/core/workflow/constants';
|
||||
import { dispatchWorkFlow } from '@fastgpt/service/core/workflow/dispatch';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import { UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
||||
import { saveChat } from '@fastgpt/service/core/chat/saveChat';
|
||||
import { getAppLatestVersion } from '@fastgpt/service/core/app/version/controller';
|
||||
|
||||
export const getScheduleTriggerApp = async () => {
|
||||
// 1. Find all the app
|
||||
const apps = await MongoApp.find({
|
||||
scheduledTriggerConfig: { $ne: null },
|
||||
scheduledTriggerNextTime: { $lte: new Date() }
|
||||
const apps = await retryFn(() => {
|
||||
return MongoApp.find({
|
||||
scheduledTriggerConfig: { $exists: true },
|
||||
scheduledTriggerNextTime: { $lte: new Date() }
|
||||
});
|
||||
});
|
||||
|
||||
// 2. Run apps
|
||||
await Promise.allSettled(
|
||||
apps.map(async (app) => {
|
||||
if (!app.scheduledTriggerConfig) return;
|
||||
// random delay 0 ~ 60s
|
||||
await delay(Math.floor(Math.random() * 60 * 1000));
|
||||
const { user } = await getUserChatInfoAndAuthTeamPoints(app.tmbId);
|
||||
|
||||
try {
|
||||
const { flowUsages } = await dispatchWorkFlow({
|
||||
chatId: getNanoid(),
|
||||
user,
|
||||
mode: 'chat',
|
||||
runningAppInfo: {
|
||||
id: String(app._id),
|
||||
teamId: String(app.teamId),
|
||||
tmbId: String(app.tmbId)
|
||||
},
|
||||
uid: String(app.tmbId),
|
||||
runtimeNodes: storeNodes2RuntimeNodes(app.modules, getWorkflowEntryNodeIds(app.modules)),
|
||||
runtimeEdges: initWorkflowEdgeStatus(app.edges),
|
||||
variables: {},
|
||||
query: [
|
||||
{
|
||||
type: ChatItemValueTypeEnum.text,
|
||||
text: {
|
||||
content: app.scheduledTriggerConfig?.defaultPrompt
|
||||
}
|
||||
if (!app.scheduledTriggerConfig) return;
|
||||
// random delay 0 ~ 60s
|
||||
await delay(Math.floor(Math.random() * 60 * 1000));
|
||||
const { user } = await getUserChatInfoAndAuthTeamPoints(app.tmbId);
|
||||
|
||||
// Get app latest version
|
||||
const { nodes, edges, chatConfig } = await getAppLatestVersion(app._id, app);
|
||||
|
||||
const chatId = getNanoid();
|
||||
const userQuery: UserChatItemValueItemType[] = [
|
||||
{
|
||||
type: ChatItemValueTypeEnum.text,
|
||||
text: {
|
||||
content: app.scheduledTriggerConfig?.defaultPrompt
|
||||
}
|
||||
],
|
||||
chatConfig: defaultApp.chatConfig,
|
||||
histories: [],
|
||||
stream: false,
|
||||
maxRunTimes: WORKFLOW_MAX_RUN_TIMES
|
||||
}
|
||||
];
|
||||
|
||||
const { flowUsages, assistantResponses, flowResponses } = await retryFn(() => {
|
||||
return dispatchWorkFlow({
|
||||
chatId,
|
||||
user,
|
||||
mode: 'chat',
|
||||
runningAppInfo: {
|
||||
id: String(app._id),
|
||||
teamId: String(app.teamId),
|
||||
tmbId: String(app.tmbId)
|
||||
},
|
||||
uid: String(app.tmbId),
|
||||
runtimeNodes: storeNodes2RuntimeNodes(nodes, getWorkflowEntryNodeIds(nodes)),
|
||||
runtimeEdges: initWorkflowEdgeStatus(edges),
|
||||
variables: {},
|
||||
query: userQuery,
|
||||
chatConfig,
|
||||
histories: [],
|
||||
stream: false,
|
||||
maxRunTimes: WORKFLOW_MAX_RUN_TIMES
|
||||
});
|
||||
});
|
||||
|
||||
// Save chat
|
||||
await saveChat({
|
||||
chatId,
|
||||
appId: app._id,
|
||||
teamId: String(app.teamId),
|
||||
tmbId: String(app.tmbId),
|
||||
nodes,
|
||||
appChatConfig: chatConfig,
|
||||
variables: {},
|
||||
isUpdateUseTime: false, // owner update use time
|
||||
newTitle: 'Cron Job',
|
||||
source: ChatSourceEnum.cronJob,
|
||||
content: [
|
||||
{
|
||||
obj: ChatRoleEnum.Human,
|
||||
value: userQuery
|
||||
},
|
||||
{
|
||||
obj: ChatRoleEnum.AI,
|
||||
value: assistantResponses,
|
||||
[DispatchNodeResponseKeyEnum.nodeResponse]: flowResponses
|
||||
}
|
||||
]
|
||||
});
|
||||
pushChatUsage({
|
||||
appName: app.name,
|
||||
@@ -66,15 +108,15 @@ export const getScheduleTriggerApp = async () => {
|
||||
source: UsageSourceEnum.cronJob,
|
||||
flowUsages
|
||||
});
|
||||
|
||||
// update next time
|
||||
app.scheduledTriggerNextTime = getNextTimeByCronStringAndTimezone(
|
||||
app.scheduledTriggerConfig
|
||||
);
|
||||
await app.save();
|
||||
} catch (error) {
|
||||
addLog.error('Schedule trigger error', error);
|
||||
addLog.warn('Schedule trigger error', { error });
|
||||
}
|
||||
|
||||
// update next time
|
||||
app.scheduledTriggerNextTime = getNextTimeByCronStringAndTimezone(app.scheduledTriggerConfig);
|
||||
await app.save();
|
||||
|
||||
return;
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
@@ -103,7 +103,7 @@ export const useAudioPlay = (
|
||||
const cancelAudio = useCallback(() => {
|
||||
try {
|
||||
window.speechSynthesis?.cancel();
|
||||
audioController.current.abort('');
|
||||
!audioController.current.signal.aborted && audioController.current.abort();
|
||||
} catch (error) {}
|
||||
if (audioRef.current) {
|
||||
audioRef.current.pause();
|
||||
|
||||
@@ -14,6 +14,8 @@ import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
import { ParentIdType, ParentTreePathItemType } from '@fastgpt/global/common/parentFolder/type';
|
||||
import { GetSystemPluginTemplatesBody } from '@/pages/api/core/app/plugin/getSystemPluginTemplates';
|
||||
import { PluginGroupSchemaType } from '@fastgpt/service/core/app/plugin/type';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { defaultGroup } from '@fastgpt/web/core/workflow/constants';
|
||||
|
||||
/* ============ team plugin ============== */
|
||||
export const getTeamPlugTemplates = (data?: ListAppBody) =>
|
||||
@@ -41,8 +43,11 @@ export const getTeamPlugTemplates = (data?: ListAppBody) =>
|
||||
export const getSystemPlugTemplates = (data: GetSystemPluginTemplatesBody) =>
|
||||
POST<NodeTemplateListItemType[]>('/core/app/plugin/getSystemPluginTemplates', data);
|
||||
|
||||
export const getPluginGroups = () =>
|
||||
GET<PluginGroupSchemaType[]>('/proApi/core/app/plugin/getPluginGroups');
|
||||
export const getPluginGroups = () => {
|
||||
return useSystemStore.getState()?.feConfigs?.isPlus
|
||||
? GET<PluginGroupSchemaType[]>('/proApi/core/app/plugin/getPluginGroups')
|
||||
: Promise.resolve([defaultGroup]);
|
||||
};
|
||||
|
||||
export const getSystemPluginPaths = (parentId: ParentIdType) => {
|
||||
if (!parentId) return Promise.resolve<ParentTreePathItemType[]>([]);
|
||||
|
||||
@@ -619,7 +619,6 @@ export const compareSnapshot = (
|
||||
return nodes
|
||||
.filter((node) => {
|
||||
if (!node) return;
|
||||
if (FlowNodeTypeEnum.systemConfig === node.type) return;
|
||||
|
||||
return true;
|
||||
})
|
||||
@@ -634,7 +633,8 @@ export const compareSnapshot = (
|
||||
key: input.key,
|
||||
selectedTypeIndex: input.selectedTypeIndex ?? 0,
|
||||
renderTypeLis: input.renderTypeList,
|
||||
valueType: input.valueType,
|
||||
// set to arrayAny for loopInputArray to skip valueType comparison
|
||||
// valueType: input.key === NodeInputKeyEnum.loopInputArray ? 'arrayAny' : input.valueType,
|
||||
value: input.value ?? undefined
|
||||
})),
|
||||
outputs: node.data.outputs.map((item: FlowNodeOutputItemType) => ({
|
||||
@@ -661,13 +661,3 @@ export const compareSnapshot = (
|
||||
|
||||
return isEqual(node1, node2);
|
||||
};
|
||||
|
||||
// remove node size
|
||||
export const simplifyWorkflowNodes = (nodes: Node[]) => {
|
||||
return nodes.map((node) => ({
|
||||
id: node.id,
|
||||
type: node.type,
|
||||
position: node.position,
|
||||
data: node.data
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -72,20 +72,22 @@ export PROCESSES_PER_GPU="1"
|
||||
|
||||
# 镜像打包和部署
|
||||
|
||||
## 打包镜像
|
||||
## 本地构建镜像
|
||||
|
||||
在 `pdf-marker` 根目录下执行:
|
||||
1. 在 `pdf-marker` 根目录下执行:
|
||||
|
||||
```bash
|
||||
sudo docker build -t model_pdf -f Dockerfile .
|
||||
```bash
|
||||
sudo docker build -t model_pdf -f Dockerfile .
|
||||
```
|
||||
2. 运行容器
|
||||
```bash
|
||||
sudo docker run --gpus all -itd -p 7231:7231 --name model_pdf_v1 model_pdf
|
||||
```
|
||||
## 快速构建镜像
|
||||
```dockerfile
|
||||
docker pull crpi-h3snc261q1dosroc.cn-hangzhou.personal.cr.aliyuncs.com/marker11/marker_images:latest
|
||||
docker run --gpus all -itd -p 7231:7231 --name model_pdf_v1 crpi-h3snc261q1dosroc.cn-hangzhou.personal.cr.aliyuncs.com/marker11/marker_images:latest
|
||||
```
|
||||
|
||||
## 运行容器
|
||||
|
||||
```bash
|
||||
sudo docker run --gpus all -itd -p 7231:7231 --name model_pdf_v1 model_pdf
|
||||
```
|
||||
|
||||
# 访问示例
|
||||
|
||||
用Post方法访问端口为 `7321 ` 的 `v1/parse/file` 服务
|
||||
|
||||
Reference in New Issue
Block a user