Fix share page whisper auth (#1161)
Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
This commit is contained in:
parent
adfad8ff7f
commit
2991c07467
@ -20,7 +20,7 @@ llm模型全部合并
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"feConfigs": {
|
"feConfigs": {
|
||||||
"lafEnv": "https://laf.dev" // laf环境
|
"lafEnv": "https://laf.dev" // laf环境。 https://laf.run (杭州阿里云) ,或者私有化的laf环境。如果使用 Laf openapi 功能,需要最新版的 laf 。
|
||||||
},
|
},
|
||||||
"systemEnv": {
|
"systemEnv": {
|
||||||
"vectorMaxProcess": 15,
|
"vectorMaxProcess": 15,
|
||||||
|
|||||||
@ -100,7 +100,7 @@ docker run -d --name reranker -p 6006:6006 -e ACCESS_TOKEN=mytoken --gpus all re
|
|||||||
version: "3"
|
version: "3"
|
||||||
services:
|
services:
|
||||||
reranker:
|
reranker:
|
||||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/rerank:v0.2
|
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/bge-rerank-base:v0.1
|
||||||
container_name: reranker
|
container_name: reranker
|
||||||
# GPU运行环境,如果宿主机未安装,将deploy配置隐藏即可
|
# GPU运行环境,如果宿主机未安装,将deploy配置隐藏即可
|
||||||
deploy:
|
deploy:
|
||||||
|
|||||||
@ -19,10 +19,16 @@ curl --location --request POST 'https://{{host}}/api/admin/clearInvalidData' \
|
|||||||
|
|
||||||
该请求会执行脏数据清理(清理无效的文件、清理无效的图片、清理无效的知识库集合、清理无效的向量)
|
该请求会执行脏数据清理(清理无效的文件、清理无效的图片、清理无效的知识库集合、清理无效的向量)
|
||||||
|
|
||||||
|
|
||||||
|
## 修改配置文件
|
||||||
|
|
||||||
|
增加了Laf环境配置:[点击查看最新的配置文件](/docs/development/configuration/)
|
||||||
|
|
||||||
|
|
||||||
## V4.7.1 更新说明
|
## V4.7.1 更新说明
|
||||||
|
|
||||||
1. 新增 - 语音输入完整配置。支持选择是否打开语音输入(包括分享页面),支持语音输入后自动发送,支持语音输入后自动语音播放(流式)。
|
1. 新增 - 语音输入完整配置。支持选择是否打开语音输入(包括分享页面),支持语音输入后自动发送,支持语音输入后自动语音播放(流式)。
|
||||||
2. 新增 - Pptx 和 xlsx 文件读取。但所有文件读取都放服务端,会消耗更多的服务器资源,以及无法在上传时预览更多内容。
|
2. 新增 - pptx 和 xlsx 文件读取。但所有文件读取都放服务端,会消耗更多的服务器资源,以及无法在上传时预览更多内容。
|
||||||
3. 新增 - 集成 Laf 云函数,可以读取 Laf 账号中的云函数作为 HTTP 模块。
|
3. 新增 - 集成 Laf 云函数,可以读取 Laf 账号中的云函数作为 HTTP 模块。
|
||||||
4. 新增 - 定时器,清理垃圾数据。(采用小范围清理,会清理最近n个小时的,所以请保证服务持续运行,长时间不允许,可以继续执行 clearInvalidData 的接口进行全量清理。)
|
4. 新增 - 定时器,清理垃圾数据。(采用小范围清理,会清理最近n个小时的,所以请保证服务持续运行,长时间不允许,可以继续执行 clearInvalidData 的接口进行全量清理。)
|
||||||
5. 商业版新增 - 后台配置系统通知。
|
5. 商业版新增 - 后台配置系统通知。
|
||||||
|
|||||||
@ -88,7 +88,7 @@ Response:
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"moduleId": "userGuide",
|
"moduleId": "userGuide",
|
||||||
"name": "core.module.template.User guide",
|
"name": "core.module.template.App system setting",
|
||||||
"flowType": "userGuide",
|
"flowType": "userGuide",
|
||||||
"position": {
|
"position": {
|
||||||
"x": 454.98510354678695,
|
"x": 454.98510354678695,
|
||||||
|
|||||||
@ -27,7 +27,7 @@ weight: 404
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"moduleId": "userGuide",
|
"moduleId": "userGuide",
|
||||||
"name": "core.module.template.User guide",
|
"name": "core.module.template.App system setting",
|
||||||
"intro": "core.app.tip.userGuideTip",
|
"intro": "core.app.tip.userGuideTip",
|
||||||
"avatar": "/imgs/module/userGuide.png",
|
"avatar": "/imgs/module/userGuide.png",
|
||||||
"flowType": "userGuide",
|
"flowType": "userGuide",
|
||||||
|
|||||||
@ -84,7 +84,7 @@ export default async function (ctx: FunctionContext) {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"moduleId": "userGuide",
|
"moduleId": "userGuide",
|
||||||
"name": "core.module.template.User guide",
|
"name": "core.module.template.App system setting",
|
||||||
"intro": "core.app.tip.userGuideTip",
|
"intro": "core.app.tip.userGuideTip",
|
||||||
"avatar": "/imgs/module/userGuide.png",
|
"avatar": "/imgs/module/userGuide.png",
|
||||||
"flowType": "userGuide",
|
"flowType": "userGuide",
|
||||||
|
|||||||
@ -27,8 +27,6 @@ Laf 提供了 PAT(访问凭证) 来实现 Laf 平台外的快捷登录,可以
|
|||||||
|
|
||||||
填入 PAT 验证后,选择需要绑定的应用(应用需要是 Running 状态),即可调用该应用下的云函数。
|
填入 PAT 验证后,选择需要绑定的应用(应用需要是 Running 状态),即可调用该应用下的云函数。
|
||||||
|
|
||||||
> 如果需要解绑则取消绑定后,点击“更新”即可
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 编写云函数
|
## 编写云函数
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { getErrText } from '../error/utils';
|
import { getErrText } from '../error/utils';
|
||||||
import { countPromptTokens } from './tiktoken';
|
import { replaceRegChars } from './tools';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* text split into chunks
|
* text split into chunks
|
||||||
@ -31,7 +31,7 @@ export const splitText2Chunks = (props: {
|
|||||||
// The larger maxLen is, the next sentence is less likely to trigger splitting
|
// The larger maxLen is, the next sentence is less likely to trigger splitting
|
||||||
const stepReges: { reg: RegExp; maxLen: number }[] = [
|
const stepReges: { reg: RegExp; maxLen: number }[] = [
|
||||||
...customReg.map((text) => ({
|
...customReg.map((text) => ({
|
||||||
reg: new RegExp(`(${text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'g'),
|
reg: new RegExp(`(${replaceRegChars(text)})`, 'g'),
|
||||||
maxLen: chunkLen * 1.4
|
maxLen: chunkLen * 1.4
|
||||||
})),
|
})),
|
||||||
{ reg: /^(#\s[^\n]+)\n/gm, maxLen: chunkLen * 1.2 },
|
{ reg: /^(#\s[^\n]+)\n/gm, maxLen: chunkLen * 1.2 },
|
||||||
|
|||||||
@ -51,3 +51,5 @@ export const replaceSensitiveText = (text: string) => {
|
|||||||
export const getNanoid = (size = 12) => {
|
export const getNanoid = (size = 12) => {
|
||||||
return customAlphabet('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890', size)();
|
return customAlphabet('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890', size)();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const replaceRegChars = (text: string) => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../node/constant';
|
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../node/constant';
|
||||||
import { FlowNodeTemplateType } from '../../type.d';
|
import { FlowNodeTemplateType } from '../../type.d';
|
||||||
import { userGuideTip } from '../tip';
|
|
||||||
import {
|
import {
|
||||||
ModuleIOValueTypeEnum,
|
ModuleIOValueTypeEnum,
|
||||||
ModuleInputKeyEnum,
|
ModuleInputKeyEnum,
|
||||||
@ -12,8 +11,8 @@ export const UserGuideModule: FlowNodeTemplateType = {
|
|||||||
templateType: FlowNodeTemplateTypeEnum.userGuide,
|
templateType: FlowNodeTemplateTypeEnum.userGuide,
|
||||||
flowType: FlowNodeTypeEnum.userGuide,
|
flowType: FlowNodeTypeEnum.userGuide,
|
||||||
avatar: '/imgs/module/userGuide.png',
|
avatar: '/imgs/module/userGuide.png',
|
||||||
name: '全局配置',
|
name: '系统配置',
|
||||||
intro: userGuideTip,
|
intro: '可以配置应用的系统参数。',
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
key: ModuleInputKeyEnum.welcomeText,
|
key: ModuleInputKeyEnum.welcomeText,
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
export const chatNodeSystemPromptTip = 'core.app.tip.chatNodeSystemPromptTip';
|
export const chatNodeSystemPromptTip = 'core.app.tip.chatNodeSystemPromptTip';
|
||||||
export const userGuideTip = 'core.app.tip.userGuideTip';
|
|
||||||
export const welcomeTextTip = 'core.app.tip.welcomeTextTip';
|
export const welcomeTextTip = 'core.app.tip.welcomeTextTip';
|
||||||
export const variableTip = 'core.app.tip.variableTip';
|
export const variableTip = 'core.app.tip.variableTip';
|
||||||
|
|||||||
1
packages/global/support/user/team/type.d.ts
vendored
1
packages/global/support/user/team/type.d.ts
vendored
@ -81,4 +81,5 @@ export type TeamTagItemType = {
|
|||||||
export type LafAccountType = {
|
export type LafAccountType = {
|
||||||
token: string;
|
token: string;
|
||||||
appid: string;
|
appid: string;
|
||||||
|
pat: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -18,6 +18,7 @@ export type BillSchemaType = {
|
|||||||
month?: number;
|
month?: number;
|
||||||
datasetSize?: number;
|
datasetSize?: number;
|
||||||
extraPoints?: number;
|
extraPoints?: number;
|
||||||
|
invoice: boolean;
|
||||||
};
|
};
|
||||||
username: string;
|
username: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -35,6 +35,7 @@ try {
|
|||||||
ImageSchema.index({ expiredTime: 1 }, { expireAfterSeconds: 60 });
|
ImageSchema.index({ expiredTime: 1 }, { expireAfterSeconds: 60 });
|
||||||
ImageSchema.index({ type: 1 });
|
ImageSchema.index({ type: 1 });
|
||||||
ImageSchema.index({ createTime: 1 });
|
ImageSchema.index({ createTime: 1 });
|
||||||
|
// delete related img
|
||||||
ImageSchema.index({ teamId: 1, 'metadata.relatedId': 1 });
|
ImageSchema.index({ teamId: 1, 'metadata.relatedId': 1 });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
export type DeleteDatasetVectorProps = {
|
export type DeleteDatasetVectorProps = (
|
||||||
|
| { id: string }
|
||||||
|
| { datasetIds: string[]; collectionIds?: string[] }
|
||||||
|
| { idList: string[] }
|
||||||
|
) & {
|
||||||
teamId: string;
|
teamId: string;
|
||||||
|
|
||||||
id?: string;
|
|
||||||
datasetIds?: string[];
|
|
||||||
collectionIds?: string[];
|
|
||||||
idList?: string[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type InsertVectorProps = {
|
export type InsertVectorProps = {
|
||||||
|
|||||||
@ -26,13 +26,7 @@ export async function initPg() {
|
|||||||
`CREATE INDEX CONCURRENTLY IF NOT EXISTS vector_index ON ${PgDatasetTableName} USING hnsw (vector vector_ip_ops) WITH (m = 32, ef_construction = 64);`
|
`CREATE INDEX CONCURRENTLY IF NOT EXISTS vector_index ON ${PgDatasetTableName} USING hnsw (vector vector_ip_ops) WITH (m = 32, ef_construction = 64);`
|
||||||
);
|
);
|
||||||
await PgClient.query(
|
await PgClient.query(
|
||||||
`CREATE INDEX CONCURRENTLY IF NOT EXISTS team_dataset_index ON ${PgDatasetTableName} USING btree(team_id, dataset_id);`
|
`CREATE INDEX CONCURRENTLY IF NOT EXISTS team_dataset_collection_index ON ${PgDatasetTableName} USING btree(team_id, dataset_id, collection_id);`
|
||||||
);
|
|
||||||
await PgClient.query(
|
|
||||||
` CREATE INDEX CONCURRENTLY IF NOT EXISTS team_collection_index ON ${PgDatasetTableName} USING btree(team_id, collection_id);`
|
|
||||||
);
|
|
||||||
await PgClient.query(
|
|
||||||
`CREATE INDEX CONCURRENTLY IF NOT EXISTS team_id_index ON ${PgDatasetTableName} USING btree(team_id, id);`
|
|
||||||
);
|
);
|
||||||
await PgClient.query(
|
await PgClient.query(
|
||||||
`CREATE INDEX CONCURRENTLY IF NOT EXISTS create_time_index ON ${PgDatasetTableName} USING btree(createtime);`
|
`CREATE INDEX CONCURRENTLY IF NOT EXISTS create_time_index ON ${PgDatasetTableName} USING btree(createtime);`
|
||||||
@ -83,31 +77,33 @@ export const deleteDatasetDataVector = async (
|
|||||||
retry?: number;
|
retry?: number;
|
||||||
}
|
}
|
||||||
): Promise<any> => {
|
): Promise<any> => {
|
||||||
const { teamId, id, datasetIds, collectionIds, idList, retry = 2 } = props;
|
const { teamId, retry = 2 } = props;
|
||||||
|
|
||||||
const teamIdWhere = `team_id='${String(teamId)}' AND`;
|
const teamIdWhere = `team_id='${String(teamId)}' AND`;
|
||||||
|
|
||||||
const where = await (() => {
|
const where = await (() => {
|
||||||
if (id) return `${teamIdWhere} id=${id}`;
|
if ('id' in props && props.id) return `${teamIdWhere} id=${props.id}`;
|
||||||
|
|
||||||
if (datasetIds) {
|
if ('datasetIds' in props && props.datasetIds) {
|
||||||
return `${teamIdWhere} dataset_id IN (${datasetIds
|
const datasetIdWhere = `dataset_id IN (${props.datasetIds
|
||||||
|
.map((id) => `'${String(id)}'`)
|
||||||
|
.join(',')})`;
|
||||||
|
|
||||||
|
if ('collectionIds' in props && props.collectionIds) {
|
||||||
|
return `${teamIdWhere} ${datasetIdWhere} AND collection_id IN (${props.collectionIds
|
||||||
.map((id) => `'${String(id)}'`)
|
.map((id) => `'${String(id)}'`)
|
||||||
.join(',')})`;
|
.join(',')})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collectionIds) {
|
return `${teamIdWhere} ${datasetIdWhere}`;
|
||||||
return `${teamIdWhere} collection_id IN (${collectionIds
|
|
||||||
.map((id) => `'${String(id)}'`)
|
|
||||||
.join(',')})`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idList) {
|
if ('idList' in props && props.idList) {
|
||||||
return `${teamIdWhere} id IN (${idList.map((id) => `'${String(id)}'`).join(',')})`;
|
return `${teamIdWhere} id IN (${props.idList.map((id) => `'${String(id)}'`).join(',')})`;
|
||||||
}
|
}
|
||||||
return Promise.reject('deleteDatasetData: no where');
|
return Promise.reject('deleteDatasetData: no where');
|
||||||
})();
|
})();
|
||||||
|
console.log(where, '===');
|
||||||
try {
|
try {
|
||||||
await PgClient.delete(PgDatasetTableName, {
|
await PgClient.delete(PgDatasetTableName, {
|
||||||
where: [where]
|
where: [where]
|
||||||
|
|||||||
@ -118,6 +118,37 @@ export function createDefaultCollection({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* delete collection related images/files */
|
||||||
|
export const delCollectionRelatedSource = async ({
|
||||||
|
collections,
|
||||||
|
session
|
||||||
|
}: {
|
||||||
|
collections: (CollectionWithDatasetType | DatasetCollectionSchemaType)[];
|
||||||
|
session: ClientSession;
|
||||||
|
}) => {
|
||||||
|
if (collections.length === 0) return;
|
||||||
|
|
||||||
|
const teamId = collections[0].teamId;
|
||||||
|
|
||||||
|
if (!teamId) return Promise.reject('teamId is not exist');
|
||||||
|
|
||||||
|
const fileIdList = collections.map((item) => item?.fileId || '').filter(Boolean);
|
||||||
|
const relatedImageIds = collections
|
||||||
|
.map((item) => item?.metadata?.relatedImgId || '')
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
// delete images
|
||||||
|
await delImgByRelatedId({
|
||||||
|
teamId,
|
||||||
|
relateIds: relatedImageIds,
|
||||||
|
session
|
||||||
|
});
|
||||||
|
// delete files
|
||||||
|
await delFileByFileIdList({
|
||||||
|
bucketName: BucketNameEnum.dataset,
|
||||||
|
fileIdList
|
||||||
|
});
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* delete collection and it related data
|
* delete collection and it related data
|
||||||
*/
|
*/
|
||||||
@ -134,26 +165,32 @@ export async function delCollectionAndRelatedSources({
|
|||||||
|
|
||||||
if (!teamId) return Promise.reject('teamId is not exist');
|
if (!teamId) return Promise.reject('teamId is not exist');
|
||||||
|
|
||||||
|
const datasetIds = Array.from(
|
||||||
|
new Set(
|
||||||
|
collections.map((item) => {
|
||||||
|
if (typeof item.datasetId === 'string') {
|
||||||
|
return String(item.datasetId);
|
||||||
|
}
|
||||||
|
return String(item.datasetId._id);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
const collectionIds = collections.map((item) => String(item._id));
|
const collectionIds = collections.map((item) => String(item._id));
|
||||||
const fileIdList = collections.map((item) => item?.fileId || '').filter(Boolean);
|
|
||||||
const relatedImageIds = collections
|
await delCollectionRelatedSource({ collections, session });
|
||||||
.map((item) => item?.metadata?.relatedImgId || '')
|
|
||||||
.filter(Boolean);
|
|
||||||
|
|
||||||
// delete training data
|
// delete training data
|
||||||
await MongoDatasetTraining.deleteMany({
|
await MongoDatasetTraining.deleteMany({
|
||||||
teamId,
|
teamId,
|
||||||
|
datasetIds: { $in: datasetIds },
|
||||||
collectionId: { $in: collectionIds }
|
collectionId: { $in: collectionIds }
|
||||||
});
|
});
|
||||||
|
|
||||||
// delete dataset.datas
|
// delete dataset.datas
|
||||||
await MongoDatasetData.deleteMany({ teamId, collectionId: { $in: collectionIds } }, { session });
|
await MongoDatasetData.deleteMany(
|
||||||
// delete imgs
|
{ teamId, datasetIds: { $in: datasetIds }, collectionId: { $in: collectionIds } },
|
||||||
await delImgByRelatedId({
|
{ session }
|
||||||
teamId,
|
);
|
||||||
relateIds: relatedImageIds,
|
|
||||||
session
|
|
||||||
});
|
|
||||||
// delete collections
|
// delete collections
|
||||||
await MongoDatasetCollection.deleteMany(
|
await MongoDatasetCollection.deleteMany(
|
||||||
{
|
{
|
||||||
@ -163,9 +200,5 @@ export async function delCollectionAndRelatedSources({
|
|||||||
);
|
);
|
||||||
|
|
||||||
// no session delete: delete files, vector data
|
// no session delete: delete files, vector data
|
||||||
await deleteDatasetDataVector({ teamId, collectionIds });
|
await deleteDatasetDataVector({ teamId, datasetIds, collectionIds });
|
||||||
await delFileByFileIdList({
|
|
||||||
bucketName: BucketNameEnum.dataset,
|
|
||||||
fileIdList
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
import { CollectionWithDatasetType, DatasetSchemaType } from '@fastgpt/global/core/dataset/type';
|
import { CollectionWithDatasetType, DatasetSchemaType } from '@fastgpt/global/core/dataset/type';
|
||||||
import { MongoDatasetCollection } from './collection/schema';
|
import { MongoDatasetCollection } from './collection/schema';
|
||||||
import { MongoDataset } from './schema';
|
import { MongoDataset } from './schema';
|
||||||
import { delCollectionAndRelatedSources } from './collection/controller';
|
import { delCollectionRelatedSource } from './collection/controller';
|
||||||
import { ClientSession } from '../../common/mongo';
|
import { ClientSession } from '../../common/mongo';
|
||||||
|
import { MongoDatasetTraining } from './training/schema';
|
||||||
|
import { MongoDatasetData } from './data/schema';
|
||||||
|
import { deleteDatasetDataVector } from '../../common/vectorStore/controller';
|
||||||
|
|
||||||
/* ============= dataset ========== */
|
/* ============= dataset ========== */
|
||||||
/* find all datasetId by top datasetId */
|
/* find all datasetId by top datasetId */
|
||||||
@ -82,5 +85,26 @@ export async function delDatasetRelevantData({
|
|||||||
'_id teamId fileId metadata'
|
'_id teamId fileId metadata'
|
||||||
).lean();
|
).lean();
|
||||||
|
|
||||||
await delCollectionAndRelatedSources({ collections, session });
|
// image and file
|
||||||
|
await delCollectionRelatedSource({ collections, session });
|
||||||
|
|
||||||
|
// delete training data
|
||||||
|
await MongoDatasetTraining.deleteMany({
|
||||||
|
teamId,
|
||||||
|
datasetId: { $in: datasetIds }
|
||||||
|
});
|
||||||
|
// delete dataset.datas
|
||||||
|
await MongoDatasetData.deleteMany({ teamId, datasetId: { $in: datasetIds } }, { session });
|
||||||
|
|
||||||
|
// delete collections
|
||||||
|
await MongoDatasetCollection.deleteMany(
|
||||||
|
{
|
||||||
|
teamId,
|
||||||
|
datasetId: { $in: datasetIds }
|
||||||
|
},
|
||||||
|
{ session }
|
||||||
|
);
|
||||||
|
|
||||||
|
// no session delete: delete files, vector data
|
||||||
|
await deleteDatasetDataVector({ teamId, datasetIds });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
import { MongoDatasetData } from './schema';
|
|
||||||
import { deleteDatasetDataVector } from '../../../common/vectorStore/controller';
|
|
||||||
@ -77,17 +77,18 @@ const DatasetDataSchema = new Schema({
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// list collection and count data; list data
|
// list collection and count data; list data; delete collection(relate data)
|
||||||
DatasetDataSchema.index(
|
DatasetDataSchema.index(
|
||||||
{ teamId: 1, datasetId: 1, collectionId: 1, chunkIndex: 1, updateTime: -1 },
|
{ teamId: 1, datasetId: 1, collectionId: 1, chunkIndex: 1, updateTime: -1 },
|
||||||
{ background: true }
|
{ background: true }
|
||||||
);
|
);
|
||||||
// same data check
|
|
||||||
DatasetDataSchema.index({ teamId: 1, collectionId: 1, q: 1, a: 1 }, { background: true });
|
|
||||||
// full text index
|
// full text index
|
||||||
DatasetDataSchema.index({ teamId: 1, datasetId: 1, fullTextToken: 'text' }, { background: true });
|
DatasetDataSchema.index({ teamId: 1, datasetId: 1, fullTextToken: 'text' }, { background: true });
|
||||||
// Recall vectors after data matching
|
// Recall vectors after data matching
|
||||||
DatasetDataSchema.index({ teamId: 1, datasetId: 1, 'indexes.dataId': 1 }, { background: true });
|
DatasetDataSchema.index(
|
||||||
|
{ teamId: 1, datasetId: 1, collectionId: 1, 'indexes.dataId': 1 },
|
||||||
|
{ background: true }
|
||||||
|
);
|
||||||
DatasetDataSchema.index({ updateTime: 1 }, { background: true });
|
DatasetDataSchema.index({ updateTime: 1 }, { background: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|||||||
@ -93,6 +93,7 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
|||||||
{
|
{
|
||||||
teamId,
|
teamId,
|
||||||
datasetId: { $in: datasetIds },
|
datasetId: { $in: datasetIds },
|
||||||
|
collectionId: { $in: results.map((item) => item.collectionId) },
|
||||||
'indexes.dataId': { $in: results.map((item) => item.id?.trim()) }
|
'indexes.dataId': { $in: results.map((item) => item.id?.trim()) }
|
||||||
},
|
},
|
||||||
'datasetId collectionId q a chunkIndex indexes'
|
'datasetId collectionId q a chunkIndex indexes'
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import type {
|
|||||||
} from '@fastgpt/global/core/dataset/api.d';
|
} from '@fastgpt/global/core/dataset/api.d';
|
||||||
import { TrainingModeEnum } from '@fastgpt/global/core/dataset/constants';
|
import { TrainingModeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||||
import { simpleText } from '@fastgpt/global/common/string/tools';
|
import { simpleText } from '@fastgpt/global/common/string/tools';
|
||||||
import { countPromptTokens } from '@fastgpt/global/common/string/tiktoken';
|
|
||||||
import { ClientSession } from '../../../common/mongo';
|
import { ClientSession } from '../../../common/mongo';
|
||||||
import { getLLMModel, getVectorModel } from '../../ai/model';
|
import { getLLMModel, getVectorModel } from '../../ai/model';
|
||||||
import { addLog } from '../../../common/system/log';
|
import { addLog } from '../../../common/system/log';
|
||||||
|
|||||||
@ -92,8 +92,8 @@ const TrainingDataSchema = new Schema({
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// lock training data; delete training data
|
// lock training data(teamId); delete training data
|
||||||
TrainingDataSchema.index({ teamId: 1, collectionId: 1 });
|
TrainingDataSchema.index({ teamId: 1, datasetId: 1 });
|
||||||
// get training data and sort
|
// get training data and sort
|
||||||
TrainingDataSchema.index({ mode: 1, lockTime: 1, weight: -1 });
|
TrainingDataSchema.index({ mode: 1, lockTime: 1, weight: -1 });
|
||||||
TrainingDataSchema.index({ expireAt: 1 }, { expireAfterSeconds: 7 * 24 * 60 * 60 }); // 7 days
|
TrainingDataSchema.index({ expireAt: 1 }, { expireAfterSeconds: 7 * 24 * 60 * 60 }); // 7 days
|
||||||
|
|||||||
@ -42,6 +42,9 @@ const TeamSchema = new Schema({
|
|||||||
},
|
},
|
||||||
appid: {
|
appid: {
|
||||||
type: String
|
type: String
|
||||||
|
},
|
||||||
|
pat: {
|
||||||
|
type: String
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -107,6 +107,7 @@ export const iconPaths = {
|
|||||||
'core/dataset/tableCollection': () => import('./icons/core/dataset/tableCollection.svg'),
|
'core/dataset/tableCollection': () => import('./icons/core/dataset/tableCollection.svg'),
|
||||||
'core/dataset/websiteDataset': () => import('./icons/core/dataset/websiteDataset.svg'),
|
'core/dataset/websiteDataset': () => import('./icons/core/dataset/websiteDataset.svg'),
|
||||||
'core/modules/basicNode': () => import('./icons/core/modules/basicNode.svg'),
|
'core/modules/basicNode': () => import('./icons/core/modules/basicNode.svg'),
|
||||||
|
'core/modules/fixview': () => import('./icons/core/modules/fixview.svg'),
|
||||||
'core/modules/flowLight': () => import('./icons/core/modules/flowLight.svg'),
|
'core/modules/flowLight': () => import('./icons/core/modules/flowLight.svg'),
|
||||||
'core/modules/previewLight': () => import('./icons/core/modules/previewLight.svg'),
|
'core/modules/previewLight': () => import('./icons/core/modules/previewLight.svg'),
|
||||||
'core/modules/systemPlugin': () => import('./icons/core/modules/systemPlugin.svg'),
|
'core/modules/systemPlugin': () => import('./icons/core/modules/systemPlugin.svg'),
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 30">
|
||||||
|
<path
|
||||||
|
d="M3.692 4.63c0-.53.4-.938.939-.938h5.215V0H4.708C2.13 0 0 2.054 0 4.63v5.216h3.692V4.631zM27.354 0h-5.2v3.692h5.17c.53 0 .984.4.984.939v5.215H32V4.631A4.624 4.624 0 0027.354 0zm.954 24.83c0 .532-.4.94-.939.94h-5.215v3.768h5.215c2.577 0 4.631-2.13 4.631-4.707v-5.139h-3.692v5.139zm-23.677.94c-.531 0-.939-.4-.939-.94v-5.138H0v5.139c0 2.577 2.13 4.707 4.708 4.707h5.138V25.77H4.631z">
|
||||||
|
</path>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 482 B |
@ -1,4 +1,4 @@
|
|||||||
### FastGPT V4.7
|
### FastGPT V4.7.1
|
||||||
|
|
||||||
1. 新增 - 语音输入完整配置。支持选择是否打开语音输入(包括分享页面),支持语音输入后自动发送,支持语音输入后自动语音播放(流式)。
|
1. 新增 - 语音输入完整配置。支持选择是否打开语音输入(包括分享页面),支持语音输入后自动发送,支持语音输入后自动语音播放(流式)。
|
||||||
2. 新增 - Pptx 和 xlsx 文件读取。但所有文件读取都放服务端,会消耗更多的服务器资源,以及无法在上传时预览更多内容。
|
2. 新增 - Pptx 和 xlsx 文件读取。但所有文件读取都放服务端,会消耗更多的服务器资源,以及无法在上传时预览更多内容。
|
||||||
|
|||||||
@ -33,7 +33,7 @@ function embedChatbot() {
|
|||||||
ChatBtnDiv.draggable = false;
|
ChatBtnDiv.draggable = false;
|
||||||
|
|
||||||
const iframe = document.createElement('iframe');
|
const iframe = document.createElement('iframe');
|
||||||
iframe.allow = 'fullscreen;microphone';
|
iframe.allow = '*';
|
||||||
iframe.referrerPolicy = 'no-referrer';
|
iframe.referrerPolicy = 'no-referrer';
|
||||||
iframe.title = 'FastGPT Chat Window';
|
iframe.title = 'FastGPT Chat Window';
|
||||||
iframe.id = chatWindowId;
|
iframe.id = chatWindowId;
|
||||||
|
|||||||
@ -230,7 +230,8 @@
|
|||||||
"Amount": "{{amount}}{{unit}}"
|
"Amount": "{{amount}}{{unit}}"
|
||||||
},
|
},
|
||||||
"speech": {
|
"speech": {
|
||||||
"error tip": "Speech Failed"
|
"error tip": "Speech Failed",
|
||||||
|
"not support": "Your browser does not support voice input"
|
||||||
},
|
},
|
||||||
"system": {
|
"system": {
|
||||||
"Commercial version function": "Commercial version special function",
|
"Commercial version function": "Commercial version special function",
|
||||||
@ -250,7 +251,7 @@
|
|||||||
},
|
},
|
||||||
"core": {
|
"core": {
|
||||||
"Chat": "Chat",
|
"Chat": "Chat",
|
||||||
"Chat test": "Chat test",
|
"Chat test": "Test",
|
||||||
"Max Token": "MaxTokens",
|
"Max Token": "MaxTokens",
|
||||||
"Start chat": "Start chat",
|
"Start chat": "Start chat",
|
||||||
"Total chars": "Total chars: {{total}}",
|
"Total chars": "Total chars: {{total}}",
|
||||||
@ -423,6 +424,7 @@
|
|||||||
"Converting to text": "Converting to text...",
|
"Converting to text": "Converting to text...",
|
||||||
"Custom History Title": "Custom history title",
|
"Custom History Title": "Custom history title",
|
||||||
"Custom History Title Description": "If set to empty, chat history will be followed automatically.",
|
"Custom History Title Description": "If set to empty, chat history will be followed automatically.",
|
||||||
|
"Debug test": "Test",
|
||||||
"Exit Chat": "Exit",
|
"Exit Chat": "Exit",
|
||||||
"Failed to initialize chat": "Failed to initialize chat",
|
"Failed to initialize chat": "Failed to initialize chat",
|
||||||
"Feedback Failed": "Feedback Failed",
|
"Feedback Failed": "Feedback Failed",
|
||||||
|
|||||||
@ -230,7 +230,8 @@
|
|||||||
"Amount": "{{amount}}{{unit}}"
|
"Amount": "{{amount}}{{unit}}"
|
||||||
},
|
},
|
||||||
"speech": {
|
"speech": {
|
||||||
"error tip": "语音转文字失败"
|
"error tip": "语音转文字失败",
|
||||||
|
"not support": "您的浏览器不支持语音输入"
|
||||||
},
|
},
|
||||||
"system": {
|
"system": {
|
||||||
"Commercial version function": "商业版特有功能",
|
"Commercial version function": "商业版特有功能",
|
||||||
@ -250,7 +251,7 @@
|
|||||||
},
|
},
|
||||||
"core": {
|
"core": {
|
||||||
"Chat": "对话",
|
"Chat": "对话",
|
||||||
"Chat test": "测试对话",
|
"Chat test": "测试",
|
||||||
"Max Token": "单条数据上限",
|
"Max Token": "单条数据上限",
|
||||||
"Start chat": "立即对话",
|
"Start chat": "立即对话",
|
||||||
"Total chars": "总字数: {{total}}",
|
"Total chars": "总字数: {{total}}",
|
||||||
@ -423,6 +424,7 @@
|
|||||||
"Converting to text": "正在转换为文本...",
|
"Converting to text": "正在转换为文本...",
|
||||||
"Custom History Title": "自定义历史记录标题",
|
"Custom History Title": "自定义历史记录标题",
|
||||||
"Custom History Title Description": "如果设置为空,会自动跟随聊天记录。",
|
"Custom History Title Description": "如果设置为空,会自动跟随聊天记录。",
|
||||||
|
"Debug test": "调试预览",
|
||||||
"Exit Chat": "退出聊天",
|
"Exit Chat": "退出聊天",
|
||||||
"Failed to initialize chat": "初始化聊天失败",
|
"Failed to initialize chat": "初始化聊天失败",
|
||||||
"Feedback Failed": "提交反馈异常",
|
"Feedback Failed": "提交反馈异常",
|
||||||
@ -608,8 +610,7 @@
|
|||||||
"success": "开始同步"
|
"success": "开始同步"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"training": {
|
"training": {}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"Auxiliary Data": "辅助数据",
|
"Auxiliary Data": "辅助数据",
|
||||||
@ -996,6 +997,7 @@
|
|||||||
"Tool module": "工具",
|
"Tool module": "工具",
|
||||||
"UnKnow Module": "未知模块",
|
"UnKnow Module": "未知模块",
|
||||||
"User guide": "用户引导",
|
"User guide": "用户引导",
|
||||||
|
"App system setting": "系统配置",
|
||||||
"http body placeholder": "与APIFox相同的语法",
|
"http body placeholder": "与APIFox相同的语法",
|
||||||
"textEditor": "文本加工",
|
"textEditor": "文本加工",
|
||||||
"textEditor intro": "可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。"
|
"textEditor intro": "可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。"
|
||||||
|
|||||||
@ -94,7 +94,7 @@ const ChatItem = ({
|
|||||||
|
|
||||||
/* AI */
|
/* AI */
|
||||||
return (
|
return (
|
||||||
<Flex flexDirection={'column'} gap={2}>
|
<Flex flexDirection={'column'} key={chat.dataId} gap={2}>
|
||||||
{chat.value.map((value, i) => {
|
{chat.value.map((value, i) => {
|
||||||
const key = `${chat.dataId}-ai-${i}`;
|
const key = `${chat.dataId}-ai-${i}`;
|
||||||
if (value.text) {
|
if (value.text) {
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import React, {
|
|||||||
useImperativeHandle,
|
useImperativeHandle,
|
||||||
ForwardedRef
|
ForwardedRef
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
import { SmallCloseIcon } from '@chakra-ui/icons';
|
||||||
import { Box, Flex, IconButton } from '@chakra-ui/react';
|
import { Box, Flex, IconButton } from '@chakra-ui/react';
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
import { streamFetch } from '@/web/common/api/fetch';
|
import { streamFetch } from '@/web/common/api/fetch';
|
||||||
@ -18,6 +19,7 @@ import type { ComponentRef, StartChatFnProps } from '@/components/ChatBox/type.d
|
|||||||
import { getGuideModule } from '@fastgpt/global/core/module/utils';
|
import { getGuideModule } from '@fastgpt/global/core/module/utils';
|
||||||
import { checkChatSupportSelectFileByModules } from '@/web/core/chat/utils';
|
import { checkChatSupportSelectFileByModules } from '@/web/core/chat/utils';
|
||||||
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
|
||||||
export type ChatTestComponentRef = {
|
export type ChatTestComponentRef = {
|
||||||
resetChatTest: () => void;
|
resetChatTest: () => void;
|
||||||
@ -35,6 +37,7 @@ const ChatTest = (
|
|||||||
},
|
},
|
||||||
ref: ForwardedRef<ChatTestComponentRef>
|
ref: ForwardedRef<ChatTestComponentRef>
|
||||||
) => {
|
) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const ChatBoxRef = useRef<ComponentRef>(null);
|
const ChatBoxRef = useRef<ComponentRef>(null);
|
||||||
const { userInfo } = useUserStore();
|
const { userInfo } = useUserStore();
|
||||||
const isOpen = useMemo(() => modules && modules.length > 0, [modules]);
|
const isOpen = useMemo(() => modules && modules.length > 0, [modules]);
|
||||||
@ -100,9 +103,9 @@ const ChatTest = (
|
|||||||
>
|
>
|
||||||
<Flex py={4} px={5} whiteSpace={'nowrap'}>
|
<Flex py={4} px={5} whiteSpace={'nowrap'}>
|
||||||
<Box fontSize={'xl'} fontWeight={'bold'} flex={1}>
|
<Box fontSize={'xl'} fontWeight={'bold'} flex={1}>
|
||||||
调试预览
|
{t('core.chat.Debug test')}
|
||||||
</Box>
|
</Box>
|
||||||
<MyTooltip label={'重置'}>
|
<MyTooltip label={t('core.chat.Restart')}>
|
||||||
<IconButton
|
<IconButton
|
||||||
className="chat"
|
className="chat"
|
||||||
size={'smSquare'}
|
size={'smSquare'}
|
||||||
@ -117,6 +120,16 @@ const ChatTest = (
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</MyTooltip>
|
</MyTooltip>
|
||||||
|
<MyTooltip label={t('common.Close')}>
|
||||||
|
<IconButton
|
||||||
|
ml={[3, 6]}
|
||||||
|
icon={<SmallCloseIcon fontSize={'22px'} />}
|
||||||
|
variant={'grayBase'}
|
||||||
|
size={'smSquare'}
|
||||||
|
aria-label={''}
|
||||||
|
onClick={onClose}
|
||||||
|
/>
|
||||||
|
</MyTooltip>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Box flex={1}>
|
<Box flex={1}>
|
||||||
<ChatBox
|
<ChatBox
|
||||||
@ -132,7 +145,7 @@ const ChatTest = (
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Box
|
{/* <Box
|
||||||
zIndex={2}
|
zIndex={2}
|
||||||
display={isOpen ? 'block' : 'none'}
|
display={isOpen ? 'block' : 'none'}
|
||||||
position={'fixed'}
|
position={'fixed'}
|
||||||
@ -141,7 +154,7 @@ const ChatTest = (
|
|||||||
bottom={0}
|
bottom={0}
|
||||||
right={0}
|
right={0}
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
/>
|
/> */}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -166,7 +166,7 @@ export const FlowProvider = ({
|
|||||||
}, [nodes]);
|
}, [nodes]);
|
||||||
|
|
||||||
const onFixView = useCallback(() => {
|
const onFixView = useCallback(() => {
|
||||||
const btn = document.querySelector('.react-flow__controls-fitview') as HTMLButtonElement;
|
const btn = document.querySelector('.custom-workflow-fix_view') as HTMLButtonElement;
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
btn && btn.click();
|
btn && btn.click();
|
||||||
|
|||||||
@ -15,8 +15,10 @@ import NodeCard from '../render/NodeCard';
|
|||||||
import type { VariableItemType } from '@fastgpt/global/core/app/type.d';
|
import type { VariableItemType } from '@fastgpt/global/core/app/type.d';
|
||||||
import QGSwitch from '@/components/core/app/QGSwitch';
|
import QGSwitch from '@/components/core/app/QGSwitch';
|
||||||
import TTSSelect from '@/components/core/app/TTSSelect';
|
import TTSSelect from '@/components/core/app/TTSSelect';
|
||||||
|
import WhisperConfig from '@/components/core/app/WhisperConfig';
|
||||||
import { splitGuideModule } from '@fastgpt/global/core/module/utils';
|
import { splitGuideModule } from '@fastgpt/global/core/module/utils';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import { TTSTypeEnum } from '@/constants/app';
|
||||||
|
|
||||||
const NodeUserGuide = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
|
const NodeUserGuide = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@ -31,6 +33,9 @@ const NodeUserGuide = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
|
|||||||
<Box pt={3} borderTop={theme.borders.base}>
|
<Box pt={3} borderTop={theme.borders.base}>
|
||||||
<TTSGuide data={data} />
|
<TTSGuide data={data} />
|
||||||
</Box>
|
</Box>
|
||||||
|
<Box mt={3} pt={3} borderTop={theme.borders.base}>
|
||||||
|
<WhisperGuide data={data} />
|
||||||
|
</Box>
|
||||||
<Box mt={3} pt={3} borderTop={theme.borders.base}>
|
<Box mt={3} pt={3} borderTop={theme.borders.base}>
|
||||||
<QuestionGuide data={data} />
|
<QuestionGuide data={data} />
|
||||||
</Box>
|
</Box>
|
||||||
@ -164,3 +169,26 @@ function TTSGuide({ data }: { data: FlowModuleItemType }) {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function WhisperGuide({ data }: { data: FlowModuleItemType }) {
|
||||||
|
const { inputs, moduleId } = data;
|
||||||
|
const { ttsConfig, whisperConfig } = splitGuideModule({ inputs } as ModuleItemType);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WhisperConfig
|
||||||
|
isOpenAudio={ttsConfig.type !== TTSTypeEnum.none}
|
||||||
|
value={whisperConfig}
|
||||||
|
onChange={(e) => {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
key: ModuleInputKeyEnum.whisper,
|
||||||
|
type: 'updateInput',
|
||||||
|
value: {
|
||||||
|
...inputs.find((item) => item.key === ModuleInputKeyEnum.whisper),
|
||||||
|
value: e
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -261,7 +261,7 @@ const NodeCard = (props: Props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Header}
|
{Header}
|
||||||
{children}
|
<Box className="nowheel">{children}</Box>
|
||||||
{RenderModal}
|
{RenderModal}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,8 +3,11 @@ import ReactFlow, {
|
|||||||
Background,
|
Background,
|
||||||
Connection,
|
Connection,
|
||||||
Controls,
|
Controls,
|
||||||
|
ControlButton,
|
||||||
|
MiniMap,
|
||||||
NodeProps,
|
NodeProps,
|
||||||
ReactFlowProvider
|
ReactFlowProvider,
|
||||||
|
useReactFlow
|
||||||
} from 'reactflow';
|
} from 'reactflow';
|
||||||
import { Box, Flex, IconButton, useDisclosure } from '@chakra-ui/react';
|
import { Box, Flex, IconButton, useDisclosure } from '@chakra-ui/react';
|
||||||
import { SmallCloseIcon } from '@chakra-ui/icons';
|
import { SmallCloseIcon } from '@chakra-ui/icons';
|
||||||
@ -20,6 +23,8 @@ import 'reactflow/dist/style.css';
|
|||||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { FlowModuleItemType } from '@fastgpt/global/core/module/type';
|
import { FlowModuleItemType } from '@fastgpt/global/core/module/type';
|
||||||
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
|
|
||||||
const NodeSimple = dynamic(() => import('./components/nodes/NodeSimple'));
|
const NodeSimple = dynamic(() => import('./components/nodes/NodeSimple'));
|
||||||
const nodeTypes: Record<`${FlowNodeTypeEnum}`, any> = {
|
const nodeTypes: Record<`${FlowNodeTypeEnum}`, any> = {
|
||||||
@ -54,19 +59,10 @@ const edgeTypes = {
|
|||||||
const Container = React.memo(function Container() {
|
const Container = React.memo(function Container() {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { reactFlowWrapper, nodes, onNodesChange, edges, onEdgesChange, onConnect } =
|
const { reactFlowWrapper, nodes, onNodesChange, edges, onEdgesChange, onConnect } =
|
||||||
useFlowProviderStore();
|
useFlowProviderStore();
|
||||||
|
|
||||||
const memoRenderTools = useMemo(
|
|
||||||
() => (
|
|
||||||
<>
|
|
||||||
<Background />
|
|
||||||
<Controls position={'bottom-right'} style={{ display: 'flex' }} showInteractive={false} />
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const customOnConnect = useCallback(
|
const customOnConnect = useCallback(
|
||||||
(connect: Connection) => {
|
(connect: Connection) => {
|
||||||
if (!connect.sourceHandle || !connect.targetHandle) {
|
if (!connect.sourceHandle || !connect.targetHandle) {
|
||||||
@ -105,7 +101,7 @@ const Container = React.memo(function Container() {
|
|||||||
onEdgesChange={onEdgesChange}
|
onEdgesChange={onEdgesChange}
|
||||||
onConnect={customOnConnect}
|
onConnect={customOnConnect}
|
||||||
>
|
>
|
||||||
{memoRenderTools}
|
<FlowController />
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -168,3 +164,40 @@ const Flow = ({ Header, ...data }: { Header: React.ReactNode }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default React.memo(Flow);
|
export default React.memo(Flow);
|
||||||
|
|
||||||
|
const FlowController = React.memo(function FlowController() {
|
||||||
|
const { fitView } = useReactFlow();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<MiniMap
|
||||||
|
style={{
|
||||||
|
height: 78,
|
||||||
|
width: 126,
|
||||||
|
marginBottom: 35
|
||||||
|
}}
|
||||||
|
pannable
|
||||||
|
/>
|
||||||
|
<Controls
|
||||||
|
position={'bottom-right'}
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
marginBottom: 5,
|
||||||
|
background: 'white',
|
||||||
|
borderRadius: '6px',
|
||||||
|
overflow: 'hidden',
|
||||||
|
boxShadow:
|
||||||
|
'0px 0px 1px 0px rgba(19, 51, 107, 0.20), 0px 12px 16px -4px rgba(19, 51, 107, 0.20)'
|
||||||
|
}}
|
||||||
|
showInteractive={false}
|
||||||
|
showFitView={false}
|
||||||
|
>
|
||||||
|
<MyTooltip label={'页面居中'}>
|
||||||
|
<ControlButton className="custom-workflow-fix_view" onClick={() => fitView()}>
|
||||||
|
<MyIcon name={'core/modules/fixview'} w={'14px'} />
|
||||||
|
</ControlButton>
|
||||||
|
</MyTooltip>
|
||||||
|
</Controls>
|
||||||
|
<Background />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
@ -18,7 +18,8 @@ import { getDocPath } from '@/web/common/system/doc';
|
|||||||
const LafAccountModal = ({
|
const LafAccountModal = ({
|
||||||
defaultData = {
|
defaultData = {
|
||||||
token: '',
|
token: '',
|
||||||
appid: ''
|
appid: '',
|
||||||
|
pat: ''
|
||||||
},
|
},
|
||||||
onClose
|
onClose
|
||||||
}: {
|
}: {
|
||||||
@ -140,7 +141,7 @@ const LafAccountModal = ({
|
|||||||
onResetForm();
|
onResetForm();
|
||||||
putUpdateTeam({
|
putUpdateTeam({
|
||||||
teamId: userInfo?.team.teamId || '',
|
teamId: userInfo?.team.teamId || '',
|
||||||
lafAccount: { token: '', appid: '' }
|
lafAccount: { token: '', appid: '', pat: '' }
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
29
projects/app/src/pages/api/admin/initv471.ts
Normal file
29
projects/app/src/pages/api/admin/initv471.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
import { jsonRes } from '@fastgpt/service/common/response';
|
||||||
|
import { connectToDatabase } from '@/service/mongo';
|
||||||
|
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||||
|
import { PgClient } from '@fastgpt/service/common/vectorStore/pg';
|
||||||
|
|
||||||
|
/* pg 中的数据搬到 mongo dataset.datas 中,并做映射 */
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
|
try {
|
||||||
|
await connectToDatabase();
|
||||||
|
await authCert({ req, authRoot: true });
|
||||||
|
|
||||||
|
// 删除索引
|
||||||
|
await PgClient.query(`DROP INDEX IF EXISTS team_dataset_index;`);
|
||||||
|
await PgClient.query(`DROP INDEX IF EXISTS team_collection_index;`);
|
||||||
|
await PgClient.query(`DROP INDEX IF EXISTS team_id_index;`);
|
||||||
|
|
||||||
|
jsonRes(res, {
|
||||||
|
message: 'success'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
|
||||||
|
jsonRes(res, {
|
||||||
|
code: 500,
|
||||||
|
error
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -29,7 +29,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
teamId,
|
teamId,
|
||||||
datasetId: collection.datasetId._id,
|
datasetId: collection.datasetId._id,
|
||||||
collectionId,
|
collectionId,
|
||||||
fields: '_id teamId fileId metadata'
|
fields: '_id teamId datasetId fileId metadata'
|
||||||
});
|
});
|
||||||
|
|
||||||
// delete
|
// delete
|
||||||
|
|||||||
@ -70,6 +70,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
|||||||
// Duplicate data check
|
// Duplicate data check
|
||||||
await hasSameValue({
|
await hasSameValue({
|
||||||
teamId,
|
teamId,
|
||||||
|
datasetId,
|
||||||
collectionId,
|
collectionId,
|
||||||
q: formatQ,
|
q: formatQ,
|
||||||
a: formatA
|
a: formatA
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import type { GetDatasetDataListProps } from '@/global/core/api/datasetReq';
|
|||||||
import { authDatasetCollection } from '@fastgpt/service/support/permission/auth/dataset';
|
import { authDatasetCollection } from '@fastgpt/service/support/permission/auth/dataset';
|
||||||
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
|
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
|
||||||
import { PagingData } from '@/types';
|
import { PagingData } from '@/types';
|
||||||
|
import { replaceRegChars } from '@fastgpt/global/common/string/tools';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
@ -28,7 +29,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
per: 'r'
|
per: 'r'
|
||||||
});
|
});
|
||||||
|
|
||||||
searchText = searchText.replace(/'/g, '');
|
searchText = replaceRegChars(searchText).replace(/'/g, '');
|
||||||
|
|
||||||
const match = {
|
const match = {
|
||||||
teamId,
|
teamId,
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { pushWhisperUsage } from '@/service/support/wallet/usage/push';
|
|||||||
import { authChatCert } from '@/service/support/permission/auth/chat';
|
import { authChatCert } from '@/service/support/permission/auth/chat';
|
||||||
import { MongoApp } from '@fastgpt/service/core/app/schema';
|
import { MongoApp } from '@fastgpt/service/core/app/schema';
|
||||||
import { getGuideModule, splitGuideModule } from '@fastgpt/global/core/module/utils';
|
import { getGuideModule, splitGuideModule } from '@fastgpt/global/core/module/utils';
|
||||||
|
import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat';
|
||||||
|
|
||||||
const upload = getUploadModel({
|
const upload = getUploadModel({
|
||||||
maxSize: 2
|
maxSize: 2
|
||||||
@ -20,15 +21,16 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
|||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
file,
|
file,
|
||||||
data: { appId, duration, teamId: spaceTeamId, teamToken }
|
data: { appId, duration, shareId, outLinkUid, teamId: spaceTeamId, teamToken }
|
||||||
} = await upload.doUpload<{
|
} = await upload.doUpload<
|
||||||
|
OutLinkChatAuthProps & {
|
||||||
appId: string;
|
appId: string;
|
||||||
duration: number;
|
duration: number;
|
||||||
shareId?: string;
|
}
|
||||||
teamId?: string;
|
>(req, res);
|
||||||
teamToken?: string;
|
|
||||||
}>(req, res);
|
|
||||||
|
|
||||||
|
req.body.shareId = shareId;
|
||||||
|
req.body.outLinkUid = outLinkUid;
|
||||||
req.body.teamId = spaceTeamId;
|
req.body.teamId = spaceTeamId;
|
||||||
req.body.teamToken = teamToken;
|
req.body.teamToken = teamToken;
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import React, { useCallback, useRef, useState } from 'react';
|
import React, { useCallback, useRef, useState } from 'react';
|
||||||
import { Box, Flex, IconButton, useTheme, useDisclosure } from '@chakra-ui/react';
|
import { Box, Flex, IconButton, useTheme, useDisclosure, Button } from '@chakra-ui/react';
|
||||||
import { SmallCloseIcon } from '@chakra-ui/icons';
|
|
||||||
import { ModuleItemType } from '@fastgpt/global/core/module/type';
|
import { ModuleItemType } from '@fastgpt/global/core/module/type';
|
||||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||||
import { AppSchema } from '@fastgpt/global/core/app/type.d';
|
import { AppSchema } from '@fastgpt/global/core/app/type.d';
|
||||||
@ -18,6 +17,7 @@ import { useAppStore } from '@/web/core/app/store/useAppStore';
|
|||||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
|
import MyMenu from '@/components/MyMenu';
|
||||||
|
|
||||||
const ImportSettings = dynamic(() => import('@/components/core/module/Flow/ImportSettings'));
|
const ImportSettings = dynamic(() => import('@/components/core/module/Flow/ImportSettings'));
|
||||||
|
|
||||||
@ -143,48 +143,36 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
|
|||||||
{app.name}
|
{app.name}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<MyTooltip label={t('app.Import Configs')}>
|
<MyMenu
|
||||||
|
Button={
|
||||||
<IconButton
|
<IconButton
|
||||||
mr={[3, 6]}
|
mr={[3, 5]}
|
||||||
size={'smSquare'}
|
icon={<MyIcon name={'more'} w={'14px'} p={2} />}
|
||||||
icon={<MyIcon name={'common/importLight'} w={['14px', '16px']} />}
|
aria-label={''}
|
||||||
|
size={'sm'}
|
||||||
variant={'whitePrimary'}
|
variant={'whitePrimary'}
|
||||||
aria-label={'save'}
|
|
||||||
onClick={onOpenImport}
|
|
||||||
/>
|
/>
|
||||||
</MyTooltip>
|
}
|
||||||
<MyTooltip label={t('app.Export Configs')}>
|
menuList={[
|
||||||
<IconButton
|
{ label: t('app.Import Configs'), icon: 'common/importLight', onClick: onOpenImport },
|
||||||
mr={[3, 6]}
|
{
|
||||||
icon={<MyIcon name={'export'} w={['14px', '16px']} />}
|
label: t('app.Export Configs'),
|
||||||
size={'smSquare'}
|
icon: 'export',
|
||||||
variant={'whitePrimary'}
|
onClick: async () => {
|
||||||
aria-label={'save'}
|
|
||||||
onClick={async () => {
|
|
||||||
const modules = await flow2ModulesAndCheck();
|
const modules = await flow2ModulesAndCheck();
|
||||||
if (modules) {
|
if (modules) {
|
||||||
copyData(filterExportModules(modules), t('app.Export Config Successful'));
|
copyData(filterExportModules(modules), t('app.Export Config Successful'));
|
||||||
}
|
}
|
||||||
}}
|
}
|
||||||
|
}
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
</MyTooltip>
|
|
||||||
|
|
||||||
{testModules ? (
|
{!testModules && (
|
||||||
<IconButton
|
<Button
|
||||||
mr={[3, 6]}
|
mr={[3, 5]}
|
||||||
icon={<SmallCloseIcon fontSize={'25px'} />}
|
size={'sm'}
|
||||||
variant={'whitePrimary'}
|
leftIcon={<MyIcon name={'core/chat/chatLight'} w={['14px', '16px']} />}
|
||||||
size={'smSquare'}
|
|
||||||
aria-label={''}
|
|
||||||
onClick={() => setTestModules(undefined)}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<MyTooltip label={t('core.Chat test')}>
|
|
||||||
<IconButton
|
|
||||||
mr={[3, 6]}
|
|
||||||
icon={<MyIcon name={'core/chat/chatLight'} w={['14px', '16px']} />}
|
|
||||||
size={'smSquare'}
|
|
||||||
aria-label={'save'}
|
|
||||||
variant={'whitePrimary'}
|
variant={'whitePrimary'}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const modules = await flow2ModulesAndCheck();
|
const modules = await flow2ModulesAndCheck();
|
||||||
@ -192,24 +180,24 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
|
|||||||
setTestModules(modules);
|
setTestModules(modules);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
</MyTooltip>
|
{t('core.Chat test')}
|
||||||
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<MyTooltip label={t('common.Save')}>
|
<Button
|
||||||
<IconButton
|
size={'sm'}
|
||||||
icon={<MyIcon name={'common/saveFill'} w={['14px', '16px']} />}
|
|
||||||
size={'smSquare'}
|
|
||||||
isLoading={isSaving}
|
isLoading={isSaving}
|
||||||
aria-label={'save'}
|
leftIcon={<MyIcon name={'common/saveFill'} w={['14px', '16px']} />}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const modules = await flow2ModulesAndCheck();
|
const modules = await flow2ModulesAndCheck();
|
||||||
if (modules) {
|
if (modules) {
|
||||||
onclickSave(modules);
|
onclickSave(modules);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
</MyTooltip>
|
{t('common.Save')}
|
||||||
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
{isOpenImport && <ImportSettings onClose={onCloseImport} />}
|
{isOpenImport && <ImportSettings onClose={onCloseImport} />}
|
||||||
<ConfirmModal
|
<ConfirmModal
|
||||||
|
|||||||
@ -88,7 +88,7 @@ const SelectUsingWayModal = ({ share, onClose }: { share: OutLinkSchema; onClose
|
|||||||
src="${linkUrl}"
|
src="${linkUrl}"
|
||||||
style="width: 100%; height: 100%;"
|
style="width: 100%; height: 100%;"
|
||||||
frameborder="0"
|
frameborder="0"
|
||||||
allow="microphone"
|
allow="*"
|
||||||
/>`
|
/>`
|
||||||
},
|
},
|
||||||
[UsingWayEnum.script]: {
|
[UsingWayEnum.script]: {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { useChatBox } from '@/components/ChatBox/hooks/useChatBox';
|
import { useChatBox } from '@/components/ChatBox/hooks/useChatBox';
|
||||||
import type { ChatItemType } from '@fastgpt/global/core/chat/type.d';
|
import type { ChatItemType } from '@fastgpt/global/core/chat/type.d';
|
||||||
import { Menu, MenuButton, MenuList, MenuItem, Box, IconButton } from '@chakra-ui/react';
|
import { Box, IconButton } from '@chakra-ui/react';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { Box, Flex, IconButton, useTheme, useDisclosure } from '@chakra-ui/react';
|
import { Box, Flex, IconButton, useTheme, useDisclosure, Button } from '@chakra-ui/react';
|
||||||
import { PluginItemSchema } from '@fastgpt/global/core/plugin/type';
|
import { PluginItemSchema } from '@fastgpt/global/core/plugin/type';
|
||||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
@ -14,6 +14,7 @@ import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
|||||||
import { ModuleItemType } from '@fastgpt/global/core/module/type';
|
import { ModuleItemType } from '@fastgpt/global/core/module/type';
|
||||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
import { ModuleOutputKeyEnum } from '@fastgpt/global/core/module/constants';
|
import { ModuleOutputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||||
|
import MyMenu from '@/components/MyMenu';
|
||||||
|
|
||||||
const ImportSettings = dynamic(() => import('@/components/core/module/Flow/ImportSettings'));
|
const ImportSettings = dynamic(() => import('@/components/core/module/Flow/ImportSettings'));
|
||||||
const PreviewPlugin = dynamic(() => import('./Preview'));
|
const PreviewPlugin = dynamic(() => import('./Preview'));
|
||||||
@ -137,38 +138,37 @@ const Header = ({ plugin, onClose }: Props) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</MyTooltip>
|
</MyTooltip>
|
||||||
<Box ml={[3, 6]} fontSize={['md', '2xl']} flex={1}>
|
<Box ml={[3, 5]} fontSize={['md', '2xl']} flex={1}>
|
||||||
{plugin.name}
|
{plugin.name}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<MyTooltip label={t('app.Import Configs')}>
|
<MyMenu
|
||||||
|
Button={
|
||||||
<IconButton
|
<IconButton
|
||||||
mr={[3, 6]}
|
mr={[3, 5]}
|
||||||
icon={<MyIcon name={'common/importLight'} w={['14px', '16px']} />}
|
icon={<MyIcon name={'more'} w={'14px'} p={2} />}
|
||||||
|
aria-label={''}
|
||||||
|
size={'sm'}
|
||||||
variant={'whitePrimary'}
|
variant={'whitePrimary'}
|
||||||
size={'smSquare'}
|
|
||||||
aria-label={'save'}
|
|
||||||
onClick={onOpenImport}
|
|
||||||
/>
|
/>
|
||||||
</MyTooltip>
|
}
|
||||||
<MyTooltip label={t('app.Export Configs')}>
|
menuList={[
|
||||||
<IconButton
|
{ label: t('app.Import Configs'), icon: 'common/importLight', onClick: onOpenImport },
|
||||||
mr={[3, 6]}
|
{
|
||||||
icon={<MyIcon name={'export'} w={['14px', '16px']} />}
|
label: t('app.Export Configs'),
|
||||||
size={'smSquare'}
|
icon: 'export',
|
||||||
variant={'whitePrimary'}
|
onClick: async () => {
|
||||||
aria-label={'save'}
|
|
||||||
onClick={async () => {
|
|
||||||
const modules = await flow2ModulesAndCheck();
|
const modules = await flow2ModulesAndCheck();
|
||||||
if (modules) {
|
if (modules) {
|
||||||
copyData(filterExportModules(modules), t('app.Export Config Successful'));
|
copyData(filterExportModules(modules), t('app.Export Config Successful'));
|
||||||
}
|
}
|
||||||
}}
|
}
|
||||||
|
}
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
</MyTooltip>
|
|
||||||
<MyTooltip label={t('module.Preview Plugin')}>
|
<MyTooltip label={t('module.Preview Plugin')}>
|
||||||
<IconButton
|
<IconButton
|
||||||
mr={[3, 6]}
|
mr={[3, 5]}
|
||||||
icon={<MyIcon name={'core/modules/previewLight'} w={['14px', '16px']} />}
|
icon={<MyIcon name={'core/modules/previewLight'} w={['14px', '16px']} />}
|
||||||
size={'smSquare'}
|
size={'smSquare'}
|
||||||
aria-label={'save'}
|
aria-label={'save'}
|
||||||
@ -181,20 +181,19 @@ const Header = ({ plugin, onClose }: Props) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</MyTooltip>
|
</MyTooltip>
|
||||||
<MyTooltip label={t('module.Save Config')}>
|
<Button
|
||||||
<IconButton
|
size={'sm'}
|
||||||
icon={<MyIcon name={'save'} w={['14px', '16px']} />}
|
|
||||||
size={'smSquare'}
|
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
aria-label={'save'}
|
leftIcon={<MyIcon name={'common/saveFill'} w={['14px', '16px']} />}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const modules = await flow2ModulesAndCheck();
|
const modules = await flow2ModulesAndCheck();
|
||||||
if (modules) {
|
if (modules) {
|
||||||
onclickSave(modules);
|
onclickSave(modules);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
</MyTooltip>
|
{t('common.Save')}
|
||||||
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
{isOpenImport && <ImportSettings onClose={onCloseImport} />}
|
{isOpenImport && <ImportSettings onClose={onCloseImport} />}
|
||||||
{!!previewModules && (
|
{!!previewModules && (
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import {
|
|||||||
delFileByFileIdList,
|
delFileByFileIdList,
|
||||||
getGFSCollection
|
getGFSCollection
|
||||||
} from '@fastgpt/service/common/file/gridfs/controller';
|
} from '@fastgpt/service/common/file/gridfs/controller';
|
||||||
|
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
|
||||||
import { addLog } from '@fastgpt/service/common/system/log';
|
import { addLog } from '@fastgpt/service/common/system/log';
|
||||||
import {
|
import {
|
||||||
deleteDatasetDataVector,
|
deleteDatasetDataVector,
|
||||||
@ -72,15 +73,19 @@ export async function checkInvalidDatasetData(start: Date, end: Date) {
|
|||||||
$lte: end
|
$lte: end
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'_id teamId collectionId'
|
'_id teamId datasetId collectionId'
|
||||||
).lean();
|
).lean();
|
||||||
|
|
||||||
// 2. 合并所有的collectionId
|
// 2. 合并所有的collectionId
|
||||||
const map = new Map<string, { teamId: string; collectionId: string }>();
|
const map = new Map<string, { teamId: string; datasetId: string; collectionId: string }>();
|
||||||
for (const item of rows) {
|
for (const item of rows) {
|
||||||
const collectionId = String(item.collectionId);
|
const collectionId = String(item.collectionId);
|
||||||
if (!map.has(collectionId)) {
|
if (!map.has(collectionId)) {
|
||||||
map.set(collectionId, { teamId: item.teamId, collectionId });
|
map.set(collectionId, {
|
||||||
|
teamId: item.teamId,
|
||||||
|
datasetId: item.datasetId,
|
||||||
|
collectionId
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const list = Array.from(map.values());
|
const list = Array.from(map.values());
|
||||||
@ -92,21 +97,28 @@ export async function checkInvalidDatasetData(start: Date, end: Date) {
|
|||||||
// 3. 查看该collection是否存在,不存在,则删除对应的数据
|
// 3. 查看该collection是否存在,不存在,则删除对应的数据
|
||||||
const collection = await MongoDatasetCollection.findOne({ _id: item.collectionId });
|
const collection = await MongoDatasetCollection.findOne({ _id: item.collectionId });
|
||||||
if (!collection) {
|
if (!collection) {
|
||||||
const result = await Promise.all([
|
await mongoSessionRun(async (session) => {
|
||||||
MongoDatasetTraining.deleteMany({
|
await MongoDatasetTraining.deleteMany(
|
||||||
|
{
|
||||||
teamId: item.teamId,
|
teamId: item.teamId,
|
||||||
collectionId: item.collectionId
|
collectionId: item.collectionId
|
||||||
}),
|
},
|
||||||
MongoDatasetData.deleteMany({
|
{ session }
|
||||||
|
);
|
||||||
|
await MongoDatasetData.deleteMany(
|
||||||
|
{
|
||||||
teamId: item.teamId,
|
teamId: item.teamId,
|
||||||
collectionId: item.collectionId
|
collectionId: item.collectionId
|
||||||
}),
|
},
|
||||||
deleteDatasetDataVector({
|
{ session }
|
||||||
|
);
|
||||||
|
await deleteDatasetDataVector({
|
||||||
teamId: item.teamId,
|
teamId: item.teamId,
|
||||||
collectionIds: [String(item.collectionId)]
|
datasetIds: [item.datasetId],
|
||||||
})
|
collectionIds: [item.collectionId]
|
||||||
]);
|
});
|
||||||
console.log(result);
|
});
|
||||||
|
|
||||||
console.log('collection is not found', item);
|
console.log('collection is not found', item);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,17 +5,20 @@ import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
|
|||||||
*/
|
*/
|
||||||
export async function hasSameValue({
|
export async function hasSameValue({
|
||||||
teamId,
|
teamId,
|
||||||
|
datasetId,
|
||||||
collectionId,
|
collectionId,
|
||||||
q,
|
q,
|
||||||
a = ''
|
a = ''
|
||||||
}: {
|
}: {
|
||||||
teamId: string;
|
teamId: string;
|
||||||
|
datasetId: string;
|
||||||
collectionId: string;
|
collectionId: string;
|
||||||
q: string;
|
q: string;
|
||||||
a?: string;
|
a?: string;
|
||||||
}) {
|
}) {
|
||||||
const count = await MongoDatasetData.countDocuments({
|
const count = await MongoDatasetData.countDocuments({
|
||||||
teamId,
|
teamId,
|
||||||
|
datasetId,
|
||||||
collectionId,
|
collectionId,
|
||||||
q,
|
q,
|
||||||
a
|
a
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import axios, {
|
|||||||
AxiosProgressEvent
|
AxiosProgressEvent
|
||||||
} from 'axios';
|
} from 'axios';
|
||||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||||
|
import { putUpdateTeam } from '@/web/support/user/team/api';
|
||||||
|
import { LafAccountType } from '@fastgpt/global/support/user/team/type';
|
||||||
|
|
||||||
interface ConfigType {
|
interface ConfigType {
|
||||||
headers?: { [key: string]: string };
|
headers?: { [key: string]: string };
|
||||||
@ -72,21 +74,33 @@ function responseSuccess(response: AxiosResponse<ResponseDataType>) {
|
|||||||
/**
|
/**
|
||||||
* 响应数据检查
|
* 响应数据检查
|
||||||
*/
|
*/
|
||||||
function checkRes(data: ResponseDataType) {
|
function checkRes(
|
||||||
if (data === undefined) {
|
res: ResponseDataType,
|
||||||
console.log('error->', data, 'data is empty');
|
url: string,
|
||||||
|
data: any,
|
||||||
|
requestConfig: ConfigType,
|
||||||
|
method: Method
|
||||||
|
) {
|
||||||
|
if (res === undefined) {
|
||||||
|
console.log('error->', res, 'res is empty');
|
||||||
return Promise.reject('服务器异常');
|
return Promise.reject('服务器异常');
|
||||||
} else if (data.error) {
|
} else if (res.error) {
|
||||||
return responseError(data.error);
|
return responseError(data.error, url, data, requestConfig, method);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 响应错误
|
* 响应错误
|
||||||
*/
|
*/
|
||||||
function responseError(err: any) {
|
function responseError(
|
||||||
|
err: any,
|
||||||
|
url: string,
|
||||||
|
data: any,
|
||||||
|
requestConfig: ConfigType,
|
||||||
|
method: Method
|
||||||
|
) {
|
||||||
console.log('error->', '请求错误', err);
|
console.log('error->', '请求错误', err);
|
||||||
|
|
||||||
if (!err) {
|
if (!err) {
|
||||||
@ -97,6 +111,25 @@ function responseError(err: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (err?.response?.data) {
|
if (err?.response?.data) {
|
||||||
|
const code = err?.response?.data?.statusCode;
|
||||||
|
if (code === 401) {
|
||||||
|
return POST<string>(`/v1/auth/pat2token`, {
|
||||||
|
pat: useUserStore.getState().userInfo?.team?.lafAccount?.pat
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
putUpdateTeam({
|
||||||
|
teamId: useUserStore.getState().userInfo?.team.teamId || '',
|
||||||
|
lafAccount: {
|
||||||
|
...useUserStore.getState().userInfo?.team?.lafAccount,
|
||||||
|
token: res
|
||||||
|
} as LafAccountType
|
||||||
|
});
|
||||||
|
return request(url, data, requestConfig, method);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
return Promise.reject({ message: '登录凭证过期' });
|
||||||
|
});
|
||||||
|
}
|
||||||
return Promise.reject(err?.response?.data);
|
return Promise.reject(err?.response?.data);
|
||||||
}
|
}
|
||||||
return Promise.reject(err);
|
return Promise.reject(err);
|
||||||
@ -115,12 +148,9 @@ instance.interceptors.request.use(startInterceptors, (err) => Promise.reject(err
|
|||||||
/* 响应拦截 */
|
/* 响应拦截 */
|
||||||
instance.interceptors.response.use(responseSuccess, (err) => Promise.reject(err));
|
instance.interceptors.response.use(responseSuccess, (err) => Promise.reject(err));
|
||||||
|
|
||||||
function request(
|
function request(url: string, data: any, requestConfig: ConfigType, method: Method): any {
|
||||||
url: string,
|
const { cancelToken, maxQuantity, ...config } = requestConfig;
|
||||||
data: any,
|
|
||||||
{ cancelToken, maxQuantity, ...config }: ConfigType,
|
|
||||||
method: Method
|
|
||||||
): any {
|
|
||||||
/* 去空 */
|
/* 去空 */
|
||||||
for (const key in data) {
|
for (const key in data) {
|
||||||
if (data[key] === null || data[key] === undefined) {
|
if (data[key] === null || data[key] === undefined) {
|
||||||
@ -140,8 +170,8 @@ function request(
|
|||||||
signal: cancelToken?.signal,
|
signal: cancelToken?.signal,
|
||||||
...config // 用户自定义配置,可以覆盖前面的配置
|
...config // 用户自定义配置,可以覆盖前面的配置
|
||||||
})
|
})
|
||||||
.then((res) => checkRes(res.data))
|
.then((res) => checkRes(res.data, url, data, requestConfig, method))
|
||||||
.catch((err) => responseError(err))
|
.catch((err) => responseError(err, url, data, requestConfig, method))
|
||||||
.finally(() => requestFinish({ url }));
|
.finally(() => requestFinish({ url }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -51,6 +51,12 @@ export const useSpeech = (props?: OutLinkChatAuthProps & { appId?: string }) =>
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const startSpeak = async (onFinish: (text: string) => void) => {
|
const startSpeak = async (onFinish: (text: string) => void) => {
|
||||||
|
if (!navigator.mediaDevices.getUserMedia) {
|
||||||
|
return toast({
|
||||||
|
status: 'warning',
|
||||||
|
title: t('common.speech.not support')
|
||||||
|
});
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
cancelWhisperSignal.current = false;
|
cancelWhisperSignal.current = false;
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
modules: [
|
modules: [
|
||||||
{
|
{
|
||||||
moduleId: 'userGuide',
|
moduleId: 'userGuide',
|
||||||
name: 'core.module.template.User guide',
|
name: 'core.module.template.App system setting',
|
||||||
avatar: '/imgs/module/userGuide.png',
|
avatar: '/imgs/module/userGuide.png',
|
||||||
flowType: 'userGuide',
|
flowType: 'userGuide',
|
||||||
position: {
|
position: {
|
||||||
@ -300,7 +300,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
modules: [
|
modules: [
|
||||||
{
|
{
|
||||||
moduleId: 'userGuide',
|
moduleId: 'userGuide',
|
||||||
name: 'core.module.template.User guide',
|
name: 'core.module.template.App system setting',
|
||||||
avatar: '/imgs/module/userGuide.png',
|
avatar: '/imgs/module/userGuide.png',
|
||||||
flowType: 'userGuide',
|
flowType: 'userGuide',
|
||||||
position: {
|
position: {
|
||||||
@ -616,7 +616,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
modules: [
|
modules: [
|
||||||
{
|
{
|
||||||
moduleId: 'userGuide',
|
moduleId: 'userGuide',
|
||||||
name: 'core.module.template.User guide',
|
name: 'core.module.template.App system setting',
|
||||||
intro: 'core.app.tip.userGuideTip',
|
intro: 'core.app.tip.userGuideTip',
|
||||||
avatar: '/imgs/module/userGuide.png',
|
avatar: '/imgs/module/userGuide.png',
|
||||||
flowType: 'userGuide',
|
flowType: 'userGuide',
|
||||||
@ -1651,7 +1651,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
moduleId: 'q9equb',
|
moduleId: 'q9equb',
|
||||||
name: 'core.module.template.User guide',
|
name: 'core.module.template.App system setting',
|
||||||
flowType: 'userGuide',
|
flowType: 'userGuide',
|
||||||
position: {
|
position: {
|
||||||
x: -272.66416216517086,
|
x: -272.66416216517086,
|
||||||
|
|||||||
@ -14,7 +14,7 @@ export async function postForm2Modules(data: AppSimpleEditFormType) {
|
|||||||
function userGuideTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
|
function userGuideTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
name: 'core.module.template.User guide',
|
name: '系统配置',
|
||||||
flowType: FlowNodeTypeEnum.userGuide,
|
flowType: FlowNodeTypeEnum.userGuide,
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
.react-flow__panel {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.react-flow__panel.react-flow__attribution {
|
.react-flow__panel.react-flow__attribution {
|
||||||
display: none !important;
|
z-index: 0;
|
||||||
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { GET, POST, PUT } from '@/web/common/api/lafRequest';
|
import { GET, POST } from '@/web/common/api/lafRequest';
|
||||||
|
|
||||||
export const postLafPat2Token = (pat: string) => POST<string>(`/v1/auth/pat2token`, { pat });
|
export const postLafPat2Token = (pat: string) => POST<string>(`/v1/auth/pat2token`, { pat });
|
||||||
|
|
||||||
|
|||||||
@ -92,7 +92,7 @@ docker run -d --name reranker -p 6006:6006 -e ACCESS_TOKEN=mytoken --gpus all re
|
|||||||
version: "3"
|
version: "3"
|
||||||
services:
|
services:
|
||||||
reranker:
|
reranker:
|
||||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/rerank:v0.2
|
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/bge-rerank-base:v0.1
|
||||||
container_name: reranker
|
container_name: reranker
|
||||||
# GPU运行环境,如果宿主机未安装,将deploy配置隐藏即可
|
# GPU运行环境,如果宿主机未安装,将deploy配置隐藏即可
|
||||||
deploy:
|
deploy:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user