Compare commits
29 Commits
test-html
...
v4.8.13-al
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
608e58ba41 | ||
|
|
044b0c57f7 | ||
|
|
7d7454ef3b | ||
|
|
0d658c0114 | ||
|
|
d58cf44778 | ||
|
|
7537330a3b | ||
|
|
a7f881fc5e | ||
|
|
fc7304d3cd | ||
|
|
aa50174066 | ||
|
|
5b2cc097b0 | ||
|
|
7a933f73b6 | ||
|
|
3e5d7d0d7a | ||
|
|
d15ec1ae69 | ||
|
|
3b82ed0aa1 | ||
|
|
dc95ab1dc1 | ||
|
|
fa2fbc1ddd | ||
|
|
10421d73f4 | ||
|
|
a9ee6e6a5e | ||
|
|
0f1932aadc | ||
|
|
65a39e80b8 | ||
|
|
0db0cbf376 | ||
|
|
f4dbe7c021 | ||
|
|
07b3a0a35d | ||
|
|
fd49ad1342 | ||
|
|
f90803c558 | ||
|
|
49cd2d7a3c | ||
|
|
727bd7144c | ||
|
|
469858877e | ||
|
|
7a929db0a5 |
42
.github/workflows/fastgpt-image.yml
vendored
@@ -90,3 +90,45 @@ jobs:
|
|||||||
-t ${Docker_Hub_Tag} \
|
-t ${Docker_Hub_Tag} \
|
||||||
-t ${Docker_Hub_Latest} \
|
-t ${Docker_Hub_Latest} \
|
||||||
.
|
.
|
||||||
|
build-fastgpt-images-child-route:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
# Set tag
|
||||||
|
- name: Set image name and tag
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.ref_name }}" == "main" ]]; then
|
||||||
|
echo "Git_Tag=ghcr.io/${{ github.repository_owner }}/fastgpt-child-route:latest" >> $GITHUB_ENV
|
||||||
|
echo "Git_Latest=ghcr.io/${{ github.repository_owner }}/fastgpt-child-route:latest" >> $GITHUB_ENV
|
||||||
|
echo "Ali_Tag=${{ secrets.ALI_IMAGE_NAME }}/fastgpt-child-route:latest" >> $GITHUB_ENV
|
||||||
|
echo "Ali_Latest=${{ secrets.ALI_IMAGE_NAME }}/fastgpt-child-route:latest" >> $GITHUB_ENV
|
||||||
|
echo "Docker_Hub_Tag=${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt-child-route:latest" >> $GITHUB_ENV
|
||||||
|
echo "Docker_Hub_Latest=${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt-child-route:latest" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "Git_Tag=ghcr.io/${{ github.repository_owner }}/fastgpt-child-route:${{ github.ref_name }}" >> $GITHUB_ENV
|
||||||
|
echo "Git_Latest=ghcr.io/${{ github.repository_owner }}/fastgpt-child-route:latest" >> $GITHUB_ENV
|
||||||
|
echo "Ali_Tag=${{ secrets.ALI_IMAGE_NAME }}/fastgpt-child-route:${{ github.ref_name }}" >> $GITHUB_ENV
|
||||||
|
echo "Ali_Latest=${{ secrets.ALI_IMAGE_NAME }}/fastgpt-child-route:latest" >> $GITHUB_ENV
|
||||||
|
echo "Docker_Hub_Tag=${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt-child-route:${{ github.ref_name }}" >> $GITHUB_ENV
|
||||||
|
echo "Docker_Hub_Latest=${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt-child-route:latest" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Build and publish image for main branch or tag push event
|
||||||
|
env:
|
||||||
|
DOCKER_REPO_TAGGED: ${{ env.DOCKER_REPO_TAGGED }}
|
||||||
|
run: |
|
||||||
|
docker buildx build \
|
||||||
|
-f projects/app/Dockerfile \
|
||||||
|
--platform linux/amd64,linux/arm64 \
|
||||||
|
--build-arg base_url=fastai \
|
||||||
|
--label "org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/FastGPT" \
|
||||||
|
--label "org.opencontainers.image.description=fastgpt image" \
|
||||||
|
--push \
|
||||||
|
--cache-from=type=local,src=/tmp/.buildx-cache \
|
||||||
|
--cache-to=type=local,dest=/tmp/.buildx-cache \
|
||||||
|
-t ${Git_Tag} \
|
||||||
|
-t ${Git_Latest} \
|
||||||
|
-t ${Ali_Tag} \
|
||||||
|
-t ${Ali_Latest} \
|
||||||
|
-t ${Docker_Hub_Tag} \
|
||||||
|
-t ${Docker_Hub_Latest} \
|
||||||
|
.
|
||||||
|
|||||||
@@ -9,6 +9,17 @@ weight: 811
|
|||||||
|
|
||||||
## 更新说明
|
## 更新说明
|
||||||
|
|
||||||
1.
|
1. 新增 - 数组变量选择支持多选,可以选多个数组或对应的单一数据类型,会自动按选择顺序进行合并。
|
||||||
2. 优化 - 知识库上传文件,优化报错提示
|
2. 新增 - 文件上传方案调整,节点直接支持接收文件链接,插件自定义变量支持文件上传。
|
||||||
3. 修复 - BI 图表生成无法写入文件
|
3. 新增 - 对话记录增加时间显示。
|
||||||
|
4. 新增 - 工作流校验错误时,跳转至错误节点。
|
||||||
|
5. 新增 - 循环节点增加下标值。
|
||||||
|
6. 新增 - 部分对话错误提醒增加翻译。
|
||||||
|
7. 优化 - 合并多个 system 提示词成 1 个,避免部分模型不支持多个 system 提示词。
|
||||||
|
8. 优化 - 知识库上传文件,优化报错提示。
|
||||||
|
9. 优化 - 全文检索语句,减少一轮查询。
|
||||||
|
10. 优化 - 修改 findLast 为 [...array].reverse().find,适配旧版浏览器。
|
||||||
|
11. 优化 - Markdown 组件自动空格,避免分割 url 中的中文。
|
||||||
|
12. 优化 - 工作流上下文拆分,性能优化。
|
||||||
|
13. 修复 - Dockerfile pnpm install 支持代理。
|
||||||
|
14. 修复 - BI 图表生成无法写入文件。
|
||||||
|
|||||||
@@ -139,6 +139,8 @@ services:
|
|||||||
- OPENAI_BASE_URL=http://oneapi:3000/v1
|
- OPENAI_BASE_URL=http://oneapi:3000/v1
|
||||||
# AI模型的API Key。(这里默认填写了OneAPI的快速默认key,测试通后,务必及时修改)
|
# AI模型的API Key。(这里默认填写了OneAPI的快速默认key,测试通后,务必及时修改)
|
||||||
- CHAT_API_KEY=sk-fastgpt
|
- CHAT_API_KEY=sk-fastgpt
|
||||||
|
# 是否将图片转成 base64 传递给模型,本地开发和内网环境使用共有模型时候需要设置为 true
|
||||||
|
- MULTIPLE_DATA_TO_BASE64=false
|
||||||
# 数据库最大连接数
|
# 数据库最大连接数
|
||||||
- DB_MAX_LINK=30
|
- DB_MAX_LINK=30
|
||||||
# 登录凭证密钥
|
# 登录凭证密钥
|
||||||
|
|||||||
@@ -97,6 +97,8 @@ services:
|
|||||||
- OPENAI_BASE_URL=http://oneapi:3000/v1
|
- OPENAI_BASE_URL=http://oneapi:3000/v1
|
||||||
# AI模型的API Key。(这里默认填写了OneAPI的快速默认key,测试通后,务必及时修改)
|
# AI模型的API Key。(这里默认填写了OneAPI的快速默认key,测试通后,务必及时修改)
|
||||||
- CHAT_API_KEY=sk-fastgpt
|
- CHAT_API_KEY=sk-fastgpt
|
||||||
|
# 是否将图片转成 base64 传递给模型,本地开发和内网环境使用共有模型时候需要设置为 true
|
||||||
|
- MULTIPLE_DATA_TO_BASE64=false
|
||||||
# 数据库最大连接数
|
# 数据库最大连接数
|
||||||
- DB_MAX_LINK=30
|
- DB_MAX_LINK=30
|
||||||
# 登录凭证密钥
|
# 登录凭证密钥
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ services:
|
|||||||
- OPENAI_BASE_URL=http://oneapi:3000/v1
|
- OPENAI_BASE_URL=http://oneapi:3000/v1
|
||||||
# AI模型的API Key。(这里默认填写了OneAPI的快速默认key,测试通后,务必及时修改)
|
# AI模型的API Key。(这里默认填写了OneAPI的快速默认key,测试通后,务必及时修改)
|
||||||
- CHAT_API_KEY=sk-fastgpt
|
- CHAT_API_KEY=sk-fastgpt
|
||||||
|
# 是否将图片转成 base64 传递给模型,本地开发和内网环境使用共有模型时候需要设置为 true
|
||||||
|
- MULTIPLE_DATA_TO_BASE64=false
|
||||||
# 数据库最大连接数
|
# 数据库最大连接数
|
||||||
- DB_MAX_LINK=30
|
- DB_MAX_LINK=30
|
||||||
# 登录凭证密钥
|
# 登录凭证密钥
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ export const bucketNameMap = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ReadFileBaseUrl = `${process.env.FE_DOMAIN || ''}/api/common/file/read`;
|
export const ReadFileBaseUrl = `${process.env.FE_DOMAIN || ''}${process.env.NEXT_PUBLIC_BASE_URL}/api/common/file/read`;
|
||||||
|
|
||||||
export const documentFileType = '.txt, .docx, .csv, .xlsx, .pdf, .md, .html, .pptx';
|
export const documentFileType = '.txt, .docx, .csv, .xlsx, .pdf, .md, .html, .pptx';
|
||||||
|
export const imageFileType =
|
||||||
|
'.jpg, .jpeg, .png, .gif, .bmp, .webp, .svg, .tiff, .tif, .ico, .heic, .heif, .avif';
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
import { detect } from 'jschardet';
|
import { detect } from 'jschardet';
|
||||||
|
import { documentFileType, imageFileType } from './constants';
|
||||||
|
import { ChatFileTypeEnum } from '../../core/chat/constants';
|
||||||
|
import { UserChatItemValueItemType } from '../../core/chat/type';
|
||||||
|
|
||||||
export const formatFileSize = (bytes: number): string => {
|
export const formatFileSize = (bytes: number): string => {
|
||||||
if (bytes === 0) return '0 B';
|
if (bytes === 0) return '0 B';
|
||||||
@@ -13,3 +16,40 @@ export const formatFileSize = (bytes: number): string => {
|
|||||||
export const detectFileEncoding = (buffer: Buffer) => {
|
export const detectFileEncoding = (buffer: Buffer) => {
|
||||||
return detect(buffer.slice(0, 200))?.encoding?.toLocaleLowerCase();
|
return detect(buffer.slice(0, 200))?.encoding?.toLocaleLowerCase();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Url => user upload file type
|
||||||
|
export const parseUrlToFileType = (url: string): UserChatItemValueItemType['file'] | undefined => {
|
||||||
|
if (typeof url !== 'string') return;
|
||||||
|
const parseUrl = new URL(url, 'https://locaohost:3000');
|
||||||
|
|
||||||
|
const filename = (() => {
|
||||||
|
// Old version file url: https://xxx.com/file/read?filename=xxx.pdf
|
||||||
|
const filenameQuery = parseUrl.searchParams.get('filename');
|
||||||
|
if (filenameQuery) return filenameQuery;
|
||||||
|
|
||||||
|
// Common file: https://xxx.com/xxx.pdf?xxxx=xxx
|
||||||
|
const pathname = parseUrl.pathname;
|
||||||
|
if (pathname) return pathname.split('/').pop();
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (!filename) return;
|
||||||
|
|
||||||
|
const extension = filename.split('.').pop()?.toLowerCase() || '';
|
||||||
|
|
||||||
|
if (!extension) return;
|
||||||
|
|
||||||
|
if (documentFileType.includes(extension)) {
|
||||||
|
return {
|
||||||
|
type: ChatFileTypeEnum.file,
|
||||||
|
name: filename,
|
||||||
|
url
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (imageFileType.includes(extension)) {
|
||||||
|
return {
|
||||||
|
type: ChatFileTypeEnum.image,
|
||||||
|
name: filename,
|
||||||
|
url
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import dayjs from 'dayjs';
|
|||||||
import cronParser from 'cron-parser';
|
import cronParser from 'cron-parser';
|
||||||
import utc from 'dayjs/plugin/utc';
|
import utc from 'dayjs/plugin/utc';
|
||||||
import timezone from 'dayjs/plugin/timezone';
|
import timezone from 'dayjs/plugin/timezone';
|
||||||
|
import { i18nT } from '../../../web/i18n/utils';
|
||||||
|
|
||||||
dayjs.extend(utc);
|
dayjs.extend(utc);
|
||||||
dayjs.extend(timezone);
|
dayjs.extend(timezone);
|
||||||
@@ -23,31 +24,51 @@ export const formatTimeToChatTime = (time: Date) => {
|
|||||||
|
|
||||||
// 如果传入时间小于60秒,返回刚刚
|
// 如果传入时间小于60秒,返回刚刚
|
||||||
if (now.diff(target, 'second') < 60) {
|
if (now.diff(target, 'second') < 60) {
|
||||||
return '刚刚';
|
return i18nT('common:just_now');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果时间是今天,展示几时:几分
|
// 如果时间是今天,展示几时:几分
|
||||||
|
//用#占位,i18n生效后replace成:
|
||||||
if (now.isSame(target, 'day')) {
|
if (now.isSame(target, 'day')) {
|
||||||
return target.format('HH : mm');
|
return target.format('HH#mm');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果是昨天,展示昨天
|
// 如果是昨天,展示昨天
|
||||||
if (now.subtract(1, 'day').isSame(target, 'day')) {
|
if (now.subtract(1, 'day').isSame(target, 'day')) {
|
||||||
return '昨天';
|
return i18nT('common:yesterday');
|
||||||
}
|
|
||||||
|
|
||||||
// 如果是前天,展示前天
|
|
||||||
if (now.subtract(2, 'day').isSame(target, 'day')) {
|
|
||||||
return '前天';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果是今年,展示某月某日
|
// 如果是今年,展示某月某日
|
||||||
if (now.isSame(target, 'year')) {
|
if (now.isSame(target, 'year')) {
|
||||||
return target.format('MM/DD');
|
return target.format('MM-DD');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果是更久之前,展示某年某月某日
|
// 如果是更久之前,展示某年某月某日
|
||||||
return target.format('YYYY/M/D');
|
return target.format('YYYY-M-D');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const formatTimeToChatItemTime = (time: Date) => {
|
||||||
|
const now = dayjs();
|
||||||
|
const target = dayjs(time);
|
||||||
|
const detailTime = target.format('HH#mm');
|
||||||
|
|
||||||
|
// 如果时间是今天,展示几时:几分
|
||||||
|
if (now.isSame(target, 'day')) {
|
||||||
|
return detailTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是昨天,展示昨天+几时:几分
|
||||||
|
if (now.subtract(1, 'day').isSame(target, 'day')) {
|
||||||
|
return i18nT('common:yesterday_detail_time');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是今年,展示某月某日+几时:几分
|
||||||
|
if (now.isSame(target, 'year')) {
|
||||||
|
return target.format('MM-DD') + ' ' + detailTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是更久之前,展示某年某月某日+几时:几分
|
||||||
|
return target.format('YYYY-M-D') + ' ' + detailTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* cron time parse */
|
/* cron time parse */
|
||||||
|
|||||||
@@ -207,8 +207,8 @@ export const Prompt_systemQuotePromptList: PromptTemplateItem[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
// Document quote prompt
|
// Document quote prompt
|
||||||
export const Prompt_DocumentQuote = `将 <Reference></Reference> 中的内容作为本次对话的参考:
|
export const Prompt_DocumentQuote = `将 <FilesContent></FilesContent> 中的内容作为本次对话的参考:
|
||||||
<Reference>
|
<FilesContent>
|
||||||
{{quote}}
|
{{quote}}
|
||||||
</Reference>
|
</FilesContent>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import type {
|
|||||||
ChatCompletionToolMessageParam
|
ChatCompletionToolMessageParam
|
||||||
} from '../../core/ai/type.d';
|
} from '../../core/ai/type.d';
|
||||||
import { ChatCompletionRequestMessageRoleEnum } from '../../core/ai/constants';
|
import { ChatCompletionRequestMessageRoleEnum } from '../../core/ai/constants';
|
||||||
|
|
||||||
const GPT2Chat = {
|
const GPT2Chat = {
|
||||||
[ChatCompletionRequestMessageRoleEnum.System]: ChatRoleEnum.System,
|
[ChatCompletionRequestMessageRoleEnum.System]: ChatRoleEnum.System,
|
||||||
[ChatCompletionRequestMessageRoleEnum.User]: ChatRoleEnum.Human,
|
[ChatCompletionRequestMessageRoleEnum.User]: ChatRoleEnum.Human,
|
||||||
@@ -61,14 +60,14 @@ export const chats2GPTMessages = ({
|
|||||||
return {
|
return {
|
||||||
type: 'image_url',
|
type: 'image_url',
|
||||||
image_url: {
|
image_url: {
|
||||||
url: item.file?.url || ''
|
url: item.file.url
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else if (item.file?.type === ChatFileTypeEnum.file) {
|
} else if (item.file?.type === ChatFileTypeEnum.file) {
|
||||||
return {
|
return {
|
||||||
type: 'file_url',
|
type: 'file_url',
|
||||||
name: item.file?.name || '',
|
name: item.file?.name || '',
|
||||||
url: item.file?.url || ''
|
url: item.file.url
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
packages/global/core/chat/type.d.ts
vendored
@@ -126,6 +126,7 @@ export type ChatSiteItemType = (UserChatItemType | SystemChatItemType | AIChatIt
|
|||||||
moduleName?: string;
|
moduleName?: string;
|
||||||
ttsBuffer?: Uint8Array;
|
ttsBuffer?: Uint8Array;
|
||||||
responseData?: ChatHistoryItemResType[];
|
responseData?: ChatHistoryItemResType[];
|
||||||
|
time?: Date;
|
||||||
} & ChatBoxInputType &
|
} & ChatBoxInputType &
|
||||||
ResponseTagItemType;
|
ResponseTagItemType;
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ export const getChatTitleFromChatMessage = (message?: ChatItemType, defaultValue
|
|||||||
// Keep the first n and last n characters
|
// Keep the first n and last n characters
|
||||||
export const getHistoryPreview = (
|
export const getHistoryPreview = (
|
||||||
completeMessages: ChatItemType[],
|
completeMessages: ChatItemType[],
|
||||||
size = 100
|
size = 100,
|
||||||
|
useVision = false
|
||||||
): {
|
): {
|
||||||
obj: `${ChatRoleEnum}`;
|
obj: `${ChatRoleEnum}`;
|
||||||
value: string;
|
value: string;
|
||||||
@@ -48,7 +49,8 @@ export const getHistoryPreview = (
|
|||||||
item.value
|
item.value
|
||||||
?.map((item) => {
|
?.map((item) => {
|
||||||
if (item?.text?.content) return item?.text?.content;
|
if (item?.text?.content) return item?.text?.content;
|
||||||
if (item.file?.type === 'image') return 'Input an image';
|
if (item.file?.type === 'image' && useVision)
|
||||||
|
return `}...)`;
|
||||||
return '';
|
return '';
|
||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
|
|||||||
@@ -201,6 +201,7 @@ export enum NodeInputKeyEnum {
|
|||||||
nodeHeight = 'nodeHeight',
|
nodeHeight = 'nodeHeight',
|
||||||
// loop start
|
// loop start
|
||||||
loopStartInput = 'loopStartInput',
|
loopStartInput = 'loopStartInput',
|
||||||
|
loopStartIndex = 'loopStartIndex',
|
||||||
// loop end
|
// loop end
|
||||||
loopEndInput = 'loopEndInput',
|
loopEndInput = 'loopEndInput',
|
||||||
|
|
||||||
@@ -256,9 +257,9 @@ export enum NodeOutputKeyEnum {
|
|||||||
|
|
||||||
// loop
|
// loop
|
||||||
loopArray = 'loopArray',
|
loopArray = 'loopArray',
|
||||||
|
|
||||||
// loop start
|
// loop start
|
||||||
loopStartInput = 'loopStartInput',
|
loopStartInput = 'loopStartInput',
|
||||||
|
loopStartIndex = 'loopStartIndex',
|
||||||
|
|
||||||
// form input
|
// form input
|
||||||
formInputResult = 'formInputResult'
|
formInputResult = 'formInputResult'
|
||||||
@@ -334,3 +335,21 @@ export enum ContentTypes {
|
|||||||
xml = 'xml',
|
xml = 'xml',
|
||||||
raw = 'raw-text'
|
raw = 'raw-text'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const ArrayTypeMap: Record<WorkflowIOValueTypeEnum, WorkflowIOValueTypeEnum> = {
|
||||||
|
[WorkflowIOValueTypeEnum.string]: WorkflowIOValueTypeEnum.arrayString,
|
||||||
|
[WorkflowIOValueTypeEnum.number]: WorkflowIOValueTypeEnum.arrayNumber,
|
||||||
|
[WorkflowIOValueTypeEnum.boolean]: WorkflowIOValueTypeEnum.arrayBoolean,
|
||||||
|
[WorkflowIOValueTypeEnum.object]: WorkflowIOValueTypeEnum.arrayObject,
|
||||||
|
[WorkflowIOValueTypeEnum.arrayString]: WorkflowIOValueTypeEnum.arrayString,
|
||||||
|
[WorkflowIOValueTypeEnum.arrayNumber]: WorkflowIOValueTypeEnum.arrayNumber,
|
||||||
|
[WorkflowIOValueTypeEnum.arrayBoolean]: WorkflowIOValueTypeEnum.arrayBoolean,
|
||||||
|
[WorkflowIOValueTypeEnum.arrayObject]: WorkflowIOValueTypeEnum.arrayObject,
|
||||||
|
[WorkflowIOValueTypeEnum.chatHistory]: WorkflowIOValueTypeEnum.arrayObject,
|
||||||
|
[WorkflowIOValueTypeEnum.datasetQuote]: WorkflowIOValueTypeEnum.arrayObject,
|
||||||
|
[WorkflowIOValueTypeEnum.dynamic]: WorkflowIOValueTypeEnum.arrayObject,
|
||||||
|
[WorkflowIOValueTypeEnum.selectDataset]: WorkflowIOValueTypeEnum.arrayObject,
|
||||||
|
[WorkflowIOValueTypeEnum.selectApp]: WorkflowIOValueTypeEnum.arrayObject,
|
||||||
|
[WorkflowIOValueTypeEnum.arrayAny]: WorkflowIOValueTypeEnum.arrayAny,
|
||||||
|
[WorkflowIOValueTypeEnum.any]: WorkflowIOValueTypeEnum.arrayAny
|
||||||
|
};
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ export enum FlowNodeInputTypeEnum { // render ui
|
|||||||
settingDatasetQuotePrompt = 'settingDatasetQuotePrompt',
|
settingDatasetQuotePrompt = 'settingDatasetQuotePrompt',
|
||||||
|
|
||||||
hidden = 'hidden',
|
hidden = 'hidden',
|
||||||
custom = 'custom'
|
custom = 'custom',
|
||||||
|
|
||||||
|
fileSelect = 'fileSelect'
|
||||||
}
|
}
|
||||||
export const FlowNodeInputMap: Record<
|
export const FlowNodeInputMap: Record<
|
||||||
FlowNodeInputTypeEnum,
|
FlowNodeInputTypeEnum,
|
||||||
@@ -85,6 +87,9 @@ export const FlowNodeInputMap: Record<
|
|||||||
},
|
},
|
||||||
[FlowNodeInputTypeEnum.textarea]: {
|
[FlowNodeInputTypeEnum.textarea]: {
|
||||||
icon: 'core/workflow/inputType/textarea'
|
icon: 'core/workflow/inputType/textarea'
|
||||||
|
},
|
||||||
|
[FlowNodeInputTypeEnum.fileSelect]: {
|
||||||
|
icon: 'core/workflow/inputType/file'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -137,43 +142,43 @@ export enum FlowNodeTypeEnum {
|
|||||||
// node IO value type
|
// node IO value type
|
||||||
export const FlowValueTypeMap = {
|
export const FlowValueTypeMap = {
|
||||||
[WorkflowIOValueTypeEnum.string]: {
|
[WorkflowIOValueTypeEnum.string]: {
|
||||||
label: 'string',
|
label: 'String',
|
||||||
value: WorkflowIOValueTypeEnum.string
|
value: WorkflowIOValueTypeEnum.string
|
||||||
},
|
},
|
||||||
[WorkflowIOValueTypeEnum.number]: {
|
[WorkflowIOValueTypeEnum.number]: {
|
||||||
label: 'number',
|
label: 'Number',
|
||||||
value: WorkflowIOValueTypeEnum.number
|
value: WorkflowIOValueTypeEnum.number
|
||||||
},
|
},
|
||||||
[WorkflowIOValueTypeEnum.boolean]: {
|
[WorkflowIOValueTypeEnum.boolean]: {
|
||||||
label: 'boolean',
|
label: 'Boolean',
|
||||||
value: WorkflowIOValueTypeEnum.boolean
|
value: WorkflowIOValueTypeEnum.boolean
|
||||||
},
|
},
|
||||||
[WorkflowIOValueTypeEnum.object]: {
|
[WorkflowIOValueTypeEnum.object]: {
|
||||||
label: 'object',
|
label: 'Object',
|
||||||
value: WorkflowIOValueTypeEnum.object
|
value: WorkflowIOValueTypeEnum.object
|
||||||
},
|
},
|
||||||
[WorkflowIOValueTypeEnum.arrayString]: {
|
[WorkflowIOValueTypeEnum.arrayString]: {
|
||||||
label: 'array<string>',
|
label: 'Array<string>',
|
||||||
value: WorkflowIOValueTypeEnum.arrayString
|
value: WorkflowIOValueTypeEnum.arrayString
|
||||||
},
|
},
|
||||||
[WorkflowIOValueTypeEnum.arrayNumber]: {
|
[WorkflowIOValueTypeEnum.arrayNumber]: {
|
||||||
label: 'array<number>',
|
label: 'Array<number>',
|
||||||
value: WorkflowIOValueTypeEnum.arrayNumber
|
value: WorkflowIOValueTypeEnum.arrayNumber
|
||||||
},
|
},
|
||||||
[WorkflowIOValueTypeEnum.arrayBoolean]: {
|
[WorkflowIOValueTypeEnum.arrayBoolean]: {
|
||||||
label: 'array<boolean>',
|
label: 'Array<boolean>',
|
||||||
value: WorkflowIOValueTypeEnum.arrayBoolean
|
value: WorkflowIOValueTypeEnum.arrayBoolean
|
||||||
},
|
},
|
||||||
[WorkflowIOValueTypeEnum.arrayObject]: {
|
[WorkflowIOValueTypeEnum.arrayObject]: {
|
||||||
label: 'array<object>',
|
label: 'Array<object>',
|
||||||
value: WorkflowIOValueTypeEnum.arrayObject
|
value: WorkflowIOValueTypeEnum.arrayObject
|
||||||
},
|
},
|
||||||
[WorkflowIOValueTypeEnum.arrayAny]: {
|
[WorkflowIOValueTypeEnum.arrayAny]: {
|
||||||
label: 'array',
|
label: 'Array',
|
||||||
value: WorkflowIOValueTypeEnum.arrayAny
|
value: WorkflowIOValueTypeEnum.arrayAny
|
||||||
},
|
},
|
||||||
[WorkflowIOValueTypeEnum.any]: {
|
[WorkflowIOValueTypeEnum.any]: {
|
||||||
label: 'any',
|
label: 'Any',
|
||||||
value: WorkflowIOValueTypeEnum.any
|
value: WorkflowIOValueTypeEnum.any
|
||||||
},
|
},
|
||||||
[WorkflowIOValueTypeEnum.chatHistory]: {
|
[WorkflowIOValueTypeEnum.chatHistory]: {
|
||||||
|
|||||||
@@ -135,6 +135,9 @@ export type DispatchNodeResponseType = {
|
|||||||
extensionResult?: string;
|
extensionResult?: string;
|
||||||
extensionTokens?: number;
|
extensionTokens?: number;
|
||||||
|
|
||||||
|
// dataset concat
|
||||||
|
concatLength?: number;
|
||||||
|
|
||||||
// cq
|
// cq
|
||||||
cqList?: ClassifyQuestionAgentItemType[];
|
cqList?: ClassifyQuestionAgentItemType[];
|
||||||
cqResult?: string;
|
cqResult?: string;
|
||||||
@@ -216,5 +219,7 @@ export type AIChatNodeProps = {
|
|||||||
[NodeInputKeyEnum.aiChatQuoteTemplate]?: string;
|
[NodeInputKeyEnum.aiChatQuoteTemplate]?: string;
|
||||||
[NodeInputKeyEnum.aiChatQuotePrompt]?: string;
|
[NodeInputKeyEnum.aiChatQuotePrompt]?: string;
|
||||||
[NodeInputKeyEnum.aiChatVision]?: boolean;
|
[NodeInputKeyEnum.aiChatVision]?: boolean;
|
||||||
|
|
||||||
[NodeInputKeyEnum.stringQuoteText]?: string;
|
[NodeInputKeyEnum.stringQuoteText]?: string;
|
||||||
|
[NodeInputKeyEnum.fileUrlList]?: string[];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { StoreNodeItemType } from '../type/node';
|
|||||||
import { StoreEdgeItemType } from '../type/edge';
|
import { StoreEdgeItemType } from '../type/edge';
|
||||||
import { RuntimeEdgeItemType, RuntimeNodeItemType } from './type';
|
import { RuntimeEdgeItemType, RuntimeNodeItemType } from './type';
|
||||||
import { VARIABLE_NODE_ID } from '../constants';
|
import { VARIABLE_NODE_ID } from '../constants';
|
||||||
import { isReferenceValue } from '../utils';
|
import { isValidReferenceValueFormat } from '../utils';
|
||||||
import { FlowNodeOutputItemType, ReferenceValueProps } from '../type/io';
|
import { FlowNodeOutputItemType, ReferenceValueType } from '../type/io';
|
||||||
import { ChatItemType, NodeOutputItemType } from '../../../core/chat/type';
|
import { ChatItemType, NodeOutputItemType } from '../../../core/chat/type';
|
||||||
import { ChatItemValueTypeEnum, ChatRoleEnum } from '../../../core/chat/constants';
|
import { ChatItemValueTypeEnum, ChatRoleEnum } from '../../../core/chat/constants';
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ export const getMaxHistoryLimitFromNodes = (nodes: StoreNodeItemType[]): number
|
|||||||
2. Check that the workflow starts at the interaction node
|
2. Check that the workflow starts at the interaction node
|
||||||
*/
|
*/
|
||||||
export const getLastInteractiveValue = (histories: ChatItemType[]) => {
|
export const getLastInteractiveValue = (histories: ChatItemType[]) => {
|
||||||
const lastAIMessage = histories.findLast((item) => item.obj === ChatRoleEnum.AI);
|
const lastAIMessage = [...histories].reverse().find((item) => item.obj === ChatRoleEnum.AI);
|
||||||
|
|
||||||
if (lastAIMessage) {
|
if (lastAIMessage) {
|
||||||
const lastValue = lastAIMessage.value[lastAIMessage.value.length - 1];
|
const lastValue = lastAIMessage.value[lastAIMessage.value.length - 1];
|
||||||
@@ -225,37 +225,129 @@ export const checkNodeRunStatus = ({
|
|||||||
return 'wait';
|
return 'wait';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get the value of the reference variable/node output
|
||||||
|
1. [string,string]
|
||||||
|
2. [string,string][]
|
||||||
|
*/
|
||||||
export const getReferenceVariableValue = ({
|
export const getReferenceVariableValue = ({
|
||||||
value,
|
value,
|
||||||
nodes,
|
nodes,
|
||||||
variables
|
variables
|
||||||
}: {
|
}: {
|
||||||
value: ReferenceValueProps;
|
value?: ReferenceValueType;
|
||||||
nodes: RuntimeNodeItemType[];
|
nodes: RuntimeNodeItemType[];
|
||||||
variables: Record<string, any>;
|
variables: Record<string, any>;
|
||||||
}) => {
|
}) => {
|
||||||
const nodeIds = nodes.map((node) => node.nodeId);
|
if (!value) return value;
|
||||||
if (!isReferenceValue(value, nodeIds)) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
const sourceNodeId = value[0];
|
|
||||||
const outputId = value[1];
|
|
||||||
|
|
||||||
if (sourceNodeId === VARIABLE_NODE_ID && outputId) {
|
// handle single reference value
|
||||||
return variables[outputId];
|
if (isValidReferenceValueFormat(value)) {
|
||||||
|
const sourceNodeId = value[0];
|
||||||
|
const outputId = value[1];
|
||||||
|
|
||||||
|
if (sourceNodeId === VARIABLE_NODE_ID) {
|
||||||
|
if (!outputId) return undefined;
|
||||||
|
return variables[outputId];
|
||||||
|
}
|
||||||
|
|
||||||
|
const node = nodes.find((node) => node.nodeId === sourceNodeId);
|
||||||
|
if (!node) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node.outputs.find((output) => output.id === outputId)?.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const node = nodes.find((node) => node.nodeId === sourceNodeId);
|
// handle reference array
|
||||||
|
if (
|
||||||
|
Array.isArray(value) &&
|
||||||
|
value.length > 0 &&
|
||||||
|
value.every((item) => isValidReferenceValueFormat(item))
|
||||||
|
) {
|
||||||
|
const result = value.map<any>((val) => {
|
||||||
|
return getReferenceVariableValue({
|
||||||
|
value: val,
|
||||||
|
nodes,
|
||||||
|
variables
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
if (!node) {
|
return result.flat().filter((item) => item !== undefined);
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const outputValue = node.outputs.find((output) => output.id === outputId)?.value;
|
return value;
|
||||||
|
|
||||||
return outputValue;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// replace {{$xx.xx$}} variables for text
|
||||||
|
export function replaceEditorVariable({
|
||||||
|
text,
|
||||||
|
nodes,
|
||||||
|
variables,
|
||||||
|
runningNode
|
||||||
|
}: {
|
||||||
|
text: any;
|
||||||
|
nodes: RuntimeNodeItemType[];
|
||||||
|
variables: Record<string, any>; // global variables
|
||||||
|
runningNode: RuntimeNodeItemType;
|
||||||
|
}) {
|
||||||
|
if (typeof text !== 'string') return text;
|
||||||
|
|
||||||
|
const globalVariables = Object.keys(variables).map((key) => {
|
||||||
|
return {
|
||||||
|
nodeId: VARIABLE_NODE_ID,
|
||||||
|
id: key,
|
||||||
|
value: variables[key]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Upstream node outputs
|
||||||
|
const nodeVariables = nodes
|
||||||
|
.map((node) => {
|
||||||
|
return node.outputs.map((output) => {
|
||||||
|
return {
|
||||||
|
nodeId: node.nodeId,
|
||||||
|
id: output.id,
|
||||||
|
value: output.value
|
||||||
|
};
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.flat();
|
||||||
|
|
||||||
|
// Get runningNode inputs(Will be replaced with reference)
|
||||||
|
const customInputs = runningNode.inputs.flatMap((item) => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: item.key,
|
||||||
|
value: getReferenceVariableValue({
|
||||||
|
value: item.value,
|
||||||
|
nodes,
|
||||||
|
variables
|
||||||
|
}),
|
||||||
|
nodeId: runningNode.nodeId
|
||||||
|
}
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
const allVariables = [...globalVariables, ...nodeVariables, ...customInputs];
|
||||||
|
|
||||||
|
// Replace {{$xxx.xxx$}} to value
|
||||||
|
for (const key in allVariables) {
|
||||||
|
const variable = allVariables[key];
|
||||||
|
const val = variable.value;
|
||||||
|
const formatVal = (() => {
|
||||||
|
if (val === undefined) return '';
|
||||||
|
if (val === null) return 'null';
|
||||||
|
|
||||||
|
return typeof val === 'object' ? JSON.stringify(val) : String(val);
|
||||||
|
})();
|
||||||
|
|
||||||
|
const regex = new RegExp(`\\{\\{\\$(${variable.nodeId}\\.${variable.id})\\$\\}\\}`, 'g');
|
||||||
|
text = text.replace(regex, formatVal);
|
||||||
|
}
|
||||||
|
return text || '';
|
||||||
|
}
|
||||||
|
|
||||||
export const textAdaptGptResponse = ({
|
export const textAdaptGptResponse = ({
|
||||||
text,
|
text,
|
||||||
model = '',
|
model = '',
|
||||||
|
|||||||
@@ -75,10 +75,17 @@ export const Input_Template_Text_Quote: FlowNodeInputItemType = {
|
|||||||
description: i18nT('app:document_quote_tip'),
|
description: i18nT('app:document_quote_tip'),
|
||||||
valueType: WorkflowIOValueTypeEnum.string
|
valueType: WorkflowIOValueTypeEnum.string
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const Input_Template_File_Link_Prompt: FlowNodeInputItemType = {
|
||||||
|
key: NodeInputKeyEnum.fileUrlList,
|
||||||
|
renderTypeList: [FlowNodeInputTypeEnum.reference, FlowNodeInputTypeEnum.input],
|
||||||
|
label: i18nT('app:file_quote_link'),
|
||||||
|
debugLabel: i18nT('app:file_quote_link'),
|
||||||
|
valueType: WorkflowIOValueTypeEnum.arrayString
|
||||||
|
};
|
||||||
export const Input_Template_File_Link: FlowNodeInputItemType = {
|
export const Input_Template_File_Link: FlowNodeInputItemType = {
|
||||||
key: NodeInputKeyEnum.fileUrlList,
|
key: NodeInputKeyEnum.fileUrlList,
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
||||||
required: true,
|
|
||||||
label: i18nT('app:workflow.user_file_input'),
|
label: i18nT('app:workflow.user_file_input'),
|
||||||
debugLabel: i18nT('app:workflow.user_file_input'),
|
debugLabel: i18nT('app:workflow.user_file_input'),
|
||||||
description: i18nT('app:workflow.user_file_input_desc'),
|
description: i18nT('app:workflow.user_file_input_desc'),
|
||||||
@@ -104,7 +111,7 @@ export const Input_Template_Node_Height: FlowNodeInputItemType = {
|
|||||||
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
||||||
valueType: WorkflowIOValueTypeEnum.number,
|
valueType: WorkflowIOValueTypeEnum.number,
|
||||||
label: '',
|
label: '',
|
||||||
value: 900
|
value: 600
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Input_Template_Stream_MODE: FlowNodeInputItemType = {
|
export const Input_Template_Stream_MODE: FlowNodeInputItemType = {
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ import {
|
|||||||
Input_Template_History,
|
Input_Template_History,
|
||||||
Input_Template_System_Prompt,
|
Input_Template_System_Prompt,
|
||||||
Input_Template_UserChatInput,
|
Input_Template_UserChatInput,
|
||||||
Input_Template_Text_Quote
|
Input_Template_Text_Quote,
|
||||||
|
Input_Template_File_Link_Prompt
|
||||||
} from '../../input';
|
} from '../../input';
|
||||||
import { chatNodeSystemPromptTip, systemPromptTip } from '../../tip';
|
import { chatNodeSystemPromptTip, systemPromptTip } from '../../tip';
|
||||||
import { getHandleConfig } from '../../utils';
|
import { getHandleConfig } from '../../utils';
|
||||||
@@ -55,7 +56,7 @@ export const AiChatModule: FlowNodeTemplateType = {
|
|||||||
showStatus: true,
|
showStatus: true,
|
||||||
isTool: true,
|
isTool: true,
|
||||||
courseUrl: '/docs/workflow/modules/ai_chat/',
|
courseUrl: '/docs/workflow/modules/ai_chat/',
|
||||||
version: '481',
|
version: '4813',
|
||||||
inputs: [
|
inputs: [
|
||||||
Input_Template_SettingAiModel,
|
Input_Template_SettingAiModel,
|
||||||
// --- settings modal
|
// --- settings modal
|
||||||
@@ -89,7 +90,7 @@ export const AiChatModule: FlowNodeTemplateType = {
|
|||||||
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
||||||
label: '',
|
label: '',
|
||||||
valueType: WorkflowIOValueTypeEnum.boolean,
|
valueType: WorkflowIOValueTypeEnum.boolean,
|
||||||
value: false
|
value: true
|
||||||
},
|
},
|
||||||
// settings modal ---
|
// settings modal ---
|
||||||
{
|
{
|
||||||
@@ -100,7 +101,7 @@ export const AiChatModule: FlowNodeTemplateType = {
|
|||||||
},
|
},
|
||||||
Input_Template_History,
|
Input_Template_History,
|
||||||
Input_Template_Dataset_Quote,
|
Input_Template_Dataset_Quote,
|
||||||
Input_Template_Text_Quote,
|
Input_Template_File_Link_Prompt,
|
||||||
|
|
||||||
{ ...Input_Template_UserChatInput, toolDescription: i18nT('workflow:user_question') }
|
{ ...Input_Template_UserChatInput, toolDescription: i18nT('workflow:user_question') }
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export const getOneQuoteInputTemplate = ({
|
|||||||
}): FlowNodeInputItemType => ({
|
}): FlowNodeInputItemType => ({
|
||||||
key,
|
key,
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
||||||
label: `${i18nT('workflow:quote_num')},{ num: ${index} }`,
|
label: `${i18nT('workflow:quote_num')}-${index}`,
|
||||||
debugLabel: i18nT('workflow:knowledge_base_reference'),
|
debugLabel: i18nT('workflow:knowledge_base_reference'),
|
||||||
canEdit: true,
|
canEdit: true,
|
||||||
valueType: WorkflowIOValueTypeEnum.datasetQuote
|
valueType: WorkflowIOValueTypeEnum.datasetQuote
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { ReferenceValueProps } from 'core/workflow/type/io';
|
import { ReferenceItemValueType } from '../../../type/io';
|
||||||
import { VariableConditionEnum } from './constant';
|
import { VariableConditionEnum } from './constant';
|
||||||
|
|
||||||
export type IfElseConditionType = 'AND' | 'OR';
|
export type IfElseConditionType = 'AND' | 'OR';
|
||||||
export type ConditionListItemType = {
|
export type ConditionListItemType = {
|
||||||
variable?: ReferenceValueProps;
|
variable?: ReferenceItemValueType;
|
||||||
condition?: VariableConditionEnum;
|
condition?: VariableConditionEnum;
|
||||||
value?: string;
|
value?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../../node/constant';
|
import {
|
||||||
|
FlowNodeInputTypeEnum,
|
||||||
|
FlowNodeOutputTypeEnum,
|
||||||
|
FlowNodeTypeEnum
|
||||||
|
} from '../../../node/constant';
|
||||||
import { FlowNodeTemplateType } from '../../../type/node.d';
|
import { FlowNodeTemplateType } from '../../../type/node.d';
|
||||||
import {
|
import {
|
||||||
FlowNodeTemplateTypeEnum,
|
FlowNodeTemplateTypeEnum,
|
||||||
NodeInputKeyEnum,
|
NodeInputKeyEnum,
|
||||||
|
NodeOutputKeyEnum,
|
||||||
WorkflowIOValueTypeEnum
|
WorkflowIOValueTypeEnum
|
||||||
} from '../../../constants';
|
} from '../../../constants';
|
||||||
import { getHandleConfig } from '../../utils';
|
import { getHandleConfig } from '../../utils';
|
||||||
@@ -28,7 +33,21 @@ export const LoopStartNode: FlowNodeTemplateType = {
|
|||||||
label: '',
|
label: '',
|
||||||
required: true,
|
required: true,
|
||||||
value: ''
|
value: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: NodeInputKeyEnum.loopStartIndex,
|
||||||
|
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
||||||
|
valueType: WorkflowIOValueTypeEnum.number,
|
||||||
|
label: i18nT('workflow:Array_element_index')
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
outputs: []
|
outputs: [
|
||||||
|
{
|
||||||
|
id: NodeOutputKeyEnum.loopStartIndex,
|
||||||
|
key: NodeOutputKeyEnum.loopStartIndex,
|
||||||
|
label: i18nT('workflow:Array_element_index'),
|
||||||
|
type: FlowNodeOutputTypeEnum.static,
|
||||||
|
valueType: WorkflowIOValueTypeEnum.number
|
||||||
|
}
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export const ReadFilesNode: FlowNodeTemplateType = {
|
|||||||
name: i18nT('app:workflow.read_files'),
|
name: i18nT('app:workflow.read_files'),
|
||||||
intro: i18nT('app:workflow.read_files_tip'),
|
intro: i18nT('app:workflow.read_files_tip'),
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
version: '489',
|
version: '4812',
|
||||||
isTool: true,
|
isTool: true,
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,17 +24,8 @@ export const TextEditorNode: FlowNodeTemplateType = {
|
|||||||
name: i18nT('workflow:text_concatenation'),
|
name: i18nT('workflow:text_concatenation'),
|
||||||
intro: i18nT('workflow:intro_text_concatenation'),
|
intro: i18nT('workflow:intro_text_concatenation'),
|
||||||
courseUrl: '/docs/workflow/modules/text_editor/',
|
courseUrl: '/docs/workflow/modules/text_editor/',
|
||||||
version: '486',
|
version: '4813',
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
|
||||||
...Input_Template_DynamicInput,
|
|
||||||
description: i18nT('workflow:dynamic_input_description_concat'),
|
|
||||||
customInputConfig: {
|
|
||||||
selectValueTypeList: Object.values(WorkflowIOValueTypeEnum),
|
|
||||||
showDescription: false,
|
|
||||||
showDefaultValue: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: NodeInputKeyEnum.textareaInput,
|
key: NodeInputKeyEnum.textareaInput,
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.textarea],
|
renderTypeList: [FlowNodeInputTypeEnum.textarea],
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { chatNodeSystemPromptTip, systemPromptTip } from '../tip';
|
|||||||
import { LLMModelTypeEnum } from '../../../ai/constants';
|
import { LLMModelTypeEnum } from '../../../ai/constants';
|
||||||
import { getHandleConfig } from '../utils';
|
import { getHandleConfig } from '../utils';
|
||||||
import { i18nT } from '../../../../../web/i18n/utils';
|
import { i18nT } from '../../../../../web/i18n/utils';
|
||||||
|
import { Input_Template_File_Link_Prompt } from '../input';
|
||||||
|
|
||||||
export const ToolModule: FlowNodeTemplateType = {
|
export const ToolModule: FlowNodeTemplateType = {
|
||||||
id: FlowNodeTypeEnum.tools,
|
id: FlowNodeTypeEnum.tools,
|
||||||
@@ -32,7 +33,7 @@ export const ToolModule: FlowNodeTemplateType = {
|
|||||||
intro: i18nT('workflow:template.tool_call_intro'),
|
intro: i18nT('workflow:template.tool_call_intro'),
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
courseUrl: '/docs/workflow/modules/tool/',
|
courseUrl: '/docs/workflow/modules/tool/',
|
||||||
version: '481',
|
version: '4813',
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
...Input_Template_SettingAiModel,
|
...Input_Template_SettingAiModel,
|
||||||
@@ -67,6 +68,7 @@ export const ToolModule: FlowNodeTemplateType = {
|
|||||||
placeholder: chatNodeSystemPromptTip
|
placeholder: chatNodeSystemPromptTip
|
||||||
},
|
},
|
||||||
Input_Template_History,
|
Input_Template_History,
|
||||||
|
Input_Template_File_Link_Prompt,
|
||||||
Input_Template_UserChatInput
|
Input_Template_UserChatInput
|
||||||
],
|
],
|
||||||
outputs: [
|
outputs: [
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { FlowNodeInputTypeEnum } from '../../../node/constant';
|
import { FlowNodeInputTypeEnum } from '../../../node/constant';
|
||||||
import { ReferenceValueProps } from '../../..//type/io';
|
import { ReferenceItemValueType, ReferenceValueType } from '../../..//type/io';
|
||||||
import { WorkflowIOValueTypeEnum } from '../../../constants';
|
import { WorkflowIOValueTypeEnum } from '../../../constants';
|
||||||
|
|
||||||
export type TUpdateListItem = {
|
export type TUpdateListItem = {
|
||||||
variable?: ReferenceValueProps;
|
variable?: ReferenceItemValueType;
|
||||||
value: ReferenceValueProps;
|
value?: ReferenceValueType; // input: ['',value], reference: [nodeId,outputId]
|
||||||
valueType?: WorkflowIOValueTypeEnum;
|
valueType?: WorkflowIOValueTypeEnum;
|
||||||
renderType: FlowNodeInputTypeEnum.input | FlowNodeInputTypeEnum.reference;
|
renderType: FlowNodeInputTypeEnum.input | FlowNodeInputTypeEnum.reference;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,6 +43,3 @@ export const WorkflowStart: FlowNodeTemplateType = {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isWorkflowStartOutput = (key?: string) =>
|
|
||||||
!!WorkflowStart.outputs.find((output) => output.key === key);
|
|
||||||
|
|||||||
9
packages/global/core/workflow/type/io.d.ts
vendored
@@ -56,6 +56,11 @@ export type FlowNodeInputItemType = InputComponentPropsType & {
|
|||||||
canEdit?: boolean; // dynamic inputs
|
canEdit?: boolean; // dynamic inputs
|
||||||
isPro?: boolean; // Pro version field
|
isPro?: boolean; // Pro version field
|
||||||
isToolOutput?: boolean;
|
isToolOutput?: boolean;
|
||||||
|
|
||||||
|
// file
|
||||||
|
canSelectFile?: boolean;
|
||||||
|
canSelectImg?: boolean;
|
||||||
|
maxFiles?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FlowNodeOutputItemType = {
|
export type FlowNodeOutputItemType = {
|
||||||
@@ -75,4 +80,6 @@ export type FlowNodeOutputItemType = {
|
|||||||
customFieldConfig?: CustomFieldConfigType;
|
customFieldConfig?: CustomFieldConfigType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ReferenceValueProps = [string, string | undefined];
|
export type ReferenceItemValueType = [string, string | undefined];
|
||||||
|
export type ReferenceArrayValueType = ReferenceItemValueType[];
|
||||||
|
export type ReferenceValueType = ReferenceItemValueType | ReferenceArrayValueType;
|
||||||
|
|||||||
@@ -12,7 +12,12 @@ import {
|
|||||||
VARIABLE_NODE_ID,
|
VARIABLE_NODE_ID,
|
||||||
NodeOutputKeyEnum
|
NodeOutputKeyEnum
|
||||||
} from './constants';
|
} from './constants';
|
||||||
import { FlowNodeInputItemType, FlowNodeOutputItemType, ReferenceValueProps } from './type/io.d';
|
import {
|
||||||
|
FlowNodeInputItemType,
|
||||||
|
FlowNodeOutputItemType,
|
||||||
|
ReferenceArrayValueType,
|
||||||
|
ReferenceItemValueType
|
||||||
|
} from './type/io.d';
|
||||||
import { StoreNodeItemType } from './type/node';
|
import { StoreNodeItemType } from './type/node';
|
||||||
import type {
|
import type {
|
||||||
VariableItemType,
|
VariableItemType,
|
||||||
@@ -30,8 +35,8 @@ import {
|
|||||||
} from '../app/constants';
|
} from '../app/constants';
|
||||||
import { IfElseResultEnum } from './template/system/ifElse/constant';
|
import { IfElseResultEnum } from './template/system/ifElse/constant';
|
||||||
import { RuntimeNodeItemType } from './runtime/type';
|
import { RuntimeNodeItemType } from './runtime/type';
|
||||||
import { getReferenceVariableValue } from './runtime/utils';
|
|
||||||
import {
|
import {
|
||||||
|
Input_Template_File_Link,
|
||||||
Input_Template_History,
|
Input_Template_History,
|
||||||
Input_Template_Stream_MODE,
|
Input_Template_Stream_MODE,
|
||||||
Input_Template_UserChatInput
|
Input_Template_UserChatInput
|
||||||
@@ -261,8 +266,10 @@ export const appData2FlowNodeIO = ({
|
|||||||
inputs: [
|
inputs: [
|
||||||
Input_Template_Stream_MODE,
|
Input_Template_Stream_MODE,
|
||||||
Input_Template_History,
|
Input_Template_History,
|
||||||
|
...(chatConfig?.fileSelectConfig?.canSelectFile || chatConfig?.fileSelectConfig?.canSelectImg
|
||||||
|
? [Input_Template_File_Link]
|
||||||
|
: []),
|
||||||
Input_Template_UserChatInput,
|
Input_Template_UserChatInput,
|
||||||
// ...(showFileLink ? [Input_Template_File_Link] : []),
|
|
||||||
...variableInput
|
...variableInput
|
||||||
],
|
],
|
||||||
outputs: [
|
outputs: [
|
||||||
@@ -298,9 +305,37 @@ export const formatEditorVariablePickerIcon = (
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isReferenceValue = (value: any, nodeIds: string[]): boolean => {
|
// Check the value is a valid reference value format: [variableId, outputId]
|
||||||
const validIdList = [VARIABLE_NODE_ID, ...nodeIds];
|
export const isValidReferenceValueFormat = (value: any): value is ReferenceItemValueType => {
|
||||||
return Array.isArray(value) && value.length === 2 && validIdList.includes(value[0]);
|
return Array.isArray(value) && value.length === 2 && typeof value[0] === 'string';
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
Check whether the value([variableId, outputId]) value is a valid reference value:
|
||||||
|
1. The value must be an array of length 2
|
||||||
|
2. The first item of the array must be one of VARIABLE_NODE_ID or nodeIds
|
||||||
|
*/
|
||||||
|
export const isValidReferenceValue = (
|
||||||
|
value: any,
|
||||||
|
nodeIds: string[]
|
||||||
|
): value is ReferenceItemValueType => {
|
||||||
|
if (!isValidReferenceValueFormat(value)) return false;
|
||||||
|
|
||||||
|
const validIdSet = new Set([VARIABLE_NODE_ID, ...nodeIds]);
|
||||||
|
return validIdSet.has(value[0]);
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
Check whether the value([variableId, outputId][]) value is a valid reference value array:
|
||||||
|
1. The value must be an array
|
||||||
|
2. The array must contain at least one element
|
||||||
|
3. Each element in the array must be a valid reference value
|
||||||
|
*/
|
||||||
|
export const isValidArrayReferenceValue = (
|
||||||
|
value: any,
|
||||||
|
nodeIds: string[]
|
||||||
|
): value is ReferenceArrayValueType => {
|
||||||
|
if (!Array.isArray(value)) return false;
|
||||||
|
|
||||||
|
return value.every((item) => isValidReferenceValue(item, nodeIds));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getElseIFLabel = (i: number) => {
|
export const getElseIFLabel = (i: number) => {
|
||||||
@@ -342,79 +377,6 @@ export const updatePluginInputByVariables = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// replace {{$xx.xx$}} variables for text
|
|
||||||
export function replaceEditorVariable({
|
|
||||||
text,
|
|
||||||
nodes,
|
|
||||||
variables,
|
|
||||||
runningNode
|
|
||||||
}: {
|
|
||||||
text: any;
|
|
||||||
nodes: RuntimeNodeItemType[];
|
|
||||||
variables: Record<string, any>; // global variables
|
|
||||||
runningNode: RuntimeNodeItemType;
|
|
||||||
}) {
|
|
||||||
if (typeof text !== 'string') return text;
|
|
||||||
|
|
||||||
const globalVariables = Object.keys(variables).map((key) => {
|
|
||||||
return {
|
|
||||||
nodeId: VARIABLE_NODE_ID,
|
|
||||||
id: key,
|
|
||||||
value: variables[key]
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Upstream node outputs
|
|
||||||
const nodeVariables = nodes
|
|
||||||
.map((node) => {
|
|
||||||
return node.outputs.map((output) => {
|
|
||||||
return {
|
|
||||||
nodeId: node.nodeId,
|
|
||||||
id: output.id,
|
|
||||||
value: output.value
|
|
||||||
};
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.flat();
|
|
||||||
|
|
||||||
// Get runningNode inputs(Will be replaced with reference)
|
|
||||||
const customInputs = runningNode.inputs.flatMap((item) => {
|
|
||||||
if (Array.isArray(item.value)) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
id: item.key,
|
|
||||||
value: getReferenceVariableValue({
|
|
||||||
value: item.value as ReferenceValueProps,
|
|
||||||
nodes,
|
|
||||||
variables
|
|
||||||
}),
|
|
||||||
nodeId: runningNode.nodeId
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
id: item.key,
|
|
||||||
value: item.value,
|
|
||||||
nodeId: runningNode.nodeId
|
|
||||||
}
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
const allVariables = [...globalVariables, ...nodeVariables, ...customInputs];
|
|
||||||
|
|
||||||
// Replace {{$xxx.xxx$}} to value
|
|
||||||
for (const key in allVariables) {
|
|
||||||
const variable = allVariables[key];
|
|
||||||
const val = variable.value;
|
|
||||||
const formatVal = typeof val === 'object' ? JSON.stringify(val) : String(val);
|
|
||||||
|
|
||||||
const regex = new RegExp(`\\{\\{\\$(${variable.nodeId}\\.${variable.id})\\$\\}\\}`, 'g');
|
|
||||||
text = text.replace(regex, formatVal);
|
|
||||||
}
|
|
||||||
return text || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get plugin runtime input user query */
|
/* Get plugin runtime input user query */
|
||||||
export const getPluginRunUserQuery = ({
|
export const getPluginRunUserQuery = ({
|
||||||
pluginInputs,
|
pluginInputs,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import type { ReadFileResponse } from '../../../worker/readFile/type';
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { addLog } from '../../system/log';
|
import { addLog } from '../../system/log';
|
||||||
import { batchRun } from '@fastgpt/global/common/fn/utils';
|
import { batchRun } from '@fastgpt/global/common/fn/utils';
|
||||||
|
import { addHours } from 'date-fns';
|
||||||
|
|
||||||
export type readRawTextByLocalFileParams = {
|
export type readRawTextByLocalFileParams = {
|
||||||
teamId: string;
|
teamId: string;
|
||||||
@@ -111,6 +112,7 @@ export const readRawContentByFileBuffer = async ({
|
|||||||
type: MongoImageTypeEnum.collectionImage,
|
type: MongoImageTypeEnum.collectionImage,
|
||||||
base64Img: `data:${item.mime};base64,${item.base64}`,
|
base64Img: `data:${item.mime};base64,${item.base64}`,
|
||||||
teamId,
|
teamId,
|
||||||
|
expiredTime: addHours(new Date(), 1),
|
||||||
metadata: {
|
metadata: {
|
||||||
...metadata,
|
...metadata,
|
||||||
mime: item.mime
|
mime: item.mime
|
||||||
|
|||||||
@@ -7,14 +7,20 @@ import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
|||||||
1. Commercial plugin: n points per times
|
1. Commercial plugin: n points per times
|
||||||
2. Other plugin: sum of children points
|
2. Other plugin: sum of children points
|
||||||
*/
|
*/
|
||||||
export const computedPluginUsage = async (
|
export const computedPluginUsage = async ({
|
||||||
plugin: PluginRuntimeType,
|
plugin,
|
||||||
childrenUsage: ChatNodeUsageType[]
|
childrenUsage,
|
||||||
) => {
|
error
|
||||||
|
}: {
|
||||||
|
plugin: PluginRuntimeType;
|
||||||
|
childrenUsage: ChatNodeUsageType[];
|
||||||
|
error?: boolean;
|
||||||
|
}) => {
|
||||||
const { source } = await splitCombinePluginId(plugin.id);
|
const { source } = await splitCombinePluginId(plugin.id);
|
||||||
|
|
||||||
// Commercial plugin: n points per times
|
// Commercial plugin: n points per times
|
||||||
if (source === PluginSourceEnum.commercial) {
|
if (source === PluginSourceEnum.commercial) {
|
||||||
|
if (error) return 0;
|
||||||
return plugin.currentCost ?? 0;
|
return plugin.currentCost ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
155
packages/service/core/chat/pushChatLog.ts
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
import { addLog } from '../../common/system/log';
|
||||||
|
import { MongoChatItem } from './chatItemSchema';
|
||||||
|
import { MongoChat } from './chatSchema';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { AIChatItemType, ChatItemType } from '@fastgpt/global/core/chat/type';
|
||||||
|
|
||||||
|
export type Metadata = {
|
||||||
|
[key: string]: {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const pushChatLog = ({
|
||||||
|
chatId,
|
||||||
|
chatItemIdHuman,
|
||||||
|
chatItemIdAi,
|
||||||
|
appId,
|
||||||
|
metadata
|
||||||
|
}: {
|
||||||
|
chatId: string;
|
||||||
|
chatItemIdHuman: string;
|
||||||
|
chatItemIdAi: string;
|
||||||
|
appId: string;
|
||||||
|
metadata?: Metadata;
|
||||||
|
}) => {
|
||||||
|
const interval = Number(process.env.CHAT_LOG_INTERVAL);
|
||||||
|
const url = process.env.CHAT_LOG_URL;
|
||||||
|
if (interval > 0 && url) {
|
||||||
|
addLog.info(`[ChatLogPush] push chat log after ${interval}ms`, {
|
||||||
|
appId,
|
||||||
|
chatItemIdHuman,
|
||||||
|
chatItemIdAi
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
pushChatLogInternal({ chatId, chatItemIdHuman, chatItemIdAi, appId, url, metadata });
|
||||||
|
}, interval);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
type ChatItem = ChatItemType & {
|
||||||
|
userGoodFeedback?: string;
|
||||||
|
userBadFeedback?: string;
|
||||||
|
chatId: string;
|
||||||
|
responseData: {
|
||||||
|
moduleType: string;
|
||||||
|
runningTime: number; //s
|
||||||
|
historyPreview: { obj: string; value: string }[];
|
||||||
|
}[];
|
||||||
|
time: Date;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ChatLog = {
|
||||||
|
title: string;
|
||||||
|
feedback: 'like' | 'dislike' | null;
|
||||||
|
chatItemId: string;
|
||||||
|
uid: string;
|
||||||
|
question: string;
|
||||||
|
answer: string;
|
||||||
|
chatId: string;
|
||||||
|
responseTime: number;
|
||||||
|
metadata: string;
|
||||||
|
sourceName: string;
|
||||||
|
createdAt: number;
|
||||||
|
sourceId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const pushChatLogInternal = async ({
|
||||||
|
chatId,
|
||||||
|
chatItemIdHuman,
|
||||||
|
chatItemIdAi,
|
||||||
|
appId,
|
||||||
|
url,
|
||||||
|
metadata
|
||||||
|
}: {
|
||||||
|
chatId: string;
|
||||||
|
chatItemIdHuman: string;
|
||||||
|
chatItemIdAi: string;
|
||||||
|
appId: string;
|
||||||
|
url: string;
|
||||||
|
metadata?: Metadata;
|
||||||
|
}) => {
|
||||||
|
try {
|
||||||
|
const [chatItemHuman, chatItemAi] = await Promise.all([
|
||||||
|
MongoChatItem.findById(chatItemIdHuman).lean(),
|
||||||
|
MongoChatItem.findById(chatItemIdAi).lean() as Promise<AIChatItemType>
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!chatItemHuman || !chatItemAi) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const chat = await MongoChat.findOne({ chatId }).lean();
|
||||||
|
|
||||||
|
// addLog.warn('ChatLogDebug', chat);
|
||||||
|
// addLog.warn('ChatLogDebug', { chatItemHuman, chatItemAi });
|
||||||
|
|
||||||
|
if (!chat) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const metadataString = JSON.stringify(metadata ?? {});
|
||||||
|
|
||||||
|
const uid = chat.outLinkUid || chat.tmbId;
|
||||||
|
// Pop last two items
|
||||||
|
const question = chatItemHuman.value[chatItemHuman.value.length - 1]?.text?.content;
|
||||||
|
const answer = chatItemAi.value[chatItemAi.value.length - 1]?.text?.content;
|
||||||
|
if (!question || !answer) {
|
||||||
|
addLog.error('[ChatLogPush] question or answer is empty', {
|
||||||
|
question: chatItemHuman.value,
|
||||||
|
answer: chatItemAi.value
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const responseData = chatItemAi.responseData;
|
||||||
|
const responseTime =
|
||||||
|
responseData?.reduce((acc, item) => acc + (item?.runningTime ?? 0), 0) || 0;
|
||||||
|
|
||||||
|
const sourceIdPrefix = process.env.SOURCE_ID_PREFIX ?? '';
|
||||||
|
|
||||||
|
const chatLog: ChatLog = {
|
||||||
|
title: chat.title,
|
||||||
|
feedback: (() => {
|
||||||
|
if (chatItemAi.userGoodFeedback) {
|
||||||
|
return 'like';
|
||||||
|
} else if (chatItemAi.userBadFeedback) {
|
||||||
|
return 'dislike';
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})(),
|
||||||
|
chatItemId: `${chatItemIdHuman},${chatItemIdAi}`,
|
||||||
|
uid,
|
||||||
|
question,
|
||||||
|
answer,
|
||||||
|
chatId,
|
||||||
|
responseTime: responseTime * 1000,
|
||||||
|
metadata: metadataString,
|
||||||
|
sourceName: chat.source ?? '-',
|
||||||
|
// @ts-ignore
|
||||||
|
createdAt: new Date(chatItemAi.time).getTime(),
|
||||||
|
sourceId: `${sourceIdPrefix}${appId}`
|
||||||
|
};
|
||||||
|
await axios
|
||||||
|
.post(`${url}/api/chat/push`, chatLog)
|
||||||
|
.then((res) => {
|
||||||
|
addLog.info('[ChatLogPush] push success', res.data);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
addLog.error('[ChatLogPush] push failed', { e, resData: e.response?.data });
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
addLog.error('[ChatLogPush] error', e);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,4 +1,9 @@
|
|||||||
import type { AIChatItemType, UserChatItemType } from '@fastgpt/global/core/chat/type.d';
|
import type {
|
||||||
|
AIChatItemType,
|
||||||
|
ChatItemType,
|
||||||
|
UserChatItemType
|
||||||
|
} from '@fastgpt/global/core/chat/type.d';
|
||||||
|
import axios from 'axios';
|
||||||
import { MongoApp } from '../app/schema';
|
import { MongoApp } from '../app/schema';
|
||||||
import {
|
import {
|
||||||
ChatItemValueTypeEnum,
|
ChatItemValueTypeEnum,
|
||||||
@@ -13,6 +18,7 @@ import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
|||||||
import { getAppChatConfig, getGuideModule } from '@fastgpt/global/core/workflow/utils';
|
import { getAppChatConfig, getGuideModule } from '@fastgpt/global/core/workflow/utils';
|
||||||
import { AppChatConfigType } from '@fastgpt/global/core/app/type';
|
import { AppChatConfigType } from '@fastgpt/global/core/app/type';
|
||||||
import { mergeChatResponseData } from '@fastgpt/global/core/chat/utils';
|
import { mergeChatResponseData } from '@fastgpt/global/core/chat/utils';
|
||||||
|
import { pushChatLog } from './pushChatLog';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
@@ -67,7 +73,7 @@ export async function saveChat({
|
|||||||
});
|
});
|
||||||
|
|
||||||
await mongoSessionRun(async (session) => {
|
await mongoSessionRun(async (session) => {
|
||||||
await MongoChatItem.insertMany(
|
const [{ _id: chatItemIdHuman }, { _id: chatItemIdAi }] = await MongoChatItem.insertMany(
|
||||||
content.map((item) => ({
|
content.map((item) => ({
|
||||||
chatId,
|
chatId,
|
||||||
teamId,
|
teamId,
|
||||||
@@ -105,6 +111,13 @@ export async function saveChat({
|
|||||||
upsert: true
|
upsert: true
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
pushChatLog({
|
||||||
|
chatId,
|
||||||
|
chatItemIdHuman: String(chatItemIdHuman),
|
||||||
|
chatItemIdAi: String(chatItemIdAi),
|
||||||
|
appId
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isUpdateUseTime) {
|
if (isUpdateUseTime) {
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ export const loadRequestMessages = async ({
|
|||||||
}
|
}
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
messages.map(async (item) => {
|
messages.map(async (item) => {
|
||||||
if (item.type === 'image_url') {
|
if (item.type === 'image_url' && process.env.MULTIPLE_DATA_TO_BASE64 === 'true') {
|
||||||
// Remove url origin
|
// Remove url origin
|
||||||
const imgUrl = (() => {
|
const imgUrl = (() => {
|
||||||
if (origin && item.image_url.url.startsWith(origin)) {
|
if (origin && item.image_url.url.startsWith(origin)) {
|
||||||
@@ -118,38 +118,51 @@ export const loadRequestMessages = async ({
|
|||||||
return item.image_url.url;
|
return item.image_url.url;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// If imgUrl is a local path, load image from local, and set url to base64
|
try {
|
||||||
if (imgUrl.startsWith('/')) {
|
// If imgUrl is a local path, load image from local, and set url to base64
|
||||||
addLog.debug('Load image from local server', {
|
if (imgUrl.startsWith('/')) {
|
||||||
baseUrl: serverRequestBaseUrl,
|
addLog.debug('Load image from local server', {
|
||||||
requestUrl: imgUrl
|
baseUrl: serverRequestBaseUrl,
|
||||||
});
|
requestUrl: imgUrl
|
||||||
const response = await axios.get(imgUrl, {
|
});
|
||||||
baseURL: serverRequestBaseUrl,
|
const response = await axios.get(imgUrl, {
|
||||||
responseType: 'arraybuffer',
|
baseURL: serverRequestBaseUrl,
|
||||||
proxy: false
|
responseType: 'arraybuffer',
|
||||||
});
|
proxy: false
|
||||||
const base64 = Buffer.from(response.data, 'binary').toString('base64');
|
});
|
||||||
const imageType =
|
const base64 = Buffer.from(response.data, 'binary').toString('base64');
|
||||||
getFileContentTypeFromHeader(response.headers['content-type']) ||
|
const imageType =
|
||||||
guessBase64ImageType(base64);
|
getFileContentTypeFromHeader(response.headers['content-type']) ||
|
||||||
|
guessBase64ImageType(base64);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
image_url: {
|
image_url: {
|
||||||
...item.image_url,
|
...item.image_url,
|
||||||
url: `data:${imageType};base64,${base64}`
|
url: `data:${imageType};base64,${base64}`
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查下这个图片是否可以被访问,如果不行的话,则过滤掉
|
||||||
|
const response = await axios.head(imgUrl, {
|
||||||
|
timeout: 10000
|
||||||
|
});
|
||||||
|
if (response.status < 200 || response.status >= 400) {
|
||||||
|
addLog.info(`Filter invalid image: ${imgUrl}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
})
|
})
|
||||||
);
|
).then((res) => res.filter(Boolean) as ChatCompletionContentPart[]);
|
||||||
};
|
};
|
||||||
// Split question text and image
|
// Split question text and image
|
||||||
const parseStringWithImages = (input: string): ChatCompletionContentPart[] => {
|
const parseStringWithImages = (input: string): ChatCompletionContentPart[] => {
|
||||||
if (!useVision) {
|
if (!useVision || input.length > 500) {
|
||||||
return [{ type: 'text', text: input || '' }];
|
return [{ type: 'text', text: input || '' }];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,8 +183,8 @@ export const loadRequestMessages = async ({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Too many images or too long text, return text
|
// Too many images return text
|
||||||
if (httpsImages.length > 4 || input.length > 1000) {
|
if (httpsImages.length > 4) {
|
||||||
return [{ type: 'text', text: input || '' }];
|
return [{ type: 'text', text: input || '' }];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +192,7 @@ export const loadRequestMessages = async ({
|
|||||||
result.push({ type: 'text', text: input });
|
result.push({ type: 'text', text: input });
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
// Parse user content(text and img)
|
// Parse user content(text and img) Store history => api messages
|
||||||
const parseUserContent = async (content: string | ChatCompletionContentPart[]) => {
|
const parseUserContent = async (content: string | ChatCompletionContentPart[]) => {
|
||||||
if (typeof content === 'string') {
|
if (typeof content === 'string') {
|
||||||
return loadImageToBase64(parseStringWithImages(content));
|
return loadImageToBase64(parseStringWithImages(content));
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
DatasetDataWithCollectionType,
|
DatasetDataWithCollectionType,
|
||||||
SearchDataResponseItemType
|
SearchDataResponseItemType
|
||||||
} from '@fastgpt/global/core/dataset/type';
|
} from '@fastgpt/global/core/dataset/type';
|
||||||
import { DatasetColCollectionName, MongoDatasetCollection } from '../collection/schema';
|
import { MongoDatasetCollection } from '../collection/schema';
|
||||||
import { reRankRecall } from '../../../core/ai/rerank';
|
import { reRankRecall } from '../../../core/ai/rerank';
|
||||||
import { countPromptTokens } from '../../../common/string/tiktoken/index';
|
import { countPromptTokens } from '../../../common/string/tiktoken/index';
|
||||||
import { datasetSearchResultConcat } from '@fastgpt/global/core/dataset/search/utils';
|
import { datasetSearchResultConcat } from '@fastgpt/global/core/dataset/search/utils';
|
||||||
@@ -320,11 +320,13 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
|||||||
const fullTextRecall = async ({
|
const fullTextRecall = async ({
|
||||||
query,
|
query,
|
||||||
limit,
|
limit,
|
||||||
filterCollectionIdList
|
filterCollectionIdList,
|
||||||
|
forbidCollectionIdList
|
||||||
}: {
|
}: {
|
||||||
query: string;
|
query: string;
|
||||||
limit: number;
|
limit: number;
|
||||||
filterCollectionIdList?: string[];
|
filterCollectionIdList?: string[];
|
||||||
|
forbidCollectionIdList: string[];
|
||||||
}): Promise<{
|
}): Promise<{
|
||||||
fullTextRecallResults: SearchDataResponseItemType[];
|
fullTextRecallResults: SearchDataResponseItemType[];
|
||||||
tokenLen: number;
|
tokenLen: number;
|
||||||
@@ -351,6 +353,13 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
|||||||
$in: filterCollectionIdList.map((id) => new Types.ObjectId(id))
|
$in: filterCollectionIdList.map((id) => new Types.ObjectId(id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
: {}),
|
||||||
|
...(forbidCollectionIdList && forbidCollectionIdList.length > 0
|
||||||
|
? {
|
||||||
|
collectionId: {
|
||||||
|
$nin: forbidCollectionIdList.map((id) => new Types.ObjectId(id))
|
||||||
|
}
|
||||||
|
}
|
||||||
: {})
|
: {})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -367,31 +376,6 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
|||||||
{
|
{
|
||||||
$limit: limit
|
$limit: limit
|
||||||
},
|
},
|
||||||
{
|
|
||||||
$lookup: {
|
|
||||||
from: DatasetColCollectionName,
|
|
||||||
let: { collectionId: '$collectionId' },
|
|
||||||
pipeline: [
|
|
||||||
{
|
|
||||||
$match: {
|
|
||||||
$expr: { $eq: ['$_id', '$$collectionId'] },
|
|
||||||
forbid: { $eq: true } // 匹配被禁用的数据
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$project: {
|
|
||||||
_id: 1 // 只需要_id字段来确认匹配
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
as: 'collection'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$match: {
|
|
||||||
collection: { $eq: [] } // 没有 forbid=true 的数据
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
$project: {
|
$project: {
|
||||||
_id: 1,
|
_id: 1,
|
||||||
@@ -509,7 +493,8 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
|||||||
fullTextRecall({
|
fullTextRecall({
|
||||||
query,
|
query,
|
||||||
limit: fullTextLimit,
|
limit: fullTextLimit,
|
||||||
filterCollectionIdList
|
filterCollectionIdList,
|
||||||
|
forbidCollectionIdList
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
totalTokens += tokens;
|
totalTokens += tokens;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import { computedMaxToken, llmCompletionsBodyFormat } from '../../../../ai/utils
|
|||||||
import { toolValueTypeList } from '@fastgpt/global/core/workflow/constants';
|
import { toolValueTypeList } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { WorkflowInteractiveResponseType } from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
import { WorkflowInteractiveResponseType } from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
||||||
import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
||||||
|
import { i18nT } from '../../../../../../web/i18n/utils';
|
||||||
|
|
||||||
type FunctionRunResponseType = {
|
type FunctionRunResponseType = {
|
||||||
toolRunResponse: DispatchFlowResponse;
|
toolRunResponse: DispatchFlowResponse;
|
||||||
@@ -549,7 +550,7 @@ async function streamResponse({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!textAnswer && functionCalls.length === 0) {
|
if (!textAnswer && functionCalls.length === 0) {
|
||||||
return Promise.reject('LLM api response empty');
|
return Promise.reject(i18nT('chat:LLM_model_response_empty'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return { answer: textAnswer, functionCalls };
|
return { answer: textAnswer, functionCalls };
|
||||||
|
|||||||
@@ -25,45 +25,16 @@ import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
|||||||
import { getMultiplePrompt, Prompt_Tool_Call } from './constants';
|
import { getMultiplePrompt, Prompt_Tool_Call } from './constants';
|
||||||
import { filterToolResponseToPreview } from './utils';
|
import { filterToolResponseToPreview } from './utils';
|
||||||
import { InteractiveNodeResponseType } from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
import { InteractiveNodeResponseType } from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
||||||
|
import { getFileContentFromLinks, getHistoryFileLinks } from '../../tools/readFiles';
|
||||||
|
import { parseUrlToFileType } from '@fastgpt/global/common/file/tools';
|
||||||
|
import { Prompt_DocumentQuote } from '@fastgpt/global/core/ai/prompt/AIChat';
|
||||||
|
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
|
|
||||||
type Response = DispatchNodeResultType<{
|
type Response = DispatchNodeResultType<{
|
||||||
[NodeOutputKeyEnum.answerText]: string;
|
[NodeOutputKeyEnum.answerText]: string;
|
||||||
[DispatchNodeResponseKeyEnum.interactive]?: InteractiveNodeResponseType;
|
[DispatchNodeResponseKeyEnum.interactive]?: InteractiveNodeResponseType;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
/*
|
|
||||||
Tool call, auth add file prompt to question。
|
|
||||||
Guide the LLM to call tool.
|
|
||||||
*/
|
|
||||||
export const toolCallMessagesAdapt = ({
|
|
||||||
userInput
|
|
||||||
}: {
|
|
||||||
userInput: UserChatItemValueItemType[];
|
|
||||||
}) => {
|
|
||||||
const files = userInput.filter((item) => item.type === 'file');
|
|
||||||
|
|
||||||
if (files.length > 0) {
|
|
||||||
return userInput.map((item) => {
|
|
||||||
if (item.type === 'text') {
|
|
||||||
const filesCount = files.filter((file) => file.file?.type === 'file').length;
|
|
||||||
const imgCount = files.filter((file) => file.file?.type === 'image').length;
|
|
||||||
const text = item.text?.content || '';
|
|
||||||
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
text: {
|
|
||||||
content: getMultiplePrompt({ fileCount: filesCount, imgCount, question: text })
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return userInput;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<Response> => {
|
export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<Response> => {
|
||||||
const {
|
const {
|
||||||
node: { nodeId, name, isEntry },
|
node: { nodeId, name, isEntry },
|
||||||
@@ -71,11 +42,21 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
|||||||
runtimeEdges,
|
runtimeEdges,
|
||||||
histories,
|
histories,
|
||||||
query,
|
query,
|
||||||
|
requestOrigin,
|
||||||
params: { model, systemPrompt, userChatInput, history = 6 }
|
chatConfig,
|
||||||
|
runningAppInfo: { teamId },
|
||||||
|
params: {
|
||||||
|
model,
|
||||||
|
systemPrompt,
|
||||||
|
userChatInput,
|
||||||
|
history = 6,
|
||||||
|
fileUrlList: fileLinks,
|
||||||
|
aiChatVision
|
||||||
|
}
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const toolModel = getLLMModel(model);
|
const toolModel = getLLMModel(model);
|
||||||
|
const useVision = aiChatVision && toolModel.vision;
|
||||||
const chatHistories = getHistories(history, histories);
|
const chatHistories = getHistories(history, histories);
|
||||||
|
|
||||||
const toolNodeIds = filterToolNodeIdByEdges({ nodeId, edges: runtimeEdges });
|
const toolNodeIds = filterToolNodeIdByEdges({ nodeId, edges: runtimeEdges });
|
||||||
@@ -109,18 +90,43 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
props.node.isEntry = false;
|
props.node.isEntry = false;
|
||||||
|
const hasReadFilesTool = toolNodes.some(
|
||||||
|
(item) => item.flowNodeType === FlowNodeTypeEnum.readFiles
|
||||||
|
);
|
||||||
|
|
||||||
|
const globalFiles = chatValue2RuntimePrompt(query).files;
|
||||||
|
const { documentQuoteText, userFiles } = await getMultiInput({
|
||||||
|
histories: chatHistories,
|
||||||
|
requestOrigin,
|
||||||
|
maxFiles: chatConfig?.fileSelectConfig?.maxFiles || 20,
|
||||||
|
teamId,
|
||||||
|
fileLinks,
|
||||||
|
inputFiles: globalFiles
|
||||||
|
});
|
||||||
|
|
||||||
|
const concatenateSystemPrompt = [
|
||||||
|
toolModel.defaultSystemChatPrompt,
|
||||||
|
systemPrompt,
|
||||||
|
documentQuoteText
|
||||||
|
? replaceVariable(Prompt_DocumentQuote, {
|
||||||
|
quote: documentQuoteText
|
||||||
|
})
|
||||||
|
: ''
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join('\n\n===---===---===\n\n');
|
||||||
|
|
||||||
const messages: ChatItemType[] = (() => {
|
const messages: ChatItemType[] = (() => {
|
||||||
const value: ChatItemType[] = [
|
const value: ChatItemType[] = [
|
||||||
...getSystemPrompt_ChatItemType(toolModel.defaultSystemChatPrompt),
|
...getSystemPrompt_ChatItemType(concatenateSystemPrompt),
|
||||||
...getSystemPrompt_ChatItemType(systemPrompt),
|
|
||||||
// Add file input prompt to histories
|
// Add file input prompt to histories
|
||||||
...chatHistories.map((item) => {
|
...chatHistories.map((item) => {
|
||||||
if (item.obj === ChatRoleEnum.Human) {
|
if (item.obj === ChatRoleEnum.Human) {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
value: toolCallMessagesAdapt({
|
value: toolCallMessagesAdapt({
|
||||||
userInput: item.value
|
userInput: item.value,
|
||||||
|
skip: !hasReadFilesTool
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -129,9 +135,10 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
|||||||
{
|
{
|
||||||
obj: ChatRoleEnum.Human,
|
obj: ChatRoleEnum.Human,
|
||||||
value: toolCallMessagesAdapt({
|
value: toolCallMessagesAdapt({
|
||||||
|
skip: !hasReadFilesTool,
|
||||||
userInput: runtimePrompt2ChatsValue({
|
userInput: runtimePrompt2ChatsValue({
|
||||||
text: userChatInput,
|
text: userChatInput,
|
||||||
files: chatValue2RuntimePrompt(query).files
|
files: userFiles
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -237,7 +244,11 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
|||||||
childTotalPoints: flatUsages.reduce((sum, item) => sum + item.totalPoints, 0),
|
childTotalPoints: flatUsages.reduce((sum, item) => sum + item.totalPoints, 0),
|
||||||
model: modelName,
|
model: modelName,
|
||||||
query: userChatInput,
|
query: userChatInput,
|
||||||
historyPreview: getHistoryPreview(GPTMessages2Chats(completeMessages, false), 10000),
|
historyPreview: getHistoryPreview(
|
||||||
|
GPTMessages2Chats(completeMessages, false),
|
||||||
|
10000,
|
||||||
|
useVision
|
||||||
|
),
|
||||||
toolDetail: childToolResponse,
|
toolDetail: childToolResponse,
|
||||||
mergeSignId: nodeId
|
mergeSignId: nodeId
|
||||||
},
|
},
|
||||||
@@ -253,3 +264,88 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
|||||||
[DispatchNodeResponseKeyEnum.interactive]: toolWorkflowInteractiveResponse
|
[DispatchNodeResponseKeyEnum.interactive]: toolWorkflowInteractiveResponse
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getMultiInput = async ({
|
||||||
|
histories,
|
||||||
|
fileLinks,
|
||||||
|
requestOrigin,
|
||||||
|
maxFiles,
|
||||||
|
teamId,
|
||||||
|
inputFiles
|
||||||
|
}: {
|
||||||
|
histories: ChatItemType[];
|
||||||
|
fileLinks?: string[];
|
||||||
|
requestOrigin?: string;
|
||||||
|
maxFiles: number;
|
||||||
|
teamId: string;
|
||||||
|
inputFiles: UserChatItemValueItemType['file'][];
|
||||||
|
}) => {
|
||||||
|
// Not file quote
|
||||||
|
if (!fileLinks) {
|
||||||
|
return {
|
||||||
|
documentQuoteText: '',
|
||||||
|
userFiles: inputFiles
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const filesFromHistories = getHistoryFileLinks(histories);
|
||||||
|
const urls = [...fileLinks, ...filesFromHistories];
|
||||||
|
|
||||||
|
if (urls.length === 0) {
|
||||||
|
return {
|
||||||
|
documentQuoteText: '',
|
||||||
|
userFiles: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get files from histories
|
||||||
|
const { text } = await getFileContentFromLinks({
|
||||||
|
// Concat fileUrlList and filesFromHistories; remove not supported files
|
||||||
|
urls,
|
||||||
|
requestOrigin,
|
||||||
|
maxFiles,
|
||||||
|
teamId
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
documentQuoteText: text,
|
||||||
|
userFiles: fileLinks.map((url) => parseUrlToFileType(url))
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Tool call, auth add file prompt to question。
|
||||||
|
Guide the LLM to call tool.
|
||||||
|
*/
|
||||||
|
const toolCallMessagesAdapt = ({
|
||||||
|
userInput,
|
||||||
|
skip
|
||||||
|
}: {
|
||||||
|
userInput: UserChatItemValueItemType[];
|
||||||
|
skip?: boolean;
|
||||||
|
}) => {
|
||||||
|
if (skip) return userInput;
|
||||||
|
|
||||||
|
const files = userInput.filter((item) => item.type === 'file');
|
||||||
|
|
||||||
|
if (files.length > 0) {
|
||||||
|
return userInput.map((item) => {
|
||||||
|
if (item.type === 'text') {
|
||||||
|
const filesCount = files.filter((file) => file.file?.type === 'file').length;
|
||||||
|
const imgCount = files.filter((file) => file.file?.type === 'image').length;
|
||||||
|
const text = item.text?.content || '';
|
||||||
|
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
text: {
|
||||||
|
content: getMultiplePrompt({ fileCount: filesCount, imgCount, question: text })
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return userInput;
|
||||||
|
};
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import { WorkflowResponseType } from '../../type';
|
|||||||
import { toolValueTypeList } from '@fastgpt/global/core/workflow/constants';
|
import { toolValueTypeList } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { WorkflowInteractiveResponseType } from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
import { WorkflowInteractiveResponseType } from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
||||||
import { ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants';
|
import { ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants';
|
||||||
|
import { i18nT } from '../../../../../../web/i18n/utils';
|
||||||
|
|
||||||
type FunctionCallCompletion = {
|
type FunctionCallCompletion = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -537,7 +538,7 @@ async function streamResponse({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!textAnswer) {
|
if (!textAnswer) {
|
||||||
return Promise.reject('LLM api response empty');
|
return Promise.reject(i18nT('chat:LLM_model_response_empty'));
|
||||||
}
|
}
|
||||||
return { answer: textAnswer.trim() };
|
return { answer: textAnswer.trim() };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import { addLog } from '../../../../../common/system/log';
|
|||||||
import { toolValueTypeList } from '@fastgpt/global/core/workflow/constants';
|
import { toolValueTypeList } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { WorkflowInteractiveResponseType } from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
import { WorkflowInteractiveResponseType } from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
||||||
import { ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants';
|
import { ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants';
|
||||||
|
import { i18nT } from '../../../../../../web/i18n/utils';
|
||||||
|
|
||||||
type ToolRunResponseType = {
|
type ToolRunResponseType = {
|
||||||
toolRunResponse: DispatchFlowResponse;
|
toolRunResponse: DispatchFlowResponse;
|
||||||
@@ -268,7 +269,7 @@ export const runToolWithToolChoice = async (
|
|||||||
},
|
},
|
||||||
toolModel
|
toolModel
|
||||||
);
|
);
|
||||||
// console.log(JSON.stringify(requestMessages, null, 2), '==requestBody');
|
// console.log(JSON.stringify(requestBody, null, 2), '==requestBody');
|
||||||
/* Run llm */
|
/* Run llm */
|
||||||
const ai = getAIApi({
|
const ai = getAIApi({
|
||||||
timeout: 480000
|
timeout: 480000
|
||||||
@@ -656,7 +657,7 @@ async function streamResponse({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!textAnswer && toolCalls.length === 0) {
|
if (!textAnswer && toolCalls.length === 0) {
|
||||||
return Promise.reject('LLM api response empty');
|
return Promise.reject(i18nT('chat:LLM_model_response_empty'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return { answer: textAnswer, toolCalls };
|
return { answer: textAnswer, toolCalls };
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export type DispatchToolModuleProps = ModuleDispatchProps<{
|
|||||||
[NodeInputKeyEnum.aiChatTemperature]: number;
|
[NodeInputKeyEnum.aiChatTemperature]: number;
|
||||||
[NodeInputKeyEnum.aiChatMaxToken]: number;
|
[NodeInputKeyEnum.aiChatMaxToken]: number;
|
||||||
[NodeInputKeyEnum.aiChatVision]?: boolean;
|
[NodeInputKeyEnum.aiChatVision]?: boolean;
|
||||||
|
[NodeInputKeyEnum.fileUrlList]?: string[];
|
||||||
}> & {
|
}> & {
|
||||||
messages: ChatCompletionMessageParam[];
|
messages: ChatCompletionMessageParam[];
|
||||||
toolNodes: ToolNodeItemType[];
|
toolNodes: ToolNodeItemType[];
|
||||||
|
|||||||
@@ -5,11 +5,7 @@ import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
|||||||
import { SseResponseEventEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
import { SseResponseEventEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
import { textAdaptGptResponse } from '@fastgpt/global/core/workflow/runtime/utils';
|
import { textAdaptGptResponse } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||||
import { getAIApi } from '../../../ai/config';
|
import { getAIApi } from '../../../ai/config';
|
||||||
import type {
|
import type { ChatCompletion, StreamChatType } from '@fastgpt/global/core/ai/type.d';
|
||||||
ChatCompletion,
|
|
||||||
ChatCompletionMessageParam,
|
|
||||||
StreamChatType
|
|
||||||
} from '@fastgpt/global/core/ai/type.d';
|
|
||||||
import { formatModelChars2Points } from '../../../../support/wallet/usage/utils';
|
import { formatModelChars2Points } from '../../../../support/wallet/usage/utils';
|
||||||
import type { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
|
import type { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
|
||||||
import { postTextCensor } from '../../../../common/api/requestPlusApi';
|
import { postTextCensor } from '../../../../common/api/requestPlusApi';
|
||||||
@@ -46,6 +42,9 @@ import { WorkflowResponseType } from '../type';
|
|||||||
import { formatTime2YMDHM } from '@fastgpt/global/common/string/time';
|
import { formatTime2YMDHM } from '@fastgpt/global/common/string/time';
|
||||||
import { AiChatQuoteRoleType } from '@fastgpt/global/core/workflow/template/system/aiChat/type';
|
import { AiChatQuoteRoleType } from '@fastgpt/global/core/workflow/template/system/aiChat/type';
|
||||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
|
import { getFileContentFromLinks, getHistoryFileLinks } from '../tools/readFiles';
|
||||||
|
import { parseUrlToFileType } from '@fastgpt/global/common/file/tools';
|
||||||
|
import { i18nT } from '../../../../../web/i18n/utils';
|
||||||
|
|
||||||
export type ChatProps = ModuleDispatchProps<
|
export type ChatProps = ModuleDispatchProps<
|
||||||
AIChatNodeProps & {
|
AIChatNodeProps & {
|
||||||
@@ -69,7 +68,9 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
|||||||
histories,
|
histories,
|
||||||
node: { name },
|
node: { name },
|
||||||
query,
|
query,
|
||||||
|
runningAppInfo: { teamId },
|
||||||
workflowStreamResponse,
|
workflowStreamResponse,
|
||||||
|
chatConfig,
|
||||||
params: {
|
params: {
|
||||||
model,
|
model,
|
||||||
temperature = 0,
|
temperature = 0,
|
||||||
@@ -83,14 +84,12 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
|||||||
quoteTemplate,
|
quoteTemplate,
|
||||||
quotePrompt,
|
quotePrompt,
|
||||||
aiChatVision,
|
aiChatVision,
|
||||||
stringQuoteText
|
fileUrlList: fileLinks, // node quote file links
|
||||||
|
stringQuoteText //abandon
|
||||||
}
|
}
|
||||||
} = props;
|
} = props;
|
||||||
const { files: inputFiles } = chatValue2RuntimePrompt(query);
|
const { files: inputFiles } = chatValue2RuntimePrompt(query); // Chat box input files
|
||||||
|
|
||||||
if (!userChatInput && inputFiles.length === 0) {
|
|
||||||
return Promise.reject('Question is empty');
|
|
||||||
}
|
|
||||||
stream = stream && isResponseAnswerText;
|
stream = stream && isResponseAnswerText;
|
||||||
|
|
||||||
const chatHistories = getHistories(history, histories);
|
const chatHistories = getHistories(history, histories);
|
||||||
@@ -100,11 +99,26 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
|||||||
return Promise.reject('The chat model is undefined, you need to select a chat model.');
|
return Promise.reject('The chat model is undefined, you need to select a chat model.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { datasetQuoteText } = await filterDatasetQuote({
|
const [{ datasetQuoteText }, { documentQuoteText, userFiles }] = await Promise.all([
|
||||||
quoteQA,
|
filterDatasetQuote({
|
||||||
model: modelConstantsData,
|
quoteQA,
|
||||||
quoteTemplate
|
model: modelConstantsData,
|
||||||
});
|
quoteTemplate
|
||||||
|
}),
|
||||||
|
getMultiInput({
|
||||||
|
histories: chatHistories,
|
||||||
|
inputFiles,
|
||||||
|
fileLinks,
|
||||||
|
stringQuoteText,
|
||||||
|
requestOrigin,
|
||||||
|
maxFiles: chatConfig?.fileSelectConfig?.maxFiles || 20,
|
||||||
|
teamId
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!userChatInput && !documentQuoteText && userFiles.length === 0) {
|
||||||
|
return Promise.reject(i18nT('chat:AI_input_is_empty'));
|
||||||
|
}
|
||||||
|
|
||||||
const [{ filterMessages }] = await Promise.all([
|
const [{ filterMessages }] = await Promise.all([
|
||||||
getChatMessages({
|
getChatMessages({
|
||||||
@@ -115,9 +129,9 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
|||||||
aiChatQuoteRole,
|
aiChatQuoteRole,
|
||||||
datasetQuotePrompt: quotePrompt,
|
datasetQuotePrompt: quotePrompt,
|
||||||
userChatInput,
|
userChatInput,
|
||||||
inputFiles,
|
|
||||||
systemPrompt,
|
systemPrompt,
|
||||||
stringQuoteText
|
userFiles,
|
||||||
|
documentQuoteText
|
||||||
}),
|
}),
|
||||||
(() => {
|
(() => {
|
||||||
// censor model and system key
|
// censor model and system key
|
||||||
@@ -132,22 +146,9 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
|||||||
})()
|
})()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Get the request messages
|
|
||||||
const concatMessages = [
|
|
||||||
...(modelConstantsData.defaultSystemChatPrompt
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
role: ChatCompletionRequestMessageRoleEnum.System,
|
|
||||||
content: modelConstantsData.defaultSystemChatPrompt
|
|
||||||
}
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
...filterMessages
|
|
||||||
] as ChatCompletionMessageParam[];
|
|
||||||
|
|
||||||
const [requestMessages, max_tokens] = await Promise.all([
|
const [requestMessages, max_tokens] = await Promise.all([
|
||||||
loadRequestMessages({
|
loadRequestMessages({
|
||||||
messages: concatMessages,
|
messages: filterMessages,
|
||||||
useVision: modelConstantsData.vision && aiChatVision,
|
useVision: modelConstantsData.vision && aiChatVision,
|
||||||
origin: requestOrigin
|
origin: requestOrigin
|
||||||
}),
|
}),
|
||||||
@@ -195,7 +196,7 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!answer) {
|
if (!answer) {
|
||||||
throw new Error('LLM model response empty');
|
return Promise.reject(i18nT('chat:LLM_model_response_empty'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -242,7 +243,11 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
|||||||
tokens,
|
tokens,
|
||||||
query: `${userChatInput}`,
|
query: `${userChatInput}`,
|
||||||
maxToken: max_tokens,
|
maxToken: max_tokens,
|
||||||
historyPreview: getHistoryPreview(chatCompleteMessages, 10000),
|
historyPreview: getHistoryPreview(
|
||||||
|
chatCompleteMessages,
|
||||||
|
10000,
|
||||||
|
modelConstantsData.vision && aiChatVision
|
||||||
|
),
|
||||||
contextTotalLen: completeMessages.length
|
contextTotalLen: completeMessages.length
|
||||||
},
|
},
|
||||||
[DispatchNodeResponseKeyEnum.nodeDispatchUsages]: [
|
[DispatchNodeResponseKeyEnum.nodeDispatchUsages]: [
|
||||||
@@ -302,7 +307,70 @@ async function filterDatasetQuote({
|
|||||||
datasetQuoteText
|
datasetQuoteText
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getMultiInput({
|
||||||
|
histories,
|
||||||
|
inputFiles,
|
||||||
|
fileLinks,
|
||||||
|
stringQuoteText,
|
||||||
|
requestOrigin,
|
||||||
|
maxFiles,
|
||||||
|
teamId
|
||||||
|
}: {
|
||||||
|
histories: ChatItemType[];
|
||||||
|
inputFiles: UserChatItemValueItemType['file'][];
|
||||||
|
fileLinks?: string[];
|
||||||
|
stringQuoteText?: string; // file quote
|
||||||
|
requestOrigin?: string;
|
||||||
|
maxFiles: number;
|
||||||
|
teamId: string;
|
||||||
|
}) {
|
||||||
|
// 旧版本适配====>
|
||||||
|
if (stringQuoteText) {
|
||||||
|
return {
|
||||||
|
documentQuoteText: stringQuoteText,
|
||||||
|
userFiles: inputFiles
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 没有引用文件参考,但是可能用了图片识别
|
||||||
|
if (!fileLinks) {
|
||||||
|
return {
|
||||||
|
documentQuoteText: '',
|
||||||
|
userFiles: inputFiles
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 旧版本适配<====
|
||||||
|
|
||||||
|
// If fileLinks params is not empty, it means it is a new version, not get the global file.
|
||||||
|
|
||||||
|
// Get files from histories
|
||||||
|
const filesFromHistories = getHistoryFileLinks(histories);
|
||||||
|
const urls = [...fileLinks, ...filesFromHistories];
|
||||||
|
|
||||||
|
if (urls.length === 0) {
|
||||||
|
return {
|
||||||
|
documentQuoteText: '',
|
||||||
|
userFiles: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const { text } = await getFileContentFromLinks({
|
||||||
|
// Concat fileUrlList and filesFromHistories; remove not supported files
|
||||||
|
urls,
|
||||||
|
requestOrigin,
|
||||||
|
maxFiles,
|
||||||
|
teamId
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
documentQuoteText: text,
|
||||||
|
userFiles: fileLinks.map((url) => parseUrlToFileType(url))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async function getChatMessages({
|
async function getChatMessages({
|
||||||
|
model,
|
||||||
aiChatQuoteRole,
|
aiChatQuoteRole,
|
||||||
datasetQuotePrompt = '',
|
datasetQuotePrompt = '',
|
||||||
datasetQuoteText,
|
datasetQuoteText,
|
||||||
@@ -310,10 +378,10 @@ async function getChatMessages({
|
|||||||
histories = [],
|
histories = [],
|
||||||
systemPrompt,
|
systemPrompt,
|
||||||
userChatInput,
|
userChatInput,
|
||||||
inputFiles,
|
userFiles,
|
||||||
model,
|
documentQuoteText
|
||||||
stringQuoteText
|
|
||||||
}: {
|
}: {
|
||||||
|
model: LLMModelItemType;
|
||||||
// dataset quote
|
// dataset quote
|
||||||
aiChatQuoteRole: AiChatQuoteRoleType; // user: replace user prompt; system: replace system prompt
|
aiChatQuoteRole: AiChatQuoteRoleType; // user: replace user prompt; system: replace system prompt
|
||||||
datasetQuotePrompt?: string;
|
datasetQuotePrompt?: string;
|
||||||
@@ -323,10 +391,11 @@ async function getChatMessages({
|
|||||||
histories: ChatItemType[];
|
histories: ChatItemType[];
|
||||||
systemPrompt: string;
|
systemPrompt: string;
|
||||||
userChatInput: string;
|
userChatInput: string;
|
||||||
inputFiles: UserChatItemValueItemType['file'][];
|
|
||||||
model: LLMModelItemType;
|
userFiles: UserChatItemValueItemType['file'][];
|
||||||
stringQuoteText?: string; // file quote
|
documentQuoteText?: string; // document quote
|
||||||
}) {
|
}) {
|
||||||
|
// Dataset prompt ====>
|
||||||
// User role or prompt include question
|
// User role or prompt include question
|
||||||
const quoteRole =
|
const quoteRole =
|
||||||
aiChatQuoteRole === 'user' || datasetQuotePrompt.includes('{{question}}') ? 'user' : 'system';
|
aiChatQuoteRole === 'user' || datasetQuotePrompt.includes('{{question}}') ? 'user' : 'system';
|
||||||
@@ -337,6 +406,7 @@ async function getChatMessages({
|
|||||||
? Prompt_userQuotePromptList[0].value
|
? Prompt_userQuotePromptList[0].value
|
||||||
: Prompt_systemQuotePromptList[0].value;
|
: Prompt_systemQuotePromptList[0].value;
|
||||||
|
|
||||||
|
// Reset user input, add dataset quote to user input
|
||||||
const replaceInputValue =
|
const replaceInputValue =
|
||||||
useDatasetQuote && quoteRole === 'user'
|
useDatasetQuote && quoteRole === 'user'
|
||||||
? replaceVariable(datasetQuotePromptTemplate, {
|
? replaceVariable(datasetQuotePromptTemplate, {
|
||||||
@@ -344,31 +414,33 @@ async function getChatMessages({
|
|||||||
question: userChatInput
|
question: userChatInput
|
||||||
})
|
})
|
||||||
: userChatInput;
|
: userChatInput;
|
||||||
|
// Dataset prompt <====
|
||||||
|
|
||||||
const replaceSystemPrompt =
|
// Concat system prompt
|
||||||
|
const concatenateSystemPrompt = [
|
||||||
|
model.defaultSystemChatPrompt,
|
||||||
|
systemPrompt,
|
||||||
useDatasetQuote && quoteRole === 'system'
|
useDatasetQuote && quoteRole === 'system'
|
||||||
? `${systemPrompt ? systemPrompt + '\n\n------\n\n' : ''}${replaceVariable(
|
? replaceVariable(datasetQuotePromptTemplate, {
|
||||||
datasetQuotePromptTemplate,
|
quote: datasetQuoteText
|
||||||
{
|
})
|
||||||
quote: datasetQuoteText
|
: '',
|
||||||
}
|
documentQuoteText
|
||||||
)}`
|
? replaceVariable(Prompt_DocumentQuote, {
|
||||||
: systemPrompt;
|
quote: documentQuoteText
|
||||||
|
})
|
||||||
|
: ''
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join('\n\n===---===---===\n\n');
|
||||||
|
|
||||||
const messages: ChatItemType[] = [
|
const messages: ChatItemType[] = [
|
||||||
...getSystemPrompt_ChatItemType(replaceSystemPrompt),
|
...getSystemPrompt_ChatItemType(concatenateSystemPrompt),
|
||||||
...(stringQuoteText // file quote
|
|
||||||
? getSystemPrompt_ChatItemType(
|
|
||||||
replaceVariable(Prompt_DocumentQuote, {
|
|
||||||
quote: stringQuoteText
|
|
||||||
})
|
|
||||||
)
|
|
||||||
: []),
|
|
||||||
...histories,
|
...histories,
|
||||||
{
|
{
|
||||||
obj: ChatRoleEnum.Human,
|
obj: ChatRoleEnum.Human,
|
||||||
value: runtimePrompt2ChatsValue({
|
value: runtimePrompt2ChatsValue({
|
||||||
files: inputFiles,
|
files: userFiles,
|
||||||
text: replaceInputValue
|
text: replaceInputValue
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,21 @@
|
|||||||
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
|
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
|
||||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
import type {
|
||||||
|
DispatchNodeResultType,
|
||||||
|
ModuleDispatchProps
|
||||||
|
} from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { datasetSearchResultConcat } from '@fastgpt/global/core/dataset/search/utils';
|
import { datasetSearchResultConcat } from '@fastgpt/global/core/dataset/search/utils';
|
||||||
import { filterSearchResultsByMaxChars } from '../../utils';
|
import { filterSearchResultsByMaxChars } from '../../utils';
|
||||||
|
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
|
|
||||||
type DatasetConcatProps = ModuleDispatchProps<
|
type DatasetConcatProps = ModuleDispatchProps<
|
||||||
{
|
{
|
||||||
[NodeInputKeyEnum.datasetMaxTokens]: number;
|
[NodeInputKeyEnum.datasetMaxTokens]: number;
|
||||||
} & { [key: string]: SearchDataResponseItemType[] }
|
} & { [key: string]: SearchDataResponseItemType[] }
|
||||||
>;
|
>;
|
||||||
type DatasetConcatResponse = {
|
type DatasetConcatResponse = DispatchNodeResultType<{
|
||||||
[NodeOutputKeyEnum.datasetQuoteQA]: SearchDataResponseItemType[];
|
[NodeOutputKeyEnum.datasetQuoteQA]: SearchDataResponseItemType[];
|
||||||
};
|
}>;
|
||||||
|
|
||||||
export async function dispatchDatasetConcat(
|
export async function dispatchDatasetConcat(
|
||||||
props: DatasetConcatProps
|
props: DatasetConcatProps
|
||||||
@@ -30,6 +34,12 @@ export async function dispatchDatasetConcat(
|
|||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
[NodeOutputKeyEnum.datasetQuoteQA]: await filterSearchResultsByMaxChars(rrfConcatResults, limit)
|
[NodeOutputKeyEnum.datasetQuoteQA]: await filterSearchResultsByMaxChars(
|
||||||
|
rrfConcatResults,
|
||||||
|
limit
|
||||||
|
),
|
||||||
|
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||||
|
concatLength: rrfConcatResults.length
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { datasetSearchQueryExtension } from '../../../dataset/search/utils';
|
|||||||
import { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
import { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
||||||
import { checkTeamReRankPermission } from '../../../../support/permission/teamLimit';
|
import { checkTeamReRankPermission } from '../../../../support/permission/teamLimit';
|
||||||
import { MongoDataset } from '../../../dataset/schema';
|
import { MongoDataset } from '../../../dataset/schema';
|
||||||
|
import { i18nT } from '../../../../../web/i18n/utils';
|
||||||
|
|
||||||
type DatasetSearchProps = ModuleDispatchProps<{
|
type DatasetSearchProps = ModuleDispatchProps<{
|
||||||
[NodeInputKeyEnum.datasetSelectList]: SelectedDatasetType;
|
[NodeInputKeyEnum.datasetSelectList]: SelectedDatasetType;
|
||||||
@@ -56,15 +57,15 @@ export async function dispatchDatasetSearch(
|
|||||||
} = props as DatasetSearchProps;
|
} = props as DatasetSearchProps;
|
||||||
|
|
||||||
if (!Array.isArray(datasets)) {
|
if (!Array.isArray(datasets)) {
|
||||||
return Promise.reject('Quote type error');
|
return Promise.reject(i18nT('chat:dataset_quote_type error'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (datasets.length === 0) {
|
if (datasets.length === 0) {
|
||||||
return Promise.reject('core.chat.error.Select dataset empty');
|
return Promise.reject(i18nT('common:core.chat.error.Select dataset empty'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userChatInput) {
|
if (!userChatInput) {
|
||||||
return Promise.reject('core.chat.error.User input empty');
|
return Promise.reject(i18nT('common:core.chat.error.User input empty'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// query extension
|
// query extension
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import {
|
|||||||
} from '@fastgpt/global/core/workflow/node/constant';
|
} from '@fastgpt/global/core/workflow/node/constant';
|
||||||
import { getNanoid, replaceVariable } from '@fastgpt/global/common/string/tools';
|
import { getNanoid, replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||||
import { getSystemTime } from '@fastgpt/global/common/time/timezone';
|
import { getSystemTime } from '@fastgpt/global/common/time/timezone';
|
||||||
import { replaceEditorVariable } from '@fastgpt/global/core/workflow/utils';
|
|
||||||
|
|
||||||
import { dispatchWorkflowStart } from './init/workflowStart';
|
import { dispatchWorkflowStart } from './init/workflowStart';
|
||||||
import { dispatchChatCompletion } from './chat/oneapi';
|
import { dispatchChatCompletion } from './chat/oneapi';
|
||||||
@@ -38,11 +37,12 @@ import { dispatchQueryExtension } from './tools/queryExternsion';
|
|||||||
import { dispatchRunPlugin } from './plugin/run';
|
import { dispatchRunPlugin } from './plugin/run';
|
||||||
import { dispatchPluginInput } from './plugin/runInput';
|
import { dispatchPluginInput } from './plugin/runInput';
|
||||||
import { dispatchPluginOutput } from './plugin/runOutput';
|
import { dispatchPluginOutput } from './plugin/runOutput';
|
||||||
import { removeSystemVariable, valueTypeFormat } from './utils';
|
import { formatHttpError, removeSystemVariable, valueTypeFormat } from './utils';
|
||||||
import {
|
import {
|
||||||
filterWorkflowEdges,
|
filterWorkflowEdges,
|
||||||
checkNodeRunStatus,
|
checkNodeRunStatus,
|
||||||
textAdaptGptResponse
|
textAdaptGptResponse,
|
||||||
|
replaceEditorVariable
|
||||||
} from '@fastgpt/global/core/workflow/runtime/utils';
|
} from '@fastgpt/global/core/workflow/runtime/utils';
|
||||||
import { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
import { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
||||||
import { dispatchRunTools } from './agent/runTool/index';
|
import { dispatchRunTools } from './agent/runTool/index';
|
||||||
@@ -72,6 +72,7 @@ import { dispatchLoopEnd } from './loop/runLoopEnd';
|
|||||||
import { dispatchLoopStart } from './loop/runLoopStart';
|
import { dispatchLoopStart } from './loop/runLoopStart';
|
||||||
import { dispatchFormInput } from './interactive/formInput';
|
import { dispatchFormInput } from './interactive/formInput';
|
||||||
import { dispatchToolParams } from './agent/runTool/toolParams';
|
import { dispatchToolParams } from './agent/runTool/toolParams';
|
||||||
|
import { responseWrite } from '../../../common/response';
|
||||||
|
|
||||||
const callbackMap: Record<FlowNodeTypeEnum, Function> = {
|
const callbackMap: Record<FlowNodeTypeEnum, Function> = {
|
||||||
[FlowNodeTypeEnum.workflowStart]: dispatchWorkflowStart,
|
[FlowNodeTypeEnum.workflowStart]: dispatchWorkflowStart,
|
||||||
@@ -386,6 +387,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
node,
|
node,
|
||||||
runtimeEdges
|
runtimeEdges
|
||||||
});
|
});
|
||||||
|
|
||||||
const nodeRunResult = await (() => {
|
const nodeRunResult = await (() => {
|
||||||
if (status === 'run') {
|
if (status === 'run') {
|
||||||
nodeRunBeforeHook(node);
|
nodeRunBeforeHook(node);
|
||||||
@@ -481,8 +483,16 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
: {};
|
: {};
|
||||||
|
|
||||||
node.inputs.forEach((input) => {
|
node.inputs.forEach((input) => {
|
||||||
|
// Special input, not format
|
||||||
if (input.key === dynamicInput?.key) return;
|
if (input.key === dynamicInput?.key) return;
|
||||||
|
|
||||||
|
// Skip some special key
|
||||||
|
if (input.key === NodeInputKeyEnum.childrenNodeIdList) {
|
||||||
|
params[input.key] = input.value;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// replace {{xx}} variables
|
// replace {{xx}} variables
|
||||||
let value = replaceVariable(input.value, variables);
|
let value = replaceVariable(input.value, variables);
|
||||||
|
|
||||||
@@ -505,7 +515,6 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
if (input.canEdit && dynamicInput && params[dynamicInput.key]) {
|
if (input.canEdit && dynamicInput && params[dynamicInput.key]) {
|
||||||
params[dynamicInput.key][input.key] = valueTypeFormat(value, input.valueType);
|
params[dynamicInput.key][input.key] = valueTypeFormat(value, input.valueType);
|
||||||
}
|
}
|
||||||
|
|
||||||
params[input.key] = valueTypeFormat(value, input.valueType);
|
params[input.key] = valueTypeFormat(value, input.valueType);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -548,7 +557,21 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
// run module
|
// run module
|
||||||
const dispatchRes: Record<string, any> = await (async () => {
|
const dispatchRes: Record<string, any> = await (async () => {
|
||||||
if (callbackMap[node.flowNodeType]) {
|
if (callbackMap[node.flowNodeType]) {
|
||||||
return callbackMap[node.flowNodeType](dispatchData);
|
try {
|
||||||
|
return await callbackMap[node.flowNodeType](dispatchData);
|
||||||
|
} catch (error) {
|
||||||
|
// Get source handles of outgoing edges
|
||||||
|
const targetEdges = runtimeEdges.filter((item) => item.source === node.nodeId);
|
||||||
|
const skipHandleIds = targetEdges.map((item) => item.sourceHandle);
|
||||||
|
|
||||||
|
// Skip all edges and return error
|
||||||
|
return {
|
||||||
|
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||||
|
error: formatHttpError(error)
|
||||||
|
},
|
||||||
|
[DispatchNodeResponseKeyEnum.skipHandleId]: skipHandleIds
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export const dispatchLoop = async (props: Props): Promise<Response> => {
|
|||||||
user,
|
user,
|
||||||
node: { name }
|
node: { name }
|
||||||
} = props;
|
} = props;
|
||||||
const { loopInputArray = [], childrenNodeIdList } = params;
|
const { loopInputArray = [], childrenNodeIdList = [] } = params;
|
||||||
|
|
||||||
if (!Array.isArray(loopInputArray)) {
|
if (!Array.isArray(loopInputArray)) {
|
||||||
return Promise.reject('Input value is not an array');
|
return Promise.reject('Input value is not an array');
|
||||||
@@ -43,23 +43,24 @@ export const dispatchLoop = async (props: Props): Promise<Response> => {
|
|||||||
let totalPoints = 0;
|
let totalPoints = 0;
|
||||||
let newVariables: Record<string, any> = props.variables;
|
let newVariables: Record<string, any> = props.variables;
|
||||||
|
|
||||||
for await (const item of loopInputArray) {
|
let index = 0;
|
||||||
|
for await (const item of loopInputArray.filter(Boolean)) {
|
||||||
runtimeNodes.forEach((node) => {
|
runtimeNodes.forEach((node) => {
|
||||||
if (
|
if (
|
||||||
childrenNodeIdList.includes(node.nodeId) &&
|
childrenNodeIdList.includes(node.nodeId) &&
|
||||||
node.flowNodeType === FlowNodeTypeEnum.loopStart
|
node.flowNodeType === FlowNodeTypeEnum.loopStart
|
||||||
) {
|
) {
|
||||||
node.isEntry = true;
|
node.isEntry = true;
|
||||||
node.inputs = node.inputs.map((input) =>
|
node.inputs.forEach((input) => {
|
||||||
input.key === NodeInputKeyEnum.loopStartInput
|
if (input.key === NodeInputKeyEnum.loopStartInput) {
|
||||||
? {
|
input.value = item;
|
||||||
...input,
|
} else if (input.key === NodeInputKeyEnum.loopStartIndex) {
|
||||||
value: item
|
input.value = index++;
|
||||||
}
|
}
|
||||||
: input
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await dispatchWorkFlow({
|
const response = await dispatchWorkFlow({
|
||||||
...props,
|
...props,
|
||||||
runtimeEdges: cloneDeep(runtimeEdges)
|
runtimeEdges: cloneDeep(runtimeEdges)
|
||||||
@@ -69,11 +70,13 @@ export const dispatchLoop = async (props: Props): Promise<Response> => {
|
|||||||
(res) => res.moduleType === FlowNodeTypeEnum.loopEnd
|
(res) => res.moduleType === FlowNodeTypeEnum.loopEnd
|
||||||
)?.loopOutputValue;
|
)?.loopOutputValue;
|
||||||
|
|
||||||
|
// Concat runtime response
|
||||||
outputValueArr.push(loopOutputValue);
|
outputValueArr.push(loopOutputValue);
|
||||||
loopDetail.push(...response.flowResponses);
|
loopDetail.push(...response.flowResponses);
|
||||||
assistantResponses.push(...response.assistantResponses);
|
assistantResponses.push(...response.assistantResponses);
|
||||||
|
totalPoints += response.flowUsages.reduce((acc, usage) => acc + usage.totalPoints, 0);
|
||||||
|
|
||||||
totalPoints = response.flowUsages.reduce((acc, usage) => acc + usage.totalPoints, 0);
|
// Concat new variables
|
||||||
newVariables = {
|
newVariables = {
|
||||||
...newVariables,
|
...newVariables,
|
||||||
...response.newVariables
|
...response.newVariables
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ import {
|
|||||||
|
|
||||||
type Props = ModuleDispatchProps<{
|
type Props = ModuleDispatchProps<{
|
||||||
[NodeInputKeyEnum.loopStartInput]: any;
|
[NodeInputKeyEnum.loopStartInput]: any;
|
||||||
|
[NodeInputKeyEnum.loopStartIndex]: number;
|
||||||
}>;
|
}>;
|
||||||
type Response = DispatchNodeResultType<{
|
type Response = DispatchNodeResultType<{
|
||||||
[NodeOutputKeyEnum.loopStartInput]: any;
|
[NodeOutputKeyEnum.loopStartInput]: any;
|
||||||
|
[NodeOutputKeyEnum.loopStartIndex]: number;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export const dispatchLoopStart = async (props: Props): Promise<Response> => {
|
export const dispatchLoopStart = async (props: Props): Promise<Response> => {
|
||||||
@@ -18,6 +20,7 @@ export const dispatchLoopStart = async (props: Props): Promise<Response> => {
|
|||||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||||
loopInputValue: params.loopStartInput
|
loopInputValue: params.loopStartInput
|
||||||
},
|
},
|
||||||
[NodeOutputKeyEnum.loopStartInput]: params.loopStartInput
|
[NodeOutputKeyEnum.loopStartInput]: params.loopStartInput,
|
||||||
|
[NodeOutputKeyEnum.loopStartIndex]: params.loopStartIndex
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -112,7 +112,11 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
|
|||||||
output.moduleLogo = plugin.avatar;
|
output.moduleLogo = plugin.avatar;
|
||||||
}
|
}
|
||||||
|
|
||||||
const usagePoints = await computedPluginUsage(plugin, flowUsages);
|
const usagePoints = await computedPluginUsage({
|
||||||
|
plugin,
|
||||||
|
childrenUsage: flowUsages,
|
||||||
|
error: !!output?.pluginOutput?.error
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// 嵌套运行时,如果 childApp stream=false,实际上不会有任何内容输出给用户,所以不需要存储
|
// 嵌套运行时,如果 childApp stream=false,实际上不会有任何内容输出给用户,所以不需要存储
|
||||||
|
|||||||
@@ -17,12 +17,14 @@ import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/ty
|
|||||||
import { authAppByTmbId } from '../../../../support/permission/app/auth';
|
import { authAppByTmbId } from '../../../../support/permission/app/auth';
|
||||||
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||||
import { getAppVersionById } from '../../../app/version/controller';
|
import { getAppVersionById } from '../../../app/version/controller';
|
||||||
|
import { parseUrlToFileType } from '@fastgpt/global/common/file/tools';
|
||||||
|
|
||||||
type Props = ModuleDispatchProps<{
|
type Props = ModuleDispatchProps<{
|
||||||
[NodeInputKeyEnum.userChatInput]: string;
|
[NodeInputKeyEnum.userChatInput]: string;
|
||||||
[NodeInputKeyEnum.history]?: ChatItemType[] | number;
|
[NodeInputKeyEnum.history]?: ChatItemType[] | number;
|
||||||
[NodeInputKeyEnum.fileUrlList]?: string[];
|
[NodeInputKeyEnum.fileUrlList]?: string[];
|
||||||
[NodeInputKeyEnum.forbidStream]?: boolean;
|
[NodeInputKeyEnum.forbidStream]?: boolean;
|
||||||
|
[NodeInputKeyEnum.fileUrlList]?: string[];
|
||||||
}>;
|
}>;
|
||||||
type Response = DispatchNodeResultType<{
|
type Response = DispatchNodeResultType<{
|
||||||
[NodeOutputKeyEnum.answerText]: string;
|
[NodeOutputKeyEnum.answerText]: string;
|
||||||
@@ -40,8 +42,24 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
|
|||||||
variables
|
variables
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const { system_forbid_stream = false, userChatInput, history, ...childrenAppVariables } = params;
|
const {
|
||||||
if (!userChatInput) {
|
system_forbid_stream = false,
|
||||||
|
userChatInput,
|
||||||
|
history,
|
||||||
|
fileUrlList,
|
||||||
|
...childrenAppVariables
|
||||||
|
} = params;
|
||||||
|
const { files } = chatValue2RuntimePrompt(query);
|
||||||
|
|
||||||
|
const userInputFiles = (() => {
|
||||||
|
if (fileUrlList) {
|
||||||
|
return fileUrlList.map((url) => parseUrlToFileType(url));
|
||||||
|
}
|
||||||
|
// Adapt version 4.8.13 upgrade
|
||||||
|
return files;
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (!userChatInput && !userInputFiles) {
|
||||||
return Promise.reject('Input is empty');
|
return Promise.reject('Input is empty');
|
||||||
}
|
}
|
||||||
if (!appId) {
|
if (!appId) {
|
||||||
@@ -72,7 +90,6 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const chatHistories = getHistories(history, histories);
|
const chatHistories = getHistories(history, histories);
|
||||||
const { files } = chatValue2RuntimePrompt(query);
|
|
||||||
|
|
||||||
// Rewrite children app variables
|
// Rewrite children app variables
|
||||||
const systemVariables = filterSystemVariables(variables);
|
const systemVariables = filterSystemVariables(variables);
|
||||||
@@ -102,7 +119,7 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
|
|||||||
histories: chatHistories,
|
histories: chatHistories,
|
||||||
variables: childrenRunVariables,
|
variables: childrenRunVariables,
|
||||||
query: runtimePrompt2ChatsValue({
|
query: runtimePrompt2ChatsValue({
|
||||||
files,
|
files: userInputFiles,
|
||||||
text: userChatInput
|
text: userChatInput
|
||||||
}),
|
}),
|
||||||
chatConfig
|
chatConfig
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
|
import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
|
||||||
|
import { ChatFileTypeEnum } from '@fastgpt/global/core/chat/constants';
|
||||||
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
@@ -11,6 +12,26 @@ export const dispatchPluginInput = (props: PluginInputProps) => {
|
|||||||
const { params, query } = props;
|
const { params, query } = props;
|
||||||
const { files } = chatValue2RuntimePrompt(query);
|
const { files } = chatValue2RuntimePrompt(query);
|
||||||
|
|
||||||
|
/*
|
||||||
|
对 params 中文件类型数据进行处理
|
||||||
|
* 插件单独运行时,这里会是一个特殊的数组
|
||||||
|
* 插件调用的话,这个参数是一个 string[] 不会进行处理
|
||||||
|
* 硬性要求:API 单独调用插件时,要避免这种特殊类型冲突
|
||||||
|
|
||||||
|
TODO: 需要 filter max files
|
||||||
|
*/
|
||||||
|
for (const key in params) {
|
||||||
|
const val = params[key];
|
||||||
|
if (
|
||||||
|
Array.isArray(val) &&
|
||||||
|
val.every(
|
||||||
|
(item) => item.type === ChatFileTypeEnum.file || item.type === ChatFileTypeEnum.image
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
params[key] = val.map((item) => item.url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...params,
|
...params,
|
||||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {},
|
[DispatchNodeResponseKeyEnum.nodeResponse]: {},
|
||||||
|
|||||||
@@ -14,10 +14,12 @@ import { SERVICE_LOCAL_HOST } from '../../../../common/system/tools';
|
|||||||
import { addLog } from '../../../../common/system/log';
|
import { addLog } from '../../../../common/system/log';
|
||||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
import { textAdaptGptResponse } from '@fastgpt/global/core/workflow/runtime/utils';
|
import {
|
||||||
|
textAdaptGptResponse,
|
||||||
|
replaceEditorVariable
|
||||||
|
} from '@fastgpt/global/core/workflow/runtime/utils';
|
||||||
import { getSystemPluginCb } from '../../../../../plugins/register';
|
import { getSystemPluginCb } from '../../../../../plugins/register';
|
||||||
import { ContentTypes } from '@fastgpt/global/core/workflow/constants';
|
import { ContentTypes } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { replaceEditorVariable } from '@fastgpt/global/core/workflow/utils';
|
|
||||||
import { uploadFileFromBase64Img } from '../../../../common/file/gridfs/controller';
|
import { uploadFileFromBase64Img } from '../../../../common/file/gridfs/controller';
|
||||||
import { ReadFileBaseUrl } from '@fastgpt/global/common/file/constants';
|
import { ReadFileBaseUrl } from '@fastgpt/global/common/file/constants';
|
||||||
import { createFileToken } from '../../../../support/permission/controller';
|
import { createFileToken } from '../../../../support/permission/controller';
|
||||||
@@ -235,7 +237,9 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
|||||||
node.outputs
|
node.outputs
|
||||||
.filter(
|
.filter(
|
||||||
(item) =>
|
(item) =>
|
||||||
item.key !== NodeOutputKeyEnum.error && item.key !== NodeOutputKeyEnum.httpRawResponse
|
item.id !== NodeOutputKeyEnum.error &&
|
||||||
|
item.id !== NodeOutputKeyEnum.httpRawResponse &&
|
||||||
|
item.id !== NodeOutputKeyEnum.addOutputParam
|
||||||
)
|
)
|
||||||
.forEach((item) => {
|
.forEach((item) => {
|
||||||
const key = item.key.startsWith('$') ? item.key : `$.${item.key}`;
|
const key = item.key.startsWith('$') ? item.key : `$.${item.key}`;
|
||||||
|
|||||||
@@ -2,16 +2,15 @@ import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runti
|
|||||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
import { documentFileType } from '@fastgpt/global/common/file/constants';
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { serverRequestBaseUrl } from '../../../../common/api/serverRequest';
|
import { serverRequestBaseUrl } from '../../../../common/api/serverRequest';
|
||||||
import { MongoRawTextBuffer } from '../../../../common/buffer/rawText/schema';
|
import { MongoRawTextBuffer } from '../../../../common/buffer/rawText/schema';
|
||||||
import { readFromSecondary } from '../../../../common/mongo/utils';
|
import { readFromSecondary } from '../../../../common/mongo/utils';
|
||||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
import { detectFileEncoding } from '@fastgpt/global/common/file/tools';
|
import { detectFileEncoding, parseUrlToFileType } from '@fastgpt/global/common/file/tools';
|
||||||
import { readRawContentByFileBuffer } from '../../../../common/file/read/utils';
|
import { readRawContentByFileBuffer } from '../../../../common/file/read/utils';
|
||||||
import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
||||||
import { UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
import { ChatItemType, UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
||||||
import { parseFileExtensionFromUrl } from '@fastgpt/global/common/string/tools';
|
import { parseFileExtensionFromUrl } from '@fastgpt/global/common/string/tools';
|
||||||
|
|
||||||
type Props = ModuleDispatchProps<{
|
type Props = ModuleDispatchProps<{
|
||||||
@@ -48,12 +47,41 @@ export const dispatchReadFiles = async (props: Props): Promise<Response> => {
|
|||||||
runningAppInfo: { teamId },
|
runningAppInfo: { teamId },
|
||||||
histories,
|
histories,
|
||||||
chatConfig,
|
chatConfig,
|
||||||
|
node: { version },
|
||||||
params: { fileUrlList = [] }
|
params: { fileUrlList = [] }
|
||||||
} = props;
|
} = props;
|
||||||
const maxFiles = chatConfig?.fileSelectConfig?.maxFiles || 20;
|
const maxFiles = chatConfig?.fileSelectConfig?.maxFiles || 20;
|
||||||
|
|
||||||
// Get files from histories
|
// Get files from histories
|
||||||
const filesFromHistories = histories
|
const filesFromHistories = version !== '489' ? [] : getHistoryFileLinks(histories);
|
||||||
|
|
||||||
|
const { text, readFilesResult } = await getFileContentFromLinks({
|
||||||
|
// Concat fileUrlList and filesFromHistories; remove not supported files
|
||||||
|
urls: [...fileUrlList, ...filesFromHistories],
|
||||||
|
requestOrigin,
|
||||||
|
maxFiles,
|
||||||
|
teamId
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
[NodeOutputKeyEnum.text]: text,
|
||||||
|
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||||
|
readFiles: readFilesResult.map((item) => ({
|
||||||
|
name: item?.filename || '',
|
||||||
|
url: item?.url || ''
|
||||||
|
})),
|
||||||
|
readFilesResult: readFilesResult
|
||||||
|
.map((item) => item?.nodeResponsePreviewText ?? '')
|
||||||
|
.join('\n******\n')
|
||||||
|
},
|
||||||
|
[DispatchNodeResponseKeyEnum.toolResponses]: {
|
||||||
|
fileContent: text
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getHistoryFileLinks = (histories: ChatItemType[]) => {
|
||||||
|
return histories
|
||||||
.filter((item) => {
|
.filter((item) => {
|
||||||
if (item.obj === ChatRoleEnum.Human) {
|
if (item.obj === ChatRoleEnum.Human) {
|
||||||
return item.value.filter((value) => value.type === 'file');
|
return item.value.filter((value) => value.type === 'file');
|
||||||
@@ -70,28 +98,38 @@ export const dispatchReadFiles = async (props: Props): Promise<Response> => {
|
|||||||
return files;
|
return files;
|
||||||
})
|
})
|
||||||
.flat();
|
.flat();
|
||||||
|
};
|
||||||
|
|
||||||
// Concat fileUrlList and filesFromHistories; remove not supported files
|
export const getFileContentFromLinks = async ({
|
||||||
const parseUrlList = [...fileUrlList, ...filesFromHistories]
|
urls,
|
||||||
|
requestOrigin,
|
||||||
|
maxFiles,
|
||||||
|
teamId
|
||||||
|
}: {
|
||||||
|
urls: string[];
|
||||||
|
requestOrigin?: string;
|
||||||
|
maxFiles: number;
|
||||||
|
teamId: string;
|
||||||
|
}) => {
|
||||||
|
const parseUrlList = urls
|
||||||
|
// Remove invalid urls
|
||||||
|
.filter((url) => {
|
||||||
|
if (typeof url !== 'string') return false;
|
||||||
|
|
||||||
|
// 检查相对路径
|
||||||
|
const validPrefixList = ['/', 'http', 'ws'];
|
||||||
|
if (validPrefixList.some((prefix) => url.startsWith(prefix))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
// Just get the document type file
|
||||||
|
.filter((url) => parseUrlToFileType(url)?.type === 'file')
|
||||||
.map((url) => {
|
.map((url) => {
|
||||||
try {
|
try {
|
||||||
// Avoid "/api/xxx" file error.
|
|
||||||
const origin = requestOrigin ?? 'http://localhost:3000';
|
|
||||||
|
|
||||||
// Check is system upload file
|
// Check is system upload file
|
||||||
if (url.startsWith('/') || (requestOrigin && url.startsWith(requestOrigin))) {
|
if (url.startsWith('/') || (requestOrigin && url.startsWith(requestOrigin))) {
|
||||||
// Parse url, get filename query. Keep only documents that can be parsed
|
|
||||||
const parseUrl = new URL(url, origin);
|
|
||||||
const filenameQuery = parseUrl.searchParams.get('filename');
|
|
||||||
|
|
||||||
// Not document
|
|
||||||
if (filenameQuery) {
|
|
||||||
const extensionQuery = filenameQuery.split('.').pop()?.toLowerCase() || '';
|
|
||||||
if (!documentFileType.includes(extensionQuery)) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the origin(Make intranet requests directly)
|
// Remove the origin(Make intranet requests directly)
|
||||||
if (requestOrigin && url.startsWith(requestOrigin)) {
|
if (requestOrigin && url.startsWith(requestOrigin)) {
|
||||||
url = url.replace(requestOrigin, '');
|
url = url.replace(requestOrigin, '');
|
||||||
@@ -123,7 +161,7 @@ export const dispatchReadFiles = async (props: Props): Promise<Response> => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get file buffer
|
// Get file buffer data
|
||||||
const response = await axios.get(url, {
|
const response = await axios.get(url, {
|
||||||
baseURL: serverRequestBaseUrl,
|
baseURL: serverRequestBaseUrl,
|
||||||
responseType: 'arraybuffer'
|
responseType: 'arraybuffer'
|
||||||
@@ -197,18 +235,7 @@ export const dispatchReadFiles = async (props: Props): Promise<Response> => {
|
|||||||
const text = readFilesResult.map((item) => item?.text ?? '').join('\n******\n');
|
const text = readFilesResult.map((item) => item?.text ?? '').join('\n******\n');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
[NodeOutputKeyEnum.text]: text,
|
text,
|
||||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
readFilesResult
|
||||||
readFiles: readFilesResult.map((item) => ({
|
|
||||||
name: item?.filename || '',
|
|
||||||
url: item?.url || ''
|
|
||||||
})),
|
|
||||||
readFilesResult: readFilesResult
|
|
||||||
.map((item) => item?.nodeResponsePreviewText ?? '')
|
|
||||||
.join('\n******\n')
|
|
||||||
},
|
|
||||||
[DispatchNodeResponseKeyEnum.toolResponses]: {
|
|
||||||
fileContent: text
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,11 +4,14 @@ import {
|
|||||||
SseResponseEventEnum
|
SseResponseEventEnum
|
||||||
} from '@fastgpt/global/core/workflow/runtime/constants';
|
} from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
import { getReferenceVariableValue } from '@fastgpt/global/core/workflow/runtime/utils';
|
import {
|
||||||
|
getReferenceVariableValue,
|
||||||
|
replaceEditorVariable
|
||||||
|
} from '@fastgpt/global/core/workflow/runtime/utils';
|
||||||
import { TUpdateListItem } from '@fastgpt/global/core/workflow/template/system/variableUpdate/type';
|
import { TUpdateListItem } from '@fastgpt/global/core/workflow/template/system/variableUpdate/type';
|
||||||
import { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
import { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
import { removeSystemVariable, valueTypeFormat } from '../utils';
|
import { removeSystemVariable, valueTypeFormat } from '../utils';
|
||||||
import { replaceEditorVariable } from '@fastgpt/global/core/workflow/utils';
|
import { isValidReferenceValue } from '@fastgpt/global/core/workflow/utils';
|
||||||
|
|
||||||
type Props = ModuleDispatchProps<{
|
type Props = ModuleDispatchProps<{
|
||||||
[NodeInputKeyEnum.updateList]: TUpdateListItem[];
|
[NodeInputKeyEnum.updateList]: TUpdateListItem[];
|
||||||
@@ -19,15 +22,24 @@ export const dispatchUpdateVariable = async (props: Props): Promise<Response> =>
|
|||||||
const { params, variables, runtimeNodes, workflowStreamResponse, node } = props;
|
const { params, variables, runtimeNodes, workflowStreamResponse, node } = props;
|
||||||
|
|
||||||
const { updateList } = params;
|
const { updateList } = params;
|
||||||
const result = updateList.map((item) => {
|
const nodeIds = runtimeNodes.map((node) => node.nodeId);
|
||||||
const varNodeId = item.variable?.[0];
|
|
||||||
const varKey = item.variable?.[1];
|
|
||||||
|
|
||||||
if (!varNodeId || !varKey) {
|
const result = updateList.map((item) => {
|
||||||
|
const variable = item.variable;
|
||||||
|
|
||||||
|
if (!isValidReferenceValue(variable, nodeIds)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const varNodeId = variable[0];
|
||||||
|
const varKey = variable[1];
|
||||||
|
|
||||||
|
if (!varKey) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const value = (() => {
|
const value = (() => {
|
||||||
|
// If first item is empty, it means it is a input value
|
||||||
if (!item.value?.[0]) {
|
if (!item.value?.[0]) {
|
||||||
const formatValue = valueTypeFormat(item.value?.[1], item.valueType);
|
const formatValue = valueTypeFormat(item.value?.[1], item.valueType);
|
||||||
|
|
||||||
@@ -48,6 +60,7 @@ export const dispatchUpdateVariable = async (props: Props): Promise<Response> =>
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// Update node output
|
||||||
// Global variable
|
// Global variable
|
||||||
if (varNodeId === VARIABLE_NODE_ID) {
|
if (varNodeId === VARIABLE_NODE_ID) {
|
||||||
variables[varKey] = value;
|
variables[varKey] = value;
|
||||||
@@ -72,6 +85,7 @@ export const dispatchUpdateVariable = async (props: Props): Promise<Response> =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
[DispatchNodeResponseKeyEnum.newVariables]: variables,
|
||||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||||
updateVarResult: result
|
updateVarResult: result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,5 @@
|
|||||||
import { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
|
import { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
|
||||||
import { countPromptTokens } from '../../common/string/tiktoken/index';
|
import { countPromptTokens } from '../../common/string/tiktoken/index';
|
||||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
|
||||||
import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
|
||||||
import {
|
|
||||||
getPluginInputsFromStoreNodes,
|
|
||||||
getPluginRunContent
|
|
||||||
} from '@fastgpt/global/core/app/plugin/utils';
|
|
||||||
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
|
||||||
import { RuntimeUserPromptType, UserChatItemType } from '@fastgpt/global/core/chat/type';
|
|
||||||
import { runtimePrompt2ChatsValue } from '@fastgpt/global/core/chat/adapt';
|
|
||||||
|
|
||||||
/* filter search result */
|
/* filter search result */
|
||||||
export const filterSearchResultsByMaxChars = async (
|
export const filterSearchResultsByMaxChars = async (
|
||||||
|
|||||||
@@ -9,3 +9,12 @@ export const getUserFingerprint = async () => {
|
|||||||
export const hasHttps = () => {
|
export const hasHttps = () => {
|
||||||
return window.location.protocol === 'https:';
|
return window.location.protocol === 'https:';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getWebReqUrl = (url: string = '') => {
|
||||||
|
if (!url) return '/';
|
||||||
|
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL;
|
||||||
|
if (!baseUrl) return url;
|
||||||
|
|
||||||
|
if (!url.startsWith('/') || url.startsWith(baseUrl)) return url;
|
||||||
|
return `${baseUrl}${url}`;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Box, Flex, Image } from '@chakra-ui/react';
|
import { Box } from '@chakra-ui/react';
|
||||||
import type { ImageProps } from '@chakra-ui/react';
|
import type { ImageProps } from '@chakra-ui/react';
|
||||||
import { LOGO_ICON } from '@fastgpt/global/common/system/constants';
|
import { LOGO_ICON } from '@fastgpt/global/common/system/constants';
|
||||||
import MyIcon from '../Icon';
|
import MyIcon from '../Icon';
|
||||||
import { iconPaths } from '../Icon/constants';
|
import { iconPaths } from '../Icon/constants';
|
||||||
|
import MyImage from '../Image/MyImage';
|
||||||
|
|
||||||
const Avatar = ({ w = '30px', src, ...props }: ImageProps) => {
|
const Avatar = ({ w = '30px', src, ...props }: ImageProps) => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -14,7 +15,7 @@ const Avatar = ({ w = '30px', src, ...props }: ImageProps) => {
|
|||||||
<MyIcon name={src as any} w={w} borderRadius={props.borderRadius} />
|
<MyIcon name={src as any} w={w} borderRadius={props.borderRadius} />
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<Image
|
<MyImage
|
||||||
fallbackSrc={LOGO_ICON}
|
fallbackSrc={LOGO_ICON}
|
||||||
fallbackStrategy={'onError'}
|
fallbackStrategy={'onError'}
|
||||||
objectFit={'contain'}
|
objectFit={'contain'}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ export const iconPaths = {
|
|||||||
book: () => import('./icons/book.svg'),
|
book: () => import('./icons/book.svg'),
|
||||||
change: () => import('./icons/change.svg'),
|
change: () => import('./icons/change.svg'),
|
||||||
chatSend: () => import('./icons/chatSend.svg'),
|
chatSend: () => import('./icons/chatSend.svg'),
|
||||||
|
check: () => import('./icons/check.svg'),
|
||||||
closeSolid: () => import('./icons/closeSolid.svg'),
|
closeSolid: () => import('./icons/closeSolid.svg'),
|
||||||
collectionLight: () => import('./icons/collectionLight.svg'),
|
collectionLight: () => import('./icons/collectionLight.svg'),
|
||||||
collectionSolid: () => import('./icons/collectionSolid.svg'),
|
collectionSolid: () => import('./icons/collectionSolid.svg'),
|
||||||
@@ -59,7 +60,6 @@ export const iconPaths = {
|
|||||||
'common/playFill': () => import('./icons/common/playFill.svg'),
|
'common/playFill': () => import('./icons/common/playFill.svg'),
|
||||||
'common/playLight': () => import('./icons/common/playLight.svg'),
|
'common/playLight': () => import('./icons/common/playLight.svg'),
|
||||||
'common/publishFill': () => import('./icons/common/publishFill.svg'),
|
'common/publishFill': () => import('./icons/common/publishFill.svg'),
|
||||||
'common/questionLight': () => import('./icons/common/questionLight.svg'),
|
|
||||||
'common/refreshLight': () => import('./icons/common/refreshLight.svg'),
|
'common/refreshLight': () => import('./icons/common/refreshLight.svg'),
|
||||||
'common/resultLight': () => import('./icons/common/resultLight.svg'),
|
'common/resultLight': () => import('./icons/common/resultLight.svg'),
|
||||||
'common/retryLight': () => import('./icons/common/retryLight.svg'),
|
'common/retryLight': () => import('./icons/common/retryLight.svg'),
|
||||||
@@ -217,6 +217,7 @@ export const iconPaths = {
|
|||||||
'core/workflow/template/FileRead': () => import('./icons/core/workflow/template/FileRead.svg'),
|
'core/workflow/template/FileRead': () => import('./icons/core/workflow/template/FileRead.svg'),
|
||||||
'core/workflow/template/aiChat': () => import('./icons/core/workflow/template/aiChat.svg'),
|
'core/workflow/template/aiChat': () => import('./icons/core/workflow/template/aiChat.svg'),
|
||||||
'core/workflow/template/baseChart': () => import('./icons/core/workflow/template/baseChart.svg'),
|
'core/workflow/template/baseChart': () => import('./icons/core/workflow/template/baseChart.svg'),
|
||||||
|
'core/workflow/template/bing': () => import('./icons/core/workflow/template/bing.svg'),
|
||||||
'core/workflow/template/codeRun': () => import('./icons/core/workflow/template/codeRun.svg'),
|
'core/workflow/template/codeRun': () => import('./icons/core/workflow/template/codeRun.svg'),
|
||||||
'core/workflow/template/customFeedback': () =>
|
'core/workflow/template/customFeedback': () =>
|
||||||
import('./icons/core/workflow/template/customFeedback.svg'),
|
import('./icons/core/workflow/template/customFeedback.svg'),
|
||||||
@@ -224,18 +225,16 @@ export const iconPaths = {
|
|||||||
import('./icons/core/workflow/template/datasetConcat.svg'),
|
import('./icons/core/workflow/template/datasetConcat.svg'),
|
||||||
'core/workflow/template/datasetSearch': () =>
|
'core/workflow/template/datasetSearch': () =>
|
||||||
import('./icons/core/workflow/template/datasetSearch.svg'),
|
import('./icons/core/workflow/template/datasetSearch.svg'),
|
||||||
|
'core/workflow/template/datasource': () =>
|
||||||
|
import('./icons/core/workflow/template/datasource.svg'),
|
||||||
'core/workflow/template/duckduckgo': () =>
|
'core/workflow/template/duckduckgo': () =>
|
||||||
import('./icons/core/workflow/template/duckduckgo.svg'),
|
import('./icons/core/workflow/template/duckduckgo.svg'),
|
||||||
'core/workflow/template/extractJson': () =>
|
'core/workflow/template/extractJson': () =>
|
||||||
import('./icons/core/workflow/template/extractJson.svg'),
|
import('./icons/core/workflow/template/extractJson.svg'),
|
||||||
'core/workflow/template/wiki': () => import('./icons/core/workflow/template/wiki.svg'),
|
|
||||||
'core/workflow/template/datasource': () =>
|
|
||||||
import('./icons/core/workflow/template/datasource.svg'),
|
|
||||||
'core/workflow/template/google': () => import('./icons/core/workflow/template/google.svg'),
|
|
||||||
'core/workflow/template/bing': () => import('./icons/core/workflow/template/bing.svg'),
|
|
||||||
'core/workflow/template/fetchUrl': () => import('./icons/core/workflow/template/fetchUrl.svg'),
|
'core/workflow/template/fetchUrl': () => import('./icons/core/workflow/template/fetchUrl.svg'),
|
||||||
'core/workflow/template/formInput': () => import('./icons/core/workflow/template/formInput.svg'),
|
'core/workflow/template/formInput': () => import('./icons/core/workflow/template/formInput.svg'),
|
||||||
'core/workflow/template/getTime': () => import('./icons/core/workflow/template/getTime.svg'),
|
'core/workflow/template/getTime': () => import('./icons/core/workflow/template/getTime.svg'),
|
||||||
|
'core/workflow/template/google': () => import('./icons/core/workflow/template/google.svg'),
|
||||||
'core/workflow/template/httpRequest': () =>
|
'core/workflow/template/httpRequest': () =>
|
||||||
import('./icons/core/workflow/template/httpRequest.svg'),
|
import('./icons/core/workflow/template/httpRequest.svg'),
|
||||||
'core/workflow/template/ifelse': () => import('./icons/core/workflow/template/ifelse.svg'),
|
'core/workflow/template/ifelse': () => import('./icons/core/workflow/template/ifelse.svg'),
|
||||||
@@ -271,6 +270,7 @@ export const iconPaths = {
|
|||||||
'core/workflow/template/variable': () => import('./icons/core/workflow/template/variable.svg'),
|
'core/workflow/template/variable': () => import('./icons/core/workflow/template/variable.svg'),
|
||||||
'core/workflow/template/variableUpdate': () =>
|
'core/workflow/template/variableUpdate': () =>
|
||||||
import('./icons/core/workflow/template/variableUpdate.svg'),
|
import('./icons/core/workflow/template/variableUpdate.svg'),
|
||||||
|
'core/workflow/template/wiki': () => import('./icons/core/workflow/template/wiki.svg'),
|
||||||
'core/workflow/template/workflowStart': () =>
|
'core/workflow/template/workflowStart': () =>
|
||||||
import('./icons/core/workflow/template/workflowStart.svg'),
|
import('./icons/core/workflow/template/workflowStart.svg'),
|
||||||
'core/workflow/touchTable': () => import('./icons/core/workflow/touchTable.svg'),
|
'core/workflow/touchTable': () => import('./icons/core/workflow/touchTable.svg'),
|
||||||
@@ -280,6 +280,7 @@ export const iconPaths = {
|
|||||||
date: () => import('./icons/date.svg'),
|
date: () => import('./icons/date.svg'),
|
||||||
delete: () => import('./icons/delete.svg'),
|
delete: () => import('./icons/delete.svg'),
|
||||||
drag: () => import('./icons/drag.svg'),
|
drag: () => import('./icons/drag.svg'),
|
||||||
|
edgeAdd: () => import('./icons/edgeAdd.svg'),
|
||||||
edit: () => import('./icons/edit.svg'),
|
edit: () => import('./icons/edit.svg'),
|
||||||
empty: () => import('./icons/empty.svg'),
|
empty: () => import('./icons/empty.svg'),
|
||||||
export: () => import('./icons/export.svg'),
|
export: () => import('./icons/export.svg'),
|
||||||
@@ -302,6 +303,7 @@ export const iconPaths = {
|
|||||||
'file/pdf': () => import('./icons/file/pdf.svg'),
|
'file/pdf': () => import('./icons/file/pdf.svg'),
|
||||||
'file/qaImport': () => import('./icons/file/qaImport.svg'),
|
'file/qaImport': () => import('./icons/file/qaImport.svg'),
|
||||||
'file/uploadFile': () => import('./icons/file/uploadFile.svg'),
|
'file/uploadFile': () => import('./icons/file/uploadFile.svg'),
|
||||||
|
help: () => import('./icons/help.svg'),
|
||||||
history: () => import('./icons/history.svg'),
|
history: () => import('./icons/history.svg'),
|
||||||
infoRounded: () => import('./icons/infoRounded.svg'),
|
infoRounded: () => import('./icons/infoRounded.svg'),
|
||||||
kbTest: () => import('./icons/kbTest.svg'),
|
kbTest: () => import('./icons/kbTest.svg'),
|
||||||
@@ -331,7 +333,6 @@ export const iconPaths = {
|
|||||||
save: () => import('./icons/save.svg'),
|
save: () => import('./icons/save.svg'),
|
||||||
stop: () => import('./icons/stop.svg'),
|
stop: () => import('./icons/stop.svg'),
|
||||||
'support/account/loginoutLight': () => import('./icons/support/account/loginoutLight.svg'),
|
'support/account/loginoutLight': () => import('./icons/support/account/loginoutLight.svg'),
|
||||||
'support/account/passwordLogin': () => import('./icons/support/account/passwordLogin.svg'),
|
|
||||||
'support/account/plans': () => import('./icons/support/account/plans.svg'),
|
'support/account/plans': () => import('./icons/support/account/plans.svg'),
|
||||||
'support/account/promotionLight': () => import('./icons/support/account/promotionLight.svg'),
|
'support/account/promotionLight': () => import('./icons/support/account/promotionLight.svg'),
|
||||||
'support/bill/extraDatasetsize': () => import('./icons/support/bill/extraDatasetsize.svg'),
|
'support/bill/extraDatasetsize': () => import('./icons/support/bill/extraDatasetsize.svg'),
|
||||||
|
|||||||
3
packages/web/components/common/Icon/icons/check.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17 17" fill="none">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.5587 3.69438C13.9492 3.30386 14.5824 3.30386 14.9729 3.69438C15.3634 4.08491 15.3634 4.71807 14.9729 5.1086L7.63956 12.4419C7.24904 12.8325 6.61587 12.8325 6.22535 12.4419L2.89201 9.1086C2.50149 8.71807 2.50149 8.08491 2.89201 7.69438C3.28254 7.30386 3.9157 7.30386 4.30623 7.69438L6.93245 10.3206L13.5587 3.69438Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 452 B |
@@ -1 +1,4 @@
|
|||||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1704259732773" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4183" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M319.20128 974.56128L348.16 1003.52l655.36-655.36-28.95872-28.95872-655.36 655.36zM675.84 1003.52l327.68-327.68-28.95872-28.95872-327.68 327.68L675.84 1003.52z" fill="#000000" p-id="4184"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="9" height="9" viewBox="0 0 9 9" fill="none">
|
||||||
|
<path d="M0.950928 8.44922L8.32385 1.07629" stroke="#8A95A7" stroke-linecap="round"/>
|
||||||
|
<path d="M4.3418 8.46167L8.32373 4.47974" stroke="#8A95A7" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 534 B After Width: | Height: | Size: 272 B |
@@ -1,6 +1,4 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" >
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||||
<path
|
<path d="M4.67391 1.54593C4.67391 1.4286 4.5788 1.3335 4.46148 1.3335C2.77062 1.3335 1.3999 2.70421 1.3999 4.39507V11.6053C1.3999 13.2961 2.77062 14.6668 4.46148 14.6668H11.6717C13.3625 14.6668 14.7332 13.2961 14.7332 11.6053V4.39507C14.7332 2.70421 13.3625 1.3335 11.6717 1.3335H10.1345C9.76634 1.3335 9.46786 1.63197 9.46786 2.00016C9.46786 2.36835 9.76634 2.66683 10.1345 2.66683H11.6717C12.6261 2.66683 13.3999 3.44059 13.3999 4.39507V11.6053C13.3999 12.5597 12.6261 13.3335 11.6717 13.3335H4.46148C3.507 13.3335 2.73324 12.5597 2.73324 11.6053V4.39507C2.73324 3.44059 3.507 2.66683 4.46148 2.66683C4.5788 2.66683 4.67391 2.57172 4.67391 2.4544V1.54593Z"/>
|
||||||
d="M4.25845 0.738983C4.25845 0.606996 4.15146 0.5 4.01947 0.5C2.11725 0.5 0.575195 2.04205 0.575195 3.94428V12.0557C0.575195 13.9579 2.11725 15.5 4.01947 15.5H12.1309C14.0331 15.5 15.5752 13.9579 15.5752 12.0557V3.94428C15.5752 2.04205 14.0331 0.5 12.1309 0.5H10.4017C9.98744 0.5 9.65166 0.835786 9.65166 1.25C9.65166 1.66421 9.98744 2 10.4017 2H12.1309C13.2047 2 14.0752 2.87048 14.0752 3.94428V12.0557C14.0752 13.1295 13.2047 14 12.1309 14H4.01947C2.94568 14 2.0752 13.1295 2.0752 12.0557V3.94428C2.0752 2.87048 2.94568 2 4.01947 2C4.15146 2 4.25845 1.893 4.25845 1.76102V0.738983Z" />
|
<path d="M7.44944 4.75954C7.34354 4.01799 7.12171 3.55235 6.74882 3.28913C5.8613 2.66266 5.20252 2.66685 5.10562 2.66747L5.0992 2.6675H4.43253V1.33416H5.0992C5.33393 1.33416 6.30657 1.34492 7.51773 2.19984C8.33645 2.77775 8.6439 3.69241 8.76938 4.57104C8.87172 5.28764 8.86601 6.09307 8.86075 6.83513C8.85961 6.99546 8.8585 7.15284 8.8585 7.30571C8.8585 7.73778 8.84925 8.14363 8.83559 8.50744L9.39664 7.94639C9.65699 7.68604 10.0791 7.68604 10.3395 7.94639C10.5998 8.20674 10.5998 8.62885 10.3395 8.8892L8.58233 10.6463C8.44087 10.7878 8.25166 10.8524 8.06659 10.8401C7.88151 10.8524 7.6923 10.7878 7.55084 10.6463L5.79372 8.8892C5.53337 8.62885 5.53337 8.20674 5.79372 7.94639C6.05407 7.68604 6.47618 7.68604 6.73653 7.94639L7.41122 8.62109L7.49304 8.7029C7.5115 8.29493 7.52517 7.81934 7.52517 7.30571C7.52517 7.1294 7.52626 6.956 7.52734 6.78569C7.53201 6.04784 7.53631 5.36788 7.44944 4.75954Z"/>
|
||||||
<path
|
|
||||||
d="M7.38092 4.3543C7.26179 3.52006 7.01223 2.99621 6.59273 2.70009C5.59427 1.99531 4.85314 2.00002 4.74413 2.00072L4.7369 2.00075H3.9869V0.500749H4.7369C5.00097 0.500749 6.0952 0.512848 7.45775 1.47464C8.37881 2.12479 8.7247 3.15378 8.86586 4.14224C8.98099 4.94841 8.97457 5.85452 8.96865 6.68934C8.96737 6.86971 8.96612 7.04676 8.96612 7.21874C8.96612 7.70483 8.95571 8.16141 8.94035 8.57069L9.57153 7.93951C9.86442 7.64661 10.3393 7.64661 10.6322 7.93951C10.9251 8.2324 10.9251 8.70727 10.6322 9.00017L8.65543 10.9769C8.49629 11.1361 8.28342 11.2087 8.07521 11.1949C7.86701 11.2087 7.65414 11.1361 7.495 10.9769L5.51824 9.00017C5.22535 8.70727 5.22535 8.2324 5.51824 7.93951C5.81113 7.64661 6.28601 7.64661 6.5789 7.93951L7.33793 8.69854L7.42997 8.79058C7.45074 8.33162 7.46612 7.79657 7.46612 7.21874C7.46612 7.02039 7.46735 6.82532 7.46856 6.63372C7.47382 5.80363 7.47866 5.03868 7.38092 4.3543Z" />
|
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
@@ -1,4 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18" fill="none">
|
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
|
||||||
d="M8.99997 2.196C5.24222 2.196 2.19596 5.24225 2.19596 9C2.19596 12.7577 5.24222 15.804 8.99997 15.804C12.7577 15.804 15.804 12.7577 15.804 9C15.804 5.24225 12.7577 2.196 8.99997 2.196ZM0.529297 9C0.529297 4.32178 4.32174 0.529331 8.99997 0.529331C13.6782 0.529331 17.4706 4.32178 17.4706 9C17.4706 13.6782 13.6782 17.4707 8.99997 17.4707C4.32174 17.4707 0.529297 13.6782 0.529297 9ZM9.18533 6.03224C8.846 5.97403 8.49702 6.0378 8.20019 6.21224C7.90337 6.38669 7.67786 6.66056 7.56361 6.98534C7.41089 7.41949 6.93512 7.64764 6.50097 7.49491C6.06681 7.34218 5.83866 6.86642 5.99139 6.43226C6.23625 5.73619 6.71956 5.14923 7.35572 4.77536C7.99188 4.40148 8.73983 4.26481 9.4671 4.38956C10.1944 4.5143 10.854 4.89241 11.3292 5.45692C11.8043 6.0213 12.0644 6.73558 12.0634 7.4733C12.063 8.67899 11.1697 9.46897 10.5467 9.88431C10.2098 10.1089 9.8788 10.2738 9.63531 10.382C9.51239 10.4367 9.4088 10.4782 9.33398 10.5067C9.2965 10.5209 9.26605 10.532 9.24377 10.54L9.21658 10.5495L9.20781 10.5525L9.20467 10.5535L9.20342 10.554C9.20317 10.554 9.20239 10.5543 8.93887 9.76373L9.20239 10.5543C8.76577 10.6998 8.29384 10.4639 8.1483 10.0273C8.00281 9.59078 8.23857 9.11902 8.67491 8.97331L8.68542 8.9696C8.69671 8.96559 8.71548 8.95878 8.74065 8.94919C8.79114 8.92996 8.86654 8.89986 8.95842 8.85902C9.14454 8.7763 9.38634 8.65481 9.62222 8.49756C10.1447 8.14925 10.3967 7.79388 10.3967 7.47253L10.3967 7.47129C10.3972 7.127 10.2759 6.79364 10.0542 6.53025C9.83245 6.26686 9.52467 6.09044 9.18533 6.03224ZM8.16663 12.8187C8.16663 12.3584 8.53973 11.9853 8.99997 11.9853H9.0076C9.46784 11.9853 9.84094 12.3584 9.84094 12.8187C9.84094 13.2789 9.46784 13.652 9.0076 13.652H8.99997C8.53973 13.652 8.16663 13.2789 8.16663 12.8187Z" />
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -1,4 +1,3 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 17" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" >
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.42475 4.58336C5.1644 4.84371 5.1644 5.26582 5.42475 5.52617C5.6851 5.78652 6.10721 5.78652 6.36756 5.52617L8.00008 3.89366L9.63259 5.52617C9.89294 5.78652 10.315 5.78652 10.5754 5.52617C10.8357 5.26582 10.8357 4.84371 10.5754 4.58336L8.47148 2.47944C8.21113 2.21909 7.78902 2.21909 7.52867 2.47944L5.42475 4.58336ZM5.42475 10.4722C5.1644 10.7325 5.1644 11.1546 5.42475 11.415L7.52867 13.5189C7.56122 13.5514 7.59629 13.5799 7.63325 13.6043C7.89202 13.7752 8.24367 13.7467 8.47148 13.5189L10.5754 11.415C10.8357 11.1546 10.8357 10.7325 10.5754 10.4722C10.315 10.2118 9.89294 10.2118 9.63259 10.4722L8.00008 12.1047L6.36756 10.4722C6.10721 10.2118 5.6851 10.2118 5.42475 10.4722Z" />
|
||||||
d="M5.42469 4.94872C5.16434 5.20906 5.16434 5.63117 5.42469 5.89152C5.68504 6.15187 6.10715 6.15187 6.3675 5.89152L8.00002 4.25901L9.63253 5.89152C9.89288 6.15187 10.315 6.15187 10.5753 5.89152C10.8357 5.63117 10.8357 5.20906 10.5753 4.94872L8.47142 2.8448C8.21107 2.58445 7.78896 2.58445 7.52861 2.8448L5.42469 4.94872ZM5.42469 10.8375C5.16434 11.0979 5.16434 11.52 5.42469 11.7803L7.52861 13.8843C7.56115 13.9168 7.59623 13.9453 7.63319 13.9697C7.89196 14.1405 8.24361 14.1121 8.47142 13.8843L10.5753 11.7803C10.8357 11.52 10.8357 11.0979 10.5753 10.8375C10.315 10.5772 9.89288 10.5772 9.63253 10.8375L8.00002 12.47L6.3675 10.8375C6.10715 10.5772 5.68504 10.5772 5.42469 10.8375Z" />
|
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 823 B After Width: | Height: | Size: 804 B |
@@ -1,11 +1,10 @@
|
|||||||
<svg viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<rect width="36" height="36" fill="url(#paint0_linear_10832_16007)"/>
|
<rect width="36" height="36" fill="url(#paint0_linear_11_1507)"/>
|
||||||
<path d="M13.9673 10.3122C13.1868 10.8479 13.1935 11.9491 13.863 12.6185C14.3986 13.1541 15.2613 13.1384 15.9008 12.7325C16.5477 12.3219 17.268 12.0318 18.0272 11.8808C19.2374 11.6401 20.4919 11.7636 21.6319 12.2358C22.7719 12.708 23.7463 13.5077 24.4318 14.5337C25.1174 15.5597 25.4833 16.7659 25.4833 17.9999C25.4833 19.2338 25.1174 20.4401 24.4318 21.4661C23.7463 22.4921 22.7719 23.2917 21.6319 23.7639C20.4919 24.2361 19.2374 24.3597 18.0272 24.119C17.268 23.968 16.5477 23.6779 15.9008 23.2673C15.2613 22.8614 14.3986 22.8457 13.863 23.3812C13.1935 24.0507 13.1868 25.1518 13.9673 25.6876C15.0044 26.3995 16.1799 26.8976 17.4252 27.1453C19.234 27.5051 21.1088 27.3204 22.8127 26.6147C24.5165 25.9089 25.9728 24.7138 26.9974 23.1803C28.022 21.6469 28.5689 19.8441 28.5689 17.9999C28.5689 16.1557 28.022 14.3528 26.9974 12.8194C25.9728 11.286 24.5165 10.0908 22.8127 9.38509C21.1088 8.67933 19.234 8.49468 17.4252 8.85447C16.1799 9.10217 15.0044 9.60029 13.9673 10.3122Z" fill="white"/>
|
<path d="M9.22505 16.905C8.38096 17.102 7.87904 17.9714 8.13047 18.8009L9.96306 24.8467C10.3439 26.1032 12.0411 26.2986 12.6976 25.1616L13.5842 23.6259C15.0589 24.1044 16.6267 24.2674 18.1843 24.0937C20.4842 23.8372 22.6439 22.8596 24.3544 21.301C26.0649 19.7424 27.2384 17.6826 27.7071 15.4164C28.074 13.6422 27.9941 11.8127 27.4853 10.0898C27.2506 9.29527 26.3514 8.96094 25.5963 9.30173L23.6663 10.1728C22.9113 10.5136 22.597 11.404 22.7351 12.2208C22.8554 12.9325 22.8437 13.6647 22.6957 14.38C22.4458 15.5886 21.8199 16.6872 20.9077 17.5184C19.9954 18.3497 18.8436 18.871 17.617 19.0078C17.1616 19.0586 16.7045 19.0555 16.2549 19.0002L17.0171 17.6799C17.6736 16.5428 16.6558 15.1707 15.3772 15.4692L9.22505 16.905Z" fill="white"/>
|
||||||
<path d="M19.2443 22.5497C17.3579 22.5497 15.7397 21.4017 15.0501 19.7663H9.19726C8.22171 19.7663 7.43087 18.9754 7.43087 17.9999C7.43087 17.0243 8.22171 16.2335 9.19726 16.2335H15.0501C15.7397 14.598 17.3579 13.45 19.2443 13.45C21.7571 13.45 23.7942 15.4871 23.7942 17.9999C23.7942 20.5127 21.7571 22.5497 19.2443 22.5497Z" fill="white"/>
|
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id="paint0_linear_10832_16007" x1="18" y1="0" x2="5.5" y2="33" gradientUnits="userSpaceOnUse">
|
<linearGradient id="paint0_linear_11_1507" x1="18" y1="0" x2="5.5" y2="33" gradientUnits="userSpaceOnUse">
|
||||||
<stop stop-color="#68C0FF"/>
|
<stop stop-color="#FF8BFD"/>
|
||||||
<stop offset="1" stop-color="#52A2FF"/>
|
<stop offset="1" stop-color="#7394FF"/>
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -1,11 +1,10 @@
|
|||||||
<svg viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<rect width="36" height="36" fill="url(#paint0_linear_10829_15860)"/>
|
<rect width="36" height="36" fill="url(#paint0_linear_11_1494)"/>
|
||||||
<path d="M22.0325 10.3122C22.813 10.8479 22.8062 11.9491 22.1368 12.6185C21.6012 13.1541 20.7384 13.1384 20.099 12.7325C19.4521 12.3219 18.7317 12.0318 17.9726 11.8808C16.7623 11.6401 15.5079 11.7636 14.3679 12.2358C13.2279 12.708 12.2535 13.5077 11.5679 14.5337C10.8824 15.5597 10.5165 16.7659 10.5165 17.9999C10.5165 19.2338 10.8824 20.4401 11.5679 21.4661C12.2535 22.4921 13.2279 23.2917 14.3679 23.7639C15.5079 24.2361 16.7624 24.3597 17.9726 24.119C18.7317 23.968 19.4521 23.6779 20.099 23.2673C20.7384 22.8614 21.6012 22.8457 22.1368 23.3812C22.8062 24.0507 22.813 25.1518 22.0325 25.6876C20.9954 26.3995 19.8199 26.8976 18.5746 27.1453C16.7658 27.5051 14.8909 27.3204 13.1871 26.6147C11.4832 25.9089 10.0269 24.7138 9.00232 23.1803C7.97772 21.6469 7.43085 19.8441 7.43085 17.9999C7.43085 16.1557 7.97772 14.3528 9.00232 12.8194C10.0269 11.286 11.4832 10.0908 13.1871 9.38509C14.8909 8.67933 16.7658 8.49468 18.5746 8.85447C19.8199 9.10217 20.9954 9.60029 22.0325 10.3122Z" fill="white"/>
|
<path d="M26.7748 18.1758C27.6189 17.9788 28.1208 17.1095 27.8693 16.2799L26.0368 10.2341C25.6559 8.97762 23.9587 8.7822 23.3022 9.91926L22.4156 11.4549C20.9409 10.9764 19.3731 10.8134 17.8155 10.9871C15.5157 11.2437 13.3559 12.2212 11.6454 13.7798C9.93493 15.3384 8.76137 17.3983 8.29272 19.6644C7.92581 21.4386 8.00571 23.2681 8.51454 24.991C8.74918 25.7855 9.64845 26.1199 10.4035 25.7791L12.3335 24.908C13.0886 24.5672 13.4028 23.6768 13.2647 22.86C13.1444 22.1483 13.1562 21.4161 13.3041 20.7008C13.554 19.4922 14.1799 18.3936 15.0922 17.5624C16.0044 16.7311 17.1562 16.2098 18.3828 16.073C18.8382 16.0222 19.2953 16.0254 19.7449 16.0807L18.9827 17.4009C18.3262 18.538 19.344 19.9101 20.6226 19.6117L26.7748 18.1758Z" fill="white"/>
|
||||||
<path d="M16.7554 22.5497C18.6418 22.5497 20.2601 21.4017 20.9497 19.7663H26.8025C27.778 19.7663 28.5689 18.9754 28.5689 17.9999C28.5689 17.0243 27.778 16.2335 26.8025 16.2335H20.9497C20.2601 14.598 18.6418 13.45 16.7554 13.45C14.2426 13.45 12.2056 15.4871 12.2056 17.9999C12.2056 20.5127 14.2426 22.5497 16.7554 22.5497Z" fill="white"/>
|
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id="paint0_linear_10829_15860" x1="18" y1="0" x2="5.5" y2="33" gradientUnits="userSpaceOnUse">
|
<linearGradient id="paint0_linear_11_1494" x1="18" y1="0" x2="5.5" y2="33" gradientUnits="userSpaceOnUse">
|
||||||
<stop stop-color="#68C0FF"/>
|
<stop stop-color="#FF8BFD"/>
|
||||||
<stop offset="1" stop-color="#52A2FF"/>
|
<stop offset="1" stop-color="#7394FF"/>
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.1 KiB |
3
packages/web/components/common/Icon/icons/edgeAdd.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg viewBox="0 0 10 9" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.09993 1.21182C6.09993 0.604303 5.60744 0.111816 4.99993 0.111816C4.39242 0.111816 3.89993 0.604303 3.89993 1.21182L3.89993 3.11182H1.9999C1.39239 3.11182 0.899902 3.6043 0.899902 4.21182C0.899902 4.81933 1.39239 5.31182 1.9999 5.31182H3.89993L3.89993 7.21182C3.89993 7.81933 4.39242 8.31182 4.99993 8.31182C5.60744 8.31182 6.09993 7.81933 6.09993 7.21182V5.31182H7.9999C8.60742 5.31182 9.0999 4.81933 9.0999 4.21182C9.0999 3.6043 8.60742 3.11182 7.9999 3.11182H6.09993V1.21182Z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 603 B |
3
packages/web/components/common/Icon/icons/help.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.99968 2.55678C4.99348 2.55678 2.55648 4.99379 2.55648 7.99998C2.55648 11.0062 4.99348 13.4432 7.99968 13.4432C11.0059 13.4432 13.4429 11.0062 13.4429 7.99998C13.4429 4.99379 11.0059 2.55678 7.99968 2.55678ZM1.22314 7.99998C1.22314 4.25741 4.2571 1.22345 7.99968 1.22345C11.7423 1.22345 14.7762 4.25741 14.7762 7.99998C14.7762 11.7426 11.7423 14.7765 7.99968 14.7765C4.2571 14.7765 1.22314 11.7426 1.22314 7.99998ZM8.14797 5.62577C7.87651 5.57921 7.59732 5.63022 7.35986 5.76978C7.1224 5.90934 6.942 6.12843 6.8506 6.38825C6.72842 6.73558 6.34781 6.9181 6.00048 6.79591C5.65315 6.67373 5.47064 6.29312 5.59282 5.9458C5.78871 5.38894 6.17536 4.91937 6.68428 4.62027C7.19321 4.32117 7.79157 4.21184 8.37338 4.31163C8.9552 4.41143 9.48292 4.71392 9.86308 5.16552C10.2432 5.61702 10.4512 6.18845 10.4504 6.77862C10.4501 7.74318 9.73548 8.37516 9.23708 8.70743C8.96754 8.88713 8.70274 9.01905 8.50796 9.10562C8.40962 9.14933 8.32674 9.18252 8.26689 9.20532C8.23691 9.21674 8.21254 9.22562 8.19473 9.23195L8.17297 9.23957L8.16595 9.24197L8.16345 9.24282L8.16245 9.24315C8.16225 9.24322 8.16162 9.24343 7.9508 8.61097L8.16162 9.24343C7.81232 9.35986 7.43478 9.17109 7.31835 8.82179C7.20195 8.47261 7.39056 8.0952 7.73963 7.97863L7.74805 7.97567C7.75708 7.97246 7.77209 7.96701 7.79223 7.95934C7.83262 7.94395 7.89294 7.91987 7.96644 7.8872C8.11534 7.82103 8.30878 7.72383 8.49748 7.59803C8.91545 7.31938 9.11709 7.03509 9.11709 6.77801L9.1171 6.77702C9.11751 6.50159 9.02042 6.2349 8.84305 6.02419C8.66567 5.81347 8.41944 5.67234 8.14797 5.62577ZM7.33301 11.0549C7.33301 10.6867 7.63149 10.3883 7.99968 10.3883H8.00579C8.37398 10.3883 8.67246 10.6867 8.67246 11.0549C8.67246 11.4231 8.37398 11.7216 8.00579 11.7216H7.99968C7.63149 11.7216 7.33301 11.4231 7.33301 11.0549Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -1,6 +0,0 @@
|
|||||||
<svg t="1709471698048" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4242"
|
|
||||||
width="128" height="128">
|
|
||||||
<path
|
|
||||||
d="M855.158154 945.664H168.999385c-28.081231 0-50.845538-22.843077-50.845539-51.003077V486.833231C118.153846 458.673231 129.457231 433.230769 157.538462 433.230769h708.923076c28.081231 0 39.502769 25.442462 39.50277 53.602462v407.827692c0 28.16-22.764308 51.003077-50.806154 51.003077z m-340.913231-376.595692a99.761231 99.761231 0 0 0-99.603692 99.958154c0 40.251077 23.827692 74.712615 57.974154 90.54523V827.076923a39.384615 39.384615 0 0 0 78.76923 0v-65.417846a99.879385 99.879385 0 0 0 62.424616-92.632615 99.761231 99.761231 0 0 0-99.564308-99.958154z m0.551385-396.524308c-104.841846 0-189.794462 81.329231-197.159385 184.123077H217.718154C229.060923 201.334154 358.321231 78.769231 516.489846 78.769231s287.428923 122.564923 298.732308 277.897846h-103.266462c-7.364923-102.793846-92.317538-184.123077-197.159384-184.123077z"
|
|
||||||
fill="#3B9BF8" p-id="4243"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.0 KiB |
7
packages/web/components/common/Image/MyImage.tsx
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Image, ImageProps } from '@chakra-ui/react';
|
||||||
|
import { getWebReqUrl } from '../../../common/system/utils';
|
||||||
|
const MyImage = (props: ImageProps) => {
|
||||||
|
return <Image {...props} src={getWebReqUrl(props.src)} alt={props.alt || ''} />;
|
||||||
|
};
|
||||||
|
export default React.memo(MyImage);
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { PhotoProvider, PhotoView } from 'react-photo-view';
|
import { PhotoProvider, PhotoView } from 'react-photo-view';
|
||||||
import 'react-photo-view/dist/react-photo-view.css';
|
import 'react-photo-view/dist/react-photo-view.css';
|
||||||
import { Box, Image, ImageProps } from '@chakra-ui/react';
|
import { ImageProps } from '@chakra-ui/react';
|
||||||
import { useSystem } from '../../../hooks/useSystem';
|
import { useSystem } from '../../../hooks/useSystem';
|
||||||
import Loading from '../MyLoading';
|
import Loading from '../MyLoading';
|
||||||
|
import MyImage from './MyImage';
|
||||||
|
|
||||||
const MyPhotoView = ({ ...props }: ImageProps) => {
|
const MyPhotoView = ({ ...props }: ImageProps) => {
|
||||||
const { isPc } = useSystem();
|
const { isPc } = useSystem();
|
||||||
@@ -15,7 +16,7 @@ const MyPhotoView = ({ ...props }: ImageProps) => {
|
|||||||
loadingElement={<Loading fixed={false} />}
|
loadingElement={<Loading fixed={false} />}
|
||||||
>
|
>
|
||||||
<PhotoView src={props.src}>
|
<PhotoView src={props.src}>
|
||||||
<Image cursor={'pointer'} {...props} />
|
<MyImage cursor={'pointer'} {...props} />
|
||||||
</PhotoView>
|
</PhotoView>
|
||||||
</PhotoProvider>
|
</PhotoProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,28 +7,50 @@ import {
|
|||||||
NumberInputProps
|
NumberInputProps
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import MyIcon from '../../Icon';
|
||||||
|
import { UseFormRegister } from 'react-hook-form';
|
||||||
|
|
||||||
type Props = Omit<NumberInputProps, 'onChange'> & {
|
type Props = Omit<NumberInputProps, 'onChange'> & {
|
||||||
onChange: (e?: number) => any;
|
onChange?: (e?: number) => any;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
register?: UseFormRegister<any>;
|
||||||
|
name?: string;
|
||||||
|
bg?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MyNumberInput = (props: Props) => {
|
const MyNumberInput = (props: Props) => {
|
||||||
|
const { register, name, onChange, placeholder, bg, ...restProps } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NumberInput
|
<NumberInput
|
||||||
{...props}
|
{...restProps}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
|
if (!onChange) return;
|
||||||
if (isNaN(Number(e))) {
|
if (isNaN(Number(e))) {
|
||||||
props?.onChange();
|
onChange();
|
||||||
} else {
|
} else {
|
||||||
props?.onChange(Number(e));
|
onChange(Number(e));
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<NumberInputField placeholder={props?.placeholder} />
|
<NumberInputField
|
||||||
|
bg={bg}
|
||||||
|
placeholder={placeholder}
|
||||||
|
{...(register && name
|
||||||
|
? register(name, {
|
||||||
|
required: props.isRequired,
|
||||||
|
min: props.min,
|
||||||
|
max: props.max
|
||||||
|
})
|
||||||
|
: {})}
|
||||||
|
/>
|
||||||
<NumberInputStepper>
|
<NumberInputStepper>
|
||||||
<NumberIncrementStepper />
|
<NumberIncrementStepper>
|
||||||
<NumberDecrementStepper />
|
<MyIcon name={'core/chat/chevronUp'} width={'12px'} />
|
||||||
|
</NumberIncrementStepper>
|
||||||
|
<NumberDecrementStepper>
|
||||||
|
<MyIcon name={'core/chat/chevronDown'} width={'12px'} />
|
||||||
|
</NumberDecrementStepper>
|
||||||
</NumberInputStepper>
|
</NumberInputStepper>
|
||||||
</NumberInput>
|
</NumberInput>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -10,7 +10,14 @@ const FormLabel = ({
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Box color={'myGray.900'} fontSize={'sm'} position={'relative'} flexShrink={0} {...props}>
|
<Box
|
||||||
|
color={'myGray.900'}
|
||||||
|
fontWeight={'medium'}
|
||||||
|
fontSize={'sm'}
|
||||||
|
position={'relative'}
|
||||||
|
flexShrink={0}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
{required && (
|
{required && (
|
||||||
<Box color={'red.600'} position={'absolute'} top={'-4px'} left={'-6px'}>
|
<Box color={'red.600'} position={'absolute'} top={'-4px'} left={'-6px'}>
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import MyIcon from '../Icon';
|
import { Flex, Box, CloseButton, FlexProps } from '@chakra-ui/react';
|
||||||
import { Flex, Image, Box, CloseButton, FlexProps } from '@chakra-ui/react';
|
|
||||||
import { useLoading } from '../../../hooks/useLoading';
|
import { useLoading } from '../../../hooks/useLoading';
|
||||||
|
import Avatar from '../Avatar';
|
||||||
|
|
||||||
type Props = FlexProps & {
|
type Props = FlexProps & {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
@@ -50,15 +50,7 @@ const CustomRightDrawer = ({
|
|||||||
py={'10px'}
|
py={'10px'}
|
||||||
px={5}
|
px={5}
|
||||||
>
|
>
|
||||||
{iconSrc && (
|
{iconSrc && <Avatar mr={3} w={'20px'} src={iconSrc} />}
|
||||||
<>
|
|
||||||
{iconSrc.startsWith('/') ? (
|
|
||||||
<Image mr={3} objectFit={'contain'} alt="" src={iconSrc} w={'20px'} />
|
|
||||||
) : (
|
|
||||||
<MyIcon mr={3} name={iconSrc as any} w={'20px'} />
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<Box flex={'1'} fontSize={'md'}>
|
<Box flex={'1'} fontSize={'md'}>
|
||||||
{title}
|
{title}
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
Box
|
Box
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { useLoading } from '../../../hooks/useLoading';
|
import { useLoading } from '../../../hooks/useLoading';
|
||||||
|
import Avatar from '../Avatar';
|
||||||
|
|
||||||
type Props = DrawerContentProps & {
|
type Props = DrawerContentProps & {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
@@ -52,15 +53,7 @@ const MyRightDrawer = ({
|
|||||||
py={'10px'}
|
py={'10px'}
|
||||||
px={5}
|
px={5}
|
||||||
>
|
>
|
||||||
{iconSrc && (
|
{iconSrc && <Avatar mr={3} w={'20px'} src={iconSrc} />}
|
||||||
<>
|
|
||||||
{iconSrc.startsWith('/') ? (
|
|
||||||
<Image mr={3} objectFit={'contain'} alt="" src={iconSrc} w={'20px'} />
|
|
||||||
) : (
|
|
||||||
<MyIcon mr={3} name={iconSrc as any} w={'20px'} />
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<Box flex={'1'} fontSize={'md'}>
|
<Box flex={'1'} fontSize={'md'}>
|
||||||
{title}
|
{title}
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -148,7 +148,6 @@ const MyMenu = ({
|
|||||||
color={isOpen ? 'primary.600' : ''}
|
color={isOpen ? 'primary.600' : ''}
|
||||||
w="fit-content"
|
w="fit-content"
|
||||||
p="1"
|
p="1"
|
||||||
bgColor={isOpen ? 'myGray.50' : ''}
|
|
||||||
h="fit-content"
|
h="fit-content"
|
||||||
borderRadius="sm"
|
borderRadius="sm"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import React, { useRef, useCallback, useState } from 'react';
|
import React, { useRef, useCallback, useState, useMemo } from 'react';
|
||||||
import { Button, useDisclosure, Box, Flex, useOutsideClick } from '@chakra-ui/react';
|
import { Button, useDisclosure, Box, Flex, useOutsideClick, Checkbox } from '@chakra-ui/react';
|
||||||
import { ChevronDownIcon } from '@chakra-ui/icons';
|
import { ListItemType, MultipleArraySelectProps, MultipleSelectProps } from './type';
|
||||||
import { MultipleSelectProps } from './type';
|
|
||||||
import EmptyTip from '../EmptyTip';
|
import EmptyTip from '../EmptyTip';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import MyIcon from '../../common/Icon';
|
||||||
|
|
||||||
const MultipleRowSelect = ({
|
export const MultipleRowSelect = ({
|
||||||
placeholder,
|
placeholder,
|
||||||
label,
|
label,
|
||||||
value = [],
|
value = [],
|
||||||
@@ -106,17 +106,25 @@ const MultipleRowSelect = ({
|
|||||||
<Button
|
<Button
|
||||||
justifyContent={'space-between'}
|
justifyContent={'space-between'}
|
||||||
width={'100%'}
|
width={'100%'}
|
||||||
rightIcon={<ChevronDownIcon />}
|
variant={'whitePrimaryOutline'}
|
||||||
variant={'whiteBase'}
|
size={'lg'}
|
||||||
|
fontSize={'sm'}
|
||||||
|
px={3}
|
||||||
|
outline={'none'}
|
||||||
|
rightIcon={<MyIcon name={'core/chat/chevronDown'} w="1rem" color={'myGray.500'} />}
|
||||||
_active={{
|
_active={{
|
||||||
transform: 'none'
|
transform: 'none'
|
||||||
}}
|
}}
|
||||||
{...(isOpen
|
{...(isOpen
|
||||||
? {
|
? {
|
||||||
boxShadow: '0px 0px 4px #A8DBFF',
|
borderColor: 'primary.600',
|
||||||
borderColor: 'primary.500'
|
color: 'primary.700',
|
||||||
|
boxShadow: '0px 0px 0px 2.4px rgba(51, 112, 255, 0.15)'
|
||||||
}
|
}
|
||||||
: {})}
|
: {
|
||||||
|
borderColor: 'myGray.200',
|
||||||
|
boxShadow: 'none'
|
||||||
|
})}
|
||||||
{...styles}
|
{...styles}
|
||||||
onClick={() => (isOpen ? onClose() : onOpenSelect())}
|
onClick={() => (isOpen ? onClose() : onOpenSelect())}
|
||||||
>
|
>
|
||||||
@@ -127,10 +135,194 @@ const MultipleRowSelect = ({
|
|||||||
position={'absolute'}
|
position={'absolute'}
|
||||||
{...(popDirection === 'top'
|
{...(popDirection === 'top'
|
||||||
? {
|
? {
|
||||||
bottom: '45px'
|
transform: 'translateY(-105%)',
|
||||||
|
top: '0'
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
top: '45px'
|
transform: 'translateY(105%)',
|
||||||
|
bottom: '0'
|
||||||
|
})}
|
||||||
|
py={2}
|
||||||
|
bg={'white'}
|
||||||
|
border={'1px solid #fff'}
|
||||||
|
boxShadow={'5'}
|
||||||
|
borderRadius={'md'}
|
||||||
|
zIndex={1}
|
||||||
|
minW={'100%'}
|
||||||
|
w={'max-content'}
|
||||||
|
>
|
||||||
|
<Flex>
|
||||||
|
<RenderList list={list} index={0} />
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const MultipleRowArraySelect = ({
|
||||||
|
placeholder,
|
||||||
|
label,
|
||||||
|
value = [],
|
||||||
|
list,
|
||||||
|
emptyTip,
|
||||||
|
maxH = 300,
|
||||||
|
onSelect,
|
||||||
|
popDirection = 'bottom',
|
||||||
|
styles
|
||||||
|
}: MultipleArraySelectProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
|
|
||||||
|
const [navigationPath, setNavigationPath] = useState<string[]>([]);
|
||||||
|
|
||||||
|
const formatValue = useMemo(() => {
|
||||||
|
return Array.isArray(value) ? value : [];
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
|
// Close when clicking outside
|
||||||
|
useOutsideClick({
|
||||||
|
ref: ref,
|
||||||
|
handler: onClose
|
||||||
|
});
|
||||||
|
|
||||||
|
const RenderList = useCallback(
|
||||||
|
({ index, list }: { index: number; list: MultipleSelectProps['list'] }) => {
|
||||||
|
const currentNavValue = navigationPath[index];
|
||||||
|
const selectedIndex = list.findIndex((item) => item.value === currentNavValue);
|
||||||
|
const children = list[selectedIndex]?.children || [];
|
||||||
|
const hasChildren = list.some((item) => item.children && item.children?.length > 0);
|
||||||
|
|
||||||
|
const handleSelect = (item: ListItemType) => {
|
||||||
|
// Has children, set parent value
|
||||||
|
if (hasChildren) {
|
||||||
|
const newPath = [...navigationPath];
|
||||||
|
newPath[index] = item.value;
|
||||||
|
setNavigationPath(newPath);
|
||||||
|
} else {
|
||||||
|
const parentValue = navigationPath[0];
|
||||||
|
const newValues = [...formatValue];
|
||||||
|
const newValue = [parentValue, item.value];
|
||||||
|
|
||||||
|
if (newValues.some((v) => v[0] === parentValue && v[1] === item.value)) {
|
||||||
|
onSelect(newValues.filter((v) => !(v[0] === parentValue && v[1] === item.value)));
|
||||||
|
} else {
|
||||||
|
onSelect([...newValues, newValue]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box
|
||||||
|
className="nowheel"
|
||||||
|
flex={'1 0 auto'}
|
||||||
|
px={2}
|
||||||
|
borderLeft={index !== 0 ? 'base' : 'none'}
|
||||||
|
maxH={`${maxH}px`}
|
||||||
|
overflowY={'auto'}
|
||||||
|
whiteSpace={'nowrap'}
|
||||||
|
>
|
||||||
|
{list.map((item) => {
|
||||||
|
const isSelected = item.value === currentNavValue;
|
||||||
|
const showCheckbox = !hasChildren;
|
||||||
|
const isChecked =
|
||||||
|
showCheckbox &&
|
||||||
|
formatValue.some((v) => v[1] === item.value && v[0] === navigationPath[0]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
key={item.value}
|
||||||
|
py={2}
|
||||||
|
cursor={'pointer'}
|
||||||
|
px={2}
|
||||||
|
borderRadius={'md'}
|
||||||
|
_hover={{
|
||||||
|
bg: 'primary.50',
|
||||||
|
color: 'primary.600'
|
||||||
|
}}
|
||||||
|
onClick={() => handleSelect(item)}
|
||||||
|
{...(isSelected ? { color: 'primary.600' } : {})}
|
||||||
|
>
|
||||||
|
{showCheckbox && (
|
||||||
|
<Checkbox
|
||||||
|
isChecked={isChecked}
|
||||||
|
icon={<MyIcon name={'common/check'} w={'12px'} />}
|
||||||
|
mr={1}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Box>{item.label}</Box>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
{list.length === 0 && (
|
||||||
|
<EmptyTip
|
||||||
|
text={emptyTip ?? t('common:common.MultipleRowSelect.No data')}
|
||||||
|
pt={1}
|
||||||
|
pb={3}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
{children.length > 0 && <RenderList list={children} index={index + 1} />}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[navigationPath, formatValue, onSelect]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onOpenSelect = useCallback(() => {
|
||||||
|
setNavigationPath([]);
|
||||||
|
onOpen();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box ref={ref} position={'relative'}>
|
||||||
|
<Button
|
||||||
|
width={'100%'}
|
||||||
|
variant={'whitePrimaryOutline'}
|
||||||
|
size={'lg'}
|
||||||
|
fontSize={'sm'}
|
||||||
|
px={3}
|
||||||
|
outline={'none'}
|
||||||
|
rightIcon={<MyIcon name={'core/chat/chevronDown'} w="1rem" color={'myGray.500'} />}
|
||||||
|
iconSpacing={2}
|
||||||
|
h={'auto'}
|
||||||
|
_active={{
|
||||||
|
transform: 'none'
|
||||||
|
}}
|
||||||
|
_hover={{
|
||||||
|
borderColor: 'primary.500'
|
||||||
|
}}
|
||||||
|
{...(isOpen
|
||||||
|
? {
|
||||||
|
borderColor: 'primary.600',
|
||||||
|
color: 'primary.700',
|
||||||
|
boxShadow: '0px 0px 0px 2.4px rgba(51, 112, 255, 0.15)'
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
borderColor: 'myGray.200',
|
||||||
|
boxShadow: 'none'
|
||||||
|
})}
|
||||||
|
{...styles}
|
||||||
|
onClick={() => (isOpen ? onClose() : onOpenSelect())}
|
||||||
|
className="nowheel"
|
||||||
|
>
|
||||||
|
<Box w={'100%'} textAlign={'left'}>
|
||||||
|
{label ?? placeholder}
|
||||||
|
</Box>
|
||||||
|
</Button>
|
||||||
|
{isOpen && (
|
||||||
|
<Box
|
||||||
|
position={'absolute'}
|
||||||
|
{...(popDirection === 'top'
|
||||||
|
? {
|
||||||
|
transform: 'translateY(-105%)',
|
||||||
|
top: '0'
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
transform: 'translateY(105%)',
|
||||||
|
bottom: '0'
|
||||||
})}
|
})}
|
||||||
py={2}
|
py={2}
|
||||||
bg={'white'}
|
bg={'white'}
|
||||||
|
|||||||
@@ -59,10 +59,11 @@ const MySelect = <T = any,>(
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
_hover: {
|
_hover: {
|
||||||
backgroundColor: 'myWhite.600'
|
backgroundColor: 'myGray.100',
|
||||||
|
color: 'primary.700'
|
||||||
},
|
},
|
||||||
_notLast: {
|
_notLast: {
|
||||||
mb: 2
|
mb: 1
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
@@ -107,16 +108,19 @@ const MySelect = <T = any,>(
|
|||||||
ref={ButtonRef}
|
ref={ButtonRef}
|
||||||
width={width}
|
width={width}
|
||||||
px={3}
|
px={3}
|
||||||
rightIcon={<ChevronDownIcon />}
|
rightIcon={<MyIcon name={'core/chat/chevronDown'} w={4} color={'myGray.500'} />}
|
||||||
variant={'whitePrimary'}
|
variant={'whitePrimaryOutline'}
|
||||||
|
size={'lg'}
|
||||||
|
fontSize={'sm'}
|
||||||
textAlign={'left'}
|
textAlign={'left'}
|
||||||
_active={{
|
_active={{
|
||||||
transform: 'none'
|
transform: 'none'
|
||||||
}}
|
}}
|
||||||
{...(isOpen
|
{...(isOpen
|
||||||
? {
|
? {
|
||||||
boxShadow: '0px 0px 4px #A8DBFF',
|
boxShadow: '0px 0px 0px 2.4px rgba(51, 112, 255, 0.15)',
|
||||||
borderColor: 'primary.500'
|
borderColor: 'primary.600',
|
||||||
|
color: 'primary.700'
|
||||||
}
|
}
|
||||||
: {})}
|
: {})}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -157,7 +161,7 @@ const MySelect = <T = any,>(
|
|||||||
{...(value === item.value
|
{...(value === item.value
|
||||||
? {
|
? {
|
||||||
ref: SelectedItemRef,
|
ref: SelectedItemRef,
|
||||||
color: 'primary.600',
|
color: 'primary.700',
|
||||||
bg: 'myGray.100'
|
bg: 'myGray.100'
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ type ListItemType = {
|
|||||||
value: any;
|
value: any;
|
||||||
children?: ListItemType[];
|
children?: ListItemType[];
|
||||||
};
|
};
|
||||||
export type MultipleSelectProps<T = any> = {
|
export type MultipleSelectProps = {
|
||||||
label?: string | React.ReactNode;
|
label?: string | React.ReactNode;
|
||||||
value: any[];
|
value?: any[];
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
list: ListItemType[];
|
list: ListItemType[];
|
||||||
emptyTip?: string;
|
emptyTip?: string;
|
||||||
@@ -15,3 +15,7 @@ export type MultipleSelectProps<T = any> = {
|
|||||||
styles?: ButtonProps;
|
styles?: ButtonProps;
|
||||||
popDirection?: 'top' | 'bottom';
|
popDirection?: 'top' | 'bottom';
|
||||||
};
|
};
|
||||||
|
export type MultipleArraySelectProps = Omit<MultipleSelectProps, 'value'> & {
|
||||||
|
value?: any[][];
|
||||||
|
onSelect: (val: any[][]) => void;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import MyTooltip from '.';
|
import MyTooltip from '.';
|
||||||
import { IconProps, QuestionOutlineIcon } from '@chakra-ui/icons';
|
import { IconProps } from '@chakra-ui/icons';
|
||||||
|
import MyIcon from '../Icon';
|
||||||
|
|
||||||
type Props = IconProps & {
|
type Props = IconProps & {
|
||||||
label?: string | React.ReactNode;
|
label?: string | React.ReactNode;
|
||||||
@@ -9,7 +10,7 @@ type Props = IconProps & {
|
|||||||
const QuestionTip = ({ label, maxW, ...props }: Props) => {
|
const QuestionTip = ({ label, maxW, ...props }: Props) => {
|
||||||
return (
|
return (
|
||||||
<MyTooltip label={label} maxW={maxW}>
|
<MyTooltip label={label} maxW={maxW}>
|
||||||
<QuestionOutlineIcon w={'0.9rem'} {...props} />
|
<MyIcon name={'help' as any} w={'16px'} color={'myGray.500'} {...props} />
|
||||||
</MyTooltip>
|
</MyTooltip>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -72,11 +72,11 @@ const LightRowTabs = <ValueType = string,>({
|
|||||||
_hover={{
|
_hover={{
|
||||||
color: activeColor
|
color: activeColor
|
||||||
}}
|
}}
|
||||||
|
fontWeight={'medium'}
|
||||||
{...(value === item.value
|
{...(value === item.value
|
||||||
? {
|
? {
|
||||||
color: activeColor,
|
color: activeColor,
|
||||||
cursor: 'default',
|
cursor: 'default',
|
||||||
fontWeight: 'bold',
|
|
||||||
borderBottomColor: activeColor
|
borderBottomColor: activeColor
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ import React, { useCallback, useRef, useState } from 'react';
|
|||||||
import Editor, { Monaco, loader } from '@monaco-editor/react';
|
import Editor, { Monaco, loader } from '@monaco-editor/react';
|
||||||
import { Box, BoxProps } from '@chakra-ui/react';
|
import { Box, BoxProps } from '@chakra-ui/react';
|
||||||
import MyIcon from '../../Icon';
|
import MyIcon from '../../Icon';
|
||||||
|
import { getWebReqUrl } from '../../../../common/system/utils';
|
||||||
|
|
||||||
loader.config({
|
loader.config({
|
||||||
paths: { vs: '/js/monaco-editor.0.45.0/vs' }
|
paths: { vs: getWebReqUrl('/js/monaco-editor.0.45.0/vs') }
|
||||||
});
|
});
|
||||||
|
|
||||||
type EditorVariablePickerType = {
|
type EditorVariablePickerType = {
|
||||||
|
|||||||
@@ -4,9 +4,10 @@ import { Box, BoxProps } from '@chakra-ui/react';
|
|||||||
import MyIcon from '../../Icon';
|
import MyIcon from '../../Icon';
|
||||||
import { useToast } from '../../../../hooks/useToast';
|
import { useToast } from '../../../../hooks/useToast';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import { getWebReqUrl } from '../../../../common/system/utils';
|
||||||
|
|
||||||
loader.config({
|
loader.config({
|
||||||
paths: { vs: '/js/monaco-editor.0.45.0/vs' }
|
paths: { vs: getWebReqUrl('/js/monaco-editor.0.45.0/vs') }
|
||||||
});
|
});
|
||||||
|
|
||||||
type EditorVariablePickerType = {
|
type EditorVariablePickerType = {
|
||||||
|
|||||||
@@ -105,10 +105,10 @@ export default function Editor({
|
|||||||
left={0}
|
left={0}
|
||||||
right={0}
|
right={0}
|
||||||
bottom={0}
|
bottom={0}
|
||||||
py={3}
|
py={2}
|
||||||
px={4}
|
px={3}
|
||||||
pointerEvents={'none'}
|
pointerEvents={'none'}
|
||||||
overflow={'overlay'}
|
overflow={'hidden'}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
color={'myGray.400'}
|
color={'myGray.400'}
|
||||||
@@ -146,12 +146,12 @@ export default function Editor({
|
|||||||
<Box
|
<Box
|
||||||
zIndex={10}
|
zIndex={10}
|
||||||
position={'absolute'}
|
position={'absolute'}
|
||||||
bottom={0}
|
bottom={-1}
|
||||||
right={2}
|
right={2}
|
||||||
cursor={'pointer'}
|
cursor={'pointer'}
|
||||||
onClick={onOpenModal}
|
onClick={onOpenModal}
|
||||||
>
|
>
|
||||||
<MyIcon name={'common/fullScreenLight'} w={'14px'} color={'myGray.600'} />
|
<MyIcon name={'common/fullScreenLight'} w={'14px'} color={'myGray.500'} />
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -9,6 +9,45 @@
|
|||||||
|
|
||||||
font-size: var(--chakra-fontSizes-sm);
|
font-size: var(--chakra-fontSizes-sm);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--chakra-colors-primary-300);
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
color: var(--chakra-colors-myGray-100);
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background-color: var(--chakra-colors-myGray-200) !important;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-thumb:hover {
|
||||||
|
background-color: var(--chakra-colors-myGray-250) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.contentEditable_isFlow {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid var(--chakra-colors-myGray-200);
|
||||||
|
border-radius: var(--chakra-radii-sm);
|
||||||
|
padding: 6px 8px;
|
||||||
|
font-size: var(--chakra-fontSizes-sm);
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--chakra-colors-primary-300);
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
color: var(--chakra-colors-myGray-100);
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background-color: var(--chakra-colors-myGray-200) !important;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-thumb:hover {
|
||||||
|
background-color: var(--chakra-colors-myGray-250) !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.contentEditable:focus {
|
.contentEditable:focus {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Box, Button, ModalBody, ModalFooter, useDisclosure } from '@chakra-ui/react';
|
import { Button, ModalBody, ModalFooter, useDisclosure } from '@chakra-ui/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { editorStateToText } from './utils';
|
import { editorStateToText } from './utils';
|
||||||
import Editor from './Editor';
|
import Editor from './Editor';
|
||||||
|
|||||||
@@ -1,97 +0,0 @@
|
|||||||
import { Box, Button, Image } from '@chakra-ui/react';
|
|
||||||
import { useTranslation } from 'next-i18next';
|
|
||||||
export default function ComfirmVar({
|
|
||||||
newVariables,
|
|
||||||
onCancel,
|
|
||||||
onConfirm
|
|
||||||
}: {
|
|
||||||
newVariables: string[];
|
|
||||||
onCancel: () => void;
|
|
||||||
onConfirm: () => void;
|
|
||||||
}) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Box
|
|
||||||
background={'rgba(35, 56, 118, 0.2)'}
|
|
||||||
rounded={'sm'}
|
|
||||||
position={'absolute'}
|
|
||||||
top={0}
|
|
||||||
left={0}
|
|
||||||
right={0}
|
|
||||||
bottom={0}
|
|
||||||
/>
|
|
||||||
<Box
|
|
||||||
position={'absolute'}
|
|
||||||
top={'50%'}
|
|
||||||
left={'50%'}
|
|
||||||
transform={'translate(-50%, -50%)'}
|
|
||||||
w={'70%'}
|
|
||||||
h={'70%'}
|
|
||||||
bg={'white'}
|
|
||||||
rounded={'lg'}
|
|
||||||
boxShadow={'0 2px 4px rgba(0, 0, 0, 0.1)'}
|
|
||||||
display={'flex'}
|
|
||||||
flexDirection={'column'}
|
|
||||||
justifyContent={'space-between'}
|
|
||||||
pb={4}
|
|
||||||
>
|
|
||||||
<Box display={'flex'} mt={4} mr={4}>
|
|
||||||
<Box
|
|
||||||
w={'36px'}
|
|
||||||
h={'36px'}
|
|
||||||
minW={'36px'}
|
|
||||||
boxShadow={'0 4px 8px rgba(0, 0, 0, 0.1)'}
|
|
||||||
display={'flex'}
|
|
||||||
alignItems={'center'}
|
|
||||||
justifyContent={'center'}
|
|
||||||
rounded={'md'}
|
|
||||||
border={'1px solid rgba(0, 0, 0, 0.1)'}
|
|
||||||
mx={4}
|
|
||||||
>
|
|
||||||
<Image alt={''} src={'/imgs/workflow/variable.png'} objectFit={'contain'} w={'20px'} />
|
|
||||||
</Box>
|
|
||||||
<Box>{t('common:undefined_var')}</Box>
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
ml={16}
|
|
||||||
mt={4}
|
|
||||||
fontSize={'sm'}
|
|
||||||
color={'rgb(28,100,242)'}
|
|
||||||
display={'flex'}
|
|
||||||
whiteSpace={'wrap'}
|
|
||||||
>
|
|
||||||
{newVariables.map((item, index) => (
|
|
||||||
<Box
|
|
||||||
key={index}
|
|
||||||
display={'flex'}
|
|
||||||
alignItems={'center'}
|
|
||||||
justifyContent={'center'}
|
|
||||||
bg={'rgb(237,242,250)'}
|
|
||||||
px={1}
|
|
||||||
h={6}
|
|
||||||
rounded={'md'}
|
|
||||||
mr={2}
|
|
||||||
>
|
|
||||||
<span>
|
|
||||||
<span style={{ opacity: '60%' }}>{`{{`}</span>
|
|
||||||
<span>{item}</span>
|
|
||||||
<span style={{ opacity: '60%' }}>{`}}`}</span>
|
|
||||||
</span>
|
|
||||||
</Box>
|
|
||||||
))}
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Box display={'flex'} justifyContent={'flex-end'} mt={4} mr={4}>
|
|
||||||
<Button size={'sm'} variant={'ghost'} onClick={onCancel}>
|
|
||||||
{t('common:common.Cancel')}
|
|
||||||
</Button>
|
|
||||||
<Button size={'sm'} variant={'primary'} ml={4} onClick={onConfirm}>
|
|
||||||
{t('common:common.Confirm')}
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -150,12 +150,20 @@ const NodeInputSelect = ({
|
|||||||
trigger="click"
|
trigger="click"
|
||||||
Button={
|
Button={
|
||||||
<Button
|
<Button
|
||||||
size={'xs'}
|
leftIcon={
|
||||||
leftIcon={<MyIcon name={renderTypeData.icon as any} w={'0.8rem'} color={'primary.600'} />}
|
<MyIcon name={renderTypeData.icon as any} w={'14px'} color={'primary.600'} mr={-0.5} />
|
||||||
rightIcon={<MyIcon name={'common/select'} w={'0.8rem'} color={'myGray.500'} />}
|
}
|
||||||
|
rightIcon={<MyIcon name={'common/select'} w={'0.8rem'} color={'myGray.500'} ml={-1} />}
|
||||||
variant={'grayBase'}
|
variant={'grayBase'}
|
||||||
border={theme.borders.base}
|
border={theme.borders.base}
|
||||||
borderRadius={'xs'}
|
borderColor={'myGray.200'}
|
||||||
|
borderRadius={'sm'}
|
||||||
|
px={'10px'}
|
||||||
|
py={'6px'}
|
||||||
|
fontSize={'mini'}
|
||||||
|
color={'myGray.600'}
|
||||||
|
h={'28px'}
|
||||||
|
bg={'myGray.100'}
|
||||||
>
|
>
|
||||||
<Box fontWeight={'medium'}>{renderTypeData.title}</Box>
|
<Box fontWeight={'medium'}>{renderTypeData.title}</Box>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
{
|
{
|
||||||
|
"Role_setting": "Role setting",
|
||||||
"Run": "Execute",
|
"Run": "Execute",
|
||||||
|
"Team Tags Set": "Team tags",
|
||||||
|
"Team_Tags": "Team tags",
|
||||||
"ai_settings": "AI Configuration",
|
"ai_settings": "AI Configuration",
|
||||||
"all_apps": "All Applications",
|
"all_apps": "All Applications",
|
||||||
"app.Version name": "Version Name",
|
"app.Version name": "Version Name",
|
||||||
@@ -27,6 +30,7 @@
|
|||||||
"cron.every_month": "Run Monthly",
|
"cron.every_month": "Run Monthly",
|
||||||
"cron.every_week": "Run Weekly",
|
"cron.every_week": "Run Weekly",
|
||||||
"cron.interval": "Run at Intervals",
|
"cron.interval": "Run at Intervals",
|
||||||
|
"dataset_search_tool_description": "Call the \"Semantic Search\" and \"Full-text Search\" capabilities to find reference content that may be related to the problem from the \"Knowledge Base\". \nPrioritize calling this tool to assist in answering user questions.",
|
||||||
"day": "Day",
|
"day": "Day",
|
||||||
"document_quote": "Document Reference",
|
"document_quote": "Document Reference",
|
||||||
"document_quote_tip": "Usually used to accept user-uploaded document content (requires document parsing), and can also be used to reference other string data.",
|
"document_quote_tip": "Usually used to accept user-uploaded document content (requires document parsing), and can also be used to reference other string data.",
|
||||||
@@ -37,6 +41,7 @@
|
|||||||
"export_config_successful": "Configuration copied, some sensitive information automatically filtered. Please check for any remaining sensitive data.",
|
"export_config_successful": "Configuration copied, some sensitive information automatically filtered. Please check for any remaining sensitive data.",
|
||||||
"export_configs": "Export Configurations",
|
"export_configs": "Export Configurations",
|
||||||
"feedback_count": "User Feedback",
|
"feedback_count": "User Feedback",
|
||||||
|
"file_quote_link": "Files",
|
||||||
"file_recover": "File will overwrite current content",
|
"file_recover": "File will overwrite current content",
|
||||||
"file_upload": "File Upload",
|
"file_upload": "File Upload",
|
||||||
"file_upload_tip": "Once enabled, documents/images can be uploaded. Documents are retained for 7 days, images for 15 days. Using this feature may incur additional costs. To ensure a good experience, please choose an AI model with a larger context length when using this feature.",
|
"file_upload_tip": "Once enabled, documents/images can be uploaded. Documents are retained for 7 days, images for 15 days. Using this feature may incur additional costs. To ensure a good experience, please choose an AI model with a larger context length when using this feature.",
|
||||||
@@ -44,7 +49,7 @@
|
|||||||
"go_to_chat": "Go to Conversation",
|
"go_to_chat": "Go to Conversation",
|
||||||
"go_to_run": "Go to Execution",
|
"go_to_run": "Go to Execution",
|
||||||
"image_upload": "Image Upload",
|
"image_upload": "Image Upload",
|
||||||
"image_upload_tip": "Please ensure to select a vision model that can process images.",
|
"image_upload_tip": "How to activate model image recognition capabilities",
|
||||||
"import_configs": "Import Configurations",
|
"import_configs": "Import Configurations",
|
||||||
"import_configs_failed": "Import configuration failed, please ensure the configuration is correct!",
|
"import_configs_failed": "Import configuration failed, please ensure the configuration is correct!",
|
||||||
"import_configs_success": "Import Successful",
|
"import_configs_success": "Import Successful",
|
||||||
@@ -58,7 +63,7 @@
|
|||||||
"intro": "A comprehensive model application orchestration system that offers out-of-the-box data processing and model invocation capabilities. It allows for rapid Dataset construction and workflow orchestration through Flow visualization, enabling complex Dataset scenarios!",
|
"intro": "A comprehensive model application orchestration system that offers out-of-the-box data processing and model invocation capabilities. It allows for rapid Dataset construction and workflow orchestration through Flow visualization, enabling complex Dataset scenarios!",
|
||||||
"llm_not_support_vision": "This model does not support image recognition",
|
"llm_not_support_vision": "This model does not support image recognition",
|
||||||
"llm_use_vision": "Enable Image Recognition",
|
"llm_use_vision": "Enable Image Recognition",
|
||||||
"llm_use_vision_tip": "Once image recognition is enabled, this model will automatically receive images uploaded from the 'dialog box' and image links in 'user questions'.",
|
"llm_use_vision_tip": "After clicking on the model selection, you can see whether the model supports image recognition and the ability to control whether to start image recognition. \nAfter starting image recognition, the model will read the image content in the file link, and if the user question is less than 500 words, it will automatically parse the image in the user question.",
|
||||||
"logs_chat_user": "user",
|
"logs_chat_user": "user",
|
||||||
"logs_empty": "No logs yet~",
|
"logs_empty": "No logs yet~",
|
||||||
"logs_message_total": "Total Messages",
|
"logs_message_total": "Total Messages",
|
||||||
@@ -71,6 +76,7 @@
|
|||||||
"month.unit": "Day",
|
"month.unit": "Day",
|
||||||
"move_app": "Move Application",
|
"move_app": "Move Application",
|
||||||
"not_json_file": "Please select a JSON file",
|
"not_json_file": "Please select a JSON file",
|
||||||
|
"open_vision_function_tip": "Models with icon switches have image recognition capabilities. \nAfter being turned on, the model will parse the pictures in the file link and automatically parse the pictures in the user's question (user question ≤ 500 words).",
|
||||||
"or_drag_JSON": "or drag in JSON file",
|
"or_drag_JSON": "or drag in JSON file",
|
||||||
"paste_config": "Paste Configuration",
|
"paste_config": "Paste Configuration",
|
||||||
"permission.des.manage": "Based on write permissions, you can configure publishing channels, view conversation logs, and assign permissions to the application.",
|
"permission.des.manage": "Based on write permissions, you can configure publishing channels, view conversation logs, and assign permissions to the application.",
|
||||||
@@ -125,14 +131,14 @@
|
|||||||
"type.Simple bot": "Simple App",
|
"type.Simple bot": "Simple App",
|
||||||
"type.Workflow bot": "Workflow",
|
"type.Workflow bot": "Workflow",
|
||||||
"upload_file_max_amount": "Maximum File Quantity",
|
"upload_file_max_amount": "Maximum File Quantity",
|
||||||
"upload_file_max_amount_tip": "1. The maximum number of files that can be uploaded at one time.\n2. The maximum number of files remembered by the chat window: each round of dialogue will automatically retrieve files from history, files beyond the range will be forgotten.",
|
"upload_file_max_amount_tip": "Maximum number of files uploaded in a single round of conversation",
|
||||||
"variable.select type_desc": "You can define a global variable that does not need to be filled in by the user.\n\nThe value of this variable can come from the API interface, the Query of the shared link, or assigned through the [Variable Update] module.",
|
"variable.select type_desc": "You can define a global variable that does not need to be filled in by the user.\n\nThe value of this variable can come from the API interface, the Query of the shared link, or assigned through the [Variable Update] module.",
|
||||||
"variable.textarea_type_desc": "Allows users to input up to 4000 characters in the dialogue box.",
|
"variable.textarea_type_desc": "Allows users to input up to 4000 characters in the dialogue box.",
|
||||||
"version.Revert success": "Revert Successful",
|
"version.Revert success": "Revert Successful",
|
||||||
"version_back": "Revert to Original State",
|
"version_back": "Revert to Original State",
|
||||||
"version_copy": "Duplicate",
|
"version_copy": "Duplicate",
|
||||||
"version_initial_copy": "Duplicate - Original State",
|
"version_initial_copy": "Duplicate - Original State",
|
||||||
"vision_model_title": "Enable Image Recognition",
|
"vision_model_title": "Image recognition ability",
|
||||||
"week.Friday": "Friday",
|
"week.Friday": "Friday",
|
||||||
"week.Monday": "Monday",
|
"week.Monday": "Monday",
|
||||||
"week.Saturday": "Saturday",
|
"week.Saturday": "Saturday",
|
||||||
@@ -149,7 +155,7 @@
|
|||||||
"workflow.read_files": "Document Parsing",
|
"workflow.read_files": "Document Parsing",
|
||||||
"workflow.read_files_result": "Document Parsing Result",
|
"workflow.read_files_result": "Document Parsing Result",
|
||||||
"workflow.read_files_result_desc": "Original document text, consisting of file names and document content, separated by hyphens between multiple files.",
|
"workflow.read_files_result_desc": "Original document text, consisting of file names and document content, separated by hyphens between multiple files.",
|
||||||
"workflow.read_files_tip": "Parse all uploaded documents in the dialogue and return the corresponding document content.",
|
"workflow.read_files_tip": "Parse the documents uploaded in this round of dialogue and return the corresponding document content",
|
||||||
"workflow.select_description": "Description Text",
|
"workflow.select_description": "Description Text",
|
||||||
"workflow.select_description_placeholder": "For example: \nAre there tomatoes in the fridge?",
|
"workflow.select_description_placeholder": "For example: \nAre there tomatoes in the fridge?",
|
||||||
"workflow.select_description_tip": "You can add a description text to explain the meaning of each option to the user.",
|
"workflow.select_description_tip": "You can add a description text to explain the meaning of each option to the user.",
|
||||||
@@ -159,4 +165,4 @@
|
|||||||
"workflow.user_file_input_desc": "Links to documents and images uploaded by users.",
|
"workflow.user_file_input_desc": "Links to documents and images uploaded by users.",
|
||||||
"workflow.user_select": "User Selection",
|
"workflow.user_select": "User Selection",
|
||||||
"workflow.user_select_tip": "This module can configure multiple options for selection during the dialogue. Different options can lead to different workflow branches."
|
"workflow.user_select_tip": "This module can configure multiple options for selection during the dialogue. Different options can lead to different workflow branches."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"AI_input_is_empty": "The content passed to the AI node is empty",
|
||||||
"Delete_all": "Clear All Lexicon",
|
"Delete_all": "Clear All Lexicon",
|
||||||
|
"LLM_model_response_empty": "The model flow response is empty, please check whether the model flow output is normal.",
|
||||||
"chat_history": "Conversation History",
|
"chat_history": "Conversation History",
|
||||||
"chat_input_guide_lexicon_is_empty": "Lexicon not configured yet",
|
"chat_input_guide_lexicon_is_empty": "Lexicon not configured yet",
|
||||||
"citations": "{{num}} References",
|
"citations": "{{num}} References",
|
||||||
@@ -12,6 +14,7 @@
|
|||||||
"contextual_preview": "Contextual Preview {{num}} Items",
|
"contextual_preview": "Contextual Preview {{num}} Items",
|
||||||
"csv_input_lexicon_tip": "Only CSV batch import is supported, click to download the template",
|
"csv_input_lexicon_tip": "Only CSV batch import is supported, click to download the template",
|
||||||
"custom_input_guide_url": "Custom Lexicon URL",
|
"custom_input_guide_url": "Custom Lexicon URL",
|
||||||
|
"dataset_quote_type error": "Knowledge base reference type is wrong, correct type: { datasetId: string }[]",
|
||||||
"delete_all_input_guide_confirm": "Are you sure you want to clear the input guide lexicon?",
|
"delete_all_input_guide_confirm": "Are you sure you want to clear the input guide lexicon?",
|
||||||
"empty_directory": "This directory is empty~",
|
"empty_directory": "This directory is empty~",
|
||||||
"file_amount_over": "Exceeded maximum file quantity {{max}}",
|
"file_amount_over": "Exceeded maximum file quantity {{max}}",
|
||||||
@@ -29,15 +32,18 @@
|
|||||||
"multiple_AI_conversations": "Multiple AI Conversations",
|
"multiple_AI_conversations": "Multiple AI Conversations",
|
||||||
"new_input_guide_lexicon": "New Lexicon",
|
"new_input_guide_lexicon": "New Lexicon",
|
||||||
"no_workflow_response": "No workflow data",
|
"no_workflow_response": "No workflow data",
|
||||||
|
"not_select_file": "No file selected",
|
||||||
"plugins_output": "Plugin Output",
|
"plugins_output": "Plugin Output",
|
||||||
"question_tip": "From top to bottom, the response order of each module",
|
"question_tip": "From top to bottom, the response order of each module",
|
||||||
|
"response.dataset_concat_length": "Combined total",
|
||||||
"response.node_inputs": "Node Inputs",
|
"response.node_inputs": "Node Inputs",
|
||||||
"select": "Select",
|
"select": "Select",
|
||||||
"select_file": "Upload File",
|
"select_file": "Upload File",
|
||||||
"select_file_img": "Upload file / image",
|
"select_file_img": "Upload file / image",
|
||||||
"select_img": "Upload Image",
|
"select_img": "Upload Image",
|
||||||
"stream_output": "Stream Output",
|
"stream_output": "Stream Output",
|
||||||
|
"unsupported_file_type": "Unsupported file types",
|
||||||
"upload": "Upload",
|
"upload": "Upload",
|
||||||
"view_citations": "View References",
|
"view_citations": "View References",
|
||||||
"web_site_sync": "Web Site Sync"
|
"web_site_sync": "Web Site Sync"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,8 +69,12 @@
|
|||||||
"code_error.system_error.community_version_num_limit": "Exceeded Open Source Version Limit, Please Upgrade to Commercial Version: https://tryfastgpt.ai",
|
"code_error.system_error.community_version_num_limit": "Exceeded Open Source Version Limit, Please Upgrade to Commercial Version: https://tryfastgpt.ai",
|
||||||
"code_error.team_error.ai_points_not_enough": "Insufficient AI Points",
|
"code_error.team_error.ai_points_not_enough": "Insufficient AI Points",
|
||||||
"code_error.team_error.app_amount_not_enough": "Application Limit Reached",
|
"code_error.team_error.app_amount_not_enough": "Application Limit Reached",
|
||||||
|
"code_error.team_error.cannot_delete_default_group": "Cannot delete default group",
|
||||||
"code_error.team_error.dataset_amount_not_enough": "Dataset Limit Reached",
|
"code_error.team_error.dataset_amount_not_enough": "Dataset Limit Reached",
|
||||||
"code_error.team_error.dataset_size_not_enough": "Insufficient Dataset Capacity, Please Expand",
|
"code_error.team_error.dataset_size_not_enough": "Insufficient Dataset Capacity, Please Expand",
|
||||||
|
"code_error.team_error.group_name_duplicate": "Duplicate group name",
|
||||||
|
"code_error.team_error.group_name_empty": "Group name cannot be empty",
|
||||||
|
"code_error.team_error.group_not_exist": "Group does not exist",
|
||||||
"code_error.team_error.over_size": "error.team.overSize",
|
"code_error.team_error.over_size": "error.team.overSize",
|
||||||
"code_error.team_error.plugin_amount_not_enough": "Plugin Limit Reached",
|
"code_error.team_error.plugin_amount_not_enough": "Plugin Limit Reached",
|
||||||
"code_error.team_error.re_rank_not_enough": "Unauthorized to Use Re-Rank",
|
"code_error.team_error.re_rank_not_enough": "Unauthorized to Use Re-Rank",
|
||||||
@@ -1115,7 +1119,6 @@
|
|||||||
"tag_list": "Tag List",
|
"tag_list": "Tag List",
|
||||||
"team_tag": "Team Tag",
|
"team_tag": "Team Tag",
|
||||||
"textarea_variable_picker_tip": "Enter \"/\" to select a variable",
|
"textarea_variable_picker_tip": "Enter \"/\" to select a variable",
|
||||||
"undefined_var": "Referenced an undefined variable, add it automatically?",
|
|
||||||
"unit.character": "Character",
|
"unit.character": "Character",
|
||||||
"unit.minute": "Minute",
|
"unit.minute": "Minute",
|
||||||
"unusable_variable": "No Usable Variables",
|
"unusable_variable": "No Usable Variables",
|
||||||
@@ -1200,5 +1203,7 @@
|
|||||||
"user.type": "Type",
|
"user.type": "Type",
|
||||||
"verification": "Verification",
|
"verification": "Verification",
|
||||||
"xx_search_result": "{{key}} Search Results",
|
"xx_search_result": "{{key}} Search Results",
|
||||||
"yes": "Yes"
|
"yes": "Yes",
|
||||||
|
"yesterday": "yesterday",
|
||||||
|
"yesterday_detail_time": "Yesterday {{time}}"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"Array_element": "Array element",
|
"Array_element": "Array element",
|
||||||
|
"Array_element_index": "Index",
|
||||||
"Code": "Code",
|
"Code": "Code",
|
||||||
"Confirm_sync_node": "It will be updated to the latest node configuration and fields that do not exist in the template will be deleted (including all custom fields).\n\nIf the fields are complex, it is recommended that you copy a node first and then update the original node to facilitate parameter copying.",
|
"Confirm_sync_node": "It will be updated to the latest node configuration and fields that do not exist in the template will be deleted (including all custom fields).\n\nIf the fields are complex, it is recommended that you copy a node first and then update the original node to facilitate parameter copying.",
|
||||||
"Node.Open_Node_Course": "Open node course",
|
"Node.Open_Node_Course": "Open node course",
|
||||||
@@ -122,13 +123,15 @@
|
|||||||
"pass_returned_object_as_output_to_next_nodes": "Pass the object returned in the code as output to the next nodes. The variable name needs to correspond to the return key.",
|
"pass_returned_object_as_output_to_next_nodes": "Pass the object returned in the code as output to the next nodes. The variable name needs to correspond to the return key.",
|
||||||
"plugin.Instruction_Tip": "You can configure an instruction to explain the purpose of the plugin. This instruction will be displayed each time the plugin is used. Supports standard Markdown syntax.",
|
"plugin.Instruction_Tip": "You can configure an instruction to explain the purpose of the plugin. This instruction will be displayed each time the plugin is used. Supports standard Markdown syntax.",
|
||||||
"plugin.Instructions": "Instructions",
|
"plugin.Instructions": "Instructions",
|
||||||
|
"plugin.global_file_input": "File links (deprecated)",
|
||||||
|
"plugin_file_abandon_tip": "Plugin global file upload has been deprecated, please adjust it as soon as possible. \nRelated functions can be achieved through plug-in input and adding image type input.",
|
||||||
"plugin_input": "Plugin Input",
|
"plugin_input": "Plugin Input",
|
||||||
"plugin_output_tool": "When the plug-in is executed as a tool, whether this field responds as a result of the tool",
|
"plugin_output_tool": "When the plug-in is executed as a tool, whether this field responds as a result of the tool",
|
||||||
"question_classification": "Question Classification",
|
"question_classification": "Question Classification",
|
||||||
"question_optimization": "Question Optimization",
|
"question_optimization": "Question Optimization",
|
||||||
"quote_content_placeholder": "The structure of the reference content can be customized to better suit different scenarios. \nSome variables can be used for template configuration\n\n{{q}} - main content\n\n{{a}} - auxiliary data\n\n{{source}} - source name\n\n{{sourceId}} - source ID\n\n{{index}} - nth reference",
|
"quote_content_placeholder": "The structure of the reference content can be customized to better suit different scenarios. \nSome variables can be used for template configuration\n\n{{q}} - main content\n\n{{a}} - auxiliary data\n\n{{source}} - source name\n\n{{sourceId}} - source ID\n\n{{index}} - nth reference",
|
||||||
"quote_content_tip": "The structure of the reference content can be customized to better suit different scenarios. Some variables can be used for template configuration:\n\n{{q}} - main content\n{{a}} - auxiliary data\n{{source}} - source name\n{{sourceId}} - source ID\n{{index}} - nth reference\nThey are all optional and the following are the default values:\n\n{{default}}",
|
"quote_content_tip": "The structure of the reference content can be customized to better suit different scenarios. Some variables can be used for template configuration:\n\n{{q}} - main content\n{{a}} - auxiliary data\n{{source}} - source name\n{{sourceId}} - source ID\n{{index}} - nth reference\nThey are all optional and the following are the default values:\n\n{{default}}",
|
||||||
"quote_num": "Quote {{num}}",
|
"quote_num": "Dataset",
|
||||||
"quote_prompt_tip": "You can use {{quote}} to insert a quote content template and {{question}} to insert a question (Role=user).\n\nThe following are the default values:\n\n{{default}}",
|
"quote_prompt_tip": "You can use {{quote}} to insert a quote content template and {{question}} to insert a question (Role=user).\n\nThe following are the default values:\n\n{{default}}",
|
||||||
"quote_role_system_tip": "Please note that the {{question}} variable is removed from the \"Quote Template Prompt Words\"",
|
"quote_role_system_tip": "Please note that the {{question}} variable is removed from the \"Quote Template Prompt Words\"",
|
||||||
"quote_role_user_tip": "Please pay attention to adding the {{question}} variable in the \"Quote Template Prompt Word\"",
|
"quote_role_user_tip": "Please pay attention to adding the {{question}} variable in the \"Quote Template Prompt Word\"",
|
||||||
@@ -190,4 +193,4 @@
|
|||||||
"workflow.Switch_success": "Switch Successful",
|
"workflow.Switch_success": "Switch Successful",
|
||||||
"workflow.Team cloud": "Team Cloud",
|
"workflow.Team cloud": "Team Cloud",
|
||||||
"workflow.exit_tips": "Your changes have not been saved. 'Exit directly' will not save your edits."
|
"workflow.exit_tips": "Your changes have not been saved. 'Exit directly' will not save your edits."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
{
|
{
|
||||||
|
"Role_setting": "权限设置",
|
||||||
"Run": "运行",
|
"Run": "运行",
|
||||||
|
"Team Tags Set": "团队标签",
|
||||||
|
"Team_Tags": "团队标签",
|
||||||
"ai_settings": "AI 配置",
|
"ai_settings": "AI 配置",
|
||||||
"all_apps": "全部应用",
|
"all_apps": "全部应用",
|
||||||
"app.Version name": "版本名称",
|
"app.Version name": "版本名称",
|
||||||
@@ -27,6 +30,7 @@
|
|||||||
"cron.every_month": "每月执行",
|
"cron.every_month": "每月执行",
|
||||||
"cron.every_week": "每周执行",
|
"cron.every_week": "每周执行",
|
||||||
"cron.interval": "间隔执行",
|
"cron.interval": "间隔执行",
|
||||||
|
"dataset_search_tool_description": "调用“语义检索”和“全文检索”能力,从“知识库”中查找可能与问题相关的参考内容。优先调用该工具来辅助回答用户的问题。",
|
||||||
"day": "日",
|
"day": "日",
|
||||||
"document_quote": "文档引用",
|
"document_quote": "文档引用",
|
||||||
"document_quote_tip": "通常用于接受用户上传的文档内容(这需要文档解析),也可以用于引用其他字符串数据。",
|
"document_quote_tip": "通常用于接受用户上传的文档内容(这需要文档解析),也可以用于引用其他字符串数据。",
|
||||||
@@ -37,6 +41,7 @@
|
|||||||
"export_config_successful": "已复制配置,自动过滤部分敏感信息,请注意检查是否仍有敏感数据",
|
"export_config_successful": "已复制配置,自动过滤部分敏感信息,请注意检查是否仍有敏感数据",
|
||||||
"export_configs": "导出配置",
|
"export_configs": "导出配置",
|
||||||
"feedback_count": "用户反馈",
|
"feedback_count": "用户反馈",
|
||||||
|
"file_quote_link": "文件链接",
|
||||||
"file_recover": "文件将覆盖当前内容",
|
"file_recover": "文件将覆盖当前内容",
|
||||||
"file_upload": "文件上传",
|
"file_upload": "文件上传",
|
||||||
"file_upload_tip": "开启后,可以上传文档/图片。文档保留7天,图片保留15天。使用该功能可能产生较多额外费用。为保证使用体验,使用该功能时,请选择上下文长度较大的AI模型。",
|
"file_upload_tip": "开启后,可以上传文档/图片。文档保留7天,图片保留15天。使用该功能可能产生较多额外费用。为保证使用体验,使用该功能时,请选择上下文长度较大的AI模型。",
|
||||||
@@ -44,7 +49,7 @@
|
|||||||
"go_to_chat": "去对话",
|
"go_to_chat": "去对话",
|
||||||
"go_to_run": "去运行",
|
"go_to_run": "去运行",
|
||||||
"image_upload": "图片上传",
|
"image_upload": "图片上传",
|
||||||
"image_upload_tip": "请确保选择可处理图片的视觉模型",
|
"image_upload_tip": "如何启动模型图片识别能力",
|
||||||
"import_configs": "导入配置",
|
"import_configs": "导入配置",
|
||||||
"import_configs_failed": "导入配置失败,请确保配置正常!",
|
"import_configs_failed": "导入配置失败,请确保配置正常!",
|
||||||
"import_configs_success": "导入成功",
|
"import_configs_success": "导入成功",
|
||||||
@@ -57,8 +62,8 @@
|
|||||||
"interval.per_hour": "每小时",
|
"interval.per_hour": "每小时",
|
||||||
"intro": "是一个大模型应用编排系统,提供开箱即用的数据处理、模型调用等能力,可以快速的构建知识库并通过 Flow 可视化进行工作流编排,实现复杂的知识库场景!",
|
"intro": "是一个大模型应用编排系统,提供开箱即用的数据处理、模型调用等能力,可以快速的构建知识库并通过 Flow 可视化进行工作流编排,实现复杂的知识库场景!",
|
||||||
"llm_not_support_vision": "该模型不支持图片识别",
|
"llm_not_support_vision": "该模型不支持图片识别",
|
||||||
"llm_use_vision": "启用图片识别",
|
"llm_use_vision": "图片识别",
|
||||||
"llm_use_vision_tip": "启用图片识别后,该模型会自动接收来自“对话框上传”的图片,以及“用户问题”中的图片链接。",
|
"llm_use_vision_tip": "点击模型选择后,可以看到模型是否支持图片识别以及控制是否启动图片识别的能力。启动图片识别后,模型会读取文件链接里图片内容,并且如果用户问题少于 500 字,会自动解析用户问题中的图片。",
|
||||||
"logs_chat_user": "使用者",
|
"logs_chat_user": "使用者",
|
||||||
"logs_empty": "还没有日志噢~",
|
"logs_empty": "还没有日志噢~",
|
||||||
"logs_message_total": "消息总数",
|
"logs_message_total": "消息总数",
|
||||||
@@ -69,9 +74,10 @@
|
|||||||
"module.type": "\"{{type}}\"类型\n{{description}}",
|
"module.type": "\"{{type}}\"类型\n{{description}}",
|
||||||
"modules.Title is required": "模块名不能为空",
|
"modules.Title is required": "模块名不能为空",
|
||||||
"month.unit": "号",
|
"month.unit": "号",
|
||||||
"move_app": "移动应用",
|
|
||||||
"move.hint": "移动后,所选应用/文件夹将继承新文件夹的权限设置,原先的权限设置失效。",
|
"move.hint": "移动后,所选应用/文件夹将继承新文件夹的权限设置,原先的权限设置失效。",
|
||||||
|
"move_app": "移动应用",
|
||||||
"not_json_file": "请选择JSON文件",
|
"not_json_file": "请选择JSON文件",
|
||||||
|
"open_vision_function_tip": "有图示开关的模型即拥有图片识别能力。若开启,模型会解析文件链接里的图片,并自动解析用户问题中的图片(用户问题≤500字时生效)。",
|
||||||
"or_drag_JSON": "或拖入JSON文件",
|
"or_drag_JSON": "或拖入JSON文件",
|
||||||
"paste_config": "粘贴配置",
|
"paste_config": "粘贴配置",
|
||||||
"permission.des.manage": "写权限基础上,可配置发布渠道、查看对话日志、分配该应用权限",
|
"permission.des.manage": "写权限基础上,可配置发布渠道、查看对话日志、分配该应用权限",
|
||||||
@@ -126,14 +132,14 @@
|
|||||||
"type.Simple bot": "简易应用",
|
"type.Simple bot": "简易应用",
|
||||||
"type.Workflow bot": "工作流",
|
"type.Workflow bot": "工作流",
|
||||||
"upload_file_max_amount": "最大文件数量",
|
"upload_file_max_amount": "最大文件数量",
|
||||||
"upload_file_max_amount_tip": "1.单次上传文件的最大数量。\n2.对话窗口记忆的最大文件数量:每轮对话会自动获取历史中的文件,超出范围的文件会被遗忘。",
|
"upload_file_max_amount_tip": "单轮对话中最大上传文件数量",
|
||||||
"variable.select type_desc": "可以为工作流定义全局变量,常用临时缓存。赋值的方式包括:\n1. 从对话页面的 query 参数获取。\n2. 通过 API 的 variables 对象传递。\n3. 通过【变量更新】节点进行赋值。",
|
"variable.select type_desc": "可以为工作流定义全局变量,常用临时缓存。赋值的方式包括:\n1. 从对话页面的 query 参数获取。\n2. 通过 API 的 variables 对象传递。\n3. 通过【变量更新】节点进行赋值。",
|
||||||
"variable.textarea_type_desc": "允许用户最多输入4000字的对话框。",
|
"variable.textarea_type_desc": "允许用户最多输入4000字的对话框。",
|
||||||
"version.Revert success": "回滚成功",
|
"version.Revert success": "回滚成功",
|
||||||
"version_back": "回到初始状态",
|
"version_back": "回到初始状态",
|
||||||
"version_copy": "副本",
|
"version_copy": "副本",
|
||||||
"version_initial_copy": "副本-初始状态",
|
"version_initial_copy": "副本-初始状态",
|
||||||
"vision_model_title": "启用图片识别",
|
"vision_model_title": "图片识别能力",
|
||||||
"week.Friday": "星期五",
|
"week.Friday": "星期五",
|
||||||
"week.Monday": "星期一",
|
"week.Monday": "星期一",
|
||||||
"week.Saturday": "星期六",
|
"week.Saturday": "星期六",
|
||||||
@@ -150,7 +156,7 @@
|
|||||||
"workflow.read_files": "文档解析",
|
"workflow.read_files": "文档解析",
|
||||||
"workflow.read_files_result": "文档解析结果",
|
"workflow.read_files_result": "文档解析结果",
|
||||||
"workflow.read_files_result_desc": "文档原文,由文件名和文档内容组成,多个文件之间通过横线隔开。",
|
"workflow.read_files_result_desc": "文档原文,由文件名和文档内容组成,多个文件之间通过横线隔开。",
|
||||||
"workflow.read_files_tip": "解析对话中所有上传的文档,并返回对应文档内容",
|
"workflow.read_files_tip": "解析本轮对话上传的文档,并返回对应文档内容",
|
||||||
"workflow.select_description": "说明文字",
|
"workflow.select_description": "说明文字",
|
||||||
"workflow.select_description_placeholder": "例如: \n冰箱里是否有西红柿?",
|
"workflow.select_description_placeholder": "例如: \n冰箱里是否有西红柿?",
|
||||||
"workflow.select_description_tip": "你可以添加一段说明文字,用以向用户说明每个选项代表的含义。",
|
"workflow.select_description_tip": "你可以添加一段说明文字,用以向用户说明每个选项代表的含义。",
|
||||||
@@ -160,4 +166,4 @@
|
|||||||
"workflow.user_file_input_desc": "用户上传的文档和图片链接",
|
"workflow.user_file_input_desc": "用户上传的文档和图片链接",
|
||||||
"workflow.user_select": "用户选择",
|
"workflow.user_select": "用户选择",
|
||||||
"workflow.user_select_tip": "该模块可配置多个选项,以供对话时选择。不同选项可导向不同工作流支线"
|
"workflow.user_select_tip": "该模块可配置多个选项,以供对话时选择。不同选项可导向不同工作流支线"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"AI_input_is_empty": "传入AI 节点的内容为空",
|
||||||
"Delete_all": "清空词库",
|
"Delete_all": "清空词库",
|
||||||
|
"LLM_model_response_empty": "模型流响应为空,请检查模型流输出是否正常",
|
||||||
"chat_history": "聊天记录",
|
"chat_history": "聊天记录",
|
||||||
"chat_input_guide_lexicon_is_empty": "还没有配置词库",
|
"chat_input_guide_lexicon_is_empty": "还没有配置词库",
|
||||||
"citations": "{{num}}条引用",
|
"citations": "{{num}}条引用",
|
||||||
@@ -12,6 +14,7 @@
|
|||||||
"contextual_preview": "上下文预览 {{num}} 条",
|
"contextual_preview": "上下文预览 {{num}} 条",
|
||||||
"csv_input_lexicon_tip": "仅支持 CSV 批量导入,点击下载模板",
|
"csv_input_lexicon_tip": "仅支持 CSV 批量导入,点击下载模板",
|
||||||
"custom_input_guide_url": "自定义词库地址",
|
"custom_input_guide_url": "自定义词库地址",
|
||||||
|
"dataset_quote_type error": "知识库引用类型错误,正确类型:{ datasetId: string }[]",
|
||||||
"delete_all_input_guide_confirm": "确定要清空输入引导词库吗?",
|
"delete_all_input_guide_confirm": "确定要清空输入引导词库吗?",
|
||||||
"empty_directory": "这个目录已经没东西可选了~",
|
"empty_directory": "这个目录已经没东西可选了~",
|
||||||
"file_amount_over": "超出最大文件数量 {{max}}",
|
"file_amount_over": "超出最大文件数量 {{max}}",
|
||||||
@@ -29,16 +32,19 @@
|
|||||||
"multiple_AI_conversations": "多组 AI 对话",
|
"multiple_AI_conversations": "多组 AI 对话",
|
||||||
"new_input_guide_lexicon": "新词库",
|
"new_input_guide_lexicon": "新词库",
|
||||||
"no_workflow_response": "没有运行数据",
|
"no_workflow_response": "没有运行数据",
|
||||||
|
"not_select_file": "未选择文件",
|
||||||
"plugins_output": "插件输出",
|
"plugins_output": "插件输出",
|
||||||
"question_tip": "从上到下,为各个模块的响应顺序",
|
"question_tip": "从上到下,为各个模块的响应顺序",
|
||||||
"response.child total points": "子工作流积分消耗",
|
"response.child total points": "子工作流积分消耗",
|
||||||
|
"response.dataset_concat_length": "合并后总数",
|
||||||
"response.node_inputs": "节点输入",
|
"response.node_inputs": "节点输入",
|
||||||
"select": "选择",
|
"select": "选择",
|
||||||
"select_file": "上传文件",
|
"select_file": "上传文件",
|
||||||
"select_file_img": "上传文件/图片",
|
"select_file_img": "上传文件/图片",
|
||||||
"select_img": "上传图片",
|
"select_img": "上传图片",
|
||||||
"stream_output": "流输出",
|
"stream_output": "流输出",
|
||||||
|
"unsupported_file_type": "不支持的文件类型",
|
||||||
"upload": "上传",
|
"upload": "上传",
|
||||||
"view_citations": "查看引用",
|
"view_citations": "查看引用",
|
||||||
"web_site_sync": "Web站点同步"
|
"web_site_sync": "Web站点同步"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,9 @@
|
|||||||
"FAQ.switch_package_a": "套餐使用规则为优先使用更高级的套餐,因此,购买的新套餐若比当前套餐更高级,则新套餐立即生效:否则将继续使用当前套餐。",
|
"FAQ.switch_package_a": "套餐使用规则为优先使用更高级的套餐,因此,购买的新套餐若比当前套餐更高级,则新套餐立即生效:否则将继续使用当前套餐。",
|
||||||
"FAQ.switch_package_q": "是否切换订阅套餐?",
|
"FAQ.switch_package_q": "是否切换订阅套餐?",
|
||||||
"Folder": "文件夹",
|
"Folder": "文件夹",
|
||||||
|
"just_now": "刚刚",
|
||||||
|
"yesterday": "昨天",
|
||||||
|
"yesterday_detail_time": "昨天 {{time}}",
|
||||||
"Login": "登录",
|
"Login": "登录",
|
||||||
"Move": "移动",
|
"Move": "移动",
|
||||||
"Name": "名称",
|
"Name": "名称",
|
||||||
@@ -1122,7 +1125,6 @@
|
|||||||
"tag_list": "标签列表",
|
"tag_list": "标签列表",
|
||||||
"team_tag": "团队标签",
|
"team_tag": "团队标签",
|
||||||
"textarea_variable_picker_tip": "输入\"/\"可选择变量",
|
"textarea_variable_picker_tip": "输入\"/\"可选择变量",
|
||||||
"undefined_var": "引用了未定义的变量,是否自动添加?",
|
|
||||||
"unit.character": "字符",
|
"unit.character": "字符",
|
||||||
"unit.minute": "分钟",
|
"unit.minute": "分钟",
|
||||||
"unusable_variable": "无可用变量",
|
"unusable_variable": "无可用变量",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"Array_element": "数组元素",
|
"Array_element": "数组元素",
|
||||||
|
"Array_element_index": "下标",
|
||||||
"Code": "代码",
|
"Code": "代码",
|
||||||
"Confirm_sync_node": "将会更新至最新的节点配置,不存在模板中的字段将会被删除(包括所有自定义字段)。\n如果字段较为复杂,建议您先复制一份节点,再更新原来的节点,便于参数复制。",
|
"Confirm_sync_node": "将会更新至最新的节点配置,不存在模板中的字段将会被删除(包括所有自定义字段)。\n如果字段较为复杂,建议您先复制一份节点,再更新原来的节点,便于参数复制。",
|
||||||
"Node.Open_Node_Course": "查看节点教程",
|
"Node.Open_Node_Course": "查看节点教程",
|
||||||
@@ -123,13 +124,15 @@
|
|||||||
"pass_returned_object_as_output_to_next_nodes": "将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key",
|
"pass_returned_object_as_output_to_next_nodes": "将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key",
|
||||||
"plugin.Instruction_Tip": "可以配置一段说明,以解释该插件的用途。每次使用插件前,会显示该段说明。支持标准 Markdown 语法。",
|
"plugin.Instruction_Tip": "可以配置一段说明,以解释该插件的用途。每次使用插件前,会显示该段说明。支持标准 Markdown 语法。",
|
||||||
"plugin.Instructions": "使用说明",
|
"plugin.Instructions": "使用说明",
|
||||||
|
"plugin.global_file_input": "文件链接(弃用)",
|
||||||
|
"plugin_file_abandon_tip": "插件全局文件上传已弃用,请尽快调整。可以通过插件输入,添加图片类型输入来实现相关功能。",
|
||||||
"plugin_input": "插件输入",
|
"plugin_input": "插件输入",
|
||||||
"plugin_output_tool": "插件作为工具执行时,该字段是否作为工具响应结果",
|
"plugin_output_tool": "插件作为工具执行时,该字段是否作为工具响应结果",
|
||||||
"question_classification": "问题分类",
|
"question_classification": "问题分类",
|
||||||
"question_optimization": "问题优化",
|
"question_optimization": "问题优化",
|
||||||
"quote_content_placeholder": "可以自定义引用内容的结构,以更好的适配不同场景。可以使用一些变量来进行模板配置\n{{q}} - 主要内容\n{{a}} - 辅助数据\n{{source}} - 来源名\n{{sourceId}} - 来源ID\n{{index}} - 第 n 个引用",
|
"quote_content_placeholder": "可以自定义引用内容的结构,以更好的适配不同场景。可以使用一些变量来进行模板配置\n{{q}} - 主要内容\n{{a}} - 辅助数据\n{{source}} - 来源名\n{{sourceId}} - 来源ID\n{{index}} - 第 n 个引用",
|
||||||
"quote_content_tip": "可以自定义引用内容的结构,以更好的适配不同场景。可以使用一些变量来进行模板配置\n{{q}} - 主要内容\n{{a}} - 辅助数据\n{{source}} - 来源名\n{{sourceId}} - 来源ID\n{{index}} - 第 n 个引用\n他们都是可选的,下面是默认值:\n{{default}}",
|
"quote_content_tip": "可以自定义引用内容的结构,以更好的适配不同场景。可以使用一些变量来进行模板配置\n{{q}} - 主要内容\n{{a}} - 辅助数据\n{{source}} - 来源名\n{{sourceId}} - 来源ID\n{{index}} - 第 n 个引用\n他们都是可选的,下面是默认值:\n{{default}}",
|
||||||
"quote_num": "引用{{num}}",
|
"quote_num": "引用",
|
||||||
"quote_prompt_tip": "可以用 {{quote}} 来插入引用内容模板,使用 {{question}} 来插入问题(Role=user)。\n下面是默认值:\n{{default}}",
|
"quote_prompt_tip": "可以用 {{quote}} 来插入引用内容模板,使用 {{question}} 来插入问题(Role=user)。\n下面是默认值:\n{{default}}",
|
||||||
"quote_role_system_tip": "请注意从“引用模板提示词”中移除 {{question}} 变量",
|
"quote_role_system_tip": "请注意从“引用模板提示词”中移除 {{question}} 变量",
|
||||||
"quote_role_user_tip": "请注意在“引用模板提示词”中添加 {{question}} 变量",
|
"quote_role_user_tip": "请注意在“引用模板提示词”中添加 {{question}} 变量",
|
||||||
@@ -192,4 +195,4 @@
|
|||||||
"workflow.Switch_success": "切换成功",
|
"workflow.Switch_success": "切换成功",
|
||||||
"workflow.Team cloud": "团队云端",
|
"workflow.Team cloud": "团队云端",
|
||||||
"workflow.exit_tips": "您的更改尚未保存,「直接退出」将不会保存您的编辑记录。"
|
"workflow.exit_tips": "您的更改尚未保存,「直接退出」将不会保存您的编辑记录。"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ const Button = defineStyleConfig({
|
|||||||
px: '2',
|
px: '2',
|
||||||
py: '0',
|
py: '0',
|
||||||
h: '24px',
|
h: '24px',
|
||||||
fontWeight: 'normal',
|
minH: '24px',
|
||||||
|
fontWeight: 'medium',
|
||||||
borderRadius: 'sm'
|
borderRadius: 'sm'
|
||||||
},
|
},
|
||||||
xsSquare: {
|
xsSquare: {
|
||||||
@@ -54,24 +55,27 @@ const Button = defineStyleConfig({
|
|||||||
px: '0',
|
px: '0',
|
||||||
py: '0',
|
py: '0',
|
||||||
h: '24px',
|
h: '24px',
|
||||||
|
minH: '24px',
|
||||||
w: '24px',
|
w: '24px',
|
||||||
fontWeight: 'normal',
|
fontWeight: 'medium',
|
||||||
borderRadius: 'sm'
|
borderRadius: 'sm'
|
||||||
},
|
},
|
||||||
sm: {
|
sm: {
|
||||||
fontSize: 'sm',
|
fontSize: 'sm',
|
||||||
px: '3',
|
px: '3',
|
||||||
py: 0,
|
py: 0,
|
||||||
fontWeight: 'normal',
|
fontWeight: 'medium',
|
||||||
h: '30px',
|
h: '30px',
|
||||||
|
minH: '30px',
|
||||||
borderRadius: 'sm'
|
borderRadius: 'sm'
|
||||||
},
|
},
|
||||||
smSquare: {
|
smSquare: {
|
||||||
fontSize: 'sm',
|
fontSize: 'sm',
|
||||||
px: '0',
|
px: '0',
|
||||||
py: 0,
|
py: 0,
|
||||||
fontWeight: 'normal',
|
fontWeight: 'medium',
|
||||||
h: '30px',
|
h: '30px',
|
||||||
|
minH: '30px',
|
||||||
w: '30px',
|
w: '30px',
|
||||||
borderRadius: 'sm'
|
borderRadius: 'sm'
|
||||||
},
|
},
|
||||||
@@ -80,34 +84,38 @@ const Button = defineStyleConfig({
|
|||||||
px: '4',
|
px: '4',
|
||||||
py: 0,
|
py: 0,
|
||||||
h: '34px',
|
h: '34px',
|
||||||
fontWeight: 'normal',
|
minH: '34px',
|
||||||
borderRadius: 'md'
|
fontWeight: 'medium',
|
||||||
|
borderRadius: 'sm'
|
||||||
},
|
},
|
||||||
mdSquare: {
|
mdSquare: {
|
||||||
fontSize: 'sm',
|
fontSize: 'sm',
|
||||||
px: '0',
|
px: '0',
|
||||||
py: 0,
|
py: 0,
|
||||||
h: '34px',
|
h: '34px',
|
||||||
|
minH: '34px',
|
||||||
w: '34px',
|
w: '34px',
|
||||||
fontWeight: 'normal',
|
fontWeight: 'medium',
|
||||||
borderRadius: 'md'
|
borderRadius: 'sm'
|
||||||
},
|
},
|
||||||
lg: {
|
lg: {
|
||||||
fontSize: 'md',
|
fontSize: 'md',
|
||||||
px: '4',
|
px: '4',
|
||||||
py: 0,
|
py: 0,
|
||||||
h: '40px',
|
h: '40px',
|
||||||
fontWeight: 'normal',
|
minH: '40px',
|
||||||
borderRadius: 'lg'
|
fontWeight: 'medium',
|
||||||
|
borderRadius: 'md'
|
||||||
},
|
},
|
||||||
lgSquare: {
|
lgSquare: {
|
||||||
fontSize: 'md',
|
fontSize: 'md',
|
||||||
px: '0',
|
px: '0',
|
||||||
py: 0,
|
py: 0,
|
||||||
h: '40px',
|
h: '40px',
|
||||||
|
minH: '40px',
|
||||||
w: '40px',
|
w: '40px',
|
||||||
fontWeight: 'normal',
|
fontWeight: 'medium',
|
||||||
borderRadius: 'lg'
|
borderRadius: 'md'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
variants: {
|
variants: {
|
||||||
@@ -175,6 +183,16 @@ const Button = defineStyleConfig({
|
|||||||
color: 'myGray.600 !important'
|
color: 'myGray.600 !important'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
whitePrimaryOutline: {
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: 'myGray.250',
|
||||||
|
bg: 'white',
|
||||||
|
transition: 'background 0.1s',
|
||||||
|
_hover: {
|
||||||
|
color: 'primary.600',
|
||||||
|
borderColor: 'primary.300'
|
||||||
|
}
|
||||||
|
},
|
||||||
whitePrimary: {
|
whitePrimary: {
|
||||||
color: 'myGray.600',
|
color: 'myGray.600',
|
||||||
border: '1px solid',
|
border: '1px solid',
|
||||||
@@ -288,12 +306,18 @@ const Input: ComponentStyleConfig = {
|
|||||||
sm: defineStyle({
|
sm: defineStyle({
|
||||||
field: {
|
field: {
|
||||||
h: '32px',
|
h: '32px',
|
||||||
borderRadius: 'md'
|
borderRadius: 'sm'
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
md: defineStyle({
|
md: defineStyle({
|
||||||
field: {
|
field: {
|
||||||
h: '34px',
|
h: '36px',
|
||||||
|
borderRadius: 'sm'
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
lg: defineStyle({
|
||||||
|
field: {
|
||||||
|
h: '40px',
|
||||||
borderRadius: 'md'
|
borderRadius: 'md'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -303,11 +327,15 @@ const Input: ComponentStyleConfig = {
|
|||||||
field: {
|
field: {
|
||||||
border: '1px solid',
|
border: '1px solid',
|
||||||
borderColor: 'borderColor.low',
|
borderColor: 'borderColor.low',
|
||||||
|
px: 3,
|
||||||
_focus: {
|
_focus: {
|
||||||
borderColor: 'primary.500',
|
borderColor: 'primary.500',
|
||||||
boxShadow: shadowLight,
|
boxShadow: shadowLight,
|
||||||
bg: 'white'
|
bg: 'white'
|
||||||
},
|
},
|
||||||
|
_hover: {
|
||||||
|
borderColor: 'primary.300'
|
||||||
|
},
|
||||||
_disabled: {
|
_disabled: {
|
||||||
color: 'myGray.400',
|
color: 'myGray.400',
|
||||||
bg: 'myWhite.300'
|
bg: 'myWhite.300'
|
||||||
@@ -326,14 +354,14 @@ const NumberInput = numInputMultiStyle({
|
|||||||
sm: defineStyle({
|
sm: defineStyle({
|
||||||
field: {
|
field: {
|
||||||
h: '32px',
|
h: '32px',
|
||||||
borderRadius: 'md',
|
borderRadius: 'sm',
|
||||||
fontsize: 'sm'
|
fontsize: 'sm'
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
md: defineStyle({
|
lg: defineStyle({
|
||||||
field: {
|
field: {
|
||||||
h: '40px',
|
h: '40px',
|
||||||
borderRadius: 'md',
|
borderRadius: 'sm',
|
||||||
fontsize: 'sm'
|
fontsize: 'sm'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -347,7 +375,7 @@ const NumberInput = numInputMultiStyle({
|
|||||||
_focus: {
|
_focus: {
|
||||||
borderColor: 'primary.500 !important',
|
borderColor: 'primary.500 !important',
|
||||||
boxShadow: `${shadowLight} !important`,
|
boxShadow: `${shadowLight} !important`,
|
||||||
bg: 'transparent'
|
bg: 'white'
|
||||||
},
|
},
|
||||||
_disabled: {
|
_disabled: {
|
||||||
color: 'myGray.400 !important',
|
color: 'myGray.400 !important',
|
||||||
@@ -356,10 +384,12 @@ const NumberInput = numInputMultiStyle({
|
|||||||
},
|
},
|
||||||
stepper: {
|
stepper: {
|
||||||
bg: 'transparent',
|
bg: 'transparent',
|
||||||
border: 'none',
|
|
||||||
color: 'myGray.600',
|
color: 'myGray.600',
|
||||||
_active: {
|
_active: {
|
||||||
color: 'primary.500'
|
color: 'primary.500'
|
||||||
|
},
|
||||||
|
_hover: {
|
||||||
|
bg: 'myGray.100'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -373,16 +403,24 @@ const Textarea: ComponentStyleConfig = {
|
|||||||
variants: {
|
variants: {
|
||||||
outline: {
|
outline: {
|
||||||
border: '1px solid',
|
border: '1px solid',
|
||||||
|
px: 3,
|
||||||
borderRadius: 'md',
|
borderRadius: 'md',
|
||||||
borderColor: 'myGray.200',
|
borderColor: 'myGray.200',
|
||||||
fontSize: 'sm',
|
fontSize: 'sm',
|
||||||
_hover: {
|
_hover: {
|
||||||
borderColor: ''
|
borderColor: 'primary.300'
|
||||||
},
|
},
|
||||||
_focus: {
|
_focus: {
|
||||||
borderColor: 'primary.500',
|
borderColor: 'primary.500',
|
||||||
boxShadow: shadowLight,
|
boxShadow: shadowLight,
|
||||||
bg: 'white'
|
bg: 'white'
|
||||||
|
},
|
||||||
|
'&::-webkit-resizer': {
|
||||||
|
background: "url('/icon/resizer.svg') no-repeat",
|
||||||
|
backgroundSize: '11px',
|
||||||
|
backgroundPosition: 'right bottom',
|
||||||
|
backgroundPositionX: 'right 12px',
|
||||||
|
backgroundPositionY: 'bottom 12px'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ OPENAI_BASE_URL=https://api.openai.com/v1
|
|||||||
# 通用key。可以是 openai 的也可以是 oneapi 的。
|
# 通用key。可以是 openai 的也可以是 oneapi 的。
|
||||||
# 此处逻辑:优先走 ONEAPI_URL,如果填写了 ONEAPI_URL,key 也需要是 ONEAPI 的 key
|
# 此处逻辑:优先走 ONEAPI_URL,如果填写了 ONEAPI_URL,key 也需要是 ONEAPI 的 key
|
||||||
CHAT_API_KEY=sk-xxxx
|
CHAT_API_KEY=sk-xxxx
|
||||||
|
# 是否将图片转成 base64 传递给模型,本地开发和内网环境使用共有模型时候需要设置为 true
|
||||||
|
MULTIPLE_DATA_TO_BASE64=true
|
||||||
|
|
||||||
# mongo 数据库连接参数,本地开发连接远程数据库时,可能需要增加 directConnection=true 参数,才能连接上。
|
# mongo 数据库连接参数,本地开发连接远程数据库时,可能需要增加 directConnection=true 参数,才能连接上。
|
||||||
MONGODB_URI=mongodb://username:password@0.0.0.0:27017/fastgpt?authSource=admin
|
MONGODB_URI=mongodb://username:password@0.0.0.0:27017/fastgpt?authSource=admin
|
||||||
|
|
||||||
@@ -32,6 +35,8 @@ SANDBOX_URL=http://localhost:3001
|
|||||||
PRO_URL=
|
PRO_URL=
|
||||||
# 页面的地址,用于自动补全相对路径资源的 domain
|
# 页面的地址,用于自动补全相对路径资源的 domain
|
||||||
FE_DOMAIN=http://localhost:3000
|
FE_DOMAIN=http://localhost:3000
|
||||||
|
# 二级路由,需要打包时候就确定
|
||||||
|
# NEXT_PUBLIC_BASE_URL=/fastai
|
||||||
|
|
||||||
# 日志等级: debug, info, warn, error
|
# 日志等级: debug, info, warn, error
|
||||||
LOG_LEVEL=debug
|
LOG_LEVEL=debug
|
||||||
@@ -41,4 +46,12 @@ STORE_LOG_LEVEL=warn
|
|||||||
# 工作流最大运行次数,避免极端的死循环情况
|
# 工作流最大运行次数,避免极端的死循环情况
|
||||||
WORKFLOW_MAX_RUN_TIMES=500
|
WORKFLOW_MAX_RUN_TIMES=500
|
||||||
# 循环最大运行次数,避免极端的死循环情况
|
# 循环最大运行次数,避免极端的死循环情况
|
||||||
WORKFLOW_MAX_LOOP_TIMES=50
|
WORKFLOW_MAX_LOOP_TIMES=50
|
||||||
|
|
||||||
|
# 对话日志推送服务
|
||||||
|
# # 日志服务地址
|
||||||
|
# CHAT_LOG_URL=http://localhost:8080
|
||||||
|
# # 日志推送间隔
|
||||||
|
# CHAT_LOG_INTERVAL=10000
|
||||||
|
# # 日志来源前缀
|
||||||
|
# SOURCE_ID_PREFIX=fastgpt-
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ ARG proxy
|
|||||||
|
|
||||||
RUN [ -z "$proxy" ] || sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
|
RUN [ -z "$proxy" ] || sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
|
||||||
RUN apk add --no-cache libc6-compat && npm install -g pnpm@9.4.0
|
RUN apk add --no-cache libc6-compat && npm install -g pnpm@9.4.0
|
||||||
# if proxy exists, set proxy
|
|
||||||
RUN [ -z "$proxy" ] || pnpm config set registry https://registry.npmmirror.com
|
|
||||||
|
|
||||||
# copy packages and one project
|
# copy packages and one project
|
||||||
COPY pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
|
COPY pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
|
||||||
@@ -16,13 +14,19 @@ COPY ./projects/app/package.json ./projects/app/package.json
|
|||||||
|
|
||||||
RUN [ -f pnpm-lock.yaml ] || (echo "Lockfile not found." && exit 1)
|
RUN [ -f pnpm-lock.yaml ] || (echo "Lockfile not found." && exit 1)
|
||||||
|
|
||||||
RUN pnpm i
|
# if proxy exists, set proxy
|
||||||
|
RUN if [ -z "$proxy" ]; then \
|
||||||
|
pnpm i; \
|
||||||
|
else \
|
||||||
|
pnpm i --registry=https://registry.npmmirror.com; \
|
||||||
|
fi
|
||||||
|
|
||||||
# --------- builder -----------
|
# --------- builder -----------
|
||||||
FROM node:20.14.0-alpine AS builder
|
FROM node:20.14.0-alpine AS builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
ARG proxy
|
ARG proxy
|
||||||
|
ARG base_url
|
||||||
|
|
||||||
# copy common node_modules and one project node_modules
|
# copy common node_modules and one project node_modules
|
||||||
COPY package.json pnpm-workspace.yaml .npmrc tsconfig.json ./
|
COPY package.json pnpm-workspace.yaml .npmrc tsconfig.json ./
|
||||||
@@ -36,6 +40,7 @@ RUN [ -z "$proxy" ] || sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /
|
|||||||
RUN apk add --no-cache libc6-compat && npm install -g pnpm@9.4.0
|
RUN apk add --no-cache libc6-compat && npm install -g pnpm@9.4.0
|
||||||
|
|
||||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||||
|
ENV NEXT_PUBLIC_BASE_URL=$base_url
|
||||||
RUN pnpm --filter=app build
|
RUN pnpm --filter=app build
|
||||||
|
|
||||||
# --------- runner -----------
|
# --------- runner -----------
|
||||||
@@ -43,6 +48,7 @@ FROM node:20.14.0-alpine AS runner
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
ARG proxy
|
ARG proxy
|
||||||
|
ARG base_url
|
||||||
|
|
||||||
# create user and use it
|
# create user and use it
|
||||||
RUN addgroup --system --gid 1001 nodejs
|
RUN addgroup --system --gid 1001 nodejs
|
||||||
@@ -78,6 +84,7 @@ RUN chown -R nextjs:nodejs /app/data
|
|||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
ENV NEXT_TELEMETRY_DISABLED=1
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
ENV PORT=3000
|
ENV PORT=3000
|
||||||
|
ENV NEXT_PUBLIC_BASE_URL=$base_url
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const isDev = process.env.NODE_ENV === 'development';
|
|||||||
|
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
|
basePath: process.env.NEXT_PUBLIC_BASE_URL,
|
||||||
i18n,
|
i18n,
|
||||||
output: 'standalone',
|
output: 'standalone',
|
||||||
reactStrictMode: isDev ? false : true,
|
reactStrictMode: isDev ? false : true,
|
||||||
|
|||||||
@@ -1,12 +1,37 @@
|
|||||||
<svg width="1041" height="1348" viewBox="0 0 1041 1348" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M340.837 0.33933L681.068 0.338989V0.455643C684.032 0.378397 686.999 0.339702 689.967 0.339702C735.961 0.3397 781.504 9.62899 823.997 27.6772C866.49 45.7254 905.099 72.1791 937.622 105.528C970.144 138.877 995.942 178.467 1013.54 222.04C1031.14 265.612 1040.2 312.312 1040.2 359.474L340.836 359.474L340.836 1347.84C296.157 1347.84 251.914 1338.55 210.636 1320.49C169.357 1302.43 131.85 1275.95 100.257 1242.58C68.6636 1209.21 43.6023 1169.59 26.5041 1125.99C11.3834 1087.43 2.75216 1046.42 0.957956 1004.81H0.605869L0.605897 368.098H0.70363C0.105752 341.831 2.23741 315.443 7.14306 289.411C20.2709 219.745 52.6748 155.754 100.257 105.528C147.839 55.3017 208.462 21.0975 274.461 7.24017C296.426 2.62833 318.657 0.339101 340.837 0.33933Z" fill="url(#paint0_linear_1172_228)"/>
|
<path d="M21.5938 10.9C21.5938 9.45229 21.1475 8.03706 20.3113 6.8333C19.4751 5.62954 18.2866 4.69132 16.8961 4.13729C15.5056 3.58326 13.9755 3.4383 12.4993 3.72075C11.0231 4.00319 9.66715 4.70034 8.60288 5.72406C7.53861 6.74777 6.81384 8.05206 6.52021 9.47199C6.22658 10.8919 6.37728 12.3637 6.95326 13.7013C7.52923 15.0388 8.50462 16.182 9.75606 16.9864C11.0075 17.7907 12.4788 18.22 13.9839 18.22V10.9H21.5938Z" fill="url(#paint0_linear_0_5622)"/>
|
||||||
<path d="M633.639 904.645H513.029V576.37H635.422V576.377C678.161 576.607 720.454 585.093 759.951 601.37C799.997 617.874 836.384 642.064 867.033 672.559C897.683 703.054 921.996 739.257 938.583 779.101C955.171 818.944 963.709 861.648 963.709 904.775H633.639V904.645Z" fill="url(#paint1_linear_1172_228)"/>
|
<path d="M29.6263 10.9C29.6263 9.93877 29.4498 8.98691 29.1069 8.09882C28.764 7.21072 28.2613 6.40377 27.6277 5.72405C26.9941 5.04433 26.2418 4.50515 25.414 4.13729C24.5861 3.76943 23.6987 3.58009 22.8027 3.58009C21.9066 3.58009 21.0192 3.76943 20.1913 4.13729C19.3635 4.50515 18.6112 5.04434 17.9776 5.72406C17.344 6.40378 16.8413 7.21072 16.4984 8.09882C16.1555 8.98692 15.979 9.93877 15.979 10.9L29.6263 10.9Z" fill="url(#paint1_linear_0_5622)"/>
|
||||||
|
<path d="M28.3745 22.634C28.3745 21.8174 28.2342 21.0087 27.9617 20.2543C27.6892 19.4998 27.2898 18.8143 26.7863 18.2368C26.2828 17.6594 25.685 17.2013 25.0272 16.8888C24.3693 16.5763 23.6642 16.4155 22.9521 16.4155V22.634H28.3745Z" fill="url(#paint2_linear_0_5622)"/>
|
||||||
|
<path d="M13.9836 20.3912C12.9843 20.3912 11.9947 20.5635 11.0715 20.8985C10.1482 21.2334 9.30926 21.7242 8.60262 22.3431C7.89597 22.9619 7.33543 23.6966 6.95299 24.5051C6.57056 25.3137 6.37372 26.1803 6.37372 27.0554C6.37372 27.9306 6.57056 28.7972 6.95299 29.6057C7.33543 30.4143 7.89597 31.1489 8.60262 31.7678C9.30926 32.3866 10.1482 32.8775 11.0715 33.2124C11.9947 33.5473 12.9843 33.7197 13.9836 33.7197L13.9836 20.3912Z" fill="url(#paint3_linear_0_5622)"/>
|
||||||
|
<path d="M13.9837 10.6101L13.9837 26.9823L6.3736 26.9823L6.3736 10.6101H13.9837Z" fill="url(#paint4_linear_0_5622)"/>
|
||||||
|
<path d="M23.0327 10.8988L13.8973 10.8988L13.8973 3.58008L23.0327 3.58008V10.8988Z" fill="url(#paint5_linear_0_5622)"/>
|
||||||
|
<path d="M23.0327 22.6316H17.9771V16.4155L23.0327 16.4155V22.6316Z" fill="url(#paint6_linear_0_5622)"/>
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id="paint0_linear_1172_228" x1="520.404" y1="0.338989" x2="520.404" y2="1347.84" gradientUnits="userSpaceOnUse">
|
<linearGradient id="paint0_linear_0_5622" x1="18" y1="3.58008" x2="18" y2="33.7197" gradientUnits="userSpaceOnUse">
|
||||||
<stop stop-color="#326DFF"/>
|
<stop stop-color="#326DFF"/>
|
||||||
<stop offset="1" stop-color="#8EAEFF"/>
|
<stop offset="1" stop-color="#8EAEFF"/>
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
<linearGradient id="paint1_linear_1172_228" x1="738.369" y1="576.37" x2="738.369" y2="904.775" gradientUnits="userSpaceOnUse">
|
<linearGradient id="paint1_linear_0_5622" x1="18" y1="3.58008" x2="18" y2="33.7197" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#326DFF"/>
|
||||||
|
<stop offset="1" stop-color="#8EAEFF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_0_5622" x1="18" y1="3.58008" x2="18" y2="33.7197" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#326DFF"/>
|
||||||
|
<stop offset="1" stop-color="#8EAEFF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint3_linear_0_5622" x1="18" y1="3.58008" x2="18" y2="33.7197" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#326DFF"/>
|
||||||
|
<stop offset="1" stop-color="#8EAEFF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint4_linear_0_5622" x1="18" y1="3.58008" x2="18" y2="33.7197" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#326DFF"/>
|
||||||
|
<stop offset="1" stop-color="#8EAEFF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint5_linear_0_5622" x1="18" y1="3.58008" x2="18" y2="33.7197" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#326DFF"/>
|
||||||
|
<stop offset="1" stop-color="#8EAEFF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint6_linear_0_5622" x1="18" y1="3.58008" x2="18" y2="33.7197" gradientUnits="userSpaceOnUse">
|
||||||
<stop stop-color="#326DFF"/>
|
<stop stop-color="#326DFF"/>
|
||||||
<stop offset="1" stop-color="#8EAEFF"/>
|
<stop offset="1" stop-color="#8EAEFF"/>
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 3.4 KiB |
4
projects/app/public/icon/resizer.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="12" height="11" viewBox="0 0 12 11" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M1.45093 7.94055L8.82385 0.567627" stroke="#8A95A7" stroke-linecap="round"/>
|
||||||
|
<path d="M4.8418 7.953L8.82373 3.97107" stroke="#8A95A7" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 271 B |
|
Before Width: | Height: | Size: 37 KiB |
207
projects/app/public/imgs/app/visionModel.svg
Normal file
|
After Width: | Height: | Size: 48 KiB |