Commit 3ba9c218 by Archer Committed by GitHub

4.8.9 test fix (#2291)

* perf: read file icon

* perf:icon

* fix: i18n

* perf: hide pro api

* perf: upload expired time

* perf: upload file frequency limit

* perf: upload file ux

* perf: input file tip

* perf: qa custom chunk size

* feat: dataset openapi

* fix: auth dataset list

* fix: openapi doc

* perf: zero temperature change to 0.01

* perf: read file prompt

* perf: read file prompt

* perf: free plan tip

* feat: cron job usage
parent 7b388b28
...@@ -531,6 +531,8 @@ data 为集合的 ID。 ...@@ -531,6 +531,8 @@ data 为集合的 ID。
{{< tab tabName="请求示例" >}} {{< tab tabName="请求示例" >}}
{{< markdownify >}} {{< markdownify >}}
使用代码上传时,请注意中文 filename 需要进行 encode 处理,否则容易乱码。
```bash ```bash
curl --location --request POST 'http://localhost:3000/api/core/dataset/collection/create/localFile' \ curl --location --request POST 'http://localhost:3000/api/core/dataset/collection/create/localFile' \
--header 'Authorization: Bearer {{authorization}}' \ --header 'Authorization: Bearer {{authorization}}' \
...@@ -1173,7 +1175,7 @@ curl --location --request PUT 'http://localhost:3000/api/core/dataset/data/updat ...@@ -1173,7 +1175,7 @@ curl --location --request PUT 'http://localhost:3000/api/core/dataset/data/updat
--header 'Authorization: Bearer {{authorization}}' \ --header 'Authorization: Bearer {{authorization}}' \
--header 'Content-Type: application/json' \ --header 'Content-Type: application/json' \
--data-raw '{ --data-raw '{
"id":"65abd4b29d1448617cba61db", "dataId":"65abd4b29d1448617cba61db",
"q":"测试111", "q":"测试111",
"a":"sss", "a":"sss",
"indexes":[ "indexes":[
...@@ -1196,7 +1198,7 @@ curl --location --request PUT 'http://localhost:3000/api/core/dataset/data/updat ...@@ -1196,7 +1198,7 @@ curl --location --request PUT 'http://localhost:3000/api/core/dataset/data/updat
{{< markdownify >}} {{< markdownify >}}
{{% alert icon=" " context="success" %}} {{% alert icon=" " context="success" %}}
- id: 数据的id - dataId: 数据的id
- q: 主要数据(选填) - q: 主要数据(选填)
- a: 辅助数据(选填) - a: 辅助数据(选填)
- indexes: 自定义索引(选填),类型参考`为集合批量添加添加数据`。如果创建时候有自定义索引, - indexes: 自定义索引(选填),类型参考`为集合批量添加添加数据`。如果创建时候有自定义索引,
......
...@@ -38,12 +38,14 @@ curl --location --request POST 'https://{{host}}/api/admin/init/489' \ ...@@ -38,12 +38,14 @@ curl --location --request POST 'https://{{host}}/api/admin/init/489' \
6. 商业版新增 - 知识库搜索节点支持标签过滤和创建时间过滤。 6. 商业版新增 - 知识库搜索节点支持标签过滤和创建时间过滤。
7. 商业版新增 - 转移 App owner 权限。 7. 商业版新增 - 转移 App owner 权限。
8. 新增 - 删除所有对话引导内容。 8. 新增 - 删除所有对话引导内容。
9. 优化 - 对话框信息懒加载,减少网络传输。 9. 新增 - QA 拆分支持自定义 chunk 大小,并优化 gpt4o-mini 拆分时,chunk 太大导致生成内容很少的问题。
10. 优化 - 清除选文件缓存,支持重复选择同一个文件。 10. 优化 - 对话框信息懒加载,减少网络传输。
11. 修复 - 知识库上传文件,网络不稳定或文件较多情况下,进度无法到 100%。 11. 优化 - 清除选文件缓存,支持重复选择同一个文件。
12. 修复 - 删除应用后回到聊天选择最后一次对话的应用为删除的应用时提示无该应用问题。 12. 修复 - 知识库上传文件,网络不稳定或文件较多情况下,进度无法到 100%。
13. 修复 - 插件动态变量配置默认值时,无法正常显示默认值。 13. 修复 - 删除应用后回到聊天选择最后一次对话的应用为删除的应用时提示无该应用问题。
14. 修复 - 工具调用温度和最大回复值未生效。 14. 修复 - 插件动态变量配置默认值时,无法正常显示默认值。
15. 修复 - 函数调用模式,assistant role 中,GPT 模型必须传入 content 参数。(不影响大部分模型,目前基本都改用用 ToolChoice 模式,FC 模式已弃用)。 15. 修复 - 工具调用温度和最大回复值未生效。
16. 修复 - 知识库文件上传进度更新可能异常。 16. 修复 - 函数调用模式,assistant role 中,GPT 模型必须传入 content 参数。(不影响大部分模型,目前基本都改用用 ToolChoice 模式,FC 模式已弃用)。
17. 修复 - 知识库 rebuilding 时候,页面总是刷新到第一页。 17. 修复 - 知识库文件上传进度更新可能异常。
18. 修复 - 知识库 rebuilding 时候,页面总是刷新到第一页。
19. 修复 - 知识库 list openapi 鉴权问题。
import { replaceSensitiveText } from '../string/tools'; import { replaceSensitiveText } from '../string/tools';
export const getErrText = (err: any, def = '') => { export const getErrText = (err: any, def = ''): any => {
const msg: string = const msg: string =
typeof err === 'string' typeof err === 'string'
? err ? err
......
...@@ -7,10 +7,12 @@ export enum BucketNameEnum { ...@@ -7,10 +7,12 @@ export enum BucketNameEnum {
} }
export const bucketNameMap = { export const bucketNameMap = {
[BucketNameEnum.dataset]: { [BucketNameEnum.dataset]: {
label: i18nT('file:bucket_file') label: i18nT('file:bucket_file'),
previewExpireMinutes: 30 // 30 minutes
}, },
[BucketNameEnum.chat]: { [BucketNameEnum.chat]: {
label: i18nT('file:bucket_chat') label: i18nT('file:bucket_chat'),
previewExpireMinutes: 7 * 24 * 60 // 7 days
} }
}; };
......
...@@ -5,5 +5,4 @@ export type FileTokenQuery = { ...@@ -5,5 +5,4 @@ export type FileTokenQuery = {
teamId: string; teamId: string;
tmbId: string; tmbId: string;
fileId: string; fileId: string;
expiredTime?: number;
}; };
export type AuthFrequencyLimitProps = {
eventId: string;
maxAmount: number;
expiredTime: Date;
};
export const Prompt_AgentQA = { export const Prompt_AgentQA = {
description: `<Context></Context> 标记中是一段文本,学习和分析它,并整理学习成果: description: `<Context></Context> 标记中是一段文本,学习和分析它,并整理学习成果:
- 提出问题并给出每个问题的答案。 - 提出问题并给出每个问题的答案。
- 答案需详细完整,尽可能保留原文描述。 - 答案需详细完整,尽可能保留原文描述,可以适当扩展答案描述
- 答案可以包含普通文字、链接、代码、表格、公示、媒体链接等 Markdown 元素。 - 答案可以包含普通文字、链接、代码、表格、公示、媒体链接等 Markdown 元素。
- 最多提出 30 个问题。 - 最多提出 50 个问题。
`, `,
fixedText: `请按以下格式整理学习成果: fixedText: `请按以下格式整理学习成果:
<Context> <Context>
......
...@@ -19,7 +19,7 @@ export const ReadFilesNodes: FlowNodeTemplateType = { ...@@ -19,7 +19,7 @@ export const ReadFilesNodes: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.readFiles, flowNodeType: FlowNodeTypeEnum.readFiles,
sourceHandle: getHandleConfig(true, true, true, true), sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true),
avatar: 'core/app/simpleMode/file', avatar: 'core/workflow/template/readFiles',
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,
......
import { i18nT } from '../../../../web/i18n/utils';
export enum UsageSourceEnum { export enum UsageSourceEnum {
fastgpt = 'fastgpt', fastgpt = 'fastgpt',
api = 'api', api = 'api',
shareLink = 'shareLink', shareLink = 'shareLink',
training = 'training' training = 'training',
cronJob = 'cronJob'
} }
export const UsageSourceMap = { export const UsageSourceMap = {
...@@ -17,5 +20,8 @@ export const UsageSourceMap = { ...@@ -17,5 +20,8 @@ export const UsageSourceMap = {
}, },
[UsageSourceEnum.training]: { [UsageSourceEnum.training]: {
label: 'dataset.Training Name' label: 'dataset.Training Name'
},
[UsageSourceEnum.cronJob]: {
label: i18nT('common:cron_job_run_app')
} }
}; };
...@@ -45,7 +45,7 @@ export const stream2Encoding = async (stream: NodeJS.ReadableStream) => { ...@@ -45,7 +45,7 @@ export const stream2Encoding = async (stream: NodeJS.ReadableStream) => {
})(); })();
const enc = detectFileEncoding(buffer); const enc = detectFileEncoding(buffer);
console.log('Get encoding time', Date.now() - start, enc);
return { return {
encoding: enc, encoding: enc,
stream: copyStream stream: copyStream
......
...@@ -3,7 +3,6 @@ import multer from 'multer'; ...@@ -3,7 +3,6 @@ import multer from 'multer';
import path from 'path'; import path from 'path';
import { BucketNameEnum, bucketNameMap } from '@fastgpt/global/common/file/constants'; import { BucketNameEnum, bucketNameMap } from '@fastgpt/global/common/file/constants';
import { getNanoid } from '@fastgpt/global/common/string/tools'; import { getNanoid } from '@fastgpt/global/common/string/tools';
import { tmpFileDirPath } from './constants';
type FileType = { type FileType = {
fieldname: string; fieldname: string;
......
...@@ -228,7 +228,7 @@ const toolChoice = async (props: ActionProps) => { ...@@ -228,7 +228,7 @@ const toolChoice = async (props: ActionProps) => {
const response = await ai.chat.completions.create({ const response = await ai.chat.completions.create({
model: extractModel.model, model: extractModel.model,
temperature: 0, temperature: 0.01,
messages: filterMessages, messages: filterMessages,
tools, tools,
tool_choice: { type: 'function', function: { name: agentFunName } } tool_choice: { type: 'function', function: { name: agentFunName } }
...@@ -273,7 +273,7 @@ const functionCall = async (props: ActionProps) => { ...@@ -273,7 +273,7 @@ const functionCall = async (props: ActionProps) => {
const response = await ai.chat.completions.create({ const response = await ai.chat.completions.create({
model: extractModel.model, model: extractModel.model,
temperature: 0, temperature: 0.01,
messages: filterMessages, messages: filterMessages,
function_call: { function_call: {
name: agentFunName name: agentFunName
......
...@@ -49,7 +49,7 @@ export const dispatchReadFiles = async (props: Props): Promise<Response> => { ...@@ -49,7 +49,7 @@ export const dispatchReadFiles = async (props: Props): Promise<Response> => {
chatConfig, chatConfig,
params: { fileUrlList = [] } params: { fileUrlList = [] }
} = props; } = props;
const maxFiles = chatConfig?.fileSelectConfig?.maxFiles || 0; const maxFiles = chatConfig?.fileSelectConfig?.maxFiles || 20;
// Get files from histories // Get files from histories
const filesFromHistories = histories const filesFromHistories = histories
...@@ -70,29 +70,35 @@ export const dispatchReadFiles = async (props: Props): Promise<Response> => { ...@@ -70,29 +70,35 @@ export const dispatchReadFiles = async (props: Props): Promise<Response> => {
}) })
.flat(); .flat();
const parseUrlList = [...fileUrlList, ...filesFromHistories].slice(0, maxFiles); // Concat fileUrlList and filesFromHistories; remove not supported files
const parseUrlList = [...fileUrlList, ...filesFromHistories]
const readFilesResult = await Promise.all( .map((url) => {
parseUrlList // System file
.map(async (url) => { if (url.startsWith('/') || (requestOrigin && url.startsWith(requestOrigin))) {
// System file // Parse url, get filename query. Keep only documents that can be parsed
if (url.startsWith('/') || (requestOrigin && url.startsWith(requestOrigin))) { const parseUrl = new URL(url);
// Parse url, get filename query. Keep only documents that can be parsed const filenameQuery = parseUrl.searchParams.get('filename');
const parseUrl = new URL(url); if (filenameQuery) {
const filenameQuery = parseUrl.searchParams.get('filename'); const extensionQuery = filenameQuery.split('.').pop()?.toLowerCase() || '';
if (filenameQuery) { if (!documentFileType.includes(extensionQuery)) {
const extensionQuery = filenameQuery.split('.').pop()?.toLowerCase() || ''; return '';
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, '');
}
} }
}
return url;
})
.filter(Boolean)
.slice(0, maxFiles);
console.log(parseUrlList);
const readFilesResult = await Promise.all(
parseUrlList
.map(async (url) => {
// Get from buffer // Get from buffer
const fileBuffer = await MongoRawTextBuffer.findOne({ sourceId: url }, undefined, { const fileBuffer = await MongoRawTextBuffer.findOne({ sourceId: url }, undefined, {
...readFromSecondary ...readFromSecondary
......
...@@ -188,7 +188,7 @@ const toolChoice = async (props: ActionProps) => { ...@@ -188,7 +188,7 @@ const toolChoice = async (props: ActionProps) => {
const response = await ai.chat.completions.create({ const response = await ai.chat.completions.create({
model: cqModel.model, model: cqModel.model,
temperature: 0, temperature: 0.01,
messages: filterMessages, messages: filterMessages,
tools, tools,
tool_choice: { type: 'function', function: { name: agentFunName } } tool_choice: { type: 'function', function: { name: agentFunName } }
...@@ -235,7 +235,7 @@ const functionCall = async (props: ActionProps) => { ...@@ -235,7 +235,7 @@ const functionCall = async (props: ActionProps) => {
const response = await ai.chat.completions.create({ const response = await ai.chat.completions.create({
model: cqModel.model, model: cqModel.model,
temperature: 0, temperature: 0.01,
messages: filterMessages, messages: filterMessages,
function_call: { function_call: {
name: agentFunName name: agentFunName
......
...@@ -10,6 +10,8 @@ import { MongoResourcePermission } from './schema'; ...@@ -10,6 +10,8 @@ import { MongoResourcePermission } from './schema';
import { ClientSession } from 'mongoose'; import { ClientSession } from 'mongoose';
import { ParentIdType } from '@fastgpt/global/common/parentFolder/type'; import { ParentIdType } from '@fastgpt/global/common/parentFolder/type';
import { ResourcePermissionType } from '@fastgpt/global/support/permission/type'; import { ResourcePermissionType } from '@fastgpt/global/support/permission/type';
import { bucketNameMap } from '@fastgpt/global/common/file/constants';
import { addMinutes } from 'date-fns';
export const getResourcePermission = async ({ export const getResourcePermission = async ({
resourceType, resourceType,
...@@ -250,15 +252,15 @@ export const clearCookie = (res: NextApiResponse) => { ...@@ -250,15 +252,15 @@ export const clearCookie = (res: NextApiResponse) => {
}; };
/* file permission */ /* file permission */
export const createFileToken = ({ export const createFileToken = (data: FileTokenQuery) => {
expiredTime = Math.floor(Date.now() / 1000) + 60 * 30,
...data
}: FileTokenQuery) => {
if (!process.env.FILE_TOKEN_KEY) { if (!process.env.FILE_TOKEN_KEY) {
return Promise.reject('System unset FILE_TOKEN_KEY'); return Promise.reject('System unset FILE_TOKEN_KEY');
} }
const key = process.env.FILE_TOKEN_KEY as string; const expireMinutes = bucketNameMap[data.bucketName].previewExpireMinutes;
const expiredTime = Math.floor(addMinutes(new Date(), expireMinutes).getTime() / 1000);
const key = (process.env.FILE_TOKEN_KEY as string) ?? 'filetoken';
const token = jwt.sign( const token = jwt.sign(
{ {
...data, ...data,
...@@ -274,7 +276,7 @@ export const authFileToken = (token?: string) => ...@@ -274,7 +276,7 @@ export const authFileToken = (token?: string) =>
if (!token) { if (!token) {
return reject(ERROR_ENUM.unAuthFile); return reject(ERROR_ENUM.unAuthFile);
} }
const key = process.env.FILE_TOKEN_KEY as string; const key = (process.env.FILE_TOKEN_KEY as string) ?? 'filetoken';
jwt.verify(token, key, function (err, decoded: any) { jwt.verify(token, key, function (err, decoded: any) {
if (err || !decoded.bucketName || !decoded?.teamId || !decoded?.tmbId || !decoded?.fileId) { if (err || !decoded.bucketName || !decoded?.teamId || !decoded?.tmbId || !decoded?.fileId) {
......
...@@ -10,7 +10,7 @@ const Avatar = ({ w = '30px', src, ...props }: ImageProps) => { ...@@ -10,7 +10,7 @@ const Avatar = ({ w = '30px', src, ...props }: ImageProps) => {
const isIcon = !!iconPaths[src as any]; const isIcon = !!iconPaths[src as any];
return isIcon ? ( return isIcon ? (
<Box {...props}> <Box display={'inline-flex'} {...props}>
<MyIcon name={src as any} w={w} borderRadius={props.borderRadius} /> <MyIcon name={src as any} w={w} borderRadius={props.borderRadius} />
</Box> </Box>
) : ( ) : (
......
...@@ -199,6 +199,7 @@ export const iconPaths = { ...@@ -199,6 +199,7 @@ export const iconPaths = {
import('./icons/core/workflow/template/queryExtension.svg'), import('./icons/core/workflow/template/queryExtension.svg'),
'core/workflow/template/questionClassify': () => 'core/workflow/template/questionClassify': () =>
import('./icons/core/workflow/template/questionClassify.svg'), import('./icons/core/workflow/template/questionClassify.svg'),
'core/workflow/template/readFiles': () => import('./icons/core/workflow/template/readFiles.svg'),
'core/workflow/template/reply': () => import('./icons/core/workflow/template/reply.svg'), 'core/workflow/template/reply': () => import('./icons/core/workflow/template/reply.svg'),
'core/workflow/template/runApp': () => import('./icons/core/workflow/template/runApp.svg'), 'core/workflow/template/runApp': () => import('./icons/core/workflow/template/runApp.svg'),
'core/workflow/template/stopTool': () => import('./icons/core/workflow/template/stopTool.svg'), 'core/workflow/template/stopTool': () => import('./icons/core/workflow/template/stopTool.svg'),
......
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="16" viewBox="0 0 22 18" fill="none"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 18" >
<path fill-rule="evenodd" clip-rule="evenodd" <path fill-rule="evenodd" clip-rule="evenodd"
d="M4.63694 1.22278C5.02752 1.61324 5.02762 2.24641 4.63715 2.63699C2.94991 4.32474 2.00208 6.61352 2.00208 8.99999C2.00208 11.3865 2.94991 13.6752 4.63715 15.363C5.02762 15.7536 5.02752 16.3867 4.63694 16.7772C4.24636 17.1677 3.61319 17.1676 3.22273 16.777C1.16054 14.7142 0.0020752 11.9168 0.0020752 8.99999C0.0020752 6.08319 1.16054 3.2858 3.22273 1.22299C3.61319 0.832409 4.24636 0.832314 4.63694 1.22278ZM17.3629 1.22278C17.7535 0.832314 18.3867 0.832409 18.7772 1.22299C20.8393 3.2858 21.9978 6.08319 21.9978 8.99999C21.9978 11.9168 20.8393 14.7142 18.7772 16.777C18.3867 17.1676 17.7535 17.1677 17.3629 16.7772C16.9724 16.3867 16.9723 15.7536 17.3627 15.363C19.05 13.6752 19.9978 11.3865 19.9978 8.99999C19.9978 6.61352 19.05 4.32474 17.3627 2.63699C16.9723 2.24641 16.9724 1.61324 17.3629 1.22278ZM7.46744 4.04328C7.85775 4.43402 7.8574 5.06719 7.46665 5.45749C7.00177 5.92186 6.63298 6.4733 6.38135 7.08029C6.12973 7.68728 6.00022 8.33792 6.00022 8.99499C6.00022 9.65207 6.12973 10.3027 6.38135 10.9097C6.63298 11.5167 7.00177 12.0681 7.46665 12.5325C7.8574 12.9228 7.85775 13.556 7.46744 13.9467C7.07713 14.3374 6.44397 14.3378 6.05323 13.9475C5.40239 13.2974 4.88608 12.5254 4.53381 11.6756C4.18154 10.8258 4.00022 9.9149 4.00022 8.99499C4.00022 8.07508 4.18154 7.1642 4.53381 6.31441C4.88608 5.46462 5.40239 4.6926 6.05323 4.04249C6.44397 3.65219 7.07713 3.65254 7.46744 4.04328ZM14.5324 4.05328C14.9227 3.66254 15.5559 3.66219 15.9467 4.05249C16.5975 4.7026 17.1138 5.47462 17.4661 6.32441C17.8183 7.1742 17.9997 8.08509 17.9997 9.00499C17.9997 9.9249 17.8183 10.8358 17.4661 11.6856C17.1138 12.5354 16.5975 13.3074 15.9467 13.9575C15.5559 14.3478 14.9227 14.3474 14.5324 13.9567C14.1421 13.566 14.1425 12.9328 14.5332 12.5425C14.9981 12.0781 15.3669 11.5267 15.6185 10.9197C15.8701 10.3127 15.9997 9.66207 15.9997 9.00499C15.9997 8.34792 15.8701 7.69728 15.6185 7.09029C15.3669 6.4833 14.9981 5.93186 14.5332 5.46749C14.1425 5.07719 14.1421 4.44402 14.5324 4.05328ZM10.9999 7.99999C10.4477 7.99999 9.99994 8.44771 9.99994 8.99999C9.99994 9.55228 10.4477 9.99999 10.9999 9.99999C11.5522 9.99999 11.9999 9.55228 11.9999 8.99999C11.9999 8.44771 11.5522 7.99999 10.9999 7.99999ZM7.99994 8.99999C7.99994 7.34314 9.34309 5.99999 10.9999 5.99999C12.6568 5.99999 13.9999 7.34314 13.9999 8.99999C13.9999 10.6568 12.6568 12 10.9999 12C9.34309 12 7.99994 10.6568 7.99994 8.99999Z" d="M4.63694 1.22278C5.02752 1.61324 5.02762 2.24641 4.63715 2.63699C2.94991 4.32474 2.00208 6.61352 2.00208 8.99999C2.00208 11.3865 2.94991 13.6752 4.63715 15.363C5.02762 15.7536 5.02752 16.3867 4.63694 16.7772C4.24636 17.1677 3.61319 17.1676 3.22273 16.777C1.16054 14.7142 0.0020752 11.9168 0.0020752 8.99999C0.0020752 6.08319 1.16054 3.2858 3.22273 1.22299C3.61319 0.832409 4.24636 0.832314 4.63694 1.22278ZM17.3629 1.22278C17.7535 0.832314 18.3867 0.832409 18.7772 1.22299C20.8393 3.2858 21.9978 6.08319 21.9978 8.99999C21.9978 11.9168 20.8393 14.7142 18.7772 16.777C18.3867 17.1676 17.7535 17.1677 17.3629 16.7772C16.9724 16.3867 16.9723 15.7536 17.3627 15.363C19.05 13.6752 19.9978 11.3865 19.9978 8.99999C19.9978 6.61352 19.05 4.32474 17.3627 2.63699C16.9723 2.24641 16.9724 1.61324 17.3629 1.22278ZM7.46744 4.04328C7.85775 4.43402 7.8574 5.06719 7.46665 5.45749C7.00177 5.92186 6.63298 6.4733 6.38135 7.08029C6.12973 7.68728 6.00022 8.33792 6.00022 8.99499C6.00022 9.65207 6.12973 10.3027 6.38135 10.9097C6.63298 11.5167 7.00177 12.0681 7.46665 12.5325C7.8574 12.9228 7.85775 13.556 7.46744 13.9467C7.07713 14.3374 6.44397 14.3378 6.05323 13.9475C5.40239 13.2974 4.88608 12.5254 4.53381 11.6756C4.18154 10.8258 4.00022 9.9149 4.00022 8.99499C4.00022 8.07508 4.18154 7.1642 4.53381 6.31441C4.88608 5.46462 5.40239 4.6926 6.05323 4.04249C6.44397 3.65219 7.07713 3.65254 7.46744 4.04328ZM14.5324 4.05328C14.9227 3.66254 15.5559 3.66219 15.9467 4.05249C16.5975 4.7026 17.1138 5.47462 17.4661 6.32441C17.8183 7.1742 17.9997 8.08509 17.9997 9.00499C17.9997 9.9249 17.8183 10.8358 17.4661 11.6856C17.1138 12.5354 16.5975 13.3074 15.9467 13.9575C15.5559 14.3478 14.9227 14.3474 14.5324 13.9567C14.1421 13.566 14.1425 12.9328 14.5332 12.5425C14.9981 12.0781 15.3669 11.5267 15.6185 10.9197C15.8701 10.3127 15.9997 9.66207 15.9997 9.00499C15.9997 8.34792 15.8701 7.69728 15.6185 7.09029C15.3669 6.4833 14.9981 5.93186 14.5332 5.46749C14.1425 5.07719 14.1421 4.44402 14.5324 4.05328ZM10.9999 7.99999C10.4477 7.99999 9.99994 8.44771 9.99994 8.99999C9.99994 9.55228 10.4477 9.99999 10.9999 9.99999C11.5522 9.99999 11.9999 9.55228 11.9999 8.99999C11.9999 8.44771 11.5522 7.99999 10.9999 7.99999ZM7.99994 8.99999C7.99994 7.34314 9.34309 5.99999 10.9999 5.99999C12.6568 5.99999 13.9999 7.34314 13.9999 8.99999C13.9999 10.6568 12.6568 12 10.9999 12C9.34309 12 7.99994 10.6568 7.99994 8.99999Z"
fill="#3370FF" /> fill="#3370FF" />
......
<svg viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="36" height="36" fill="url(#paint0_linear_8908_31922)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.7763 8.13002C21.1563 8.34961 21.486 8.65917 22.1453 9.27829L25.0531 12.009C25.7718 12.6839 26.1312 13.0214 26.387 13.4225C26.6045 13.7635 26.7661 14.1369 26.8658 14.5288C26.9831 14.9899 26.9831 15.4829 26.9831 16.4688V22.2622C26.9831 24.4263 26.9831 25.5083 26.5553 26.332C26.1947 27.026 25.6288 27.5919 24.9348 27.9524C24.1112 28.3802 23.0292 28.3802 20.8651 28.3802H15.1348C12.9708 28.3802 11.8887 28.3802 11.0651 27.9524C10.3711 27.5919 9.8052 27.026 9.44467 26.332C9.01685 25.5083 9.01685 24.4263 9.01685 22.2622V13.7381C9.01685 11.5741 9.01685 10.492 9.44467 9.66841C9.8052 8.97437 10.3711 8.40847 11.0651 8.04795C11.8887 7.62012 12.9708 7.62012 15.1348 7.62012H17.9572C18.8616 7.62012 19.3138 7.62012 19.7411 7.72015C20.1045 7.80521 20.4533 7.94331 20.7763 8.13002ZM20.3328 10.6528C19.7396 10.084 19.443 9.79959 19.1884 9.78928C18.9862 9.78109 18.791 9.86434 18.657 10.016C18.4882 10.2069 18.4882 10.6178 18.4882 11.4397V12.378C18.4882 13.5803 18.4882 14.1814 18.7222 14.6405C18.928 15.0445 19.2564 15.3729 19.6603 15.5787C20.1195 15.8126 20.7206 15.8126 21.9228 15.8126H23.0022C23.8674 15.8126 24.3 15.8126 24.4924 15.638C24.6451 15.4995 24.7258 15.2986 24.7115 15.093C24.6935 14.8338 24.3812 14.5344 23.7567 13.9356L20.3328 10.6528ZM13.0047 19.6764C13.0047 19.1241 13.4524 18.6764 14.0047 18.6764H21.9996C22.5519 18.6764 22.9996 19.1241 22.9996 19.6764C22.9996 20.2287 22.5519 20.6764 21.9996 20.6764H14.0047C13.4524 20.6764 13.0047 20.2287 13.0047 19.6764ZM12.993 23.4246C12.993 22.8723 13.4407 22.4246 13.993 22.4246H19.9946C20.5469 22.4246 20.9946 22.8723 20.9946 23.4246C20.9946 23.9769 20.5469 24.4246 19.9946 24.4246H13.993C13.4407 24.4246 12.993 23.9769 12.993 23.4246Z" fill="white"/>
<defs>
<linearGradient id="paint0_linear_8908_31922" x1="18" y1="0" x2="5.5" y2="33" gradientUnits="userSpaceOnUse">
<stop stop-color="#3ED9C6"/>
<stop offset="1" stop-color="#13C7BC"/>
</linearGradient>
</defs>
</svg>
...@@ -103,10 +103,12 @@ ...@@ -103,10 +103,12 @@
"Simple bot": "Simple bot", "Simple bot": "Simple bot",
"Workflow bot": "Workflow" "Workflow bot": "Workflow"
}, },
"upload_file_max_amount": "Maximum number of files to be uploaded in a single round", "upload_file_max_amount": "Max files",
"upload_file_max_amount_tip": "1. The maximum number of files to be uploaded at a time.\n2. The maximum number of files that can be remembered in the dialog window: Files in the history are automatically retrieved for each round of conversation, and files that are out of range are forgotten.",
"version": { "version": {
"Revert success": "Revert success" "Revert success": "Revert success"
}, },
"vision_model_title": "Enable image recognition",
"week": { "week": {
"Friday": "Friday", "Friday": "Friday",
"Monday": "Monday", "Monday": "Monday",
...@@ -122,7 +124,7 @@ ...@@ -122,7 +124,7 @@
"read_files": "Documents parse", "read_files": "Documents parse",
"read_files_result": "Document parsing results", "read_files_result": "Document parsing results",
"read_files_result_desc": "The original text of the document consists of the file name and the document content. Multiple files are separated by horizontal lines.", "read_files_result_desc": "The original text of the document consists of the file name and the document content. Multiple files are separated by horizontal lines.",
"read_files_tip": "Parse the document link passed in the conversation and return the corresponding document content", "read_files_tip": "Parse all uploaded documents in the conversation and return the corresponding document content",
"template": { "template": {
"communication": "Communication" "communication": "Communication"
}, },
......
...@@ -223,6 +223,7 @@ ...@@ -223,6 +223,7 @@
}, },
"error": { "error": {
"Select avatar failed": "Avatar selection failed", "Select avatar failed": "Avatar selection failed",
"too_many_request": "Too many requests, please try again later.",
"unKnow": "An unexpected error occurred~" "unKnow": "An unexpected error occurred~"
}, },
"failed": "fail", "failed": "fail",
...@@ -650,7 +651,7 @@ ...@@ -650,7 +651,7 @@
"Down load csv template": "Click to download CSV template", "Down load csv template": "Click to download CSV template",
"Embedding Estimated Price Tips": "Only using the index model, consumes a small amount of AI points: {{price}} points/1k Tokens", "Embedding Estimated Price Tips": "Only using the index model, consumes a small amount of AI points: {{price}} points/1k Tokens",
"Ideal chunk length": "Ideal chunk length", "Ideal chunk length": "Ideal chunk length",
"Ideal chunk length Tips": "Segment by end symbols. We recommend that your document should reasonably use punctuation to ensure that each complete sentence does not exceed this value\nChinese documents recommend 400~1000\nEnglish documents recommend 600~1200", "Ideal chunk length Tips": "Segment according to the end symbol, and combine the segments into a block. This value determines the estimated size of the block.",
"Import success": "Import successful, please wait for training", "Import success": "Import successful, please wait for training",
"Link name": "Network link", "Link name": "Network link",
"Link name placeholder": "Only supports static links, if the data is empty after upload, the link may not be readable\nOne per line, up to 10 links at a time", "Link name placeholder": "Only supports static links, if the data is empty after upload, the link may not be readable\nOne per line, up to 10 links at a time",
...@@ -957,6 +958,7 @@ ...@@ -957,6 +958,7 @@
} }
}, },
"create": "to create", "create": "to create",
"cron_job_run_app": "Cron job",
"dataset": { "dataset": {
"Confirm move the folder": "Confirm moving to the folder", "Confirm move the folder": "Confirm moving to the folder",
"Confirm to delete the data": "Confirm to delete the data?", "Confirm to delete the data": "Confirm to delete the data?",
...@@ -1017,7 +1019,8 @@ ...@@ -1017,7 +1019,8 @@
"missingParams": "Insufficient parameters", "missingParams": "Insufficient parameters",
"team": { "team": {
"overSize": "Team members exceed the limit" "overSize": "Team members exceed the limit"
} },
"upload_file_error_filename": "{{name}} upload failed"
}, },
"extraction_results": "Extract results", "extraction_results": "Extract results",
"field_name": "Name", "field_name": "Name",
...@@ -1030,7 +1033,7 @@ ...@@ -1030,7 +1033,7 @@
"csv_download": "Click to download batch test template", "csv_download": "Click to download batch test template",
"csv_message": "Read the first column of the CSV file for batch testing, supporting up to 100 sets of data at a time.", "csv_message": "Read the first column of the CSV file for batch testing, supporting up to 100 sets of data at a time.",
"felid_message": "The field key must be pure English letters or numbers, and cannot start with a number.", "felid_message": "The field key must be pure English letters or numbers, and cannot start with a number.",
"free_plan": "When free version users have no usage records for 30 days, the system will automatically clean up the account knowledge base.", "free_plan": "When a free version user does not log in to the system for 30 consecutive days, the system will automatically clean up the account knowledge base.",
"include": "Includes standard package and additional resource package", "include": "Includes standard package and additional resource package",
"node_info": "Adjusting this module will have an impact on the timing of tool calls.\n\nYou can guide the model to make tool calls by accurately describing the function of the module.", "node_info": "Adjusting this module will have an impact on the timing of tool calls.\n\nYou can guide the model to make tool calls by accurately describing the function of the module.",
"old_version_attention": "If it is detected that your advanced arrangement is an old version, the system will automatically format it into a new version of the workflow for you.\n\n\nDue to large version differences, some workflows may not be arranged normally. Please reconnect the workflows manually. \nIf the error persists, try deleting the corresponding node and adding it again.\n\n\nYou can directly click Debug to perform workflow testing, and click Publish after debugging is completed. \nThe new workflow will not actually save and take effect until you click Publish.\n\n\nAutosave will not take effect until you publish the new workflow.", "old_version_attention": "If it is detected that your advanced arrangement is an old version, the system will automatically format it into a new version of the workflow for you.\n\n\nDue to large version differences, some workflows may not be arranged normally. Please reconnect the workflows manually. \nIf the error persists, try deleting the corresponding node and adding it again.\n\n\nYou can directly click Debug to perform workflow testing, and click Publish after debugging is completed. \nThe new workflow will not actually save and take effect until you click Publish.\n\n\nAutosave will not take effect until you publish the new workflow.",
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
"has new version": "有新版本" "has new version": "有新版本"
} }
}, },
"intro": "是一个大模型应用编排系统,提供开箱即用的数据处理、模型调用等能力,可以快速的构建知识库并通过 Flow 可视化进行工作流编排,实现复杂的知识库场景!",
"app_detail": "应用详情", "app_detail": "应用详情",
"chat_debug": "调试预览", "chat_debug": "调试预览",
"chat_logs": "对话日志", "chat_logs": "对话日志",
...@@ -19,10 +18,20 @@ ...@@ -19,10 +18,20 @@
"confirm_delete_folder_tip": "确认删除该文件夹?将会删除它下面所有应用及对应的聊天记录,请确认!", "confirm_delete_folder_tip": "确认删除该文件夹?将会删除它下面所有应用及对应的聊天记录,请确认!",
"copy_one_app": "创建副本", "copy_one_app": "创建副本",
"create_copy_success": "创建副本成功", "create_copy_success": "创建副本成功",
"cron": {
"every_day": "每天执行",
"every_month": "每月执行",
"every_week": "每周执行",
"interval": "间隔执行"
},
"current_settings": "当前配置", "current_settings": "当前配置",
"day": "日",
"document_quote": "文档引用",
"document_quote_tip": "通常用于接受用户上传的文档内容(这需要文档解析),也可以用于引用其他字符串数据。",
"document_upload": "文档上传", "document_upload": "文档上传",
"edit_app": "编辑应用", "edit_app": "编辑应用",
"edit_info": "编辑信息", "edit_info": "编辑信息",
"execute_time": "执行时间",
"export_config_successful": "已复制配置,自动过滤部分敏感信息,请注意检查是否仍有敏感数据", "export_config_successful": "已复制配置,自动过滤部分敏感信息,请注意检查是否仍有敏感数据",
"export_configs": "导出配置", "export_configs": "导出配置",
"feedback_count": "用户反馈", "feedback_count": "用户反馈",
...@@ -34,6 +43,15 @@ ...@@ -34,6 +43,15 @@
"image_upload_tip": "请确保选择可处理图片的视觉模型", "image_upload_tip": "请确保选择可处理图片的视觉模型",
"import_configs": "导入配置", "import_configs": "导入配置",
"import_configs_failed": "导入配置失败,请确保配置正常!", "import_configs_failed": "导入配置失败,请确保配置正常!",
"interval": {
"12_hours": "每12小时",
"2_hours": "每2小时",
"3_hours": "每3小时",
"4_hours": "每4小时",
"6_hours": "每6小时",
"per_hour": "每小时"
},
"intro": "是一个大模型应用编排系统,提供开箱即用的数据处理、模型调用等能力,可以快速的构建知识库并通过 Flow 可视化进行工作流编排,实现复杂的知识库场景!",
"llm_not_support_vision": "该模型不支持图片识别", "llm_not_support_vision": "该模型不支持图片识别",
"llm_use_vision": "启用图片识别", "llm_use_vision": "启用图片识别",
"llm_use_vision_tip": "启用图片识别后,该模型会自动接收来自“对话框上传”的图片,以及“用户问题”中的图片链接。", "llm_use_vision_tip": "启用图片识别后,该模型会自动接收来自“对话框上传”的图片,以及“用户问题”中的图片链接。",
...@@ -50,6 +68,9 @@ ...@@ -50,6 +68,9 @@
"modules": { "modules": {
"Title is required": "模块名不能为空" "Title is required": "模块名不能为空"
}, },
"month": {
"unit": "号"
},
"move_app": "移动应用", "move_app": "移动应用",
"paste_config": "粘贴配置", "paste_config": "粘贴配置",
"plugin_cost_per_times": "{{cost}}/次", "plugin_cost_per_times": "{{cost}}/次",
...@@ -63,6 +84,7 @@ ...@@ -63,6 +84,7 @@
"template": { "template": {
"simple_robot": "简易机器人" "simple_robot": "简易机器人"
}, },
"time_zone": "时区",
"tool_input_param_tip": "该插件正常运行需要配置相关信息", "tool_input_param_tip": "该插件正常运行需要配置相关信息",
"transition_to_workflow": "转成工作流", "transition_to_workflow": "转成工作流",
"transition_to_workflow_create_new_placeholder": "创建一个新的应用,而不是修改当前应用", "transition_to_workflow_create_new_placeholder": "创建一个新的应用,而不是修改当前应用",
...@@ -81,52 +103,32 @@ ...@@ -81,52 +103,32 @@
"Simple bot": "简易应用", "Simple bot": "简易应用",
"Workflow bot": "工作流" "Workflow bot": "工作流"
}, },
"upload_file_max_amount": "单轮最大文件上传数量", "upload_file_max_amount": "最大文件数量",
"upload_file_max_amount_tip": "1.单次上传文件的最大数量。\n2.对话窗口记忆的最大文件数量:每轮对话会自动获取历史中的文件,超出范围的文件会被遗忘。",
"version": { "version": {
"Revert success": "回滚成功" "Revert success": "回滚成功"
}, },
"vision_model_title": "启用图片识别",
"week": {
"Friday": "星期五",
"Monday": "星期一",
"Saturday": "星期六",
"Sunday": "星期日",
"Thursday": "星期四",
"Tuesday": "星期二",
"Wednesday": "星期三"
},
"workflow": { "workflow": {
"Input guide": "填写说明", "Input guide": "填写说明",
"file_url": "文档链接", "file_url": "文档链接",
"read_files": "文档解析", "read_files": "文档解析",
"read_files_result": "文档解析结果", "read_files_result": "文档解析结果",
"read_files_result_desc": "文档原文,由文件名和文档内容组成,多个文件之间通过横线隔开。", "read_files_result_desc": "文档原文,由文件名和文档内容组成,多个文件之间通过横线隔开。",
"read_files_tip": "解析对话中上传的文档,返回对应文档内容", "read_files_tip": "解析对话中所有上传的文档,并返回对应文档内容",
"template": { "template": {
"communication": "通信" "communication": "通信"
}, },
"user_file_input": "文件链接", "user_file_input": "文件链接",
"user_file_input_desc": "用户上传的文档和图片链接" "user_file_input_desc": "用户上传的文档和图片链接"
}, }
"interval": {
"per_hour": "每小时",
"2_hours": "每2小时",
"3_hours": "每3小时",
"4_hours": "每4小时",
"6_hours": "每6小时",
"12_hours": "每12小时"
},
"week": {
"Monday": "星期一",
"Tuesday": "星期二",
"Wednesday": "星期三",
"Thursday": "星期四",
"Friday": "星期五",
"Saturday": "星期六",
"Sunday": "星期日"
},
"month": {
"unit": "号"
},
"cron": {
"every_day": "每天执行",
"every_month": "每月执行",
"every_week": "每周执行",
"interval": "间隔执行"
},
"day": "日",
"execute_time": "执行时间",
"time_zone": "时区",
"document_quote": "文档引用",
"document_quote_tip": "通常用于接受用户上传的文档内容(这需要文档解析),也可以用于引用其他字符串数据。"
} }
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
"verification_code": "验证码", "verification_code": "验证码",
"confirm": "确认密码", "confirm": "确认密码",
"not_match": "两次密码不一致", "not_match": "两次密码不一致",
"to_login": "去登", "to_login": "去登",
"get_code": "获取验证码", "get_code": "获取验证码",
"get_code_again": "s后重新获取", "get_code_again": "s后重新获取",
"code_sended": "验证码已发送", "code_sended": "验证码已发送",
......
This source diff could not be displayed because it is too large. You can view the blob instead.
<svg viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="36" height="36" rx="6" fill="#F0F4FF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.9998 9.83496C13.4905 9.83496 9.83496 13.4905 9.83496 17.9998C9.83496 22.5091 13.4905 26.1646 17.9998 26.1646C22.5091 26.1646 26.1646 22.5091 26.1646 17.9998C26.1646 13.4905 22.5091 9.83496 17.9998 9.83496ZM7.83496 17.9998C7.83496 12.3859 12.3859 7.83496 17.9998 7.83496C23.6136 7.83496 28.1646 12.3859 28.1646 17.9998C28.1646 23.6136 23.6136 28.1646 17.9998 28.1646C12.3859 28.1646 7.83496 23.6136 7.83496 17.9998ZM18.2222 14.4384C17.815 14.3686 17.3962 14.4451 17.04 14.6545C16.6838 14.8638 16.4132 15.1924 16.2761 15.5822C16.0929 16.1032 15.522 16.3769 15.001 16.1937C14.48 16.0104 14.2062 15.4395 14.3895 14.9185C14.6833 14.0832 15.2633 13.3788 16.0267 12.9302C16.7901 12.4815 17.6876 12.3175 18.5603 12.4672C19.433 12.6169 20.2246 13.0707 20.7949 13.7481C21.365 14.4253 21.6771 15.2825 21.6759 16.1677C21.6754 17.6145 20.6035 18.5625 19.8559 19.0609C19.4516 19.3305 19.0544 19.5284 18.7622 19.6582C18.6147 19.7238 18.4904 19.7736 18.4006 19.8078C18.3556 19.8249 18.3191 19.8382 18.2923 19.8477L18.2597 19.8591L18.2492 19.8627L18.2454 19.864L18.2439 19.8645C18.2436 19.8646 18.2427 19.8649 17.9264 18.9162L18.2427 19.8649C17.7187 20.0396 17.1524 19.7564 16.9778 19.2325C16.8032 18.7087 17.0861 18.1426 17.6097 17.9677L17.6223 17.9633C17.6359 17.9585 17.6584 17.9503 17.6886 17.9388C17.7492 17.9157 17.8397 17.8796 17.9499 17.8306C18.1733 17.7313 18.4634 17.5855 18.7465 17.3968C19.3734 16.9789 19.6759 16.5524 19.6759 16.1668L19.6759 16.1653C19.6765 15.7522 19.5309 15.3521 19.2648 15.0361C18.9987 14.72 18.6294 14.5083 18.2222 14.4384ZM16.9998 22.5822C16.9998 22.0299 17.4475 21.5822 17.9998 21.5822H18.0089C18.5612 21.5822 19.0089 22.0299 19.0089 22.5822C19.0089 23.1344 18.5612 23.5822 18.0089 23.5822H17.9998C17.4475 23.5822 16.9998 23.1344 16.9998 22.5822Z" fill="#3370FF"/>
</svg>
...@@ -20,6 +20,8 @@ import { defaultAppSelectFileConfig } from '@fastgpt/global/core/app/constants'; ...@@ -20,6 +20,8 @@ import { defaultAppSelectFileConfig } from '@fastgpt/global/core/app/constants';
import ChatFunctionTip from './Tip'; import ChatFunctionTip from './Tip';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel'; import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import { useMount } from 'ahooks'; import { useMount } from 'ahooks';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
const FileSelect = ({ const FileSelect = ({
forbidVision = false, forbidVision = false,
...@@ -31,7 +33,9 @@ const FileSelect = ({ ...@@ -31,7 +33,9 @@ const FileSelect = ({
onChange: (e: AppFileSelectConfigType) => void; onChange: (e: AppFileSelectConfigType) => void;
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { feConfigs } = useSystemStore();
const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen, onOpen, onClose } = useDisclosure();
const maxSelectFiles = Math.min(feConfigs?.uploadFileMaxAmount ?? 20, 30);
const formLabel = useMemo( const formLabel = useMemo(
() => () =>
...@@ -106,22 +110,27 @@ const FileSelect = ({ ...@@ -106,22 +110,27 @@ const FileSelect = ({
)} )}
</HStack> </HStack>
{!forbidVision && ( {!forbidVision && (
<Box mt={2} color={'myGray.500'} fontSize={'xs'}> <Flex mt={2} color={'myGray.500'}>
{t('app:image_upload_tip')} <Box fontSize={'xs'}>{t('app:image_upload_tip')}</Box>
</Box> <ChatFunctionTip type="visionModel" />
</Flex>
)} )}
<Box mt={6}> <Box mt={6}>
<FormLabel>{t('app:upload_file_max_amount')}</FormLabel> <HStack spacing={1}>
<FormLabel>{t('app:upload_file_max_amount')}</FormLabel>
<QuestionTip label={t('app:upload_file_max_amount_tip')} />
</HStack>
<Box mt={5}> <Box mt={5}>
<MySlider <MySlider
markList={[ markList={[
{ label: '1', value: 1 }, { label: '1', value: 1 },
{ label: '20', value: 20 } { label: `${maxSelectFiles}`, value: maxSelectFiles }
]} ]}
width={'100%'} width={'100%'}
min={1} min={1}
max={20} max={maxSelectFiles}
step={1} step={1}
value={value.maxFiles ?? 5} value={value.maxFiles ?? 5}
onChange={(e) => { onChange={(e) => {
......
...@@ -97,12 +97,8 @@ const TTSSelect = ({ ...@@ -97,12 +97,8 @@ const TTSSelect = ({
</Button> </Button>
</MyTooltip> </MyTooltip>
<MyModal <MyModal
title={ iconSrc="core/app/simpleMode/tts"
<> title={t('common:core.app.TTS')}
<MyIcon name={'core/app/simpleMode/tts'} mr={2} w={'20px'} />
{t('common:core.app.TTS')}
</>
}
isOpen={isOpen} isOpen={isOpen}
onClose={onCloseTTSModal} onClose={onCloseTTSModal}
w={'500px'} w={'500px'}
......
...@@ -10,7 +10,8 @@ enum FnTypeEnum { ...@@ -10,7 +10,8 @@ enum FnTypeEnum {
tts = 'tts', tts = 'tts',
variable = 'variable', variable = 'variable',
welcome = 'welcome', welcome = 'welcome',
file = 'file' file = 'file',
visionModel = 'visionModel'
} }
const ChatFunctionTip = ({ type }: { type: `${FnTypeEnum}` }) => { const ChatFunctionTip = ({ type }: { type: `${FnTypeEnum}` }) => {
...@@ -52,7 +53,13 @@ const ChatFunctionTip = ({ type }: { type: `${FnTypeEnum}` }) => { ...@@ -52,7 +53,13 @@ const ChatFunctionTip = ({ type }: { type: `${FnTypeEnum}` }) => {
icon: '/imgs/app/welcome-icon.svg', icon: '/imgs/app/welcome-icon.svg',
title: t('app:file_upload'), title: t('app:file_upload'),
desc: t('app:file_upload_tip'), desc: t('app:file_upload_tip'),
imgUrl: '/imgs/app/fileUploadPlaceholder.svg' imgUrl: '/imgs/app/fileUploadPlaceholder.png'
},
[FnTypeEnum.visionModel]: {
icon: '/imgs/app/question.svg',
title: t('app:vision_model_title'),
desc: t('app:llm_use_vision_tip'),
imgUrl: '/imgs/app/visionModel.png'
} }
}); });
const data = map.current[type]; const data = map.current[type];
...@@ -62,8 +69,8 @@ const ChatFunctionTip = ({ type }: { type: `${FnTypeEnum}` }) => { ...@@ -62,8 +69,8 @@ const ChatFunctionTip = ({ type }: { type: `${FnTypeEnum}` }) => {
maxW={'420px'} maxW={'420px'}
ml={1} ml={1}
label={ label={
<Box> <Box pt={2}>
<Flex> <Flex alignItems={'flex-start'}>
<Image src={data.icon} w={'36px'} alt={''} /> <Image src={data.icon} w={'36px'} alt={''} />
<Box ml={3}> <Box ml={3}>
<Box fontWeight="bold">{data.title}</Box> <Box fontWeight="bold">{data.title}</Box>
......
...@@ -15,6 +15,7 @@ export type UserInputFileItemType = { ...@@ -15,6 +15,7 @@ export type UserInputFileItemType = {
icon: string; // img is base64 icon: string; // img is base64
status: 0 | 1; // 0: uploading, 1: success status: 0 | 1; // 0: uploading, 1: success
url?: string; url?: string;
process?: number;
}; };
export type ChatBoxInputFormType = { export type ChatBoxInputFormType = {
......
...@@ -430,10 +430,6 @@ const PlanUsage = () => { ...@@ -430,10 +430,6 @@ const PlanUsage = () => {
{isFreeTeam ? ( {isFreeTeam ? (
<> <>
<Flex mt="2" color={'#485264'} fontSize="sm">
<Box>{t('common:support.wallet.Plan reset time')}:</Box>
<Box ml={2}>{formatTime2YMD(standardPlan?.expiredTime)}</Box>
</Flex>
<Box mt="2" color={'#485264'} fontSize="sm"> <Box mt="2" color={'#485264'} fontSize="sm">
{t('common:info.free_plan')} {t('common:info.free_plan')}
</Box> </Box>
......
...@@ -7,8 +7,21 @@ import { removeFilesByPaths } from '@fastgpt/service/common/file/utils'; ...@@ -7,8 +7,21 @@ import { removeFilesByPaths } from '@fastgpt/service/common/file/utils';
import { NextAPI } from '@/service/middleware/entry'; import { NextAPI } from '@/service/middleware/entry';
import { createFileToken } from '@fastgpt/service/support/permission/controller'; import { createFileToken } from '@fastgpt/service/support/permission/controller';
import { ReadFileBaseUrl } from '@fastgpt/global/common/file/constants'; import { ReadFileBaseUrl } from '@fastgpt/global/common/file/constants';
import { addLog } from '@fastgpt/service/common/system/log';
import { authFrequencyLimit } from '@/service/common/frequencyLimit/api';
import { addSeconds } from 'date-fns';
const authUploadLimit = (tmbId: string) => {
if (!global.feConfigs.uploadFileMaxAmount) return;
return authFrequencyLimit({
eventId: `${tmbId}-uploadfile`,
maxAmount: global.feConfigs.uploadFileMaxAmount * 2,
expiredTime: addSeconds(new Date(), 30) // 30s
});
};
async function handler(req: NextApiRequest, res: NextApiResponse<any>) { async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const start = Date.now();
/* Creates the multer uploader */ /* Creates the multer uploader */
const upload = getUploadModel({ const upload = getUploadModel({
maxSize: (global.feConfigs?.uploadFileMaxSize || 500) * 1024 * 1024 maxSize: (global.feConfigs?.uploadFileMaxSize || 500) * 1024 * 1024
...@@ -16,9 +29,13 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) { ...@@ -16,9 +29,13 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const filePaths: string[] = []; const filePaths: string[] = [];
try { try {
const { teamId, tmbId } = await authCert({ req, authToken: true });
await authUploadLimit(tmbId);
const { file, bucketName, metadata } = await upload.doUpload(req, res); const { file, bucketName, metadata } = await upload.doUpload(req, res);
const { teamId, tmbId } = await authCert({ req, authToken: true }); addLog.info(`Upload file success ${file.originalname}, cost ${Date.now() - start}ms`);
if (!bucketName) { if (!bucketName) {
throw new Error('bucketName is empty'); throw new Error('bucketName is empty');
...@@ -34,22 +51,15 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) { ...@@ -34,22 +51,15 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
metadata: metadata metadata: metadata
}); });
jsonRes<{ return {
fileId: string; fileId,
previewUrl: string; previewUrl: `${ReadFileBaseUrl}?filename=${file.originalname}&token=${await createFileToken({
}>(res, { bucketName,
data: { teamId,
fileId, tmbId,
previewUrl: `${ReadFileBaseUrl}?filename=${file.originalname}&token=${await createFileToken( fileId
{ })}`
bucketName, };
teamId,
tmbId,
fileId
}
)}`
}
});
} catch (error) { } catch (error) {
jsonRes(res, { jsonRes(res, {
code: 500, code: 500,
......
...@@ -36,6 +36,7 @@ async function handler(req: ApiRequestProps<GetDatasetListBody>) { ...@@ -36,6 +36,7 @@ async function handler(req: ApiRequestProps<GetDatasetListBody>) {
return await authDataset({ return await authDataset({
req, req,
authToken: true, authToken: true,
authApiKey: true,
per: ReadPermissionVal, per: ReadPermissionVal,
datasetId: parentId datasetId: parentId
}); });
......
...@@ -37,11 +37,12 @@ type DatasetImportContextType = { ...@@ -37,11 +37,12 @@ type DatasetImportContextType = {
setSources: React.Dispatch<React.SetStateAction<ImportSourceItemType[]>>; setSources: React.Dispatch<React.SetStateAction<ImportSourceItemType[]>>;
} & TrainingFiledType; } & TrainingFiledType;
type ChunkSizeFieldType = 'embeddingChunkSize'; type ChunkSizeFieldType = 'embeddingChunkSize' | 'qaChunkSize';
export type ImportFormType = { export type ImportFormType = {
mode: TrainingModeEnum; mode: TrainingModeEnum;
way: ImportProcessWayEnum; way: ImportProcessWayEnum;
embeddingChunkSize: number; embeddingChunkSize: number;
qaChunkSize: number;
customSplitChar: string; customSplitChar: string;
qaPrompt: string; qaPrompt: string;
webSelector: string; webSelector: string;
...@@ -147,7 +148,6 @@ const DatasetImportContextProvider = ({ children }: { children: React.ReactNode ...@@ -147,7 +148,6 @@ const DatasetImportContextProvider = ({ children }: { children: React.ReactNode
steps steps
}); });
// -----
const vectorModel = datasetDetail.vectorModel; const vectorModel = datasetDetail.vectorModel;
const agentModel = datasetDetail.agentModel; const agentModel = datasetDetail.agentModel;
...@@ -156,6 +156,7 @@ const DatasetImportContextProvider = ({ children }: { children: React.ReactNode ...@@ -156,6 +156,7 @@ const DatasetImportContextProvider = ({ children }: { children: React.ReactNode
mode: TrainingModeEnum.chunk, mode: TrainingModeEnum.chunk,
way: ImportProcessWayEnum.auto, way: ImportProcessWayEnum.auto,
embeddingChunkSize: vectorModel?.defaultToken || 512, embeddingChunkSize: vectorModel?.defaultToken || 512,
qaChunkSize: Math.min(agentModel.maxResponse * 1, agentModel.maxContext * 0.7),
customSplitChar: '', customSplitChar: '',
qaPrompt: Prompt_AgentQA.description, qaPrompt: Prompt_AgentQA.description,
webSelector: '' webSelector: ''
...@@ -168,6 +169,7 @@ const DatasetImportContextProvider = ({ children }: { children: React.ReactNode ...@@ -168,6 +169,7 @@ const DatasetImportContextProvider = ({ children }: { children: React.ReactNode
const mode = processParamsForm.watch('mode'); const mode = processParamsForm.watch('mode');
const way = processParamsForm.watch('way'); const way = processParamsForm.watch('way');
const embeddingChunkSize = processParamsForm.watch('embeddingChunkSize'); const embeddingChunkSize = processParamsForm.watch('embeddingChunkSize');
const qaChunkSize = processParamsForm.watch('qaChunkSize');
const customSplitChar = processParamsForm.watch('customSplitChar'); const customSplitChar = processParamsForm.watch('customSplitChar');
const modeStaticParams: Record<TrainingModeEnum, TrainingFiledType> = { const modeStaticParams: Record<TrainingModeEnum, TrainingFiledType> = {
...@@ -180,7 +182,7 @@ const DatasetImportContextProvider = ({ children }: { children: React.ReactNode ...@@ -180,7 +182,7 @@ const DatasetImportContextProvider = ({ children }: { children: React.ReactNode
showChunkInput: false, showChunkInput: false,
showPromptInput: false, showPromptInput: false,
charsPointsPrice: agentModel.charsPointsPrice, charsPointsPrice: agentModel.charsPointsPrice,
priceTip: t('core.dataset.import.Auto mode Estimated Price Tips', { priceTip: t('common:core.dataset.import.Auto mode Estimated Price Tips', {
price: agentModel.charsPointsPrice price: agentModel.charsPointsPrice
}), }),
uploadRate: 100 uploadRate: 100
...@@ -195,22 +197,22 @@ const DatasetImportContextProvider = ({ children }: { children: React.ReactNode ...@@ -195,22 +197,22 @@ const DatasetImportContextProvider = ({ children }: { children: React.ReactNode
showChunkInput: true, showChunkInput: true,
showPromptInput: false, showPromptInput: false,
charsPointsPrice: vectorModel.charsPointsPrice, charsPointsPrice: vectorModel.charsPointsPrice,
priceTip: t('core.dataset.import.Embedding Estimated Price Tips', { priceTip: t('common:core.dataset.import.Embedding Estimated Price Tips', {
price: vectorModel.charsPointsPrice price: vectorModel.charsPointsPrice
}), }),
uploadRate: 150 uploadRate: 150
}, },
[TrainingModeEnum.qa]: { [TrainingModeEnum.qa]: {
chunkSizeField: 'embeddingChunkSize' as ChunkSizeFieldType, chunkSizeField: 'qaChunkSize' as ChunkSizeFieldType,
chunkOverlapRatio: 0, chunkOverlapRatio: 0,
maxChunkSize: 4096, maxChunkSize: Math.min(agentModel.maxResponse * 4, agentModel.maxContext * 0.7),
minChunkSize: 512, minChunkSize: 4000,
autoChunkSize: agentModel.maxContext * 0.55 || 6000, autoChunkSize: Math.min(agentModel.maxResponse * 1, agentModel.maxContext * 0.7),
chunkSize: embeddingChunkSize || agentModel.maxContext * 0.55 || 6000, chunkSize: qaChunkSize,
showChunkInput: true, showChunkInput: true,
showPromptInput: true, showPromptInput: true,
charsPointsPrice: agentModel.charsPointsPrice, charsPointsPrice: agentModel.charsPointsPrice,
priceTip: t('core.dataset.import.QA Estimated Price Tips', { priceTip: t('common:core.dataset.import.QA Estimated Price Tips', {
price: agentModel?.charsPointsPrice price: agentModel?.charsPointsPrice
}), }),
uploadRate: 30 uploadRate: 30
...@@ -228,7 +230,6 @@ const DatasetImportContextProvider = ({ children }: { children: React.ReactNode ...@@ -228,7 +230,6 @@ const DatasetImportContextProvider = ({ children }: { children: React.ReactNode
customSplitChar customSplitChar
} }
}; };
const chunkSize = wayStaticPrams[way].chunkSize; const chunkSize = wayStaticPrams[way].chunkSize;
const contextValue = { const contextValue = {
......
...@@ -42,7 +42,8 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean ...@@ -42,7 +42,8 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean
showChunkInput, showChunkInput,
showPromptInput, showPromptInput,
maxChunkSize, maxChunkSize,
priceTip priceTip,
chunkSize
} = useContextSelector(DatasetImportContext, (v) => v); } = useContextSelector(DatasetImportContext, (v) => v);
const { getValues, setValue, register, watch } = processParamsForm; const { getValues, setValue, register, watch } = processParamsForm;
const { toast } = useToast(); const { toast } = useToast();
...@@ -74,8 +75,15 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean ...@@ -74,8 +75,15 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean
); );
return ( return (
<Box h={'100%'} display={['block', 'flex']} gap={5} fontSize={'sm'}> <Box h={'100%'} display={['block', 'flex']} fontSize={'sm'}>
<Box flex={'1 0 0'} minW={['auto', '540px']} maxW={'600px'}> <Box
flex={'1 0 0'}
minW={['auto', '540px']}
maxW={'600px'}
h={['auto', '100%']}
overflow={'auto'}
pr={[0, 3]}
>
<Flex alignItems={'center'}> <Flex alignItems={'center'}>
<MyIcon name={'common/settingLight'} w={'20px'} /> <MyIcon name={'common/settingLight'} w={'20px'} />
<Box fontSize={'md'}>{t('common:core.dataset.import.Data process params')}</Box> <Box fontSize={'md'}>{t('common:core.dataset.import.Data process params')}</Box>
...@@ -138,7 +146,7 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean ...@@ -138,7 +146,7 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean
}} }}
> >
<MyTooltip <MyTooltip
label={t('core.dataset.import.Chunk Range', { label={t('common:core.dataset.import.Chunk Range', {
min: minChunkSize, min: minChunkSize,
max: maxChunkSize max: maxChunkSize
})} })}
...@@ -148,6 +156,7 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean ...@@ -148,6 +156,7 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean
step={100} step={100}
min={minChunkSize} min={minChunkSize}
max={maxChunkSize} max={maxChunkSize}
value={chunkSize}
onChange={(e) => { onChange={(e) => {
setValue(chunkSizeField, +e); setValue(chunkSizeField, +e);
}} }}
...@@ -279,7 +288,7 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean ...@@ -279,7 +288,7 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean
</Button> </Button>
</Flex> </Flex>
</Box> </Box>
<Box flex={'1 0 0'} w={['auto', '0']}> <Box flex={'1 0 0'} w={['auto', '0']} h={['auto', '100%']} overflow={'auto'} pl={[0, 3]}>
<Preview showPreviewChunks={showPreviewChunks} /> <Preview showPreviewChunks={showPreviewChunks} />
</Box> </Box>
......
import { AuthFrequencyLimitProps } from '@fastgpt/global/common/frequenctLimit/type';
import { POST } from '@fastgpt/service/common/api/plusRequest';
export const authFrequencyLimit = (data: AuthFrequencyLimitProps) => {
if (!global.feConfigs.isPlus) return;
return POST('/common/freequencyLimit/auth', data);
};
import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team'; import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team';
import { pushChatUsage } from '@/service/support/wallet/usage/push';
import { defaultApp } from '@/web/core/app/constants'; import { defaultApp } from '@/web/core/app/constants';
import { getNextTimeByCronStringAndTimezone } from '@fastgpt/global/common/string/time'; import { getNextTimeByCronStringAndTimezone } from '@fastgpt/global/common/string/time';
import { getNanoid } from '@fastgpt/global/common/string/tools'; import { getNanoid } from '@fastgpt/global/common/string/tools';
...@@ -9,6 +10,7 @@ import { ...@@ -9,6 +10,7 @@ import {
initWorkflowEdgeStatus, initWorkflowEdgeStatus,
storeNodes2RuntimeNodes storeNodes2RuntimeNodes
} from '@fastgpt/global/core/workflow/runtime/utils'; } from '@fastgpt/global/core/workflow/runtime/utils';
import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
import { addLog } from '@fastgpt/service/common/system/log'; import { addLog } from '@fastgpt/service/common/system/log';
import { MongoApp } from '@fastgpt/service/core/app/schema'; import { MongoApp } from '@fastgpt/service/core/app/schema';
import { dispatchWorkFlow } from '@fastgpt/service/core/workflow/dispatch'; import { dispatchWorkFlow } from '@fastgpt/service/core/workflow/dispatch';
...@@ -29,7 +31,7 @@ export const getScheduleTriggerApp = async () => { ...@@ -29,7 +31,7 @@ export const getScheduleTriggerApp = async () => {
const { user } = await getUserChatInfoAndAuthTeamPoints(app.tmbId); const { user } = await getUserChatInfoAndAuthTeamPoints(app.tmbId);
try { try {
await dispatchWorkFlow({ const { flowUsages } = await dispatchWorkFlow({
chatId: getNanoid(), chatId: getNanoid(),
user, user,
mode: 'chat', mode: 'chat',
...@@ -53,6 +55,14 @@ export const getScheduleTriggerApp = async () => { ...@@ -53,6 +55,14 @@ export const getScheduleTriggerApp = async () => {
detail: false, detail: false,
maxRunTimes: 200 maxRunTimes: 200
}); });
pushChatUsage({
appName: app.name,
appId: app._id,
teamId: String(app.teamId),
tmbId: String(app.tmbId),
source: UsageSourceEnum.cronJob,
flowUsages
});
} catch (error) { } catch (error) {
addLog.error('Schedule trigger error', error); addLog.error('Schedule trigger error', error);
} }
......
...@@ -13,6 +13,7 @@ import { ...@@ -13,6 +13,7 @@ import {
import { defaultDatasetDetail } from '../constants'; import { defaultDatasetDetail } from '../constants';
import { DatasetUpdateBody } from '@fastgpt/global/core/dataset/api'; import { DatasetUpdateBody } from '@fastgpt/global/core/dataset/api';
import { DatasetItemType, DatasetTagType } from '@fastgpt/global/core/dataset/type'; import { DatasetItemType, DatasetTagType } from '@fastgpt/global/core/dataset/type';
import { useSystemStore } from '@/web/common/system/useSystemStore';
type DatasetPageContextType = { type DatasetPageContextType = {
datasetId: string; datasetId: string;
...@@ -83,6 +84,7 @@ export const DatasetPageContextProvider = ({ ...@@ -83,6 +84,7 @@ export const DatasetPageContextProvider = ({
datasetId: string; datasetId: string;
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { feConfigs } = useSystemStore();
// dataset detail // dataset detail
const [datasetDetail, setDatasetDetail] = useState(defaultDatasetDetail); const [datasetDetail, setDatasetDetail] = useState(defaultDatasetDetail);
...@@ -123,6 +125,8 @@ export const DatasetPageContextProvider = ({ ...@@ -123,6 +125,8 @@ export const DatasetPageContextProvider = ({
const [allDatasetTags, setAllDatasetTags] = useState<DatasetTagType[]>([]); const [allDatasetTags, setAllDatasetTags] = useState<DatasetTagType[]>([]);
const loadAllDatasetTags = async ({ id }: { id: string }) => { const loadAllDatasetTags = async ({ id }: { id: string }) => {
if (!feConfigs?.isPlus) return;
const { list } = await getAllTags(id); const { list } = await getAllTags(id);
setAllDatasetTags(list); setAllDatasetTags(list);
}; };
......
...@@ -4,7 +4,6 @@ import { UserAuthTypeEnum } from '@fastgpt/global/support/user/auth/constants'; ...@@ -4,7 +4,6 @@ import { UserAuthTypeEnum } from '@fastgpt/global/support/user/auth/constants';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { i18nT } from '@fastgpt/web/i18n/utils';
let timer: NodeJS.Timeout; let timer: NodeJS.Timeout;
export const useSendCode = () => { export const useSendCode = () => {
...@@ -29,8 +28,8 @@ export const useSendCode = () => { ...@@ -29,8 +28,8 @@ export const useSendCode = () => {
}, 1000); }, 1000);
}, },
{ {
successToast: i18nT('user:password.code_sended'), successToast: t('user:password.code_sended'),
errorToast: i18nT('user:password.code_send_error'), errorToast: t('user:password.code_send_error'),
refreshDeps: [codeCountDown, feConfigs?.googleClientVerKey] refreshDeps: [codeCountDown, feConfigs?.googleClientVerKey]
} }
); );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment