fix: import dataset step error;perf: ai proxy avatar (#4074)
* perf: pg config params * perf: ai proxy avatar * fix: import dataset step error * feat: data input ux * perf: app dataset rewite
@ -100,7 +100,7 @@ services:
|
||||
exec docker-entrypoint.sh "$$@" &
|
||||
|
||||
# 等待MongoDB服务启动
|
||||
until mongo -u myusername -p mypassword --authenticationDatabase admin --eval "print('waited for connection')" > /dev/null 2>&1; do
|
||||
until mongo -u myusername -p mypassword --authenticationDatabase admin --eval "print('waited for connection')"; do
|
||||
echo "Waiting for MongoDB to start..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
@ -58,7 +58,7 @@ services:
|
||||
exec docker-entrypoint.sh "$$@" &
|
||||
|
||||
# 等待MongoDB服务启动
|
||||
until mongo -u myusername -p mypassword --authenticationDatabase admin --eval "print('waited for connection')" > /dev/null 2>&1; do
|
||||
until mongo -u myusername -p mypassword --authenticationDatabase admin --eval "print('waited for connection')"; do
|
||||
echo "Waiting for MongoDB to start..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
@ -41,7 +41,7 @@ services:
|
||||
exec docker-entrypoint.sh "$$@" &
|
||||
|
||||
# 等待MongoDB服务启动
|
||||
until mongo -u myusername -p mypassword --authenticationDatabase admin --eval "print('waited for connection')" > /dev/null 2>&1; do
|
||||
until mongo -u myusername -p mypassword --authenticationDatabase admin --eval "print('waited for connection')"; do
|
||||
echo "Waiting for MongoDB to start..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
@ -4,7 +4,7 @@ description: 'FastGPT V4.8.23 更新说明'
|
||||
icon: 'upgrade'
|
||||
draft: false
|
||||
toc: true
|
||||
weight: 802
|
||||
weight: 801
|
||||
---
|
||||
|
||||
## 更新指南
|
||||
|
||||
@ -4,7 +4,7 @@ description: 'FastGPT V4.9.0 更新说明'
|
||||
icon: 'upgrade'
|
||||
draft: false
|
||||
toc: true
|
||||
weight: 801
|
||||
weight: 800
|
||||
---
|
||||
|
||||
|
||||
|
||||
24
docSite/content/zh-cn/docs/development/upgrading/491.md
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
title: 'V4.9.1'
|
||||
description: 'FastGPT V4.9.1 更新说明'
|
||||
icon: 'upgrade'
|
||||
draft: false
|
||||
toc: true
|
||||
weight: 799
|
||||
---
|
||||
|
||||
## 🚀 新增内容
|
||||
|
||||
|
||||
## ⚙️ 优化
|
||||
|
||||
1. 知识库数据输入框交互
|
||||
2. 应用拉取绑定知识库数据交由后端处理。
|
||||
3. 增加依赖包安全版本检测,并升级部分依赖包。
|
||||
|
||||
## 🐛 修复
|
||||
|
||||
1. 最大响应 tokens 提示显示错误的问题。
|
||||
2. HTTP Node 中,字符串包含换行符时,会解析失败。
|
||||
3. 知识库问题优化中,未传递历史记录。
|
||||
4. 错误提示翻译缺失。
|
||||
@ -93,7 +93,7 @@ ${mdSplitString}
|
||||
|
||||
/*
|
||||
1. 自定义分隔符:不需要重叠,不需要小块合并
|
||||
2. Markdown 标题:不需要重叠;标题嵌套共享,不需要小块合并
|
||||
2. Markdown 标题:不需要重叠;标题嵌套共享,需要小块合并
|
||||
3. 特殊 markdown 语法:不需要重叠,需要小块合并
|
||||
4. 段落:尽可能保证它是一个完整的段落。
|
||||
5. 标点分割:重叠
|
||||
@ -227,7 +227,7 @@ const commonSplit = (props: SplitProps): SplitResponse => {
|
||||
}): string[] => {
|
||||
const isMarkdownStep = checkIsMarkdownSplit(step);
|
||||
const isCustomStep = checkIsCustomStep(step);
|
||||
const forbidConcat = isMarkdownStep || isCustomStep; // forbid=true时候,lastText肯定为空
|
||||
const forbidConcat = isCustomStep; // forbid=true时候,lastText肯定为空
|
||||
|
||||
// oversize
|
||||
if (step >= stepReges.length) {
|
||||
|
||||
@ -38,6 +38,27 @@ export class PgVectorCtrl {
|
||||
await PgClient.query(
|
||||
`CREATE INDEX CONCURRENTLY IF NOT EXISTS create_time_index ON ${DatasetVectorTableName} USING btree(createtime);`
|
||||
);
|
||||
// 10w rows
|
||||
// await PgClient.query(`
|
||||
// ALTER TABLE modeldata SET (
|
||||
// autovacuum_vacuum_scale_factor = 0.1,
|
||||
// autovacuum_analyze_scale_factor = 0.05,
|
||||
// autovacuum_vacuum_threshold = 50,
|
||||
// autovacuum_analyze_threshold = 50,
|
||||
// autovacuum_vacuum_cost_delay = 20,
|
||||
// autovacuum_vacuum_cost_limit = 200
|
||||
// );`);
|
||||
|
||||
// 100w rows
|
||||
// await PgClient.query(`
|
||||
// ALTER TABLE modeldata SET (
|
||||
// autovacuum_vacuum_scale_factor = 0.01,
|
||||
// autovacuum_analyze_scale_factor = 0.02,
|
||||
// autovacuum_vacuum_threshold = 1000,
|
||||
// autovacuum_analyze_threshold = 1000,
|
||||
// autovacuum_vacuum_cost_delay = 10,
|
||||
// autovacuum_vacuum_cost_limit = 2000
|
||||
// );`)
|
||||
|
||||
addLog.info('init pg successful');
|
||||
} catch (error) {
|
||||
|
||||
@ -4,20 +4,13 @@ import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import type { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
||||
|
||||
export type ListByAppIdAndDatasetIdsBody = {
|
||||
teamId: string;
|
||||
datasetIdList: string[];
|
||||
};
|
||||
|
||||
interface Dataset {
|
||||
datasetId: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export async function listAppDatasetDataByTeamIdAndDatasetIds({
|
||||
teamId,
|
||||
datasetIdList
|
||||
}: ListByAppIdAndDatasetIdsBody) {
|
||||
}: {
|
||||
teamId?: string;
|
||||
datasetIdList: string[];
|
||||
}) {
|
||||
const myDatasets = await MongoDataset.find({
|
||||
teamId,
|
||||
_id: { $in: datasetIdList }
|
||||
@ -31,9 +24,18 @@ export async function listAppDatasetDataByTeamIdAndDatasetIds({
|
||||
}));
|
||||
}
|
||||
|
||||
export async function rewriteAppWorkflowToDetail(nodes: StoreNodeItemType[], teamId: string) {
|
||||
export async function rewriteAppWorkflowToDetail({
|
||||
nodes,
|
||||
teamId,
|
||||
isRoot
|
||||
}: {
|
||||
nodes: StoreNodeItemType[];
|
||||
teamId: string;
|
||||
isRoot: boolean;
|
||||
}) {
|
||||
const datasetIdSet = new Set<string>();
|
||||
|
||||
// Get all dataset ids from nodes
|
||||
nodes.forEach((node) => {
|
||||
if (node.flowNodeType !== FlowNodeTypeEnum.datasetSearchNode) return;
|
||||
|
||||
@ -41,83 +43,83 @@ export async function rewriteAppWorkflowToDetail(nodes: StoreNodeItemType[], tea
|
||||
if (!input) return;
|
||||
|
||||
const rawValue = input.value as undefined | { datasetId: string }[] | { datasetId: string };
|
||||
if (!rawValue) return;
|
||||
|
||||
const datasetIds = Array.isArray(rawValue)
|
||||
? rawValue
|
||||
.map((v) => v?.datasetId)
|
||||
.filter((id): id is string => !!id && typeof id === 'string')
|
||||
: rawValue?.datasetId
|
||||
? rawValue.map((v) => v?.datasetId).filter((id) => !!id && typeof id === 'string')
|
||||
: rawValue.datasetId
|
||||
? [String(rawValue.datasetId)]
|
||||
: [];
|
||||
|
||||
if (datasetIds.length === 0) return;
|
||||
|
||||
datasetIds.forEach((id) => datasetIdSet.add(id));
|
||||
});
|
||||
|
||||
if (datasetIdSet.size === 0) return;
|
||||
|
||||
const uniqueDatasetIds = Array.from(datasetIdSet);
|
||||
// Load dataset list
|
||||
const datasetList = await listAppDatasetDataByTeamIdAndDatasetIds({
|
||||
teamId,
|
||||
datasetIdList: uniqueDatasetIds
|
||||
teamId: isRoot ? undefined : teamId,
|
||||
datasetIdList: Array.from(datasetIdSet)
|
||||
});
|
||||
const datasetMap = new Map(datasetList.map((ds) => [String(ds.datasetId), ds]));
|
||||
|
||||
const datasetMap = new Map(
|
||||
datasetList.map((ds) => [
|
||||
String(ds.datasetId),
|
||||
{
|
||||
...ds,
|
||||
vectorModel: getEmbeddingModel(ds.vectorModel.model)
|
||||
}
|
||||
])
|
||||
);
|
||||
|
||||
// Rewrite dataset ids, add dataset info to nodes
|
||||
nodes.forEach((node) => {
|
||||
if (node.flowNodeType !== FlowNodeTypeEnum.datasetSearchNode) return;
|
||||
|
||||
const input = node.inputs.find((item) => item.key === NodeInputKeyEnum.datasetSelectList);
|
||||
if (!input) return;
|
||||
node.inputs.forEach((item) => {
|
||||
if (item.key !== NodeInputKeyEnum.datasetSelectList) return;
|
||||
|
||||
const rawValue = input.value as undefined | { datasetId: string }[] | { datasetId: string };
|
||||
const val = item.value as undefined | { datasetId: string }[] | { datasetId: string };
|
||||
|
||||
const datasetIds = Array.isArray(rawValue)
|
||||
? rawValue
|
||||
.map((v) => v?.datasetId)
|
||||
.filter((id): id is string => !!id && typeof id === 'string')
|
||||
: rawValue?.datasetId
|
||||
? [String(rawValue.datasetId)]
|
||||
: [];
|
||||
|
||||
if (datasetIds.length === 0) return;
|
||||
|
||||
input.value = datasetIds
|
||||
.map((id) => {
|
||||
const data = datasetMap.get(String(id));
|
||||
return data
|
||||
? {
|
||||
datasetId: data.datasetId,
|
||||
avatar: data.avatar,
|
||||
name: data.name,
|
||||
vectorModel: data.vectorModel
|
||||
}
|
||||
: undefined;
|
||||
})
|
||||
.filter((item): item is NonNullable<typeof item> => !!item);
|
||||
if (Array.isArray(val)) {
|
||||
item.value = val.map((v) => {
|
||||
const data = datasetMap.get(String(v.datasetId))!;
|
||||
return {
|
||||
datasetId: data.datasetId,
|
||||
avatar: data.avatar,
|
||||
name: data.name,
|
||||
vectorModel: data.vectorModel
|
||||
};
|
||||
});
|
||||
} else if (typeof val === 'object' && val !== null) {
|
||||
const data = datasetMap.get(String(val.datasetId))!;
|
||||
item.value = {
|
||||
datasetId: data.datasetId,
|
||||
avatar: data.avatar,
|
||||
name: data.name,
|
||||
vectorModel: data.vectorModel
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export async function rewriteAppWorkflowToSimple(formatNodes: StoreNodeItemType[]) {
|
||||
formatNodes.forEach((node) => {
|
||||
if (node.flowNodeType !== FlowNodeTypeEnum.datasetSearchNode) return;
|
||||
|
||||
const datasetsInput = node.inputs.find(
|
||||
(input) => input.key === NodeInputKeyEnum.datasetSelectList
|
||||
);
|
||||
if (datasetsInput?.value) {
|
||||
datasetsInput.value = datasetsInput.value.map((dataset: Dataset) => ({
|
||||
datasetId: dataset.datasetId
|
||||
}));
|
||||
}
|
||||
node.inputs.forEach((input) => {
|
||||
if (input.key === NodeInputKeyEnum.datasetSelectList) {
|
||||
const val = input.value as undefined | { datasetId: string }[] | { datasetId: string };
|
||||
if (!val) {
|
||||
input.value = [];
|
||||
} else if (Array.isArray(val)) {
|
||||
input.value = val
|
||||
.map((dataset: { datasetId: string }) => ({
|
||||
datasetId: dataset.datasetId
|
||||
}))
|
||||
.filter((item) => !!item.datasetId);
|
||||
} else if (typeof val === 'object' && val !== null) {
|
||||
input.value = [
|
||||
{
|
||||
datasetId: val.datasetId
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -34,6 +34,7 @@ const MyIconButton = ({
|
||||
color: hoverColor
|
||||
}}
|
||||
onClick={onClick}
|
||||
sx={{ userSelect: 'none' }}
|
||||
{...props}
|
||||
>
|
||||
<MyIcon name={icon as any} w={size} />
|
||||
|
||||
@ -373,9 +373,13 @@ export const iconPaths = {
|
||||
'modal/teamPlans': () => import('./icons/modal/teamPlans.svg'),
|
||||
'model/BAAI': () => import('./icons/model/BAAI.svg'),
|
||||
'model/alicloud': () => import('./icons/model/alicloud.svg'),
|
||||
'model/aws': () => import('./icons/model/aws.svg'),
|
||||
'model/azure': () => import('./icons/model/azure.svg'),
|
||||
'model/baichuan': () => import('./icons/model/baichuan.svg'),
|
||||
'model/chatglm': () => import('./icons/model/chatglm.svg'),
|
||||
'model/claude': () => import('./icons/model/claude.svg'),
|
||||
'model/cloudflare': () => import('./icons/model/cloudflare.svg'),
|
||||
'model/cohere': () => import('./icons/model/cohere.svg'),
|
||||
'model/deepseek': () => import('./icons/model/deepseek.svg'),
|
||||
'model/doubao': () => import('./icons/model/doubao.svg'),
|
||||
'model/ernie': () => import('./icons/model/ernie.svg'),
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
<svg viewBox="0 0 19 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.237 6.21967C4.5299 5.92678 5.00477 5.92678 5.29766 6.21967L9.26733 10.1893L13.237 6.21967C13.5299 5.92678 14.0048 5.92678 14.2977 6.21967C14.5906 6.51256 14.5906 6.98744 14.2977 7.28033L9.79766 11.7803C9.50477 12.0732 9.0299 12.0732 8.737 11.7803L4.237 7.28033C3.94411 6.98744 3.94411 6.51256 4.237 6.21967Z" />
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" >
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.52858 5.52876C3.78892 5.26841 4.21103 5.26841 4.47138 5.52876L7.99998 9.05735L11.5286 5.52876C11.7889 5.26841 12.211 5.26841 12.4714 5.52876C12.7317 5.78911 12.7317 6.21122 12.4714 6.47157L8.47138 10.4716C8.21103 10.7319 7.78892 10.7319 7.52858 10.4716L3.52858 6.47157C3.26823 6.21122 3.26823 5.78911 3.52858 5.52876Z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 444 B After Width: | Height: | Size: 445 B |
@ -1,3 +1,3 @@
|
||||
<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.96967 11.7803C4.26256 12.0732 4.73744 12.0732 5.03033 11.7803L9 7.81066L12.9697 11.7803C13.2626 12.0732 13.7374 12.0732 14.0303 11.7803C14.3232 11.4874 14.3232 11.0126 14.0303 10.7197L9.53033 6.21967C9.23744 5.92678 8.76256 5.92678 8.46967 6.21967L3.96967 10.7197C3.67678 11.0126 3.67678 11.4874 3.96967 11.7803Z" />
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" >
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.52858 10.4712C3.78892 10.7316 4.21103 10.7316 4.47138 10.4712L7.99998 6.94265L11.5286 10.4712C11.7889 10.7316 12.211 10.7316 12.4714 10.4712C12.7317 10.2109 12.7317 9.78878 12.4714 9.52843L8.47138 5.52843C8.21103 5.26808 7.78892 5.26808 7.52858 5.52843L3.52858 9.52843C3.26823 9.78878 3.26823 10.2109 3.52858 10.4712Z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 449 B After Width: | Height: | Size: 445 B |
1
packages/web/components/common/Icon/icons/model/aws.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1741332650600" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6423" width="64" height="64"><path d="M288.695 427.886c0 12.653 1.316 22.893 3.73 30.427 2.706 7.534 6.144 15.726 10.972 24.576a14.848 14.848 0 0 1 2.34 7.9c0 3.364-2.048 6.802-6.51 10.24l-21.43 14.336a16.31 16.31 0 0 1-8.85 3.072c-3.438 0-6.803-1.683-10.24-4.755a105.618 105.618 0 0 1-12.289-16.091 263.607 263.607 0 0 1-10.532-20.114c-26.551 31.451-59.977 47.104-100.206 47.104-28.526 0-51.42-8.192-68.023-24.576-16.75-16.384-25.307-38.254-25.307-65.61 0-29.11 10.24-52.662 31.012-70.436s48.42-26.697 83.456-26.697c11.63 0 23.552 1.024 36.133 2.78 12.58 1.681 25.6 4.388 39.204 7.533V322.56c0-26.039-5.485-44.105-16.091-54.71-10.825-10.607-29.257-15.727-55.442-15.727-11.923 0-24.21 1.39-36.791 4.389a269.897 269.897 0 0 0-36.791 11.703 97.573 97.573 0 0 1-11.922 4.388 20.7 20.7 0 0 1-5.486 1.024c-4.754 0-7.168-3.364-7.168-10.605v-16.53c0-5.486 0.731-9.582 2.414-11.996a25.454 25.454 0 0 1 9.508-7.168c11.923-6.144 26.259-11.337 42.935-15.36 16.677-4.462 34.377-6.583 53.175-6.583 40.521 0 70.217 9.29 89.234 27.794 18.725 18.36 28.307 46.446 28.307 84.042v110.665h0.658z m-138.313 51.931c11.264 0 22.82-2.048 35.108-6.144 12.215-4.096 23.113-11.63 32.33-21.87a54.272 54.272 0 0 0 11.63-21.942 122.88 122.88 0 0 0 3.364-29.696v-14.336a255.927 255.927 0 0 0-63.342-7.9c-22.82 0-39.497 4.462-50.761 13.751-11.264 9.216-16.677 22.162-16.677 39.278 0 16.091 4.023 28.013 12.58 36.205 8.193 8.558 20.115 12.654 35.768 12.654z m273.554 36.937c-6.144 0-10.24-1.024-12.946-3.437-2.707-2.048-5.12-6.803-7.168-13.312l-80.019-264.192a59.83 59.83 0 0 1-3.072-13.678c0-5.486 2.707-8.558 8.12-8.558h33.426c6.436 0 10.898 1.024 13.312 3.438 2.706 2.048 4.754 6.802 6.802 13.312l57.198 226.23 53.174-226.23c1.683-6.876 3.73-11.264 6.437-13.312a23.406 23.406 0 0 1 13.605-3.438h27.282c6.51 0 10.971 1.024 13.604 3.438 2.78 2.048 5.12 6.802 6.51 13.312l53.833 228.937 58.953-228.937a29.403 29.403 0 0 1 6.803-13.312 22.235 22.235 0 0 1 13.239-3.438h31.744c5.412 0 8.484 2.706 8.484 8.558 0 1.682-0.366 3.364-0.731 5.412a50.103 50.103 0 0 1-2.34 8.558L648.118 500.37c-2.048 6.803-4.389 11.264-7.168 13.312a21.723 21.723 0 0 1-12.946 3.438h-29.258c-6.582 0-10.971-1.024-13.677-3.438-2.707-2.413-5.12-6.875-6.437-13.677l-52.809-220.453-52.517 220.16c-1.682 6.802-3.73 11.19-6.436 13.605s-7.534 3.437-13.605 3.437h-29.33z m437.76 9.216c-17.7 0-35.401-2.048-52.443-6.144a155.063 155.063 0 0 1-39.205-13.677c-5.413-3.072-9.216-6.51-10.533-9.509a24.137 24.137 0 0 1-2.048-9.655v-17.408c0-7.168 2.707-10.606 7.827-10.606 2.048 0 4.096 0.366 6.144 1.024 2.048 0.732 5.12 2.048 8.484 3.438a188.428 188.428 0 0 0 37.45 11.996c13.677 2.706 26.99 4.096 40.594 4.096 21.43 0 38.107-3.804 49.737-11.264a36.937 36.937 0 0 0 17.7-32.549 33.353 33.353 0 0 0-9.216-23.918c-6.144-6.51-17.7-12.288-34.377-17.773l-49.444-15.36c-24.869-7.9-43.228-19.456-54.492-34.89a81.554 81.554 0 0 1-7.826-87.478 87.771 87.771 0 0 1 24.503-28.014c10.24-7.9 21.87-13.678 35.474-17.774 13.605-4.096 27.94-5.851 42.935-5.851 7.46 0 15.36 0.365 22.82 1.39 7.827 1.023 14.995 2.413 22.09 3.73 6.875 1.755 13.312 3.437 19.456 5.485 6.144 2.048 10.898 4.096 14.336 6.144a29.477 29.477 0 0 1 10.24 8.558 18.432 18.432 0 0 1 2.999 11.264v16.092c0 7.168-2.707 10.971-7.827 10.971a35.109 35.109 0 0 1-12.946-4.17 155.502 155.502 0 0 0-65.39-13.311c-19.456 0-34.743 3.072-45.348 9.582-10.533 6.51-16.019 16.384-16.019 30.427 0 9.509 3.438 17.774 10.24 24.283 6.803 6.51 19.456 12.947 37.523 18.798l48.347 15.36c24.503 7.9 42.204 18.798 52.81 32.841 10.532 13.97 15.652 30.062 15.652 47.836 0 14.701-3.072 28.013-8.777 39.643-6.071 11.703-14.629 21.943-24.942 30.062a109.714 109.714 0 0 1-37.815 19.163c-15.36 4.755-31.305 7.168-48.713 7.168z" fill="#252F3E" p-id="6424"></path><path d="M926.062 692.15C814.08 775.169 651.118 819.2 511.122 819.2c-196.242 0-373.028-72.777-506.587-193.829-10.533-9.508-1.024-22.528 11.63-14.994C160.549 694.491 338.725 745.4 523.045 745.4c124.342 0 260.973-26.039 386.706-79.36 18.724-8.485 34.743 12.361 16.31 26.039z" fill="#FF9900" p-id="6425"></path><path d="M972.8 638.757c-14.336-18.432-94.793-8.85-131.218-4.389-10.972 1.317-12.58-8.265-2.707-15.36 64-45.202 169.326-32.183 181.541-17.115 12.288 15.36-3.365 120.978-63.342 171.593-9.216 7.826-18.066 3.73-13.97-6.583 13.605-33.792 43.886-110.007 29.623-128.146z" fill="#FF9900" p-id="6426"></path></svg>
|
||||
|
After Width: | Height: | Size: 4.3 KiB |
@ -0,0 +1 @@
|
||||
<svg t="1741332590124" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2637" width="64" height="64"><path d="M384.032 128h227.264l-235.904 741.792a36.48 36.48 0 0 1-34.336 26.208H164.16A37.312 37.312 0 0 1 128 857.632a41.6 41.6 0 0 1 1.92-12.32l219.84-691.168A36.48 36.48 0 0 1 384.032 128" fill="#01579B" p-id="2638"></path><path d="M714.24 640H353.92a17.184 17.184 0 0 0-16.704 17.6 18.24 18.24 0 0 0 5.312 13.056l231.552 214.912a35.2 35.2 0 0 0 24.8 10.4h204.032z" fill="#1976D2" p-id="2639"></path><path d="M674.272 154.112A36.48 36.48 0 0 0 640.032 128h-253.28a36.48 36.48 0 0 1 34.304 26.08l219.776 691.168a39.04 39.04 0 0 1-22.72 48.64 35.2 35.2 0 0 1-11.584 2.048h253.28A37.312 37.312 0 0 0 896 857.6a41.6 41.6 0 0 0-1.92-12.32L674.304 154.144z" fill="#29B6F6" p-id="2640"></path></svg>
|
||||
|
After Width: | Height: | Size: 838 B |
@ -0,0 +1 @@
|
||||
<svg t="1741333125459" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11365" width="64" height="64"><path d="M704.38432 718.72c6.304-21.632 3.872-41.408-6.624-56.128-9.568-13.504-25.792-21.28-45.28-22.208l-369.472-4.8h-0.096a6.688 6.688 0 0 1-5.568-3.008l-0.032-0.032a8.192 8.192 0 0 1-0.896-6.624 10.24 10.24 0 0 1 8.672-6.656l372.736-4.8c44.16-2.08 92.16-37.824 108.96-81.632l21.28-55.52a11.584 11.584 0 0 0 0.64-7.168 242.4 242.4 0 0 0-236.8-189.664 242.656 242.656 0 0 0-229.856 164.768 110.176 110.176 0 0 0-76.544-21.28 109.28 109.28 0 0 0-94.816 135.648 155.04 155.04 0 0 0-150.656 155.168c0 7.456 0.608 15.008 1.504 22.496a7.456 7.456 0 0 0 7.2 6.304h681.888a9.312 9.312 0 0 0 8.672-6.624l5.12-18.208z m117.6-237.376c-3.296 0-6.88 0-10.176 0.48-2.4 0-4.512 1.76-5.408 4.16l-14.4 50.112c-6.304 21.632-3.904 41.408 6.592 56.16 9.632 13.504 25.824 21.248 45.344 22.176l78.656 4.832c2.368 0 4.512 1.12 5.664 3.008a8.64 8.64 0 0 1 0.928 6.656 10.24 10.24 0 0 1-8.704 6.624l-81.952 4.8c-44.416 2.08-92.096 37.824-108.928 81.664l-5.984 15.296c-1.216 3.04 0.928 6.048 4.192 6.048h281.504a7.36 7.36 0 0 0 7.2-5.376c4.8-17.408 7.488-35.712 7.488-54.624 0-111.04-90.656-201.696-202.016-201.696z" fill="#F38020" p-id="11366"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1 @@
|
||||
<svg t="1741332939210" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7576" width="64" height="64"><path d="M331.712601 609.625898c27.560944 0 82.426848-1.535904 158.112785-32.723288 88.31448-36.349728 264.004833-102.3936 390.716913-170.144032 88.655792-47.35704 127.480032-110.158448 127.480033-194.547841A212.168073 212.168073 0 0 0 795.811595 0H304.791617A304.791617 304.791617 0 0 0 0 304.791617c0 168.309481 127.736016 304.834281 331.712601 304.834281z" fill="#39594D" p-id="7577"></path><path d="M414.736746 819.490115a204.147241 204.147241 0 0 1 125.8588-188.574881l154.699665-64.166656c156.406225-64.84928 328.598129 50.044872 328.598129 219.420953a237.510489 237.510489 0 0 1-237.638481 237.510489h-167.413537a204.147241 204.147241 0 0 1-204.104576-204.189905z" fill="#D18EE2" p-id="7578"></path><path d="M175.690353 649.772723A175.690353 175.690353 0 0 0 0 825.548403v22.739912a175.690353 175.690353 0 0 0 351.423369 0v-22.739912a175.690353 175.690353 0 0 0-175.733016-175.690352z" fill="#FF7759" p-id="7579"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@ -534,16 +534,10 @@
|
||||
"core.dataset.collection.status.active": "Ready",
|
||||
"core.dataset.collection.sync.result.sameRaw": "Content Unchanged, No Update Needed",
|
||||
"core.dataset.collection.sync.result.success": "Sync Started",
|
||||
"core.dataset.data.Auxiliary Data": "Auxiliary Data",
|
||||
"core.dataset.data.Auxiliary Data Placeholder": "This part is optional and is usually used to construct structured prompts in conjunction with the 'Data Content' above for special scenarios, up to {{maxToken}} characters.",
|
||||
"core.dataset.data.Auxiliary Data Tip": "This part is optional\nThis content is usually used to construct structured prompts in conjunction with the data content above for special scenarios",
|
||||
"core.dataset.data.Data Content": "Related Data Content",
|
||||
"core.dataset.data.Data Content Placeholder": "This input box is required. This content is usually a description of the knowledge point or a user's question, up to {{maxToken}} characters.",
|
||||
"core.dataset.data.Data Content Tip": "This input box is required\nThis content is usually a description of the knowledge point or a user's question.",
|
||||
"core.dataset.data.Default Index Tip": "Cannot be edited. The default index will use the text of 'Related Data Content' and 'Auxiliary Data' to generate the index directly.",
|
||||
"core.dataset.data.Edit": "Edit Data",
|
||||
"core.dataset.data.Empty Tip": "This collection has no data yet",
|
||||
"core.dataset.data.Main Content": "Main Content",
|
||||
"core.dataset.data.Search data placeholder": "Search Related Data",
|
||||
"core.dataset.data.Too Long": "Total Length Exceeded",
|
||||
"core.dataset.data.group": "Group",
|
||||
@ -867,6 +861,12 @@
|
||||
"dataset.dataset_name": "Dataset Name",
|
||||
"dataset.deleteFolderTips": "Confirm to Delete This Folder and All Its Contained Datasets? Data Cannot Be Recovered After Deletion, Please Confirm!",
|
||||
"dataset.test.noResult": "No Search Results",
|
||||
"dataset_data_import_q_placeholder": "Up to {{maxToken}} words.",
|
||||
"dataset_data_input_a": "Answer",
|
||||
"dataset_data_input_chunk": "Chunk",
|
||||
"dataset_data_input_chunk_content": "Chunk",
|
||||
"dataset_data_input_q": "question",
|
||||
"dataset_data_input_qa": "QA",
|
||||
"dataset_text_model_tip": "Used for text processing in the knowledge base preprocessing stage, such as automatic supplementary indexing, Q&A pair extraction.",
|
||||
"deep_rag_search": "In-depth search",
|
||||
"delete_api": "Are you sure you want to delete this API key? \nAfter deletion, the key will become invalid immediately and the corresponding conversation log will not be deleted. Please confirm!",
|
||||
|
||||
@ -69,6 +69,7 @@
|
||||
"import_model_config": "Model selection",
|
||||
"import_param_setting": "Parameter settings",
|
||||
"import_select_file": "Select a file",
|
||||
"import_select_link": "Enter link",
|
||||
"is_open_schedule": "Enable scheduled synchronization",
|
||||
"keep_image": "Keep the picture",
|
||||
"move.hint": "After moving, the selected knowledge base/folder will inherit the permission settings of the new folder, and the original permission settings will become invalid.",
|
||||
|
||||
@ -537,16 +537,10 @@
|
||||
"core.dataset.collection.status.active": "已就绪",
|
||||
"core.dataset.collection.sync.result.sameRaw": "内容未变动,无需更新",
|
||||
"core.dataset.collection.sync.result.success": "开始同步",
|
||||
"core.dataset.data.Auxiliary Data": "辅助数据",
|
||||
"core.dataset.data.Auxiliary Data Placeholder": "该部分为可选填项,通常是为了与前面的【数据内容】配合,构建结构化提示词,用于特殊场景,最多 {{maxToken}} 字。",
|
||||
"core.dataset.data.Auxiliary Data Tip": "该部分为可选填项\n该内容通常是为了与前面的数据内容配合,构建结构化提示词,用于特殊场景",
|
||||
"core.dataset.data.Data Content": "相关数据内容",
|
||||
"core.dataset.data.Data Content Placeholder": "该输入框是必填项,该内容通常是对于知识点的描述,也可以是用户的问题,最多 {{maxToken}} 字。",
|
||||
"core.dataset.data.Data Content Tip": "该输入框是必填项\n该内容通常是对于知识点的描述,也可以是用户的问题。",
|
||||
"core.dataset.data.Default Index Tip": "无法编辑,默认索引会使用【相关数据内容】与【辅助数据】的文本直接生成索引。",
|
||||
"core.dataset.data.Edit": "编辑数据",
|
||||
"core.dataset.data.Empty Tip": "这个集合还没有数据~",
|
||||
"core.dataset.data.Main Content": "主要内容",
|
||||
"core.dataset.data.Search data placeholder": "搜索相关数据",
|
||||
"core.dataset.data.Too Long": "总长度超长了",
|
||||
"core.dataset.data.group": "组",
|
||||
@ -560,6 +554,7 @@
|
||||
"core.dataset.error.unAuthDatasetData": "无权操作该数据",
|
||||
"core.dataset.error.unAuthDatasetFile": "无权操作该文件",
|
||||
"core.dataset.error.unCreateCollection": "无权操作该数据",
|
||||
"core.dataset.error.unExistDataset": "数据集不存在",
|
||||
"core.dataset.error.unLinkCollection": "不是网络链接集合",
|
||||
"core.dataset.externalFile": "外部文件库",
|
||||
"core.dataset.file": "文件",
|
||||
@ -664,7 +659,6 @@
|
||||
"core.dataset.website.Selector Course": "使用教程",
|
||||
"core.dataset.website.Start Sync": "开始同步",
|
||||
"core.dataset.website.UnValid Website Tip": "您的站点可能非静态站点,无法同步",
|
||||
"core.dataset.error.unExistDataset": "数据集不存在",
|
||||
"core.module.Add question type": "添加问题类型",
|
||||
"core.module.Add_option": "添加选项",
|
||||
"core.module.Can not connect self": "不能连接自身",
|
||||
@ -871,6 +865,12 @@
|
||||
"dataset.dataset_name": "知识库名称",
|
||||
"dataset.deleteFolderTips": "确认删除该文件夹及其包含的所有知识库?删除后数据无法恢复,请确认!",
|
||||
"dataset.test.noResult": "搜索结果为空",
|
||||
"dataset_data_import_q_placeholder": "最多 {{maxToken}} 字。",
|
||||
"dataset_data_input_a": "答案",
|
||||
"dataset_data_input_chunk": "常规模式",
|
||||
"dataset_data_input_chunk_content": "内容",
|
||||
"dataset_data_input_q": "问题",
|
||||
"dataset_data_input_qa": "QA 模式",
|
||||
"dataset_text_model_tip": "用于知识库预处理阶段的文本处理,例如自动补充索引、问答对提取。",
|
||||
"deep_rag_search": "深度搜索",
|
||||
"delete_api": "确认删除该API密钥?删除后该密钥立即失效,对应的对话日志不会删除,请确认!",
|
||||
|
||||
@ -69,6 +69,7 @@
|
||||
"import_model_config": "模型选择",
|
||||
"import_param_setting": "参数设置",
|
||||
"import_select_file": "选择文件",
|
||||
"import_select_link": "输入链接",
|
||||
"is_open_schedule": "启用定时同步",
|
||||
"keep_image": "保留图片",
|
||||
"move.hint": "移动后,所选知识库/文件夹将继承新文件夹的权限设置,原先的权限设置失效。",
|
||||
|
||||
@ -533,16 +533,10 @@
|
||||
"core.dataset.collection.status.active": "已就緒",
|
||||
"core.dataset.collection.sync.result.sameRaw": "內容未變更,無需更新",
|
||||
"core.dataset.collection.sync.result.success": "開始同步",
|
||||
"core.dataset.data.Auxiliary Data": "輔助資料",
|
||||
"core.dataset.data.Auxiliary Data Placeholder": "此部分為選填項目,通常是為了與前面的【資料內容】配合,建構結構化提示詞,用於特殊場景,最多 {{maxToken}} 字。",
|
||||
"core.dataset.data.Auxiliary Data Tip": "此部分為選填項目\n此內容通常是為了與前面的資料內容配合,建構結構化提示詞,用於特殊場景",
|
||||
"core.dataset.data.Data Content": "相關資料內容",
|
||||
"core.dataset.data.Data Content Placeholder": "此輸入欄位為必填項目,此內容通常是知識點的描述,也可以是使用者的問題,最多 {{maxToken}} 字。",
|
||||
"core.dataset.data.Data Content Tip": "此輸入欄位為必填項目\n此內容通常是知識點的描述,也可以是使用者的問題。",
|
||||
"core.dataset.data.Default Index Tip": "無法編輯,預設索引會使用【相關資料內容】與【輔助資料】的文字直接產生索引。",
|
||||
"core.dataset.data.Edit": "編輯資料",
|
||||
"core.dataset.data.Empty Tip": "此集合還沒有資料",
|
||||
"core.dataset.data.Main Content": "主要內容",
|
||||
"core.dataset.data.Search data placeholder": "搜尋相關資料",
|
||||
"core.dataset.data.Too Long": "總長度超出上限",
|
||||
"core.dataset.data.group": "組",
|
||||
@ -867,6 +861,12 @@
|
||||
"dataset.dataset_name": "知識庫名稱",
|
||||
"dataset.deleteFolderTips": "確認刪除此資料夾及其包含的所有知識庫?刪除後資料無法復原,請確認!",
|
||||
"dataset.test.noResult": "搜尋結果為空",
|
||||
"dataset_data_import_q_placeholder": "最多 {{maxToken}} 字。",
|
||||
"dataset_data_input_a": "答案",
|
||||
"dataset_data_input_chunk": "常規模式",
|
||||
"dataset_data_input_chunk_content": "內容",
|
||||
"dataset_data_input_q": "問題",
|
||||
"dataset_data_input_qa": "QA 模式",
|
||||
"dataset_text_model_tip": "用於知識庫預處理階段的文本處理,例如自動補充索引、問答對提取。",
|
||||
"deep_rag_search": "深度搜索",
|
||||
"delete_api": "確認刪除此 API 金鑰?\n刪除後該金鑰將立即失效,對應的對話記錄不會被刪除,請確認!",
|
||||
|
||||
@ -69,6 +69,7 @@
|
||||
"import_model_config": "模型選擇",
|
||||
"import_param_setting": "參數設置",
|
||||
"import_select_file": "選擇文件",
|
||||
"import_select_link": "輸入鏈接",
|
||||
"is_open_schedule": "啟用定時同步",
|
||||
"keep_image": "保留圖片",
|
||||
"move.hint": "移動後,所選資料集/資料夾將繼承新資料夾的權限設定,原先的權限設定將失效。",
|
||||
|
||||
@ -40,12 +40,16 @@ export const defaultChannel: ChannelInfoType = {
|
||||
priority: 0
|
||||
};
|
||||
|
||||
export const aiproxyIdMap: Record<number, { label: string; provider: ModelProviderIdType }> = {
|
||||
export const aiproxyIdMap: Record<
|
||||
number,
|
||||
{ label: string; provider: ModelProviderIdType; avatar?: string }
|
||||
> = {
|
||||
1: {
|
||||
label: 'OpenAI',
|
||||
provider: 'OpenAI'
|
||||
},
|
||||
3: {
|
||||
avatar: 'model/azure',
|
||||
label: i18nT('account_model:azure'),
|
||||
provider: 'OpenAI'
|
||||
},
|
||||
@ -124,5 +128,28 @@ export const aiproxyIdMap: Record<number, { label: string; provider: ModelProvid
|
||||
30: {
|
||||
label: 'Ollama',
|
||||
provider: 'Ollama'
|
||||
},
|
||||
23: {
|
||||
label: 'OneAPI',
|
||||
provider: 'Hunyuan'
|
||||
},
|
||||
44: {
|
||||
label: 'doubao audio',
|
||||
provider: 'Doubao'
|
||||
},
|
||||
33: {
|
||||
label: 'AWS',
|
||||
provider: 'Other',
|
||||
avatar: 'model/aws'
|
||||
},
|
||||
35: {
|
||||
label: 'Cohere',
|
||||
provider: 'Other',
|
||||
avatar: 'model/cohere'
|
||||
},
|
||||
37: {
|
||||
label: 'Cloudflare',
|
||||
provider: 'Other',
|
||||
avatar: 'model/cloudflare'
|
||||
}
|
||||
};
|
||||
|
||||
@ -79,7 +79,7 @@ const EditChannelModal = ({
|
||||
order: provider.order,
|
||||
defaultBaseUrl: value.defaultBaseUrl,
|
||||
keyHelp: value.keyHelp,
|
||||
icon: provider.avatar,
|
||||
icon: mapData?.avatar ?? provider.avatar,
|
||||
label: t(mapData.label as any),
|
||||
value: Number(key)
|
||||
};
|
||||
@ -90,6 +90,7 @@ const EditChannelModal = ({
|
||||
manual: false
|
||||
}
|
||||
);
|
||||
|
||||
const selectedProvider = useMemo(() => {
|
||||
const res = providerList.find((item) => item.value === providerType);
|
||||
return res;
|
||||
|
||||
@ -113,7 +113,7 @@ const DatasetImportContextProvider = ({ children }: { children: React.ReactNode
|
||||
],
|
||||
[ImportDataSourceEnum.fileLink]: [
|
||||
{
|
||||
title: t('dataset:import_select_file')
|
||||
title: t('dataset:import_select_link')
|
||||
},
|
||||
{
|
||||
title: t('dataset:import_param_setting')
|
||||
|
||||
@ -21,6 +21,7 @@ const DataProcess = dynamic(() => import('../commonProgress/DataProcess'), {
|
||||
loading: () => <Loading fixed={false} />
|
||||
});
|
||||
const Upload = dynamic(() => import('../commonProgress/Upload'));
|
||||
const PreviewData = dynamic(() => import('../commonProgress/PreviewData'));
|
||||
|
||||
const APIDatasetCollection = () => {
|
||||
const activeStep = useContextSelector(DatasetImportContext, (v) => v.activeStep);
|
||||
@ -29,7 +30,8 @@ const APIDatasetCollection = () => {
|
||||
<>
|
||||
{activeStep === 0 && <CustomAPIFileInput />}
|
||||
{activeStep === 1 && <DataProcess />}
|
||||
{activeStep === 2 && <Upload />}
|
||||
{activeStep === 2 && <PreviewData />}
|
||||
{activeStep === 3 && <Upload />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -27,6 +27,7 @@ const DataProcess = dynamic(() => import('../commonProgress/DataProcess'), {
|
||||
loading: () => <Loading fixed={false} />
|
||||
});
|
||||
const Upload = dynamic(() => import('../commonProgress/Upload'));
|
||||
const PreviewData = dynamic(() => import('../commonProgress/PreviewData'));
|
||||
|
||||
const ExternalFileCollection = () => {
|
||||
const activeStep = useContextSelector(DatasetImportContext, (v) => v.activeStep);
|
||||
@ -35,7 +36,8 @@ const ExternalFileCollection = () => {
|
||||
<>
|
||||
{activeStep === 0 && <CustomLinkInput />}
|
||||
{activeStep === 1 && <DataProcess />}
|
||||
{activeStep === 2 && <Upload />}
|
||||
{activeStep === 2 && <PreviewData />}
|
||||
{activeStep === 3 && <Upload />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -13,6 +13,7 @@ const DataProcess = dynamic(() => import('../commonProgress/DataProcess'), {
|
||||
loading: () => <Loading fixed={false} />
|
||||
});
|
||||
const Upload = dynamic(() => import('../commonProgress/Upload'));
|
||||
const PreviewData = dynamic(() => import('../commonProgress/PreviewData'));
|
||||
|
||||
const CustomTet = () => {
|
||||
const activeStep = useContextSelector(DatasetImportContext, (v) => v.activeStep);
|
||||
@ -20,7 +21,8 @@ const CustomTet = () => {
|
||||
<>
|
||||
{activeStep === 0 && <CustomTextInput />}
|
||||
{activeStep === 1 && <DataProcess />}
|
||||
{activeStep === 2 && <Upload />}
|
||||
{activeStep === 2 && <PreviewData />}
|
||||
{activeStep === 3 && <Upload />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -16,6 +16,7 @@ const DataProcess = dynamic(() => import('../commonProgress/DataProcess'), {
|
||||
loading: () => <Loading fixed={false} />
|
||||
});
|
||||
const Upload = dynamic(() => import('../commonProgress/Upload'));
|
||||
const PreviewData = dynamic(() => import('../commonProgress/PreviewData'));
|
||||
|
||||
const LinkCollection = () => {
|
||||
const activeStep = useContextSelector(DatasetImportContext, (v) => v.activeStep);
|
||||
@ -24,7 +25,8 @@ const LinkCollection = () => {
|
||||
<>
|
||||
{activeStep === 0 && <CustomLinkImport />}
|
||||
{activeStep === 1 && <DataProcess />}
|
||||
{activeStep === 2 && <Upload />}
|
||||
{activeStep === 2 && <PreviewData />}
|
||||
{activeStep === 3 && <Upload />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -57,7 +57,7 @@ const ReTraining = () => {
|
||||
qaChunkSize: collection.chunkSize,
|
||||
customSplitChar: collection.chunkSplitter,
|
||||
qaPrompt: collection.qaPrompt,
|
||||
webSelector: collection.metadata?.webSelector
|
||||
webSelector: collection.metadata?.webPageSelector
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,12 +1,6 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Box, Flex, Button, Textarea } from '@chakra-ui/react';
|
||||
import {
|
||||
FieldArrayWithId,
|
||||
UseFieldArrayRemove,
|
||||
UseFormRegister,
|
||||
useFieldArray,
|
||||
useForm
|
||||
} from 'react-hook-form';
|
||||
import { Box, Flex, Button, Textarea, ModalFooter, HStack, VStack } from '@chakra-ui/react';
|
||||
import { UseFormRegister, useFieldArray, useForm } from 'react-hook-form';
|
||||
import {
|
||||
postInsertData2Dataset,
|
||||
putDatasetDataById,
|
||||
@ -17,7 +11,6 @@ import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import { getSourceNameIcon } from '@fastgpt/global/core/dataset/utils';
|
||||
@ -28,25 +21,27 @@ import { getDocPath } from '@/web/common/system/doc';
|
||||
import MyBox from '@fastgpt/web/components/common/MyBox';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
|
||||
import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs';
|
||||
import styles from './styles.module.scss';
|
||||
import {
|
||||
DatasetDataIndexTypeEnum,
|
||||
getDatasetIndexMapData
|
||||
} from '@fastgpt/global/core/dataset/data/constants';
|
||||
import FillRowTabs from '@fastgpt/web/components/common/Tabs/FillRowTabs';
|
||||
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
|
||||
import MyIconButton from '@fastgpt/web/components/common/Icon/button';
|
||||
|
||||
export type InputDataType = {
|
||||
q: string;
|
||||
a: string;
|
||||
indexes: (Omit<DatasetDataIndexItemType, 'dataId'> & {
|
||||
dataId?: string; // pg data id
|
||||
fold: boolean;
|
||||
})[];
|
||||
};
|
||||
|
||||
enum TabEnum {
|
||||
content = 'content',
|
||||
index = 'index'
|
||||
chunk = 'chunk',
|
||||
qa = 'qa'
|
||||
}
|
||||
|
||||
const InputDataModal = ({
|
||||
@ -64,73 +59,47 @@ const InputDataModal = ({
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
const [currentTab, setCurrentTab] = useState(TabEnum.content);
|
||||
const { embeddingModelList, defaultModels } = useSystemStore();
|
||||
|
||||
const [currentTab, setCurrentTab] = useState(TabEnum.chunk);
|
||||
|
||||
const { register, handleSubmit, reset, control } = useForm<InputDataType>();
|
||||
const {
|
||||
fields: indexes,
|
||||
append: appendIndexes,
|
||||
remove: removeIndexes
|
||||
prepend: prependIndexes,
|
||||
remove: removeIndexes,
|
||||
update: updateIndexes
|
||||
} = useFieldArray({
|
||||
control,
|
||||
name: 'indexes'
|
||||
});
|
||||
|
||||
const tabList = [
|
||||
{
|
||||
label: (
|
||||
<Flex align={'center'}>
|
||||
<Box>{t('common:dataset.data.edit.divide_content')}</Box>
|
||||
</Flex>
|
||||
),
|
||||
value: TabEnum.content
|
||||
},
|
||||
{
|
||||
label: (
|
||||
<Flex align={'center'}>
|
||||
<Box>{t('common:dataset.data.edit.Index', { amount: indexes.length })}</Box>
|
||||
<MyTooltip label={t('common:core.app.tool_label.view_doc')}>
|
||||
<MyIcon
|
||||
name={'book'}
|
||||
w={'1rem'}
|
||||
mr={'0.38rem'}
|
||||
color={'myGray.500'}
|
||||
ml={1}
|
||||
onClick={() =>
|
||||
window.open(getDocPath('/docs/guide/knowledge_base/dataset_engine/'), '_blank')
|
||||
}
|
||||
_hover={{
|
||||
color: 'primary.600',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
),
|
||||
value: TabEnum.index
|
||||
}
|
||||
];
|
||||
|
||||
const { data: collection = defaultCollectionDetail } = useQuery(
|
||||
['loadCollectionId', collectionId],
|
||||
const { data: collection = defaultCollectionDetail } = useRequest2(
|
||||
() => {
|
||||
return getDatasetCollectionById(collectionId);
|
||||
},
|
||||
{
|
||||
manual: false,
|
||||
refreshDeps: [collectionId]
|
||||
}
|
||||
);
|
||||
const { isFetching: isFetchingData } = useQuery(
|
||||
['getDatasetDataItemById', dataId],
|
||||
() => {
|
||||
const { loading: isFetchingData } = useRequest2(
|
||||
async () => {
|
||||
if (dataId) return getDatasetDataItemById(dataId);
|
||||
return null;
|
||||
},
|
||||
{
|
||||
manual: false,
|
||||
refreshDeps: [dataId],
|
||||
onSuccess(res) {
|
||||
if (res) {
|
||||
reset({
|
||||
q: res.q,
|
||||
a: res.a,
|
||||
indexes: res.indexes
|
||||
indexes: res.indexes.map((item) => ({
|
||||
...item,
|
||||
fold: true
|
||||
}))
|
||||
});
|
||||
} else if (defaultValue) {
|
||||
reset({
|
||||
@ -138,6 +107,10 @@ const InputDataModal = ({
|
||||
a: defaultValue.a
|
||||
});
|
||||
}
|
||||
|
||||
if (res?.a || defaultValue?.a) {
|
||||
setCurrentTab(TabEnum.qa);
|
||||
}
|
||||
},
|
||||
onError(err) {
|
||||
toast({
|
||||
@ -161,7 +134,6 @@ const InputDataModal = ({
|
||||
const { runAsync: sureImportData, loading: isImporting } = useRequest2(
|
||||
async (e: InputDataType) => {
|
||||
if (!e.q) {
|
||||
setCurrentTab(TabEnum.content);
|
||||
return Promise.reject(t('common:dataset.data.input is empty'));
|
||||
}
|
||||
|
||||
@ -175,9 +147,9 @@ const InputDataModal = ({
|
||||
const dataId = await postInsertData2Dataset({
|
||||
collectionId: collection._id,
|
||||
q: e.q,
|
||||
a: e.a,
|
||||
a: currentTab === TabEnum.qa ? e.a : '',
|
||||
// Contains no default index
|
||||
indexes: e.indexes
|
||||
indexes: e.indexes.filter((item) => !!item.text?.trim())
|
||||
});
|
||||
|
||||
return {
|
||||
@ -186,6 +158,7 @@ const InputDataModal = ({
|
||||
};
|
||||
},
|
||||
{
|
||||
refreshDeps: [currentTab],
|
||||
successToast: t('common:dataset.data.Input Success Tip'),
|
||||
onSuccess(e) {
|
||||
reset({
|
||||
@ -208,8 +181,9 @@ const InputDataModal = ({
|
||||
// not exactly same
|
||||
await putDatasetDataById({
|
||||
dataId,
|
||||
...e,
|
||||
indexes: e.indexes
|
||||
q: e.q,
|
||||
a: currentTab === TabEnum.qa ? e.a : '',
|
||||
indexes: e.indexes.filter((item) => !!item.text?.trim())
|
||||
});
|
||||
|
||||
return {
|
||||
@ -218,6 +192,7 @@ const InputDataModal = ({
|
||||
};
|
||||
},
|
||||
{
|
||||
refreshDeps: [currentTab],
|
||||
successToast: t('common:dataset.data.Update Success Tip'),
|
||||
onSuccess(data) {
|
||||
onSuccess(data);
|
||||
@ -267,49 +242,166 @@ const InputDataModal = ({
|
||||
isLoading={isLoading}
|
||||
h={'100%'}
|
||||
py={[6, '1.5rem']}
|
||||
px={[5, '3.25rem']}
|
||||
>
|
||||
<Flex justify={'space-between'} gap={4} w={'100%'}>
|
||||
<Flex justify={'space-between'} pb={4}>
|
||||
<LightRowTabs<TabEnum>
|
||||
list={tabList}
|
||||
p={0}
|
||||
value={currentTab}
|
||||
onChange={(e: TabEnum) => setCurrentTab(e)}
|
||||
/>
|
||||
</Flex>
|
||||
{currentTab === TabEnum.index && (
|
||||
<Button
|
||||
variant={'whiteBase'}
|
||||
boxShadow={'1'}
|
||||
p={0}
|
||||
onClick={() =>
|
||||
appendIndexes({
|
||||
type: DatasetDataIndexTypeEnum.custom,
|
||||
text: ''
|
||||
})
|
||||
}
|
||||
>
|
||||
<Flex px={'0.62rem'} py={2}>
|
||||
<MyIcon name={'common/addLight'} w={'1rem'} mr={'0.38rem'} />
|
||||
{t('common:add_new')}
|
||||
</Flex>
|
||||
</Button>
|
||||
)}
|
||||
</Flex>
|
||||
<Box w={'100%'} flexGrow={1} overflow={'scroll'}>
|
||||
{currentTab === TabEnum.content && <InputTab maxToken={maxToken} register={register} />}
|
||||
{currentTab === TabEnum.index && (
|
||||
<DataIndex
|
||||
register={register}
|
||||
maxToken={maxToken}
|
||||
removeIndexes={removeIndexes}
|
||||
indexes={indexes}
|
||||
/>
|
||||
)}
|
||||
{/* Tab */}
|
||||
<Box px={[5, '3.25rem']}>
|
||||
<FillRowTabs
|
||||
list={[
|
||||
{ label: t('common:dataset_data_input_chunk'), value: TabEnum.chunk },
|
||||
{ label: t('common:dataset_data_input_qa'), value: TabEnum.qa }
|
||||
]}
|
||||
py={1}
|
||||
value={currentTab}
|
||||
onChange={(e) => {
|
||||
setCurrentTab(e);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Flex justifyContent={'flex-end'} pt={8} pb={[8, 0]} h={[24, 16]}>
|
||||
<Flex
|
||||
pt={4}
|
||||
flex={'1 0 0'}
|
||||
gap={6}
|
||||
flexDir={['column', 'row']}
|
||||
overflow={'auto'}
|
||||
px={[5, '3.25rem']}
|
||||
>
|
||||
{/* Data */}
|
||||
<Flex flexDir={'column'} h={'100%'} gap={3} flex={'1 0 0'}>
|
||||
<Flex flexDir={'column'} h={'100%'}>
|
||||
<FormLabel required mb={1} h={'30px'}>
|
||||
{currentTab === TabEnum.chunk
|
||||
? t('common:dataset_data_input_chunk_content')
|
||||
: t('common:dataset_data_input_q')}
|
||||
</FormLabel>
|
||||
<Textarea
|
||||
resize={'none'}
|
||||
placeholder={t('common:dataset_data_import_q_placeholder', { maxToken })}
|
||||
className={styles.scrollbar}
|
||||
maxLength={maxToken}
|
||||
flex={'1 0 0'}
|
||||
tabIndex={1}
|
||||
_focus={{
|
||||
borderColor: 'primary.500',
|
||||
boxShadow: '0px 0px 0px 2.4px rgba(51, 112, 255, 0.15)',
|
||||
bg: 'white'
|
||||
}}
|
||||
bg={'myGray.25'}
|
||||
borderRadius={'md'}
|
||||
borderColor={'myGray.200'}
|
||||
{...register(`q`, {
|
||||
required: true
|
||||
})}
|
||||
/>
|
||||
</Flex>
|
||||
{currentTab === TabEnum.qa && (
|
||||
<Flex flexDir={'column'} h={'100%'}>
|
||||
<FormLabel required mb={1}>
|
||||
{t('common:dataset_data_input_a')}
|
||||
</FormLabel>
|
||||
<Textarea
|
||||
resize={'none'}
|
||||
placeholder={t('common:dataset_data_import_q_placeholder', { maxToken })}
|
||||
className={styles.scrollbar}
|
||||
flex={'1 0 0'}
|
||||
tabIndex={1}
|
||||
bg={'myGray.25'}
|
||||
maxLength={maxToken}
|
||||
borderRadius={'md'}
|
||||
border={'1.5px solid '}
|
||||
borderColor={'myGray.200'}
|
||||
{...register('a', { required: true })}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
{/* Index */}
|
||||
<Box flex={'1 0 0'}>
|
||||
<Flex alignItems={'flex-start'} justifyContent={'space-between'} h={'30px'}>
|
||||
<FormLabel>
|
||||
{t('common:dataset.data.edit.Index', {
|
||||
amount: indexes.length
|
||||
})}
|
||||
</FormLabel>
|
||||
<Button
|
||||
variant={'whiteBase'}
|
||||
size={'sm'}
|
||||
p={0}
|
||||
transform={'translateY(-6px)'}
|
||||
onClick={() =>
|
||||
prependIndexes({
|
||||
type: DatasetDataIndexTypeEnum.custom,
|
||||
text: '',
|
||||
fold: false
|
||||
})
|
||||
}
|
||||
>
|
||||
<Flex px={'0.62rem'} py={2}>
|
||||
<MyIcon name={'common/addLight'} w={'1rem'} mr={'0.38rem'} />
|
||||
{t('common:add_new')}
|
||||
</Flex>
|
||||
</Button>
|
||||
</Flex>
|
||||
|
||||
<VStack>
|
||||
{indexes?.map((index, i) => {
|
||||
const data = getDatasetIndexMapData(index.type);
|
||||
return (
|
||||
<Box
|
||||
key={index.dataId || i}
|
||||
p={4}
|
||||
borderRadius={'md'}
|
||||
border={'base'}
|
||||
bg={'myGray.25'}
|
||||
w={'100%'}
|
||||
_hover={{
|
||||
'& .delete': {
|
||||
display: 'block'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{/* Header */}
|
||||
<Flex mb={2} alignItems={'center'}>
|
||||
<FormLabel flex={'1 0 0'}>{t(data.label)}</FormLabel>
|
||||
{/* Delete */}
|
||||
{index.type !== 'default' && (
|
||||
<HStack className={'delete'} borderRight={'base'} pr={3} mr={2}>
|
||||
<DeleteIcon
|
||||
onClick={() => {
|
||||
removeIndexes(i);
|
||||
}}
|
||||
/>
|
||||
</HStack>
|
||||
)}
|
||||
{indexes.length > 1 && (
|
||||
<MyIconButton
|
||||
icon={index.fold ? 'core/chat/chevronDown' : 'core/chat/chevronUp'}
|
||||
onClick={() => {
|
||||
updateIndexes(i, { ...index, fold: !index.fold });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
{/* Content */}
|
||||
<DataIndexTextArea
|
||||
disabled={index.type === 'default'}
|
||||
index={i}
|
||||
value={index.text}
|
||||
isFolder={index.fold && indexes.length > 1}
|
||||
maxToken={maxToken}
|
||||
register={register}
|
||||
onFocus={() => {
|
||||
updateIndexes(i, { ...index, fold: false });
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</VStack>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
<ModalFooter px={[5, '3.25rem']} py={0} pt={4}>
|
||||
<MyTooltip
|
||||
label={collection.permission.hasWritePer ? '' : t('common:dataset.data.Can not edit')}
|
||||
>
|
||||
@ -322,7 +414,7 @@ const InputDataModal = ({
|
||||
{dataId ? t('common:common.Confirm Update') : t('common:common.Confirm Import')}
|
||||
</Button>
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
</ModalFooter>
|
||||
</MyBox>
|
||||
</MyModal>
|
||||
);
|
||||
@ -330,153 +422,23 @@ const InputDataModal = ({
|
||||
|
||||
export default React.memo(InputDataModal);
|
||||
|
||||
const InputTab = ({
|
||||
maxToken,
|
||||
register
|
||||
}: {
|
||||
maxToken: number;
|
||||
register: UseFormRegister<InputDataType>;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex h={'100%'} gap={6} flexDir={['column', 'row']} w={'100%'}>
|
||||
<Flex flexDir={'column'} flex={1}>
|
||||
<Flex mb={2} fontWeight={'medium'} fontSize={'sm'} alignItems={'center'} h={8}>
|
||||
<Box color={'red.600'}>*</Box>
|
||||
<Box color={'myGray.900'}>{t('common:core.dataset.data.Main Content')}</Box>
|
||||
<QuestionTip label={t('common:core.dataset.data.Data Content Tip')} ml={1} />
|
||||
</Flex>
|
||||
<Box
|
||||
borderRadius={'md'}
|
||||
border={'1.5px solid var(--Gray-Modern-200, #E8EBF0)'}
|
||||
bg={'myGray.25'}
|
||||
flex={1}
|
||||
>
|
||||
<Textarea
|
||||
resize={'none'}
|
||||
placeholder={t('core.dataset.data.Data Content Placeholder', { maxToken })}
|
||||
className={styles.scrollbar}
|
||||
maxLength={maxToken}
|
||||
h={'100%'}
|
||||
tabIndex={1}
|
||||
_focus={{
|
||||
borderColor: 'primary.500',
|
||||
boxShadow: '0px 0px 0px 2.4px rgba(51, 112, 255, 0.15)',
|
||||
bg: 'white'
|
||||
}}
|
||||
borderColor={'transparent'}
|
||||
bg={'myGray.25'}
|
||||
{...register(`q`, {
|
||||
required: true
|
||||
})}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex flex={1} flexDir={'column'}>
|
||||
<Flex mb={2} fontWeight={'medium'} fontSize={'sm'} alignItems={'center'} h={8}>
|
||||
<Box color={'myGray.900'}>{t('common:core.dataset.data.Auxiliary Data')}</Box>
|
||||
<QuestionTip label={t('common:core.dataset.data.Auxiliary Data Tip')} ml={1} />
|
||||
</Flex>
|
||||
<Box
|
||||
borderRadius={'md'}
|
||||
border={'1.5px solid '}
|
||||
borderColor={'myGray.200'}
|
||||
bg={'myGray.25'}
|
||||
flex={1}
|
||||
>
|
||||
<Textarea
|
||||
resize={'none'}
|
||||
placeholder={t('core.dataset.data.Auxiliary Data Placeholder', {
|
||||
maxToken: maxToken * 1.5
|
||||
})}
|
||||
className={styles.scrollbar}
|
||||
borderColor={'transparent'}
|
||||
h={'100%'}
|
||||
tabIndex={1}
|
||||
bg={'myGray.25'}
|
||||
maxLength={maxToken * 1.5}
|
||||
{...register('a')}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const DataIndex = ({
|
||||
maxToken,
|
||||
register,
|
||||
indexes,
|
||||
removeIndexes
|
||||
}: {
|
||||
maxToken: number;
|
||||
register: UseFormRegister<InputDataType>;
|
||||
indexes: FieldArrayWithId<InputDataType, 'indexes', 'id'>[];
|
||||
removeIndexes: UseFieldArrayRemove;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex mt={3} gap={3} flexDir={'column'}>
|
||||
{indexes?.map((index, i) => {
|
||||
const data = getDatasetIndexMapData(index.type);
|
||||
return (
|
||||
<Box
|
||||
key={index.dataId || i}
|
||||
p={4}
|
||||
borderRadius={'md'}
|
||||
border={'1.5px solid var(--Gray-Modern-200, #E8EBF0)'}
|
||||
bg={'myGray.25'}
|
||||
_hover={{
|
||||
'& .delete': {
|
||||
display: 'block'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Flex mb={2}>
|
||||
<Box flex={1} fontWeight={'medium'} fontSize={'sm'} color={'myGray.900'}>
|
||||
{t(data.label)}
|
||||
</Box>
|
||||
{index.type !== 'default' && (
|
||||
<DeleteIcon
|
||||
onClick={() => {
|
||||
removeIndexes(i);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
<DataIndexTextArea
|
||||
disabled={index.type === 'default'}
|
||||
index={i}
|
||||
value={index.text}
|
||||
maxToken={maxToken}
|
||||
register={register}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</Flex>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const textareaMinH = '40px';
|
||||
const DataIndexTextArea = ({
|
||||
value,
|
||||
index,
|
||||
maxToken,
|
||||
register,
|
||||
disabled
|
||||
disabled,
|
||||
isFolder,
|
||||
onFocus
|
||||
}: {
|
||||
value: string;
|
||||
index: number;
|
||||
maxToken: number;
|
||||
register: UseFormRegister<InputDataType>;
|
||||
disabled?: boolean;
|
||||
isFolder: boolean;
|
||||
onFocus: () => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const TextareaDom = useRef<HTMLTextAreaElement | null>(null);
|
||||
@ -501,41 +463,76 @@ const DataIndexTextArea = ({
|
||||
}
|
||||
}, []);
|
||||
|
||||
return disabled ? (
|
||||
<Box fontSize={'sm'} color={'myGray.500'} whiteSpace={'pre-wrap'}>
|
||||
{value}
|
||||
const onclickMark = () => {
|
||||
TextareaDom?.current?.focus();
|
||||
onFocus();
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
pos={'relative'}
|
||||
{...(isFolder
|
||||
? {
|
||||
maxH: '50px',
|
||||
overflow: 'hidden'
|
||||
}
|
||||
: {
|
||||
maxH: 'auto'
|
||||
})}
|
||||
>
|
||||
{disabled ? (
|
||||
<Box fontSize={'sm'} color={'myGray.500'} whiteSpace={'pre-wrap'}>
|
||||
{value}
|
||||
</Box>
|
||||
) : (
|
||||
<Textarea
|
||||
maxLength={maxToken}
|
||||
borderColor={'transparent'}
|
||||
className={styles.scrollbar}
|
||||
minH={textareaMinH}
|
||||
px={0}
|
||||
pt={0}
|
||||
isRequired={required}
|
||||
whiteSpace={'pre-wrap'}
|
||||
resize={'none'}
|
||||
_focus={{
|
||||
px: 3,
|
||||
py: 1,
|
||||
borderColor: 'primary.500',
|
||||
boxShadow: '0px 0px 0px 2.4px rgba(51, 112, 255, 0.15)',
|
||||
bg: 'white'
|
||||
}}
|
||||
placeholder={t('common:dataset.data.Index Placeholder')}
|
||||
ref={(e) => {
|
||||
if (e) TextareaDom.current = e;
|
||||
TextareaRef(e);
|
||||
}}
|
||||
required
|
||||
name={name}
|
||||
onChange={(e) => {
|
||||
autoHeight(e);
|
||||
onTextChange(e);
|
||||
}}
|
||||
onFocus={autoHeight}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
)}
|
||||
{isFolder && (
|
||||
<Box
|
||||
pos={'absolute'}
|
||||
bottom={0}
|
||||
left={0}
|
||||
right={0}
|
||||
top={0}
|
||||
bg={'linear-gradient(182deg, rgba(251, 251, 252, 0.00) 1.76%, #FBFBFC 84.07%)'}
|
||||
{...(disabled
|
||||
? {}
|
||||
: {
|
||||
cursor: 'pointer',
|
||||
onClick: onclickMark
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
) : (
|
||||
<Textarea
|
||||
maxLength={maxToken}
|
||||
borderColor={'transparent'}
|
||||
className={styles.scrollbar}
|
||||
minH={textareaMinH}
|
||||
px={0}
|
||||
pt={0}
|
||||
isRequired={required}
|
||||
whiteSpace={'pre-wrap'}
|
||||
resize={'none'}
|
||||
_focus={{
|
||||
px: 3,
|
||||
py: 1,
|
||||
borderColor: 'primary.500',
|
||||
boxShadow: '0px 0px 0px 2.4px rgba(51, 112, 255, 0.15)',
|
||||
bg: 'white'
|
||||
}}
|
||||
placeholder={t('common:dataset.data.Index Placeholder')}
|
||||
ref={(e) => {
|
||||
if (e) TextareaDom.current = e;
|
||||
TextareaRef(e);
|
||||
}}
|
||||
required
|
||||
name={name}
|
||||
onChange={(e) => {
|
||||
autoHeight(e);
|
||||
onTextChange(e);
|
||||
}}
|
||||
onFocus={autoHeight}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -199,8 +199,6 @@ const UsageTable = () => {
|
||||
[
|
||||
t,
|
||||
dateRange,
|
||||
usageTab,
|
||||
unit,
|
||||
userInfo?.team?.permission.hasManagePer,
|
||||
tmbList,
|
||||
selectTmbIds,
|
||||
|
||||
@ -18,7 +18,7 @@ import { isProduction } from '@fastgpt/global/common/system/constants';
|
||||
import * as fs from 'fs';
|
||||
import { llmCompletionsBodyFormat } from '@fastgpt/service/core/ai/utils';
|
||||
|
||||
export type testQuery = { model: string };
|
||||
export type testQuery = { model: string; channelId?: string };
|
||||
|
||||
export type testBody = {};
|
||||
|
||||
@ -30,7 +30,7 @@ async function handler(
|
||||
): Promise<testResponse> {
|
||||
await authSystemAdmin({ req });
|
||||
|
||||
const { model } = req.query;
|
||||
const { model, channelId } = req.query;
|
||||
const modelData = findModelFromAlldata(model);
|
||||
|
||||
if (!modelData) return Promise.reject('Model not found');
|
||||
@ -65,8 +65,7 @@ const testLLMModel = async (model: LLMModelItemType) => {
|
||||
{
|
||||
model: model.model,
|
||||
messages: [{ role: 'user', content: 'hi' }],
|
||||
stream: false,
|
||||
max_tokens: 10
|
||||
stream: false
|
||||
},
|
||||
model
|
||||
);
|
||||
|
||||
@ -13,10 +13,18 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
Promise.reject(CommonErrEnum.missingParams);
|
||||
}
|
||||
// 凭证校验
|
||||
const { app } = await authApp({ req, authToken: true, appId, per: ReadPermissionVal });
|
||||
const teamId = app.teamId;
|
||||
const { app, teamId, isRoot } = await authApp({
|
||||
req,
|
||||
authToken: true,
|
||||
appId,
|
||||
per: ReadPermissionVal
|
||||
});
|
||||
|
||||
await rewriteAppWorkflowToDetail(app.modules, teamId);
|
||||
await rewriteAppWorkflowToDetail({
|
||||
nodes: app.modules,
|
||||
teamId,
|
||||
isRoot
|
||||
});
|
||||
|
||||
if (!app.permission.hasWritePer) {
|
||||
return {
|
||||
|
||||
@ -6,6 +6,7 @@ import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'
|
||||
import { AppVersionSchemaType } from '@fastgpt/global/core/app/version';
|
||||
import { formatTime2YMDHM } from '@fastgpt/global/common/string/time';
|
||||
import { checkNode } from '@/service/core/app/utils';
|
||||
import { rewriteAppWorkflowToDetail } from '@fastgpt/service/core/app/utils';
|
||||
|
||||
type Props = {
|
||||
versionId: string;
|
||||
@ -18,13 +19,24 @@ async function handler(
|
||||
): Promise<AppVersionSchemaType> {
|
||||
const { versionId, appId } = req.query as Props;
|
||||
|
||||
const { app } = await authApp({ req, authToken: true, appId, per: WritePermissionVal });
|
||||
const { app, teamId, isRoot } = await authApp({
|
||||
req,
|
||||
authToken: true,
|
||||
appId,
|
||||
per: WritePermissionVal
|
||||
});
|
||||
const result = await MongoAppVersion.findById(versionId).lean();
|
||||
|
||||
if (!result) {
|
||||
return Promise.reject('version not found');
|
||||
}
|
||||
|
||||
await rewriteAppWorkflowToDetail({
|
||||
nodes: result.nodes,
|
||||
teamId,
|
||||
isRoot
|
||||
});
|
||||
|
||||
return {
|
||||
...result,
|
||||
nodes: await Promise.all(
|
||||
|
||||
@ -24,16 +24,18 @@ async function handler(
|
||||
req: ApiRequestProps<getLatestVersionBody, getLatestVersionQuery>,
|
||||
res: ApiResponseType<any>
|
||||
): Promise<getLatestVersionResponse> {
|
||||
const { app } = await authApp({
|
||||
const { app, isRoot, teamId } = await authApp({
|
||||
req,
|
||||
authToken: true,
|
||||
appId: req.query.appId,
|
||||
per: WritePermissionVal
|
||||
});
|
||||
|
||||
const teamId = app.teamId;
|
||||
|
||||
await rewriteAppWorkflowToDetail(app.modules, teamId);
|
||||
await rewriteAppWorkflowToDetail({
|
||||
nodes: app.modules,
|
||||
teamId,
|
||||
isRoot
|
||||
});
|
||||
|
||||
return getAppLatestVersion(req.query.appId, app);
|
||||
}
|
||||
|
||||