Compare commits
6 Commits
v4.8-alpha
...
v4.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59fd94384d | ||
|
|
ee8cb0915e | ||
|
|
8cf643d972 | ||
|
|
26f4c92124 | ||
|
|
f351d4ea68 | ||
|
|
d70efe1d6f |
43
.vscode/i18n-ally-custom-framework.yml
vendored
Normal file
43
.vscode/i18n-ally-custom-framework.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# .vscode/i18n-ally-custom-framework.yml
|
||||
|
||||
# An array of strings which contain Language Ids defined by VS Code
|
||||
# You can check available language ids here: https://code.visualstudio.com/docs/languages/identifiers
|
||||
languageIds:
|
||||
- javascript
|
||||
- typescript
|
||||
- javascriptreact
|
||||
- typescriptreact
|
||||
|
||||
# An array of RegExes to find the key usage. **The key should be captured in the first match group**.
|
||||
# You should unescape RegEx strings in order to fit in the YAML file
|
||||
# To help with this, you can use https://www.freeformatter.com/json-escape.html
|
||||
usageMatchRegex:
|
||||
# The following example shows how to detect `t("your.i18n.keys")`
|
||||
# the `{key}` will be placed by a proper keypath matching regex,
|
||||
# you can ignore it and use your own matching rules as well
|
||||
- "[^\\w\\d]t\\(['\"`]({key})['\"`]"
|
||||
- "[^\\w\\d]commonT\\(['\"`]({key})['\"`]"
|
||||
# 支持 appT("your.i18n.keys")
|
||||
- "[^\\w\\d]appT\\(['\"`]({key})['\"`]"
|
||||
# 支持 datasetT("your.i18n.keys")
|
||||
- "[^\\w\\d]datasetT\\(['\"`]({key})['\"`]"
|
||||
- "[^\\w\\d]fileT\\(['\"`]({key})['\"`]"
|
||||
- "[^\\w\\d]publishT\\(['\"`]({key})['\"`]"
|
||||
|
||||
# A RegEx to set a custom scope range. This scope will be used as a prefix when detecting keys
|
||||
# and works like how the i18next framework identifies the namespace scope from the
|
||||
# useTranslation() hook.
|
||||
# You should unescape RegEx strings in order to fit in the YAML file
|
||||
# To help with this, you can use https://www.freeformatter.com/json-escape.html
|
||||
scopeRangeRegex: "useTranslation\\(\\s*\\[?\\s*['\"`](.*?)['\"`]"
|
||||
|
||||
# An array of strings containing refactor templates.
|
||||
# The "$1" will be replaced by the keypath specified.
|
||||
# Optional: uncomment the following two lines to use
|
||||
|
||||
# refactorTemplates:
|
||||
# - i18n.get("$1")
|
||||
|
||||
|
||||
# If set to true, only enables this custom framework (will disable all built-in frameworks)
|
||||
monopoly: true
|
||||
@@ -257,6 +257,13 @@ PG 数据库没有连接上/初始化失败,可以查看日志。FastGPT 会
|
||||
2. 非 docker 部署的,需要手动安装 pg vector 插件
|
||||
3. 查看 fastgpt 日志,有没有相关报错
|
||||
|
||||
### Illegal instruction
|
||||
|
||||
可能原因:
|
||||
|
||||
1. arm架构。需要使用 Mongo 官方镜像: mongo:5.0.18
|
||||
2. cpu 不支持 AVX,无法用 mongo5,需要换成 mongo4.x。把 mongo 的 image 换成: mongo:4.4.29
|
||||
|
||||
### Operation `auth_codes.findOne()` buffering timed out after 10000ms
|
||||
|
||||
mongo连接失败,查看mongo的运行状态对应日志。
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
# 数据库的默认账号和密码仅首次运行时设置有效
|
||||
# 如果修改了账号密码,记得改数据库和项目连接参数,别只改一处~
|
||||
# 该配置文件只是给快速启动,测试使用。正式使用,记得务必修改账号密码,以及调整合适的知识库参数,共享内存等。
|
||||
# 如何无法访问 dockerhub 和 git,可以用阿里云(阿里云没有arm包)
|
||||
|
||||
version: '3.3'
|
||||
services:
|
||||
pg:
|
||||
# image: pgvector/pgvector:0.7.0-pg15 # docker hub
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.7.0 # 阿里云
|
||||
image: pgvector/pgvector:0.7.0-pg15 # docker hub
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.7.0 # 阿里云
|
||||
container_name: pg
|
||||
restart: always
|
||||
ports: # 生产环境建议不要暴露
|
||||
@@ -21,7 +22,9 @@ services:
|
||||
volumes:
|
||||
- ./pg/data:/var/lib/postgresql/data
|
||||
mongo:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/mongo:5.0.18
|
||||
image: mongo:5.0.18 # dockerhub
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/mongo:5.0.18 # 阿里云
|
||||
# image: mongo:4.4.29 # cpu不支持AVX时候使用
|
||||
container_name: mongo
|
||||
restart: always
|
||||
ports:
|
||||
@@ -66,8 +69,8 @@ services:
|
||||
wait $$!
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.7 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.7 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt:v4.8 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8 # 阿里云
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
||||
@@ -4,7 +4,7 @@ export enum BucketNameEnum {
|
||||
}
|
||||
export const bucketNameMap = {
|
||||
[BucketNameEnum.dataset]: {
|
||||
label: 'common.file.bucket.dataset'
|
||||
label: 'file.bucket.dataset'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -13,36 +13,36 @@ export enum MongoImageTypeEnum {
|
||||
}
|
||||
export const mongoImageTypeMap = {
|
||||
[MongoImageTypeEnum.systemAvatar]: {
|
||||
label: 'common.file.type.appAvatar',
|
||||
label: 'appAvatar',
|
||||
unique: true
|
||||
},
|
||||
[MongoImageTypeEnum.appAvatar]: {
|
||||
label: 'common.file.type.appAvatar',
|
||||
label: 'appAvatar',
|
||||
unique: true
|
||||
},
|
||||
[MongoImageTypeEnum.pluginAvatar]: {
|
||||
label: 'common.file.type.pluginAvatar',
|
||||
label: 'pluginAvatar',
|
||||
unique: true
|
||||
},
|
||||
[MongoImageTypeEnum.datasetAvatar]: {
|
||||
label: 'common.file.type.datasetAvatar',
|
||||
label: 'datasetAvatar',
|
||||
unique: true
|
||||
},
|
||||
[MongoImageTypeEnum.userAvatar]: {
|
||||
label: 'common.file.type.userAvatar',
|
||||
label: 'userAvatar',
|
||||
unique: true
|
||||
},
|
||||
[MongoImageTypeEnum.teamAvatar]: {
|
||||
label: 'common.file.type.teamAvatar',
|
||||
label: 'teamAvatar',
|
||||
unique: true
|
||||
},
|
||||
|
||||
[MongoImageTypeEnum.chatImage]: {
|
||||
label: 'common.file.type.chatImage',
|
||||
label: 'chatImage',
|
||||
unique: false
|
||||
},
|
||||
[MongoImageTypeEnum.collectionImage]: {
|
||||
label: 'common.file.type.collectionImage',
|
||||
label: 'collectionImage',
|
||||
unique: false
|
||||
}
|
||||
};
|
||||
|
||||
@@ -52,13 +52,35 @@ export const str2OpenApiSchema = async (yamlStr = ''): Promise<OpenApiJsonSchema
|
||||
})
|
||||
.flat()
|
||||
.filter(Boolean) as OpenApiJsonSchema['pathData'];
|
||||
|
||||
return { pathData, serverPath };
|
||||
} catch (err) {
|
||||
throw new Error('Invalid Schema');
|
||||
}
|
||||
};
|
||||
|
||||
export const getType = (schema: { type: string; items?: { type: string } }) => {
|
||||
const typeMap: { [key: string]: WorkflowIOValueTypeEnum } = {
|
||||
string: WorkflowIOValueTypeEnum.arrayString,
|
||||
number: WorkflowIOValueTypeEnum.arrayNumber,
|
||||
integer: WorkflowIOValueTypeEnum.arrayNumber,
|
||||
boolean: WorkflowIOValueTypeEnum.arrayBoolean,
|
||||
object: WorkflowIOValueTypeEnum.arrayObject
|
||||
};
|
||||
|
||||
if (schema?.type === 'integer') {
|
||||
return WorkflowIOValueTypeEnum.number;
|
||||
}
|
||||
|
||||
if (schema?.type === 'array' && schema?.items) {
|
||||
const itemType = typeMap[schema.items.type];
|
||||
if (itemType) {
|
||||
return itemType;
|
||||
}
|
||||
}
|
||||
|
||||
return schema?.type as WorkflowIOValueTypeEnum;
|
||||
};
|
||||
|
||||
export const httpApiSchema2Plugins = async ({
|
||||
parentId,
|
||||
apiSchemaStr = '',
|
||||
@@ -87,7 +109,7 @@ export const httpApiSchema2Plugins = async ({
|
||||
...(item.params?.map((param: any) => {
|
||||
return {
|
||||
key: param.name,
|
||||
valueType: param.schema.type,
|
||||
valueType: getType(param.schema),
|
||||
label: param.name,
|
||||
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
||||
required: param.required,
|
||||
@@ -109,7 +131,7 @@ export const httpApiSchema2Plugins = async ({
|
||||
const prop = properties[key];
|
||||
return {
|
||||
key,
|
||||
valueType: prop.type,
|
||||
valueType: getType(prop),
|
||||
label: key,
|
||||
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
||||
required: false,
|
||||
@@ -136,7 +158,7 @@ export const httpApiSchema2Plugins = async ({
|
||||
return {
|
||||
id,
|
||||
key: param.name,
|
||||
valueType: param.schema.type,
|
||||
valueType: getType(param.schema),
|
||||
label: param.name,
|
||||
type: FlowNodeOutputTypeEnum.source
|
||||
};
|
||||
@@ -147,7 +169,7 @@ export const httpApiSchema2Plugins = async ({
|
||||
return {
|
||||
id,
|
||||
key,
|
||||
valueType: properties[key].type,
|
||||
valueType: getType(properties[key]),
|
||||
label: key,
|
||||
type: FlowNodeOutputTypeEnum.source,
|
||||
edit: true
|
||||
@@ -159,7 +181,7 @@ export const httpApiSchema2Plugins = async ({
|
||||
...(item.params?.map((param: any) => {
|
||||
return {
|
||||
key: param.name,
|
||||
valueType: param.schema.type,
|
||||
valueType: getType(param.schema),
|
||||
label: param.name,
|
||||
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
||||
canEdit: true,
|
||||
@@ -173,7 +195,7 @@ export const httpApiSchema2Plugins = async ({
|
||||
...(propsKeys?.map((key) => {
|
||||
return {
|
||||
key,
|
||||
valueType: properties[key].type,
|
||||
valueType: getType(properties[key]),
|
||||
label: key,
|
||||
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
||||
canEdit: true,
|
||||
@@ -197,7 +219,7 @@ export const httpApiSchema2Plugins = async ({
|
||||
if (param.in === 'header') {
|
||||
httpNodeHeaders.push({
|
||||
key: param.name,
|
||||
type: param.schema?.type || WorkflowIOValueTypeEnum.string,
|
||||
type: getType(param.schema) || WorkflowIOValueTypeEnum.string,
|
||||
value: `{{${param.name}}}`
|
||||
});
|
||||
} else if (param.in === 'body') {
|
||||
@@ -209,7 +231,7 @@ export const httpApiSchema2Plugins = async ({
|
||||
} else if (param.in === 'query') {
|
||||
httpNodeParams.push({
|
||||
key: param.name,
|
||||
type: param.schema?.type || WorkflowIOValueTypeEnum.string,
|
||||
type: getType(param.schema) || WorkflowIOValueTypeEnum.string,
|
||||
value: `{{${param.name}}}`
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,14 +8,14 @@ export const mongoSessionRun = async <T = unknown>(fn: (session: ClientSession)
|
||||
const result = await fn(session);
|
||||
|
||||
await session.commitTransaction();
|
||||
session.endSession();
|
||||
await session.endSession();
|
||||
|
||||
return result as T;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
await session.abortTransaction();
|
||||
session.endSession();
|
||||
await session.endSession();
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"papaparse": "^5.4.1",
|
||||
"pdfjs-dist": "4.0.269",
|
||||
"react": "18.2.0",
|
||||
"use-context-selector": "^1.4.4",
|
||||
"react-day-picker": "^8.7.1",
|
||||
"react-dom": "18.2.0",
|
||||
"react-i18next": "13.5.0",
|
||||
|
||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -301,6 +301,9 @@ importers:
|
||||
react-i18next:
|
||||
specifier: 13.5.0
|
||||
version: 13.5.0(i18next@23.10.0)(react-dom@18.2.0)(react@18.2.0)
|
||||
use-context-selector:
|
||||
specifier: ^1.4.4
|
||||
version: 1.4.4(react-dom@18.2.0)(react@18.2.0)(scheduler@0.23.0)
|
||||
devDependencies:
|
||||
'@types/lodash':
|
||||
specifier: ^4.14.191
|
||||
|
||||
45
projects/app/i18n/en/app.json
Normal file
45
projects/app/i18n/en/app.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"AI Advanced Settings": "AI Advanced Settings",
|
||||
"AI Settings": "AI Settings",
|
||||
"Advance App TestTip": "Current app may be in advanced orchestration mode\nTo switch to【Simple Mode】please click the save button on the left",
|
||||
"App Detail": "App Details",
|
||||
"Apps Share": "Apps Share",
|
||||
"Basic Settings": "Basic Settings",
|
||||
"Chat Debug": "Chat Debug",
|
||||
"Chat Logs Tips": "Logs will record online, shared and API (chatId required) conversation records for this app",
|
||||
"Chat logs": "Chat Logs",
|
||||
"Confirm Del App Tip": "Confirm to delete this app and all its chat records?",
|
||||
"Connection is invalid": "Connection is invalid",
|
||||
"Connection type is different": "Connection type is different",
|
||||
"Copy Module Config": "Copy Config",
|
||||
"Dataset Quote Template": "Knowledge Base QA Mode",
|
||||
"Export Config Successful": "Config copied, please check for important data",
|
||||
"Export Configs": "Export Configs",
|
||||
"Feedback Count": "User Feedback",
|
||||
"Import Configs": "Import Configs",
|
||||
"Import Configs Failed": "Failed to import configs, please ensure configs are valid!",
|
||||
"Input Field Settings": "Input Field Settings",
|
||||
"Logs Empty": "No logs yet~",
|
||||
"Logs Message Total": "Total Messages",
|
||||
"Logs Source": "Source",
|
||||
"Logs Time": "Time",
|
||||
"Logs Title": "Title",
|
||||
"Mark Count": "Marked Answer Count",
|
||||
"My Apps": "My Apps",
|
||||
"Output Field Settings": "Output Field Settings",
|
||||
"Paste Config": "Paste Config",
|
||||
"To Chat": "Go to Chat",
|
||||
"To Settings": "View Details",
|
||||
"Variable Key Repeat Tip": "Variable key is duplicate",
|
||||
"module": {
|
||||
"Combine Modules": "Combine Modules",
|
||||
"Custom Title Tip": "This title will be displayed during the conversation",
|
||||
"My Modules": "My Modules",
|
||||
"No Modules": "No modules yet~",
|
||||
"System Module": "System Module",
|
||||
"type": "\"{{type}}\" type\n{{description}}"
|
||||
},
|
||||
"modules": {
|
||||
"Title is required": "Module name cannot be empty"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
0
projects/app/i18n/en/dataset.json
Normal file
0
projects/app/i18n/en/dataset.json
Normal file
23
projects/app/i18n/en/file.json
Normal file
23
projects/app/i18n/en/file.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Click to view file": "Click to view the original file",
|
||||
"Release the mouse to upload the file": "Release the mouse to upload the file",
|
||||
"upload error description": "Only supports uploading multiple files or one folder at a time",
|
||||
|
||||
"Empty file tip": "The file content is empty, the file may not be readable or it may be a pure image file.",
|
||||
"File Content": "File Content",
|
||||
"File Name": "File Name",
|
||||
"File Size": "File Size",
|
||||
"File content can not be empty": "File content cannot be empty",
|
||||
"Filename Can not Be Empty": "Filename cannot be empty",
|
||||
"Read File Error": "File parsing failed",
|
||||
"Select and drag file tip": "Click or drag files here to upload",
|
||||
"Select failed": "File selection failed",
|
||||
"Select file amount limit": "You can select up to {{max}} files",
|
||||
"Select file amount limit 100": "You can select up to 100 files at a time",
|
||||
"Some file count exceeds limit": "Exceeds {{maxCount}} files, automatically truncated",
|
||||
"Some file size exceeds limit": "Some files exceed: {{maxSize}}, have been filtered",
|
||||
"Support file type": "Supports {{fileType}} type files",
|
||||
"Support max count": "Supports up to {{maxCount}} files.",
|
||||
"Support max size": "Maximum size per file: {{maxSize}}.",
|
||||
"Upload failed": "Upload failed"
|
||||
}
|
||||
22
projects/app/i18n/en/publish.json
Normal file
22
projects/app/i18n/en/publish.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"Copy IFrame": "Embed webpage",
|
||||
"Copy Link": "Copy",
|
||||
"Create API Key": "Create new Key",
|
||||
"Create Link": "Create link",
|
||||
"Default Response": "Default Response",
|
||||
"Delete Link": "Delete link",
|
||||
"Edit API Key": "Edit Key information",
|
||||
"Edit IFrame Link": "Update embed link",
|
||||
"Edit Link": "Edit",
|
||||
"Edit Share Window": "Update share window",
|
||||
"Feishu name": "Lark",
|
||||
"Link Name": "Name of the share link",
|
||||
"QPM Tips": "How many times per minute can each IP ask at most",
|
||||
"QPM is empty": "QPM cannot be empty",
|
||||
"app key tips": "These keys have the current application identification, refer to the document for specific use ",
|
||||
"key alias": "key alias, for display only ",
|
||||
"key tips": "You can use the API Key to access certain interfaces (you can't access the app, you need to use the API key within the app to access the app)",
|
||||
"token auth": "Token authentication",
|
||||
"token auth Tips": "Identity verification server address, if this value is filled, a request will be sent to the specified server before each conversation to perform identity verification",
|
||||
"token auth use cases": "View usage instructions for identity verification"
|
||||
}
|
||||
44
projects/app/i18n/zh/app.json
Normal file
44
projects/app/i18n/zh/app.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"AI Settings": "AI 配置",
|
||||
"Advance App TestTip": "当前应用可能为高级编排模式\n如需切换为【简易模式】请点击左侧保存按键",
|
||||
"App Detail": "应用详情",
|
||||
"Apps Share": "应用分享",
|
||||
"Basic Settings": "基本信息",
|
||||
"Chat Debug": "调试预览",
|
||||
"Chat Logs Tips": "日志会记录该应用的在线、分享和 API(需填写 chatId) 对话记录",
|
||||
"Chat logs": "对话日志",
|
||||
"Confirm Del App Tip": "确认删除该应用及其所有聊天记录?",
|
||||
"Connection is invalid": "连接无效",
|
||||
"Connection type is different": "连接的类型不一致",
|
||||
"Copy Module Config": "复制配置",
|
||||
"Dataset Quote Template": "知识库问答模式",
|
||||
"Export Config Successful": "已复制配置,自动过滤部分敏感信息,请注意检查是否仍有敏感数据",
|
||||
"Export Configs": "导出配置",
|
||||
"Feedback Count": "用户反馈",
|
||||
"Import Configs": "导入配置",
|
||||
"Import Configs Failed": "导入配置失败,请确保配置正常!",
|
||||
"Input Field Settings": "输入字段编辑",
|
||||
"Logs Empty": "还没有日志噢~",
|
||||
"Logs Message Total": "消息总数",
|
||||
"Logs Source": "来源",
|
||||
"Logs Time": "时间",
|
||||
"Logs Title": "标题",
|
||||
"Mark Count": "标注答案数量",
|
||||
"My Apps": "我的应用",
|
||||
"Output Field Settings": "输出字段编辑",
|
||||
"Paste Config": "粘贴配置",
|
||||
"To Chat": "前去对话",
|
||||
"To Settings": "查看详情",
|
||||
"Variable Key Repeat Tip": "变量 key 重复",
|
||||
"module": {
|
||||
"Combine Modules": "组合模块",
|
||||
"Custom Title Tip": "该标题名字会展示在对话过程中",
|
||||
"My Modules": "",
|
||||
"No Modules": "还没有模块~",
|
||||
"System Module": "系统模块",
|
||||
"type": "\"{{type}}\"类型\n{{description}}"
|
||||
},
|
||||
"modules": {
|
||||
"Title is required": "模块名不能为空"
|
||||
}
|
||||
}
|
||||
@@ -2,57 +2,14 @@
|
||||
"App": "应用",
|
||||
"Export": "导出",
|
||||
"Folder": "文件夹",
|
||||
"Login": "登录",
|
||||
"Move": "移动",
|
||||
"Name": "名称",
|
||||
"New Create": "新建",
|
||||
"Rename": "重命名",
|
||||
"Running": "运行中",
|
||||
"UnKnow": "未知",
|
||||
"Warning": "提示",
|
||||
"app": {
|
||||
"AI Advanced Settings": "AI 高级配置",
|
||||
"AI Settings": "AI 配置",
|
||||
"Advance App TestTip": "当前应用可能为高级编排模式\n如需切换为【简易模式】请点击左侧保存按键",
|
||||
"App Detail": "应用详情",
|
||||
"Apps Share": "应用分享",
|
||||
"Basic Settings": "基本信息",
|
||||
"Chat Debug": "调试预览",
|
||||
"Chat Logs Tips": "日志会记录该应用的在线、分享和 API(需填写 chatId) 对话记录",
|
||||
"Chat logs": "对话日志",
|
||||
"Confirm Del App Tip": "确认删除该应用及其所有聊天记录?",
|
||||
"Connection is invalid": "连接无效",
|
||||
"Connection type is different": "连接的类型不一致",
|
||||
"Copy Module Config": "复制配置",
|
||||
"Dataset Quote Template": "知识库问答模式",
|
||||
"Export Config Successful": "已复制配置,自动过滤部分敏感信息,请注意检查是否仍有敏感数据",
|
||||
"Export Configs": "导出配置",
|
||||
"Feedback Count": "用户反馈",
|
||||
"Import Configs": "导入配置",
|
||||
"Import Configs Failed": "导入配置失败,请确保配置正常!",
|
||||
"Input Field Settings": "输入字段编辑",
|
||||
"Logs Empty": "还没有日志噢~",
|
||||
"Logs Message Total": "消息总数",
|
||||
"Logs Source": "来源",
|
||||
"Logs Time": "时间",
|
||||
"Logs Title": "标题",
|
||||
"Mark Count": "标注答案数量",
|
||||
"My Apps": "我的应用",
|
||||
"Output Field Settings": "输出字段编辑",
|
||||
"Paste Config": "粘贴配置",
|
||||
"To Chat": "前去对话",
|
||||
"To Settings": "查看详情",
|
||||
"Variable Key Repeat Tip": "变量 key 重复",
|
||||
"module": {
|
||||
"Combine Modules": "组合模块",
|
||||
"Custom Title Tip": "该标题名字会展示在对话过程中",
|
||||
"My Modules": "",
|
||||
"No Modules": "还没有模块~",
|
||||
"System Module": "系统模块",
|
||||
"type": "\"{{type}}\"类型\n{{description}}"
|
||||
},
|
||||
"modules": {
|
||||
"Title is required": "模块名不能为空"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"Action": "操作",
|
||||
"Add": "添加",
|
||||
@@ -113,7 +70,6 @@
|
||||
"Name": "名称",
|
||||
"Name Can": "名称不能为空",
|
||||
"Name is empty": "名称不能为空",
|
||||
"New Create": "新建",
|
||||
"Next Step": "下一步",
|
||||
"No more data": "没有更多了~",
|
||||
"Not open": "未开启",
|
||||
@@ -193,26 +149,6 @@
|
||||
"Update error": "更新失败",
|
||||
"unKnow": "出现了点意外~"
|
||||
},
|
||||
"export": "",
|
||||
"file": {
|
||||
"Empty file tip": "文件内容为空,可能该文件无法读取或为纯图片文件内容。",
|
||||
"File Content": "文件内容",
|
||||
"File Name": "文件名",
|
||||
"File Size": "文件大小",
|
||||
"File content can not be empty": "文件内容不能为空",
|
||||
"Filename Can not Be Empty": "文件名不能为空",
|
||||
"Read File Error": "解析文件失败",
|
||||
"Select and drag file tip": "点击或拖动文件到此处上传",
|
||||
"Select failed": "选择文件异常",
|
||||
"Select file amount limit": "最多选择 {{max}} 个文件",
|
||||
"Select file amount limit 100": "每次最多选择100个文件",
|
||||
"Some file count exceeds limit": "超出{{maxCount}}个文件,已自动截取",
|
||||
"Some file size exceeds limit": "部分文件超出: {{maxSize}},已被过滤",
|
||||
"Support file type": "支持 {{fileType}} 类型文件",
|
||||
"Support max count": "最多支持 {{maxCount}} 个文件。",
|
||||
"Support max size": "单个文件最大 {{maxSize}}。",
|
||||
"Upload failed": "上传异常"
|
||||
},
|
||||
"folder": {
|
||||
"Drag Tip": "点我可拖动",
|
||||
"Move Success": "移动成功",
|
||||
@@ -644,7 +580,8 @@
|
||||
"success": "开始同步"
|
||||
}
|
||||
},
|
||||
"training": {}
|
||||
"training": {
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"Auxiliary Data": "辅助数据",
|
||||
@@ -707,7 +644,6 @@
|
||||
"Estimated Price Tips": "QA计费为\n输入: {{charsPointsPrice}}积分/1k Tokens",
|
||||
"Estimated points": "预估消耗 {{points}} 积分",
|
||||
"Fetch Error": "获取链接失败",
|
||||
"Fetch Url": "网络链接",
|
||||
"Fetch url placeholder": "最多10个链接,每行一个。",
|
||||
"Fetch url tip": "仅支持读取静态链接,请注意检查结果",
|
||||
"File chunk amount": "分段: {{amount}}",
|
||||
@@ -933,10 +869,10 @@
|
||||
"params": "Params"
|
||||
},
|
||||
"input": {
|
||||
"Add Branch": "添加分支",
|
||||
"Add Input": "添加入参",
|
||||
"Input Number": "入参: {{length}}",
|
||||
"add": "添加条件",
|
||||
"Add Branch": "添加分支",
|
||||
"description": {
|
||||
"Background": "你可以添加一些特定内容的介绍,从而更好的识别用户的问题类型。这个内容通常是给模型介绍一个它不知道的内容。",
|
||||
"HTTP Dynamic Input": "接收前方节点的输出值作为变量,这些变量可以被HTTP请求参数使用。",
|
||||
@@ -1252,73 +1188,6 @@
|
||||
"overSize": "团队成员超出上限"
|
||||
}
|
||||
},
|
||||
"file": {
|
||||
"Click to download file template": "点击下载模板:{{name}}",
|
||||
"Click to view file": "点击查看原始文件",
|
||||
"Create File": "创建新文件",
|
||||
"Create file": "创建文件",
|
||||
"Drag and drop": "拖拽文件至此",
|
||||
"Fetch Url": "链接读取",
|
||||
"If the imported file is garbled, please convert CSV to UTF-8 encoding format": "如果导入文件乱码,请将 CSV 转成 UTF-8 编码格式",
|
||||
"Parse": "{{name}} 解析中...",
|
||||
"Release the mouse to upload the file": "松开鼠标上传文件",
|
||||
"Select a maximum of 10 files": "最多选择10个文件",
|
||||
"Uploading": "正在上传 {{name}},进度: {{percent}}%",
|
||||
"max 10": "最多选择 10 个文件",
|
||||
"select a document": "选择文件",
|
||||
"support": "支持 {{fileExtension}} 文件",
|
||||
"upload error description": "单次只支持上传多个文件或者一个文件夹"
|
||||
},
|
||||
"home": {
|
||||
"AI Assistant": "AI 客服",
|
||||
"AI Assistant Desc": "无论对内还是对外,AI 将 24 小时为您的用户提供服务",
|
||||
"Advanced Settings": "高级编排",
|
||||
"Advanced Settings Desc": "基于 Flow 的流程编排模式,让你的 AI 轻松实现数据库查询、IO 操作、联网通信等扩展能力",
|
||||
"Choice Debug": "调试便捷",
|
||||
"Choice Debug Desc": "拥有搜索测试、引用修改、完整对话预览等多种调试途径",
|
||||
"Choice Desc": "",
|
||||
"Choice Extension": "无限扩展",
|
||||
"Choice Extension Desc": "基于 HTTP 实现扩展,轻松实现定制功能",
|
||||
"Choice Fast": "开箱即用",
|
||||
"Choice Fast Desc": "{{title}} 提供开箱即用的可视化操作,点点点即可构建 AI 应用",
|
||||
"Choice Models": "支持多种模型",
|
||||
"Choice Models Desc": "支持 GPT、Claude、Spark、ChatGLM等多模型",
|
||||
"Choice Open": "更开放",
|
||||
"Choice Open Desc": "{{title}} 遵循 Apache License 2.0 开源协议",
|
||||
"Choice QA": "独特的 QA 结构",
|
||||
"Choice QA Desc": "采用 QA 对的结构构建索引,适应问答、阅读等多种场景",
|
||||
"Choice Visual": "可视化工作流",
|
||||
"Choice Visual Desc": "可视化模块操作,轻松实现复杂工作流,让你的 AI 不再单一",
|
||||
"Commercial": "商务咨询",
|
||||
"Community": "社区",
|
||||
"Dateset": "自动数据预处理",
|
||||
"Dateset Desc": "提供手动输入、直接分段、LLM 自动处理和 CSV 等多种数据导入途径",
|
||||
"Docs": "文档",
|
||||
"FastGPT Ability": "{{title}} 能力",
|
||||
"FastGPT Desc": "{{title}} 是一个基于 LLM 大语言模型的知识库问答系统,提供开箱即用的数据处理、模型调用等能力。同时可以通过 Flow 可视化进行工作流编排,从而实现复杂的问答场景!",
|
||||
"Features": "特点",
|
||||
"Footer Developer": "开发者",
|
||||
"Footer Docs": "文档",
|
||||
"Footer FastGPT Cloud": "{{title}} 线上服务",
|
||||
"Footer Feedback": "反馈",
|
||||
"Footer Git": "源码",
|
||||
"Footer Product": "产品",
|
||||
"Footer Support": "支持",
|
||||
"Login": "登录",
|
||||
"Open": "",
|
||||
"OpenAPI": "OpenAPI",
|
||||
"OpenAPI Desc": "与 GPT API 一致的对外接口,助你轻松接入已有应用",
|
||||
"Quickly build AI question and answer library": "快速搭建 AI 问答系统",
|
||||
"Start Now": "立即开始",
|
||||
"Visual AI orchestration": "可视化 AI 编排",
|
||||
"Why FastGPT": "为什么选择 {{title}}",
|
||||
"desc": "基于 LLM 大模型的 AI 知识库问答平台",
|
||||
"navbar": {
|
||||
"Use guidance": "使用引导",
|
||||
"chatbot": "问答机器人"
|
||||
},
|
||||
"slogan": "让 AI 更懂你的知识"
|
||||
},
|
||||
"module": {
|
||||
"Confirm Delete Module": "确认删除该自定义模块?",
|
||||
"Confirm Sync Plugin": "确认同步插件最新信息?插件的连线和输入的内容将会被清空,请确认!",
|
||||
@@ -1343,30 +1212,6 @@
|
||||
"Store": "应用市场",
|
||||
"Tools": "工具"
|
||||
},
|
||||
"openapi": {
|
||||
"app key tips": "这些 key 已有当前应用标识,具体使用可参考文档",
|
||||
"key alias": "key 的别名,仅用于展示",
|
||||
"key tips": "你可以使用 API 秘钥访问一些特定的接口(无法访问应用,访问应用需使用应用内的API Key)"
|
||||
},
|
||||
"outlink": {
|
||||
"Copy IFrame": "嵌入网页",
|
||||
"Copy Link": "复制",
|
||||
"Create API Key": "创建新 Key",
|
||||
"Create Link": "创建链接",
|
||||
"Delete Link": "删除链接",
|
||||
"Edit API Key": "编辑 Key 信息",
|
||||
"Edit IFrame Link": "更新嵌入链接",
|
||||
"Edit Link": "编辑",
|
||||
"Edit Share Window": "更新分享窗口",
|
||||
"Link Name": "分享链接的名字",
|
||||
"Link is empty": "",
|
||||
"QPM": "",
|
||||
"QPM Tips": "每个 IP 每分钟最多提问多少次",
|
||||
"QPM is empty": "QPM 不能为空",
|
||||
"token auth": "身份验证",
|
||||
"token auth Tips": "身份校验服务器地址,如填写该值,每次对话前都会向指定服务器发送一个请求,进行身份校验",
|
||||
"token auth use cases": "查看身份验证使用说明"
|
||||
},
|
||||
"permission": {
|
||||
"Private": "私有",
|
||||
"Private Tip": "仅自己可用",
|
||||
|
||||
0
projects/app/i18n/zh/dataset.json
Normal file
0
projects/app/i18n/zh/dataset.json
Normal file
23
projects/app/i18n/zh/file.json
Normal file
23
projects/app/i18n/zh/file.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Click to view file": "点击查看原始文件",
|
||||
"Release the mouse to upload the file": "松开鼠标上传文件",
|
||||
"upload error description": "单次只支持上传多个文件或者一个文件夹",
|
||||
|
||||
"Empty file tip": "文件内容为空,可能该文件无法读取或为纯图片文件内容。",
|
||||
"File Content": "文件内容",
|
||||
"File Name": "文件名",
|
||||
"File Size": "文件大小",
|
||||
"File content can not be empty": "文件内容不能为空",
|
||||
"Filename Can not Be Empty": "文件名不能为空",
|
||||
"Read File Error": "解析文件失败",
|
||||
"Select and drag file tip": "点击或拖动文件到此处上传",
|
||||
"Select failed": "选择文件异常",
|
||||
"Select file amount limit": "最多选择 {{max}} 个文件",
|
||||
"Select file amount limit 100": "每次最多选择100个文件",
|
||||
"Some file count exceeds limit": "超出{{maxCount}}个文件,已自动截取",
|
||||
"Some file size exceeds limit": "部分文件超出: {{maxSize}},已被过滤",
|
||||
"Support file type": "支持 {{fileType}} 类型文件",
|
||||
"Support max count": "最多支持 {{maxCount}} 个文件。",
|
||||
"Support max size": "单个文件最大 {{maxSize}}。",
|
||||
"Upload failed": "上传异常"
|
||||
}
|
||||
20
projects/app/i18n/zh/publish.json
Normal file
20
projects/app/i18n/zh/publish.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"Create API Key": "创建新 Key",
|
||||
"Create Link": "创建链接",
|
||||
"Default Response": "默认回复",
|
||||
"Delete Link": "删除链接",
|
||||
"Edit API Key": "编辑 Key 信息",
|
||||
"Edit IFrame Link": "更新嵌入链接",
|
||||
"Edit Link": "编辑",
|
||||
"Edit Share Window": "更新分享窗口",
|
||||
"Feishu name": "飞书",
|
||||
"Link Name": "分享链接的名字",
|
||||
"QPM Tips": "每个 IP 每分钟最多提问多少次",
|
||||
"QPM is empty": "QPM 不能为空",
|
||||
"app key tips": "这些 key 已有当前应用标识,具体使用可参考文档",
|
||||
"key alias": "key 的别名,仅用于展示",
|
||||
"key tips": "你可以使用 API 秘钥访问一些特定的接口(无法访问应用,访问应用需使用应用内的API Key)",
|
||||
"token auth": "身份验证",
|
||||
"token auth Tips": "身份校验服务器地址,如填写该值,每次对话前都会向指定服务器发送一个请求,进行身份校验",
|
||||
"token auth use cases": "查看身份验证使用说明"
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { type ChatHistoryItemResType } from '@fastgpt/global/core/chat/type.d';
|
||||
import { DispatchNodeResponseType } from '@fastgpt/global/core/workflow/runtime/type.d';
|
||||
import { Flex, BoxProps, useDisclosure, useTheme, Box } from '@chakra-ui/react';
|
||||
import { Flex, useDisclosure, useTheme, Box } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Box, BoxProps, Image } from '@chakra-ui/react';
|
||||
import { Box, BoxProps } from '@chakra-ui/react';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
@@ -8,6 +8,7 @@ import { getFileAndOpen } from '@/web/core/dataset/utils';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { getSourceNameIcon } from '@fastgpt/global/core/dataset/utils';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
type Props = BoxProps & {
|
||||
sourceName?: string;
|
||||
@@ -17,6 +18,7 @@ type Props = BoxProps & {
|
||||
|
||||
const RawSourceBox = ({ sourceId, sourceName = '', canView = true, ...props }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { fileT } = useI18n();
|
||||
const { toast } = useToast();
|
||||
const { setLoading } = useSystemStore();
|
||||
|
||||
@@ -25,10 +27,7 @@ const RawSourceBox = ({ sourceId, sourceName = '', canView = true, ...props }: P
|
||||
const icon = useMemo(() => getSourceNameIcon({ sourceId, sourceName }), [sourceId, sourceName]);
|
||||
|
||||
return (
|
||||
<MyTooltip
|
||||
label={canPreview ? t('file.Click to view file') || '' : ''}
|
||||
shouldWrapChildren={false}
|
||||
>
|
||||
<MyTooltip label={canPreview ? fileT('Click to view file') : ''} shouldWrapChildren={false}>
|
||||
<Box
|
||||
color={'myGray.900'}
|
||||
fontWeight={'medium'}
|
||||
@@ -44,7 +43,7 @@ const RawSourceBox = ({ sourceId, sourceName = '', canView = true, ...props }: P
|
||||
await getFileAndOpen(sourceId as string);
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: t(getErrText(error, 'error.fileNotFound')),
|
||||
title: getErrText(error, t('error.fileNotFound')),
|
||||
status: 'error'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Textarea, Button, ModalBody, ModalFooter } from '@chakra-ui/react';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../context';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
type Props = {
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
const ImportSettings = ({ onClose }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { appT } = useI18n();
|
||||
const { toast } = useToast();
|
||||
|
||||
const initData = useContextSelector(WorkflowContext, (v) => v.initData);
|
||||
const [value, setValue] = useState('');
|
||||
|
||||
@@ -23,11 +22,11 @@ const ImportSettings = ({ onClose }: Props) => {
|
||||
w={'600px'}
|
||||
onClose={onClose}
|
||||
iconSrc="/imgs/modal/params.svg"
|
||||
title={t('app.Import Configs')}
|
||||
title={appT('Import Configs')}
|
||||
>
|
||||
<ModalBody>
|
||||
<Textarea
|
||||
placeholder={t('app.Paste Config') || 'app.Paste Config'}
|
||||
placeholder={appT('Paste Config')}
|
||||
defaultValue={value}
|
||||
rows={16}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
@@ -46,7 +45,7 @@ const ImportSettings = ({ onClose }: Props) => {
|
||||
onClose();
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: t('app.Import Configs Failed')
|
||||
title: appT('Import Configs Failed')
|
||||
});
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -28,6 +28,7 @@ import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../context';
|
||||
import { useCreation } from 'ahooks';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
type ModuleTemplateListProps = {
|
||||
isOpen: boolean;
|
||||
@@ -251,6 +252,8 @@ const RenderList = React.memo(function RenderList({
|
||||
setCurrentParent
|
||||
}: RenderListProps) {
|
||||
const { t } = useTranslation();
|
||||
const { appT } = useI18n();
|
||||
|
||||
const { isPc } = useSystemStore();
|
||||
const { x, y, zoom } = useViewport();
|
||||
const { setLoading } = useSystemStore();
|
||||
@@ -323,7 +326,7 @@ const RenderList = React.memo(function RenderList({
|
||||
|
||||
const Render = useMemo(() => {
|
||||
return templates.length === 0 ? (
|
||||
<EmptyTip text={t('app.module.No Modules')} />
|
||||
<EmptyTip text={appT('module.No Modules')} />
|
||||
) : (
|
||||
<Box flex={'1 0 0'} overflow={'overlay'} px={'20px'}>
|
||||
<Box mx={'auto'}>
|
||||
|
||||
@@ -9,7 +9,7 @@ import { useTranslation } from 'next-i18next';
|
||||
import { getLafAppDetail } from '@/web/support/laf/api';
|
||||
import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||
import { getApiSchemaByUrl } from '@/web/core/plugin/api';
|
||||
import { str2OpenApiSchema } from '@fastgpt/global/core/plugin/httpPlugin/utils';
|
||||
import { getType, str2OpenApiSchema } from '@fastgpt/global/core/plugin/httpPlugin/utils';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { ChevronRightIcon } from '@chakra-ui/icons';
|
||||
@@ -155,7 +155,7 @@ const NodeLaf = (props: NodeProps<FlowNodeItemType>) => {
|
||||
desc: bodyParams[key].description,
|
||||
required: requiredParams?.includes(key) || false,
|
||||
value: `{{${key}}}`,
|
||||
type: bodyParams[key].type
|
||||
type: getType(bodyParams[key])
|
||||
}))
|
||||
].filter((item) => !inputs.find((input) => input.key === item.name));
|
||||
|
||||
@@ -189,7 +189,7 @@ const NodeLaf = (props: NodeProps<FlowNodeItemType>) => {
|
||||
|
||||
const allResponseParams = [
|
||||
...Object.keys(responseParams).map((key) => ({
|
||||
valueType: responseParams[key].type,
|
||||
valueType: getType(responseParams[key]),
|
||||
name: key,
|
||||
desc: responseParams[key].description,
|
||||
required: requiredResponseParams?.includes(key) || false
|
||||
|
||||
@@ -203,16 +203,16 @@ const MyTargetHandle = React.memo(function MyTargetHandle({
|
||||
|
||||
if (connectingEdge?.handleId && !connectingEdge.handleId?.includes('source')) return false;
|
||||
|
||||
// From same source node
|
||||
// From same source node and same handle
|
||||
if (
|
||||
connectedEdges.some(
|
||||
(item) => item.source === connectingEdge?.nodeId && item.target === nodeId
|
||||
(item) => item.sourceHandle === connectingEdge?.handleId && item.target === nodeId
|
||||
)
|
||||
)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}, [connectedEdges, connectingEdge?.handleId, connectingEdge?.nodeId, edges, node, nodeId]);
|
||||
}, [connectedEdges, connectingEdge?.handleId, edges, node, nodeId]);
|
||||
|
||||
const RenderHandle = useMemo(() => {
|
||||
return (
|
||||
|
||||
@@ -22,6 +22,7 @@ import { storeNode2FlowNode } from '@/web/core/workflow/utils';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../../context';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
type Props = FlowNodeItemType & {
|
||||
children?: React.ReactNode | React.ReactNode[] | string;
|
||||
@@ -38,6 +39,8 @@ type Props = FlowNodeItemType & {
|
||||
|
||||
const NodeCard = (props: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { appT } = useI18n();
|
||||
|
||||
const { toast } = useToast();
|
||||
|
||||
const {
|
||||
@@ -66,7 +69,7 @@ const NodeCard = (props: Props) => {
|
||||
// custom title edit
|
||||
const { onOpenModal: onOpenCustomTitleModal, EditModal: EditTitleModal } = useEditTitle({
|
||||
title: t('common.Custom Title'),
|
||||
placeholder: t('app.module.Custom Title Tip') || ''
|
||||
placeholder: appT('module.Custom Title Tip') || ''
|
||||
});
|
||||
|
||||
const showToolHandle = useMemo(
|
||||
@@ -105,7 +108,7 @@ const NodeCard = (props: Props) => {
|
||||
onSuccess: (e) => {
|
||||
if (!e) {
|
||||
return toast({
|
||||
title: t('app.modules.Title is required'),
|
||||
title: appT('modules.Title is required'),
|
||||
status: 'warning'
|
||||
});
|
||||
}
|
||||
@@ -132,8 +135,8 @@ const NodeCard = (props: Props) => {
|
||||
</Box>
|
||||
);
|
||||
}, [
|
||||
nodeId,
|
||||
showToolHandle,
|
||||
nodeId,
|
||||
avatar,
|
||||
t,
|
||||
name,
|
||||
@@ -143,7 +146,8 @@ const NodeCard = (props: Props) => {
|
||||
intro,
|
||||
onOpenCustomTitleModal,
|
||||
onChangeNode,
|
||||
toast
|
||||
toast,
|
||||
appT
|
||||
]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -43,6 +43,7 @@ import MyTooltip from '@/components/MyTooltip';
|
||||
import { getDocPath } from '@/web/common/system/doc';
|
||||
import MyMenu from '@fastgpt/web/components/common/MyMenu';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
type EditProps = EditApiKeyProps & { _id?: string };
|
||||
const defaultEditData: EditProps = {
|
||||
@@ -135,7 +136,7 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
|
||||
})
|
||||
}
|
||||
>
|
||||
{t('common.New Create')}
|
||||
{t('New Create')}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -295,6 +296,7 @@ function EditKeyModal({
|
||||
onEdit: () => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { publishT } = useI18n();
|
||||
const isEdit = useMemo(() => !!defaultData._id, [defaultData]);
|
||||
const { feConfigs } = useSystemStore();
|
||||
|
||||
@@ -324,13 +326,13 @@ function EditKeyModal({
|
||||
<MyModal
|
||||
isOpen={true}
|
||||
iconSrc="/imgs/modal/key.svg"
|
||||
title={isEdit ? t('outlink.Edit API Key') : t('outlink.Create API Key')}
|
||||
title={isEdit ? publishT('Edit API Key') : publishT('Create API Key')}
|
||||
>
|
||||
<ModalBody>
|
||||
<Flex alignItems={'center'}>
|
||||
<Box flex={'0 0 90px'}>{t('Name')}:</Box>
|
||||
<Input
|
||||
placeholder={t('openapi.key alias') || 'key alias'}
|
||||
placeholder={publishT('key alias') || 'key alias'}
|
||||
maxLength={20}
|
||||
{...register('name', {
|
||||
required: t('common.Name is empty') || 'Name is empty'
|
||||
|
||||
@@ -6,6 +6,7 @@ import { appWithTranslation } from 'next-i18next';
|
||||
|
||||
import QueryClientContext from '@/web/context/QueryClient';
|
||||
import ChakraUIContext from '@/web/context/ChakraUI';
|
||||
import I18nContextProvider from '@/web/context/I18n';
|
||||
import { useInitApp } from '@/web/context/useInitApp';
|
||||
|
||||
import '@/web/styles/reset.scss';
|
||||
@@ -34,11 +35,13 @@ function App({ Component, pageProps }: AppProps) {
|
||||
{scripts?.map((item, i) => <Script key={i} strategy="lazyOnload" {...item}></Script>)}
|
||||
|
||||
<QueryClientContext>
|
||||
<ChakraUIContext>
|
||||
<Layout>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
</ChakraUIContext>
|
||||
<I18nContextProvider>
|
||||
<ChakraUIContext>
|
||||
<Layout>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
</ChakraUIContext>
|
||||
</I18nContextProvider>
|
||||
</QueryClientContext>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import ApiKeyTable from '@/components/support/apikey/Table';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
const ApiKey = () => {
|
||||
const { t } = useTranslation();
|
||||
return <ApiKeyTable tips={t('openapi.key tips')}></ApiKeyTable>;
|
||||
const { publishT } = useI18n();
|
||||
return <ApiKeyTable tips={publishT('key tips')}></ApiKeyTable>;
|
||||
};
|
||||
|
||||
export default ApiKey;
|
||||
|
||||
@@ -190,7 +190,7 @@ export async function getServerSideProps(content: any) {
|
||||
return {
|
||||
props: {
|
||||
currentTab: content?.query?.currentTab || TabEnum.info,
|
||||
...(await serviceSideProps(content))
|
||||
...(await serviceSideProps(content, ['publish']))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import {
|
||||
delFileByFileIdList,
|
||||
readFileContentFromMongo
|
||||
} from '@fastgpt/service/common/file/gridfs/controller';
|
||||
import { readFileContentFromMongo } from '@fastgpt/service/common/file/gridfs/controller';
|
||||
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
|
||||
import { FileIdCreateDatasetCollectionParams } from '@fastgpt/global/core/dataset/api';
|
||||
import { createOneCollection } from '@fastgpt/service/core/dataset/collection/controller';
|
||||
@@ -24,6 +21,7 @@ import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants'
|
||||
import { getLLMModel, getVectorModel } from '@fastgpt/service/core/ai/model';
|
||||
import { hashStr } from '@fastgpt/global/common/string/tools';
|
||||
import { startTrainingQueue } from '@/service/core/dataset/training/utils';
|
||||
import { MongoRawTextBuffer } from '@fastgpt/service/common/buffer/rawText/schema';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
const {
|
||||
@@ -139,6 +137,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
return collectionId;
|
||||
});
|
||||
|
||||
// remove buffer
|
||||
await MongoRawTextBuffer.deleteOne({ sourceId: fileId });
|
||||
|
||||
startTrainingQueue(true);
|
||||
|
||||
jsonRes(res);
|
||||
|
||||
@@ -1,34 +1,24 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
|
||||
import { checkExportDatasetLimit } from '@fastgpt/service/support/user/utils';
|
||||
import { NextAPI } from '@/service/middle/entry';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
await connectToDatabase();
|
||||
const { datasetId } = req.query as {
|
||||
datasetId: string;
|
||||
};
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
const { datasetId } = req.query as {
|
||||
datasetId: string;
|
||||
};
|
||||
|
||||
if (!datasetId) {
|
||||
throw new Error('datasetId is required');
|
||||
}
|
||||
|
||||
// 凭证校验
|
||||
const { teamId } = await authDataset({ req, authToken: true, datasetId, per: 'w' });
|
||||
|
||||
await checkExportDatasetLimit({
|
||||
teamId,
|
||||
limitMinutes: global.feConfigs?.limit?.exportDatasetLimitMinutes
|
||||
});
|
||||
|
||||
jsonRes(res);
|
||||
} catch (err) {
|
||||
res.status(500);
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error: err
|
||||
});
|
||||
if (!datasetId) {
|
||||
throw new Error('datasetId is required');
|
||||
}
|
||||
|
||||
// 凭证校验
|
||||
const { teamId } = await authDataset({ req, authToken: true, datasetId, per: 'w' });
|
||||
|
||||
await checkExportDatasetLimit({
|
||||
teamId,
|
||||
limitMinutes: global.feConfigs?.limit?.exportDatasetLimitMinutes
|
||||
});
|
||||
}
|
||||
|
||||
export default NextAPI(handler);
|
||||
|
||||
@@ -26,6 +26,7 @@ import { formatTime2HM } from '@fastgpt/global/common/string/time';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext, getWorkflowStore } from '@/components/core/workflow/context';
|
||||
import { useInterval, useUpdateEffect } from 'ahooks';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
const ImportSettings = dynamic(() => import('@/components/core/workflow/Flow/ImportSettings'));
|
||||
const PublishHistories = dynamic(
|
||||
@@ -56,6 +57,8 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
|
||||
const theme = useTheme();
|
||||
const { toast } = useToast();
|
||||
const { t } = useTranslation();
|
||||
const { appT } = useI18n();
|
||||
|
||||
const { copyData } = useCopyData();
|
||||
const { openConfirm: openConfigPublish, ConfirmModal } = useConfirm({
|
||||
content: t('core.app.Publish Confirm')
|
||||
@@ -177,10 +180,10 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
|
||||
null,
|
||||
2
|
||||
),
|
||||
t('app.Export Config Successful')
|
||||
appT('Export Config Successful')
|
||||
);
|
||||
}
|
||||
}, [copyData, flowData2StoreDataAndCheck, t]);
|
||||
}, [appT, copyData, flowData2StoreDataAndCheck]);
|
||||
|
||||
// effect
|
||||
useBeforeunload({
|
||||
@@ -254,12 +257,12 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
|
||||
}
|
||||
menuList={[
|
||||
{
|
||||
label: t('app.Import Configs'),
|
||||
label: appT('Import Configs'),
|
||||
icon: 'common/importLight',
|
||||
onClick: onOpenImport
|
||||
},
|
||||
{
|
||||
label: t('app.Export Configs'),
|
||||
label: appT('Export Configs'),
|
||||
icon: 'export',
|
||||
onClick: onExportWorkflow
|
||||
}
|
||||
@@ -316,6 +319,7 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
|
||||
isV2Workflow,
|
||||
t,
|
||||
saveLabel,
|
||||
appT,
|
||||
onOpenImport,
|
||||
onExportWorkflow,
|
||||
openConfigPublish,
|
||||
|
||||
@@ -33,9 +33,12 @@ import { usePagination } from '@fastgpt/web/hooks/usePagination';
|
||||
import DateRangePicker, { DateRangeType } from '@fastgpt/web/components/common/DateRangePicker';
|
||||
import { formatChatValue2InputType } from '@/components/ChatBox/utils';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
const Logs = ({ appId }: { appId: string }) => {
|
||||
const { t } = useTranslation();
|
||||
const { appT } = useI18n();
|
||||
|
||||
const { isPc } = useSystemStore();
|
||||
|
||||
const [dateRange, setDateRange] = useState<DateRangeType>({
|
||||
@@ -73,10 +76,10 @@ const Logs = ({ appId }: { appId: string }) => {
|
||||
{isPc && (
|
||||
<>
|
||||
<Box fontWeight={'bold'} fontSize={['md', 'xl']} mb={2}>
|
||||
{t('app.Chat logs')}
|
||||
{appT('Chat logs')}
|
||||
</Box>
|
||||
<Box color={'myGray.500'} fontSize={'sm'}>
|
||||
{t('app.Chat Logs Tips')},{' '}
|
||||
{appT('Chat Logs Tips')},{' '}
|
||||
<Box
|
||||
as={'span'}
|
||||
mr={2}
|
||||
@@ -97,11 +100,11 @@ const Logs = ({ appId }: { appId: string }) => {
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>{t('core.app.logs.Source And Time')}</Th>
|
||||
<Th>{t('app.Logs Title')}</Th>
|
||||
<Th>{t('app.Logs Message Total')}</Th>
|
||||
<Th>{t('app.Feedback Count')}</Th>
|
||||
<Th>{appT('Logs Title')}</Th>
|
||||
<Th>{appT('Logs Message Total')}</Th>
|
||||
<Th>{appT('Feedback Count')}</Th>
|
||||
<Th>{t('core.app.feedback.Custom feedback')}</Th>
|
||||
<Th>{t('app.Mark Count')}</Th>
|
||||
<Th>{appT('Mark Count')}</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
@@ -176,7 +179,7 @@ const Logs = ({ appId }: { appId: string }) => {
|
||||
<Flex h={'100%'} flexDirection={'column'} alignItems={'center'} pt={'10vh'}>
|
||||
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
|
||||
<Box mt={2} color={'myGray.500'}>
|
||||
{t('app.Logs Empty')}
|
||||
{appT('Logs Empty')}
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
@@ -2,12 +2,13 @@ import React, { useEffect, useState } from 'react';
|
||||
import ApiKeyTable from '@/components/support/apikey/Table';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { Box } from '@chakra-ui/react';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
const API = ({ appId }: { appId: string }) => {
|
||||
const { t } = useTranslation();
|
||||
const { publishT } = useI18n();
|
||||
return (
|
||||
<Box pt={3}>
|
||||
<ApiKeyTable tips={t('openapi.app key tips')} appId={appId} />
|
||||
<ApiKeyTable tips={publishT('app key tips')} appId={appId} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useForm } from 'react-hook-form';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import dayjs from 'dayjs';
|
||||
import { createShareChat, updateShareChat } from '@/web/support/outLink/api';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
const FeiShuEditModal = ({
|
||||
appId,
|
||||
@@ -25,6 +26,7 @@ const FeiShuEditModal = ({
|
||||
onEdit: () => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { publishT } = useI18n();
|
||||
const {
|
||||
register,
|
||||
setValue,
|
||||
@@ -58,13 +60,13 @@ const FeiShuEditModal = ({
|
||||
<MyModal
|
||||
isOpen={true}
|
||||
iconSrc="/imgs/modal/shareFill.svg"
|
||||
title={isEdit ? t('outlink.Edit Link') : t('outlink.Create Link')}
|
||||
title={isEdit ? publishT('Edit Link') : publishT('Create Link')}
|
||||
>
|
||||
<ModalBody>
|
||||
<Flex alignItems={'center'}>
|
||||
<Box flex={'0 0 90px'}>{t('Name')}</Box>
|
||||
<Input
|
||||
placeholder={t('outlink.Feishu name') || 'Link Name'} // TODO: i18n
|
||||
placeholder={publishT('Feishu name') || 'Link Name'} // TODO: i18n
|
||||
maxLength={20}
|
||||
{...register('name', {
|
||||
required: t('common.Name is empty') || 'Name is empty'
|
||||
@@ -74,7 +76,7 @@ const FeiShuEditModal = ({
|
||||
<Flex alignItems={'center'} mt={4}>
|
||||
<Flex flex={'0 0 90px'} alignItems={'center'}>
|
||||
QPM
|
||||
<MyTooltip label={t('outlink.QPM Tips' || '')}>
|
||||
<MyTooltip label={publishT('QPM Tips' || '')}>
|
||||
<QuestionOutlineIcon ml={1} />
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
@@ -84,7 +86,7 @@ const FeiShuEditModal = ({
|
||||
min: 0,
|
||||
max: 1000,
|
||||
valueAsNumber: true,
|
||||
required: t('outlink.QPM is empty') || ''
|
||||
required: publishT('QPM is empty') || ''
|
||||
})}
|
||||
/>
|
||||
</Flex>
|
||||
@@ -126,10 +128,10 @@ const FeiShuEditModal = ({
|
||||
{/* TODO: i18n */}
|
||||
</Flex>
|
||||
<Input
|
||||
placeholder={t('outlink.Default Response') || 'Link Name'}
|
||||
placeholder={publishT('Default Response') || 'Link Name'}
|
||||
maxLength={20}
|
||||
{...register('defaultResponse', {
|
||||
required: t('common.default Response is empty') || 'Name is empty'
|
||||
required: true
|
||||
})}
|
||||
/>
|
||||
</Flex>
|
||||
@@ -139,10 +141,10 @@ const FeiShuEditModal = ({
|
||||
{/* TODO: i18n */}
|
||||
</Flex>
|
||||
<Input
|
||||
placeholder={t('outlink.Default Response') || 'Link Name'}
|
||||
placeholder={publishT('Default Response') || 'Link Name'}
|
||||
maxLength={20}
|
||||
{...register('immediateResponse', {
|
||||
required: t('common.default Response is empty') || 'Name is empty'
|
||||
required: true
|
||||
})}
|
||||
/>
|
||||
</Flex>
|
||||
@@ -152,14 +154,14 @@ const FeiShuEditModal = ({
|
||||
placeholder={t('core.module.http.appId') || 'Link Name'}
|
||||
// maxLength={20}
|
||||
{...register('app.appId', {
|
||||
required: t('common.Name is empty') || 'Name is empty'
|
||||
required: true
|
||||
})}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex alignItems={'center'} mt={4}>
|
||||
<Box flex={'0 0 90px'}>{t('core.module.http.AppSecret')}</Box>
|
||||
<Input
|
||||
placeholder={t('outlink.AppSecret') || 'Link Name'}
|
||||
placeholder={'App Secret'}
|
||||
// maxLength={20}
|
||||
{...register('app.appSecret', {
|
||||
required: t('common.Name is empty') || 'Name is empty'
|
||||
|
||||
@@ -44,6 +44,7 @@ import { getDocPath } from '@/web/common/system/doc';
|
||||
import dynamic from 'next/dynamic';
|
||||
import MyMenu from '@fastgpt/web/components/common/MyMenu';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
const SelectUsingWayModal = dynamic(() => import('./SelectUsingWayModal'));
|
||||
|
||||
@@ -261,6 +262,7 @@ function EditLinkModal({
|
||||
}) {
|
||||
const { feConfigs } = useSystemStore();
|
||||
const { t } = useTranslation();
|
||||
const { publishT } = useI18n();
|
||||
const {
|
||||
register,
|
||||
setValue,
|
||||
@@ -293,13 +295,13 @@ function EditLinkModal({
|
||||
<MyModal
|
||||
isOpen={true}
|
||||
iconSrc="/imgs/modal/shareFill.svg"
|
||||
title={isEdit ? t('outlink.Edit Link') : t('outlink.Create Link')}
|
||||
title={isEdit ? publishT('Edit Link') : publishT('Create Link')}
|
||||
>
|
||||
<ModalBody>
|
||||
<Flex alignItems={'center'}>
|
||||
<Box flex={'0 0 90px'}>{t('Name')}</Box>
|
||||
<Input
|
||||
placeholder={t('outlink.Link Name') || 'Link Name'}
|
||||
placeholder={publishT('Link Name')}
|
||||
maxLength={20}
|
||||
{...register('name', {
|
||||
required: t('common.Name is empty') || 'Name is empty'
|
||||
@@ -327,7 +329,7 @@ function EditLinkModal({
|
||||
<Flex alignItems={'center'} mt={4}>
|
||||
<Flex flex={'0 0 90px'} alignItems={'center'}>
|
||||
QPM
|
||||
<MyTooltip label={t('outlink.QPM Tips' || '')}>
|
||||
<MyTooltip label={publishT('QPM Tips' || '')}>
|
||||
<QuestionOutlineIcon ml={1} />
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
@@ -337,7 +339,7 @@ function EditLinkModal({
|
||||
min: 0,
|
||||
max: 1000,
|
||||
valueAsNumber: true,
|
||||
required: t('outlink.QPM is empty') || ''
|
||||
required: publishT('QPM is empty') || ''
|
||||
})}
|
||||
/>
|
||||
</Flex>
|
||||
@@ -360,13 +362,13 @@ function EditLinkModal({
|
||||
|
||||
<Flex alignItems={'center'} mt={4}>
|
||||
<Flex flex={'0 0 90px'} alignItems={'center'}>
|
||||
{t('outlink.token auth')}
|
||||
<MyTooltip label={t('outlink.token auth Tips') || ''}>
|
||||
{publishT('token auth')}
|
||||
<MyTooltip label={publishT('token auth Tips') || ''}>
|
||||
<QuestionOutlineIcon ml={1} />
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
<Input
|
||||
placeholder={t('outlink.token auth Tips') || ''}
|
||||
placeholder={publishT('token auth Tips') || ''}
|
||||
fontSize={'sm'}
|
||||
{...register('limit.hookUrl')}
|
||||
/>
|
||||
@@ -377,7 +379,7 @@ function EditLinkModal({
|
||||
fontSize={'sm'}
|
||||
color={'myGray.500'}
|
||||
>
|
||||
{t('outlink.token auth use cases')}
|
||||
{publishT('token auth use cases')}
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -15,11 +15,14 @@ import Avatar from '@/components/Avatar';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import TagsEditModal from './TagsEditModal';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
const InfoModal = dynamic(() => import('../InfoModal'));
|
||||
|
||||
const AppCard = ({ appId }: { appId: string }) => {
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
const { appT } = useI18n();
|
||||
|
||||
const { toast } = useToast();
|
||||
const { appDetail } = useAppStore();
|
||||
const { feConfigs } = useSystemStore();
|
||||
@@ -27,7 +30,7 @@ const AppCard = ({ appId }: { appId: string }) => {
|
||||
const [TeamTagsSet, setTeamTagsSet] = useState<AppSchema>();
|
||||
|
||||
const { openConfirm: openConfirmDel, ConfirmModal: ConfirmDelModal } = useConfirm({
|
||||
content: t('app.Confirm Del App Tip'),
|
||||
content: appT('Confirm Del App Tip'),
|
||||
type: 'delete'
|
||||
});
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import { UseFormReturn } from 'react-hook-form';
|
||||
import { AppSimpleEditFormType } from '@fastgpt/global/core/app/type';
|
||||
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
||||
import { form2AppWorkflow } from '@/web/core/app/utils';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
const ChatTest = ({
|
||||
editForm,
|
||||
@@ -30,6 +31,8 @@ const ChatTest = ({
|
||||
appId: string;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { appT } = useI18n();
|
||||
|
||||
const { userInfo } = useUserStore();
|
||||
const ChatBoxRef = useRef<ComponentRef>(null);
|
||||
const { appDetail } = useAppStore();
|
||||
@@ -114,7 +117,7 @@ const ChatTest = ({
|
||||
>
|
||||
<Flex px={[2, 5]}>
|
||||
<Box fontSize={['md', 'xl']} fontWeight={'bold'} flex={1}>
|
||||
{t('app.Chat Debug')}
|
||||
{appT('Chat Debug')}
|
||||
</Box>
|
||||
<MyTooltip label={t('core.chat.Restart')}>
|
||||
<IconButton
|
||||
@@ -160,7 +163,7 @@ const ChatTest = ({
|
||||
whiteSpace={'pre-wrap'}
|
||||
textAlign={'center'}
|
||||
>
|
||||
<Box>{t('app.Advance App TestTip')}</Box>
|
||||
<Box>{appT('Advance App TestTip')}</Box>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
@@ -29,6 +29,7 @@ import DeleteIcon, { hoverDeleteStyles } from '@fastgpt/web/components/common/Ic
|
||||
import { TTSTypeEnum } from '@/constants/app';
|
||||
import { getSystemVariables } from '@/web/core/app/utils';
|
||||
import { useUpdate } from 'ahooks';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
const DatasetSelectModal = dynamic(() => import('@/components/core/app/DatasetSelectModal'));
|
||||
const DatasetParamsModal = dynamic(() => import('@/components/core/app/DatasetParamsModal'));
|
||||
@@ -61,6 +62,8 @@ const EditForm = ({
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
const { appT } = useI18n();
|
||||
|
||||
const { publishApp, appDetail } = useAppStore();
|
||||
|
||||
const { allDatasets } = useDatasetStore();
|
||||
@@ -200,7 +203,7 @@ const EditForm = ({
|
||||
<Flex alignItems={'center'}>
|
||||
<MyIcon name={'core/app/simpleMode/ai'} w={'20px'} />
|
||||
<Box ml={2} flex={1}>
|
||||
{t('app.AI Settings')}
|
||||
{appT('AI Settings')}
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex alignItems={'center'} mt={5}>
|
||||
|
||||
@@ -17,6 +17,7 @@ import { serviceSideProps } from '@/web/common/utils/i18n';
|
||||
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
||||
import Head from 'next/head';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
const FlowEdit = dynamic(() => import('./components/FlowEdit'), {
|
||||
loading: () => <Loading />
|
||||
@@ -34,6 +35,8 @@ enum TabEnum {
|
||||
|
||||
const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
||||
const { t } = useTranslation();
|
||||
const { appT } = useI18n();
|
||||
|
||||
const router = useRouter();
|
||||
const theme = useTheme();
|
||||
const { feConfigs } = useSystemStore();
|
||||
@@ -74,10 +77,10 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
||||
id: TabEnum.publish,
|
||||
icon: 'support/outlink/shareLight'
|
||||
},
|
||||
{ label: t('app.Chat logs'), id: TabEnum.logs, icon: 'core/app/logsLight' },
|
||||
{ label: appT('Chat logs'), id: TabEnum.logs, icon: 'core/app/logsLight' },
|
||||
{ label: t('core.Start chat'), id: TabEnum.startChat, icon: 'core/chat/chatLight' }
|
||||
],
|
||||
[feConfigs?.hide_app_flow, t]
|
||||
[appT, feConfigs?.hide_app_flow, t]
|
||||
);
|
||||
|
||||
const onCloseFlowEdit = useCallback(() => setCurrentTab(TabEnum.simpleEdit), [setCurrentTab]);
|
||||
@@ -150,7 +153,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
||||
borderRadius={'50%'}
|
||||
aria-label={''}
|
||||
/>
|
||||
{t('app.My Apps')}
|
||||
{appT('My Apps')}
|
||||
</Flex>
|
||||
</Box>
|
||||
{/* phone tab */}
|
||||
@@ -193,7 +196,7 @@ export async function getServerSideProps(context: any) {
|
||||
const currentTab = context?.query?.currentTab || TabEnum.simpleEdit;
|
||||
|
||||
return {
|
||||
props: { currentTab, ...(await serviceSideProps(context)) }
|
||||
props: { currentTab, ...(await serviceSideProps(context, ['app', 'file', 'publish'])) }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useState, useEffect } from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
import { Box, Grid, Flex, IconButton, Button, useDisclosure } from '@chakra-ui/react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
@@ -7,7 +7,6 @@ import { delModelById } from '@/web/core/app/api';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { serviceSideProps } from '@/web/common/utils/i18n';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import PageContainer from '@/components/PageContainer';
|
||||
import Avatar from '@/components/Avatar';
|
||||
@@ -16,10 +15,12 @@ import CreateModal from './component/CreateModal';
|
||||
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
||||
import PermissionIconText from '@/components/support/permission/IconText';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
const MyApps = () => {
|
||||
const { toast } = useToast();
|
||||
const { t } = useTranslation();
|
||||
const { appT, commonT } = useI18n();
|
||||
|
||||
const router = useRouter();
|
||||
const { userInfo } = useUserStore();
|
||||
const { myApps, loadMyApps } = useAppStore();
|
||||
@@ -62,10 +63,10 @@ const MyApps = () => {
|
||||
<PageContainer isLoading={isFetching} insertProps={{ px: [5, '48px'] }}>
|
||||
<Flex pt={[4, '30px']} alignItems={'center'} justifyContent={'space-between'}>
|
||||
<Box letterSpacing={1} fontSize={['20px', '24px']} color={'myGray.900'}>
|
||||
{t('app.My Apps')}
|
||||
{appT('My Apps')}
|
||||
</Box>
|
||||
<Button leftIcon={<AddIcon />} variant={'primaryOutline'} onClick={onOpenCreateModal}>
|
||||
{t('common.New Create')}
|
||||
{commonT('New Create')}
|
||||
</Button>
|
||||
</Flex>
|
||||
<Grid
|
||||
@@ -76,7 +77,7 @@ const MyApps = () => {
|
||||
{myApps.map((app) => (
|
||||
<MyTooltip
|
||||
key={app._id}
|
||||
label={userInfo?.team.canWrite ? t('app.To Settings') : t('app.To Chat')}
|
||||
label={userInfo?.team.canWrite ? appT('To Settings') : appT('To Chat')}
|
||||
>
|
||||
<Box
|
||||
lineHeight={1.5}
|
||||
@@ -168,9 +169,6 @@ const MyApps = () => {
|
||||
</MyTooltip>
|
||||
))}
|
||||
</Grid>
|
||||
{/* (
|
||||
<ShareBox></ShareBox>
|
||||
) */}
|
||||
|
||||
{myApps.length === 0 && (
|
||||
<Flex mt={'35vh'} flexDirection={'column'} alignItems={'center'}>
|
||||
@@ -191,7 +189,7 @@ const MyApps = () => {
|
||||
export async function getServerSideProps(content: any) {
|
||||
return {
|
||||
props: {
|
||||
...(await serviceSideProps(content))
|
||||
...(await serviceSideProps(content, ['app']))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { AppListItemType } from '@fastgpt/global/core/app/type';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
type HistoryItemType = {
|
||||
id: string;
|
||||
@@ -68,6 +69,8 @@ const ChatHistorySlider = ({
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
const { appT } = useI18n();
|
||||
|
||||
const { isPc } = useSystemStore();
|
||||
const { userInfo } = useUserStore();
|
||||
|
||||
@@ -86,7 +89,8 @@ const ChatHistorySlider = ({
|
||||
const concatHistory = useMemo<HistoryItemType[]>(
|
||||
() =>
|
||||
!activeChatId
|
||||
? [{ id: activeChatId, title: t('core.chat.New Chat') }].concat(history)
|
||||
? //@ts-ignore
|
||||
[{ id: activeChatId, title: t('core.chat.New Chat') }].concat(history)
|
||||
: history,
|
||||
[activeChatId, history, t]
|
||||
);
|
||||
@@ -115,7 +119,7 @@ const ChatHistorySlider = ({
|
||||
whiteSpace={'nowrap'}
|
||||
>
|
||||
{isPc && (
|
||||
<MyTooltip label={canRouteToDetail ? t('app.App Detail') : ''} offset={[0, 0]}>
|
||||
<MyTooltip label={canRouteToDetail ? appT('App Detail') : ''} offset={[0, 0]}>
|
||||
<Flex
|
||||
pt={5}
|
||||
pb={2}
|
||||
|
||||
@@ -371,7 +371,7 @@ export async function getServerSideProps(context: any) {
|
||||
props: {
|
||||
appId: context?.query?.appId || '',
|
||||
chatId: context?.query?.chatId || '',
|
||||
...(await serviceSideProps(context))
|
||||
...(await serviceSideProps(context, ['file']))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -431,7 +431,7 @@ export async function getServerSideProps(context: any) {
|
||||
appName: app?.appId?.name || '',
|
||||
appAvatar: app?.appId?.avatar || '',
|
||||
appIntro: app?.appId?.intro || '',
|
||||
...(await serviceSideProps(context))
|
||||
...(await serviceSideProps(context, ['file']))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -382,7 +382,7 @@ const OutLink = () => {
|
||||
export async function getServerSideProps(context: any) {
|
||||
return {
|
||||
props: {
|
||||
...(await serviceSideProps(context))
|
||||
...(await serviceSideProps(context, ['file']))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,9 +27,11 @@ import {
|
||||
postCreateDatasetTextCollection
|
||||
} from '@/web/core/dataset/api';
|
||||
import Tag from '@fastgpt/web/components/common/Tag/index';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
const Upload = () => {
|
||||
const { t } = useTranslation();
|
||||
const { fileT } = useI18n();
|
||||
const { toast } = useToast();
|
||||
const router = useRouter();
|
||||
const { datasetDetail } = useDatasetStore();
|
||||
@@ -131,7 +133,7 @@ const Upload = () => {
|
||||
)
|
||||
);
|
||||
},
|
||||
errorToast: t('common.file.Upload failed')
|
||||
errorToast: fileT('Upload failed')
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -13,6 +13,7 @@ import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { uploadFile2DB } from '@/web/common/file/controller';
|
||||
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
|
||||
import { ImportSourceItemType } from '@/web/core/dataset/type';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
export type SelectFileItemType = {
|
||||
fileId: string;
|
||||
@@ -35,6 +36,8 @@ const FileSelector = ({
|
||||
onFinishSelect: () => void;
|
||||
} & FlexProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { fileT } = useI18n();
|
||||
|
||||
const { toast } = useToast();
|
||||
const { feConfigs } = useSystemStore();
|
||||
|
||||
@@ -129,7 +132,7 @@ const FileSelector = ({
|
||||
files = files.slice(0, maxCount - selectFiles.length);
|
||||
toast({
|
||||
status: 'warning',
|
||||
title: t('common.file.Some file count exceeds limit', { maxCount })
|
||||
title: fileT('Some file count exceeds limit', { maxCount })
|
||||
});
|
||||
}
|
||||
// size check
|
||||
@@ -141,7 +144,7 @@ const FileSelector = ({
|
||||
if (filterFiles.length < files.length) {
|
||||
toast({
|
||||
status: 'warning',
|
||||
title: t('common.file.Some file size exceeds limit', { maxSize: formatFileSize(maxSize) })
|
||||
title: fileT('Some file size exceeds limit', { maxSize: formatFileSize(maxSize) })
|
||||
});
|
||||
}
|
||||
|
||||
@@ -203,7 +206,7 @@ const FileSelector = ({
|
||||
let isErr = files.some((item) => item.type === '');
|
||||
if (isErr) {
|
||||
return toast({
|
||||
title: t('file.upload error description'),
|
||||
title: fileT('upload error description'),
|
||||
status: 'error'
|
||||
});
|
||||
}
|
||||
@@ -262,18 +265,18 @@ const FileSelector = ({
|
||||
<>
|
||||
<Box fontWeight={'bold'}>
|
||||
{isDragging
|
||||
? t('file.Release the mouse to upload the file')
|
||||
: t('common.file.Select and drag file tip')}
|
||||
? fileT('Release the mouse to upload the file')
|
||||
: fileT('Select and drag file tip')}
|
||||
</Box>
|
||||
{/* file type */}
|
||||
<Box color={'myGray.500'} fontSize={'xs'}>
|
||||
{t('common.file.Support file type', { fileType })}
|
||||
{fileT('Support file type', { fileType })}
|
||||
</Box>
|
||||
<Box color={'myGray.500'} fontSize={'xs'}>
|
||||
{/* max count */}
|
||||
{maxCount && t('common.file.Support max count', { maxCount })}
|
||||
{maxCount && fileT('Support max count', { maxCount })}
|
||||
{/* max size */}
|
||||
{maxSize && t('common.file.Support max size', { maxSize: formatFileSize(maxSize) })}
|
||||
{maxSize && fileT('Support max size', { maxSize: formatFileSize(maxSize) })}
|
||||
</Box>
|
||||
|
||||
<File
|
||||
|
||||
@@ -16,6 +16,7 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
const PreviewRawText = dynamic(() => import('./PreviewRawText'));
|
||||
|
||||
@@ -29,6 +30,7 @@ export const RenderUploadFiles = ({
|
||||
showPreviewContent?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { fileT } = useI18n();
|
||||
const [previewFile, setPreviewFile] = useState<ImportSourceItemType>();
|
||||
|
||||
return files.length > 0 ? (
|
||||
@@ -38,13 +40,13 @@ export const RenderUploadFiles = ({
|
||||
<Thead draggable={false}>
|
||||
<Tr bg={'myGray.100'} mb={2}>
|
||||
<Th borderLeftRadius={'md'} borderBottom={'none'} py={4}>
|
||||
{t('common.file.File Name')}
|
||||
{fileT('File Name')}
|
||||
</Th>
|
||||
<Th borderBottom={'none'} py={4}>
|
||||
{t('core.dataset.import.Upload file progress')}
|
||||
</Th>
|
||||
<Th borderBottom={'none'} py={4}>
|
||||
{t('common.file.File Size')}
|
||||
{fileT('File Size')}
|
||||
</Th>
|
||||
<Th borderRightRadius={'md'} borderBottom={'none'} py={4}>
|
||||
{t('common.Action')}
|
||||
|
||||
@@ -295,7 +295,7 @@ export async function getServerSideProps(context: any) {
|
||||
const datasetId = context?.query?.datasetId;
|
||||
|
||||
return {
|
||||
props: { currentTab, datasetId, ...(await serviceSideProps(context)) }
|
||||
props: { currentTab, datasetId, ...(await serviceSideProps(context, ['file'])) }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
isLoading={requesting}
|
||||
onClick={handleSubmit(onclickLogin)}
|
||||
>
|
||||
{t('home.Login')}
|
||||
{t('Login')}
|
||||
</Button>
|
||||
|
||||
{feConfigs?.show_register && (
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
} from '@/web/core/workflow/utils';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext, getWorkflowStore } from '@/components/core/workflow/context';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
const ImportSettings = dynamic(() => import('@/components/core/workflow/Flow/ImportSettings'));
|
||||
|
||||
@@ -25,6 +26,8 @@ type Props = { plugin: PluginItemSchema; onClose: () => void };
|
||||
const Header = ({ plugin, onClose }: Props) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const { appT } = useI18n();
|
||||
|
||||
const { toast } = useToast();
|
||||
const { copyData } = useCopyData();
|
||||
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||
@@ -77,10 +80,10 @@ const Header = ({ plugin, onClose }: Props) => {
|
||||
null,
|
||||
2
|
||||
),
|
||||
t('app.Export Config Successful')
|
||||
appT('Export Config Successful')
|
||||
);
|
||||
}
|
||||
}, [copyData, flowData2StoreDataAndCheck, t]);
|
||||
}, [appT, copyData, flowData2StoreDataAndCheck]);
|
||||
|
||||
const Render = useMemo(() => {
|
||||
return (
|
||||
@@ -118,9 +121,9 @@ const Header = ({ plugin, onClose }: Props) => {
|
||||
/>
|
||||
}
|
||||
menuList={[
|
||||
{ label: t('app.Import Configs'), icon: 'common/importLight', onClick: onOpenImport },
|
||||
{ label: appT('Import Configs'), icon: 'common/importLight', onClick: onOpenImport },
|
||||
{
|
||||
label: t('app.Export Configs'),
|
||||
label: appT('Export Configs'),
|
||||
icon: 'export',
|
||||
onClick: onCopy
|
||||
}
|
||||
@@ -139,6 +142,7 @@ const Header = ({ plugin, onClose }: Props) => {
|
||||
</>
|
||||
);
|
||||
}, [
|
||||
appT,
|
||||
isLoading,
|
||||
isOpenImport,
|
||||
onClose,
|
||||
|
||||
@@ -13,7 +13,8 @@ export const NextAPI = (...args: NextApiHandler[]): NextApiHandler => {
|
||||
response = await handler(req, res);
|
||||
}
|
||||
|
||||
if (!res.writableFinished) {
|
||||
const contentType = res.getHeader('Content-Type');
|
||||
if ((!contentType || contentType === 'application/json') && !res.writableFinished) {
|
||||
return jsonRes(res, {
|
||||
code: 200,
|
||||
data: response
|
||||
|
||||
18
projects/app/src/types/i18n.d.ts
vendored
18
projects/app/src/types/i18n.d.ts
vendored
@@ -1,14 +1,24 @@
|
||||
import 'i18next';
|
||||
//import common from '../../i18n/en/common.json';
|
||||
import common from '../../i18n/zh/common.json';
|
||||
import dataset from '../../i18n/zh/dataset.json';
|
||||
import app from '../../i18n/zh/app.json';
|
||||
import file from '../../i18n/zh/file.json';
|
||||
import publish from '../../i18n/zh/publish.json';
|
||||
|
||||
interface I18nNamespaces {
|
||||
common: any;
|
||||
export interface I18nNamespaces {
|
||||
common: typeof common;
|
||||
dataset: typeof dataset;
|
||||
app: typeof app;
|
||||
file: typeof file;
|
||||
publish: typeof publish;
|
||||
}
|
||||
|
||||
export type I18nNsType = (keyof I18nNamespaces)[];
|
||||
|
||||
declare module 'i18next' {
|
||||
interface CustomTypeOptions {
|
||||
returnNull: false;
|
||||
defaultNs: 'common';
|
||||
// resources: I18nNamespaces;
|
||||
resources: I18nNamespaces;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useRef, useCallback } from 'react';
|
||||
import { Box } from '@chakra-ui/react';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
export const useSelectFile = (props?: {
|
||||
fileType?: string;
|
||||
@@ -9,6 +10,7 @@ export const useSelectFile = (props?: {
|
||||
maxCount?: number;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { fileT } = useI18n();
|
||||
const { fileType = '*', multiple = false, maxCount = 10 } = props || {};
|
||||
const { toast } = useToast();
|
||||
const SelectFileDom = useRef<HTMLInputElement>(null);
|
||||
@@ -30,7 +32,7 @@ export const useSelectFile = (props?: {
|
||||
if (fileList.length > maxCount) {
|
||||
toast({
|
||||
status: 'warning',
|
||||
title: t('common.file.Select file amount limit', { max: maxCount })
|
||||
title: fileT('Select file amount limit', { max: maxCount })
|
||||
});
|
||||
fileList = fileList.slice(0, maxCount);
|
||||
}
|
||||
@@ -39,7 +41,7 @@ export const useSelectFile = (props?: {
|
||||
/>
|
||||
</Box>
|
||||
),
|
||||
[fileType, maxCount, multiple, t, toast]
|
||||
[fileT, fileType, maxCount, multiple, toast]
|
||||
);
|
||||
|
||||
const onOpen = useCallback((sign?: any) => {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { I18nNsType } from '@/types/i18n';
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
||||
|
||||
export const LANG_KEY = 'NEXT_LOCALE_LANG';
|
||||
@@ -16,8 +17,8 @@ export const langMap = {
|
||||
}
|
||||
};
|
||||
|
||||
export const serviceSideProps = (content: any) => {
|
||||
return serverSideTranslations(content.locale, undefined, null, content.locales);
|
||||
export const serviceSideProps = (content: any, ns: I18nNsType = []) => {
|
||||
return serverSideTranslations(content.locale, ['common', ...ns], null, content.locales);
|
||||
};
|
||||
|
||||
export const getLng = (lng: string) => {
|
||||
|
||||
44
projects/app/src/web/context/I18n.tsx
Normal file
44
projects/app/src/web/context/I18n.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import { createContext, useContextSelector } from 'use-context-selector';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { TFunction } from 'i18next';
|
||||
|
||||
type I18nContextType = {
|
||||
commonT: TFunction<['common'], undefined>;
|
||||
appT: TFunction<['app'], undefined>;
|
||||
datasetT: TFunction<['dataset'], undefined>;
|
||||
fileT: TFunction<['file'], undefined>;
|
||||
publishT: TFunction<['publish'], undefined>;
|
||||
};
|
||||
|
||||
export const I18nContext = createContext<I18nContextType>({
|
||||
// @ts-ignore
|
||||
commonT: undefined
|
||||
});
|
||||
|
||||
const I18nContextProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
const { t: commonT } = useTranslation('common');
|
||||
const { t: appT } = useTranslation('app');
|
||||
const { t: datasetT } = useTranslation('dataset');
|
||||
const { t: fileT } = useTranslation('file');
|
||||
const { t: publishT } = useTranslation('publish');
|
||||
|
||||
return (
|
||||
<I18nContext.Provider
|
||||
value={{
|
||||
commonT,
|
||||
appT,
|
||||
datasetT,
|
||||
fileT,
|
||||
publishT
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</I18nContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default I18nContextProvider;
|
||||
|
||||
export const useI18n = () => {
|
||||
return useContextSelector(I18nContext, (ctx) => ctx);
|
||||
};
|
||||
@@ -290,7 +290,11 @@ export const v1Workflow2V2 = (
|
||||
const newInput: FlowNodeInputItemType = {
|
||||
...input,
|
||||
selectedTypeIndex: 0,
|
||||
renderTypeList: inputTypeMap[input.type] ? [inputTypeMap[input.type]] : [],
|
||||
renderTypeList: !input.type
|
||||
? [FlowNodeInputTypeEnum.custom]
|
||||
: inputTypeMap[input.type]
|
||||
? [inputTypeMap[input.type]]
|
||||
: [],
|
||||
|
||||
key: input.key,
|
||||
value: input.value,
|
||||
|
||||
Reference in New Issue
Block a user