mirror of
https://github.com/labring/FastGPT.git
synced 2025-12-25 20:02:47 +00:00
optimize app update time (#6127)
* feat: add chat visibility controls and improve quote reader permissions (#6102) * feat: add chat visibility controls and improve quote reader permissions * fix test * zod * fix * test & openapi * frontend filter * update name * fix * fix * rename variables * fix * test * fix build * fix * fix --------- Co-authored-by: archer <545436317@qq.com> * app update time * recent app * fix * type * fix * context * perf: update app usingtime code * fix: ts * update parent * doc * perf: code per * unauth refresh --------- Co-authored-by: archer <545436317@qq.com>
This commit is contained in:
parent
ab743b9358
commit
f175a1a30c
|
|
@ -437,7 +437,7 @@ import {
|
|||
setAgentRuntimeStop,
|
||||
waitForWorkflowComplete
|
||||
} from '@fastgpt/service/core/workflow/dispatch/workflowStatus';
|
||||
import { StopV2ChatSchema, type StopV2ChatResponse } from '@fastgpt/global/openapi/core/chat/api';
|
||||
import { StopV2ChatSchema, type StopV2ChatResponse } from '@fastgpt/global/openapi/core/chat/controler/api';
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse): Promise<StopV2ChatResponse> {
|
||||
const { appId, chatId, outLinkAuthData } = StopV2ChatSchema.parse(req.body);
|
||||
|
|
@ -527,7 +527,7 @@ LLM 节点,流输出时会同时被终止,但 HTTP 请求节点这种可能
|
|||
|
||||
```typescript
|
||||
import { POST } from '@/web/common/api/request';
|
||||
import type { StopV2ChatParams, StopV2ChatResponse } from '@fastgpt/global/openapi/core/chat/api';
|
||||
import type { StopV2ChatParams, StopV2ChatResponse } from '@fastgpt/global/openapi/core/chat/controler/api';
|
||||
|
||||
/**
|
||||
* 停止 v2 版本工作流运行
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ description: 'FastGPT V4.14.5 更新说明'
|
|||
## 🚀 新增内容
|
||||
|
||||
1. 对话记录使用侧改成软删除,增加从日志管理里删除对话记录。
|
||||
2. 更新Agent/工具时,会更新其上层所有目录的更新时间,以便其会排在列表前面。
|
||||
3. 门户页支持配置单个应用运行可见度配。
|
||||
|
||||
## ⚙️ 优化
|
||||
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@
|
|||
"document/content/docs/upgrading/4-14/4142.mdx": "2025-11-18T19:27:14+08:00",
|
||||
"document/content/docs/upgrading/4-14/4143.mdx": "2025-11-26T20:52:05+08:00",
|
||||
"document/content/docs/upgrading/4-14/4144.mdx": "2025-12-16T14:56:04+08:00",
|
||||
"document/content/docs/upgrading/4-14/4145.mdx": "2025-12-21T19:15:10+08:00",
|
||||
"document/content/docs/upgrading/4-14/4145.mdx": "2025-12-21T23:28:19+08:00",
|
||||
"document/content/docs/upgrading/4-8/40.mdx": "2025-08-02T19:38:37+08:00",
|
||||
"document/content/docs/upgrading/4-8/41.mdx": "2025-08-02T19:38:37+08:00",
|
||||
"document/content/docs/upgrading/4-8/42.mdx": "2025-08-02T19:38:37+08:00",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import type { OpenAPIPath } from '../../type';
|
||||
import { AppLogPath } from './log';
|
||||
import { PublishChannelPath } from './publishChannel';
|
||||
|
||||
export const AppPath: OpenAPIPath = {
|
||||
...AppLogPath
|
||||
...AppLogPath,
|
||||
...PublishChannelPath
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
import { PlaygroundPath } from './playground';
|
||||
|
||||
export const PublishChannelPath = {
|
||||
...PlaygroundPath
|
||||
};
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
import { z } from 'zod';
|
||||
import { ObjectIdSchema } from '../../../../../common/type/mongo';
|
||||
|
||||
// Playground Visibility Config Fields
|
||||
const PlaygroundVisibilityConfigFieldsSchema = z.object({
|
||||
showRunningStatus: z.boolean().meta({
|
||||
example: true,
|
||||
description: '是否显示运行状态'
|
||||
}),
|
||||
showCite: z.boolean().meta({
|
||||
example: true,
|
||||
description: '是否显示引用'
|
||||
}),
|
||||
showFullText: z.boolean().meta({
|
||||
example: true,
|
||||
description: '是否显示全文'
|
||||
}),
|
||||
canDownloadSource: z.boolean().meta({
|
||||
example: true,
|
||||
description: '是否可下载来源'
|
||||
})
|
||||
});
|
||||
|
||||
// Get Playground Visibility Config Parameters
|
||||
export const GetPlaygroundVisibilityConfigParamsSchema = z.object({
|
||||
appId: ObjectIdSchema.meta({
|
||||
example: '68ad85a7463006c963799a05',
|
||||
description: '应用 ID'
|
||||
})
|
||||
});
|
||||
export type GetPlaygroundVisibilityConfigParamsType = z.infer<
|
||||
typeof GetPlaygroundVisibilityConfigParamsSchema
|
||||
>;
|
||||
|
||||
// Playground Visibility Config Response
|
||||
export const PlaygroundVisibilityConfigResponseSchema = PlaygroundVisibilityConfigFieldsSchema;
|
||||
export type PlaygroundVisibilityConfigResponseType = z.infer<
|
||||
typeof PlaygroundVisibilityConfigResponseSchema
|
||||
>;
|
||||
|
||||
// Update Playground Visibility Config Parameters
|
||||
export const UpdatePlaygroundVisibilityConfigParamsSchema = z
|
||||
.object({
|
||||
appId: ObjectIdSchema.meta({
|
||||
example: '68ad85a7463006c963799a05',
|
||||
description: '应用 ID'
|
||||
})
|
||||
})
|
||||
.extend(PlaygroundVisibilityConfigFieldsSchema.shape);
|
||||
export type UpdatePlaygroundVisibilityConfigParamsType = z.infer<
|
||||
typeof UpdatePlaygroundVisibilityConfigParamsSchema
|
||||
>;
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
import { z } from 'zod';
|
||||
import type { OpenAPIPath } from '../../../../type';
|
||||
import {
|
||||
GetPlaygroundVisibilityConfigParamsSchema,
|
||||
PlaygroundVisibilityConfigResponseSchema,
|
||||
UpdatePlaygroundVisibilityConfigParamsSchema
|
||||
} from './api';
|
||||
import { TagsMap } from '../../../../tag';
|
||||
|
||||
export const PlaygroundPath: OpenAPIPath = {
|
||||
'/api/support/outLink/playground/config': {
|
||||
get: {
|
||||
summary: '获取门户配置',
|
||||
description:
|
||||
'获取指定应用的门户聊天界面的可见性配置,包括节点状态、响应详情、全文显示和原始来源显示的设置',
|
||||
tags: [TagsMap.publishChannel],
|
||||
requestParams: {
|
||||
query: GetPlaygroundVisibilityConfigParamsSchema
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: '成功返回门户配置',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: PlaygroundVisibilityConfigResponseSchema
|
||||
}
|
||||
}
|
||||
},
|
||||
400: {
|
||||
description: '请求参数错误',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: z.object({
|
||||
code: z.literal(500),
|
||||
statusText: z.literal('Invalid Params'),
|
||||
message: z.string(),
|
||||
data: z.null()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
401: {
|
||||
description: '用户未授权',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: z.object({
|
||||
code: z.literal(401),
|
||||
statusText: z.literal('unAuthorization'),
|
||||
message: z.string(),
|
||||
data: z.null()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'/api/support/outLink/playground/update': {
|
||||
post: {
|
||||
summary: '更新门户配置',
|
||||
description:
|
||||
'更新指定应用的门户聊天界面的可见性配置,包括节点状态、响应详情、全文显示和原始来源显示的设置。如果配置不存在则创建新配置',
|
||||
tags: [TagsMap.publishChannel],
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: UpdatePlaygroundVisibilityConfigParamsSchema
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: '成功更新门户配置',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: z.null()
|
||||
}
|
||||
}
|
||||
},
|
||||
400: {
|
||||
description: '请求参数错误',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: z.object({
|
||||
code: z.literal(500),
|
||||
statusText: z.literal('Invalid Params'),
|
||||
message: z.string(),
|
||||
data: z.null()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
401: {
|
||||
description: '用户未授权',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: z.object({
|
||||
code: z.literal(401),
|
||||
statusText: z.literal('unAuthorization'),
|
||||
message: z.string(),
|
||||
data: z.null()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1,72 +1,12 @@
|
|||
import { OutLinkChatAuthSchema } from '../../../support/permission/chat/type';
|
||||
import { ObjectIdSchema } from '../../../common/type/mongo';
|
||||
import z from 'zod';
|
||||
|
||||
/* ============ v2/chat/stop ============ */
|
||||
export const StopV2ChatSchema = z
|
||||
.object({
|
||||
/* Recently Used Apps */
|
||||
export const GetRecentlyUsedAppsResponseSchema = z.array(
|
||||
z.object({
|
||||
appId: ObjectIdSchema.describe('应用ID'),
|
||||
chatId: z.string().min(1).describe('对话ID'),
|
||||
outLinkAuthData: OutLinkChatAuthSchema.optional().describe('外链鉴权数据')
|
||||
name: z.string().min(1).describe('应用名称'),
|
||||
avatar: z.string().min(1).describe('应用头像')
|
||||
})
|
||||
.meta({
|
||||
example: {
|
||||
appId: '1234567890',
|
||||
chatId: '1234567890',
|
||||
outLinkAuthData: {
|
||||
shareId: '1234567890',
|
||||
outLinkUid: '1234567890'
|
||||
}
|
||||
}
|
||||
});
|
||||
export type StopV2ChatParams = z.infer<typeof StopV2ChatSchema>;
|
||||
|
||||
export const StopV2ChatResponseSchema = z
|
||||
.object({
|
||||
success: z.boolean().describe('是否成功停止')
|
||||
})
|
||||
.meta({
|
||||
example: {
|
||||
success: true
|
||||
}
|
||||
});
|
||||
export type StopV2ChatResponse = z.infer<typeof StopV2ChatResponseSchema>;
|
||||
|
||||
/* ============ chat file ============ */
|
||||
export const PresignChatFileGetUrlSchema = z
|
||||
.object({
|
||||
key: z.string().min(1).describe('文件key'),
|
||||
appId: ObjectIdSchema.describe('应用ID'),
|
||||
outLinkAuthData: OutLinkChatAuthSchema.optional().describe('外链鉴权数据')
|
||||
})
|
||||
.meta({
|
||||
example: {
|
||||
key: '1234567890',
|
||||
appId: '1234567890',
|
||||
outLinkAuthData: {
|
||||
shareId: '1234567890',
|
||||
outLinkUid: '1234567890'
|
||||
}
|
||||
}
|
||||
});
|
||||
export type PresignChatFileGetUrlParams = z.infer<typeof PresignChatFileGetUrlSchema>;
|
||||
|
||||
export const PresignChatFilePostUrlSchema = z
|
||||
.object({
|
||||
filename: z.string().min(1).describe('文件名'),
|
||||
appId: ObjectIdSchema.describe('应用ID'),
|
||||
chatId: z.string().min(1).describe('对话ID'),
|
||||
outLinkAuthData: OutLinkChatAuthSchema.optional().describe('外链鉴权数据')
|
||||
})
|
||||
.meta({
|
||||
example: {
|
||||
filename: '1234567890',
|
||||
appId: '1234567890',
|
||||
chatId: '1234567890',
|
||||
outLinkAuthData: {
|
||||
shareId: '1234567890',
|
||||
outLinkUid: '1234567890'
|
||||
}
|
||||
}
|
||||
});
|
||||
export type PresignChatFilePostUrlParams = z.infer<typeof PresignChatFilePostUrlSchema>;
|
||||
);
|
||||
export type GetRecentlyUsedAppsResponseType = z.infer<typeof GetRecentlyUsedAppsResponseSchema>;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
import { OutLinkChatAuthSchema } from '../../../../support/permission/chat/type';
|
||||
import { ObjectIdSchema } from '../../../../common/type/mongo';
|
||||
import z from 'zod';
|
||||
|
||||
/* ============ v2/chat/stop ============ */
|
||||
export const StopV2ChatSchema = z
|
||||
.object({
|
||||
appId: ObjectIdSchema.describe('应用ID'),
|
||||
chatId: z.string().min(1).describe('对话ID'),
|
||||
outLinkAuthData: OutLinkChatAuthSchema.optional().describe('外链鉴权数据')
|
||||
})
|
||||
.meta({
|
||||
example: {
|
||||
appId: '1234567890',
|
||||
chatId: '1234567890',
|
||||
outLinkAuthData: {
|
||||
shareId: '1234567890',
|
||||
outLinkUid: '1234567890'
|
||||
}
|
||||
}
|
||||
});
|
||||
export type StopV2ChatParams = z.infer<typeof StopV2ChatSchema>;
|
||||
|
||||
export const StopV2ChatResponseSchema = z
|
||||
.object({
|
||||
success: z.boolean().describe('是否成功停止')
|
||||
})
|
||||
.meta({
|
||||
example: {
|
||||
success: true
|
||||
}
|
||||
});
|
||||
export type StopV2ChatResponse = z.infer<typeof StopV2ChatResponseSchema>;
|
||||
|
||||
/* ============ chat file ============ */
|
||||
export const PresignChatFileGetUrlSchema = z
|
||||
.object({
|
||||
key: z.string().min(1).describe('文件key'),
|
||||
appId: ObjectIdSchema.describe('应用ID'),
|
||||
outLinkAuthData: OutLinkChatAuthSchema.optional().describe('外链鉴权数据')
|
||||
})
|
||||
.meta({
|
||||
example: {
|
||||
key: '1234567890',
|
||||
appId: '1234567890',
|
||||
outLinkAuthData: {
|
||||
shareId: '1234567890',
|
||||
outLinkUid: '1234567890'
|
||||
}
|
||||
}
|
||||
});
|
||||
export type PresignChatFileGetUrlParams = z.infer<typeof PresignChatFileGetUrlSchema>;
|
||||
|
||||
export const PresignChatFilePostUrlSchema = z
|
||||
.object({
|
||||
filename: z.string().min(1).describe('文件名'),
|
||||
appId: ObjectIdSchema.describe('应用ID'),
|
||||
chatId: z.string().min(1).describe('对话ID'),
|
||||
outLinkAuthData: OutLinkChatAuthSchema.optional().describe('外链鉴权数据')
|
||||
})
|
||||
.meta({
|
||||
example: {
|
||||
filename: '1234567890',
|
||||
appId: '1234567890',
|
||||
chatId: '1234567890',
|
||||
outLinkAuthData: {
|
||||
shareId: '1234567890',
|
||||
outLinkUid: '1234567890'
|
||||
}
|
||||
}
|
||||
});
|
||||
export type PresignChatFilePostUrlParams = z.infer<typeof PresignChatFilePostUrlSchema>;
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
import type { OpenAPIPath } from '../../../type';
|
||||
import { TagsMap } from '../../../tag';
|
||||
import {
|
||||
StopV2ChatSchema,
|
||||
StopV2ChatResponseSchema,
|
||||
PresignChatFilePostUrlSchema,
|
||||
PresignChatFileGetUrlSchema
|
||||
} from './api';
|
||||
import { CreatePostPresignedUrlResultSchema } from '../../../../../service/common/s3/type';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const ChatControllerPath: OpenAPIPath = {
|
||||
'/v2/chat/stop': {
|
||||
post: {
|
||||
summary: '停止 Agent 运行',
|
||||
description: `优雅停止正在运行的 Agent, 会尝试等待当前节点结束后返回,最长 5s,超过 5s 仍未结束,则会返回成功。
|
||||
LLM 节点,流输出时会同时被终止,但 HTTP 请求节点这种可能长时间运行的,不会被终止。`,
|
||||
tags: [TagsMap.chatController],
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: StopV2ChatSchema
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: '成功停止工作流',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: StopV2ChatResponseSchema
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'/core/chat/presignChatFilePostUrl': {
|
||||
post: {
|
||||
summary: '获取文件上传 URL',
|
||||
description: '获取文件上传 URL',
|
||||
tags: [TagsMap.chatController],
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: PresignChatFilePostUrlSchema
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: '成功上传对话文件预签名 URL',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: CreatePostPresignedUrlResultSchema
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'/core/chat/presignChatFileGetUrl': {
|
||||
post: {
|
||||
summary: '获取文件预览地址',
|
||||
description: '获取文件预览地址',
|
||||
tags: [TagsMap.chatController],
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: PresignChatFileGetUrlSchema
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: '成功获取对话文件预签名 URL',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: z.string()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -3,89 +3,28 @@ import { ChatSettingPath } from './setting';
|
|||
import { ChatFavouriteAppPath } from './favourite/index';
|
||||
import { ChatFeedbackPath } from './feedback/index';
|
||||
import { ChatHistoryPath } from './history/index';
|
||||
import { z } from 'zod';
|
||||
import { CreatePostPresignedUrlResultSchema } from '../../../../service/common/s3/type';
|
||||
import {
|
||||
PresignChatFileGetUrlSchema,
|
||||
PresignChatFilePostUrlSchema,
|
||||
StopV2ChatSchema,
|
||||
StopV2ChatResponseSchema
|
||||
} from './api';
|
||||
import { GetRecentlyUsedAppsResponseSchema } from './api';
|
||||
import { TagsMap } from '../../tag';
|
||||
import { ChatControllerPath } from './controler';
|
||||
|
||||
export const ChatPath: OpenAPIPath = {
|
||||
...ChatSettingPath,
|
||||
...ChatFavouriteAppPath,
|
||||
...ChatFeedbackPath,
|
||||
...ChatHistoryPath,
|
||||
...ChatControllerPath,
|
||||
|
||||
'/v2/chat/stop': {
|
||||
post: {
|
||||
summary: '停止 Agent 运行',
|
||||
description: `优雅停止正在运行的 Agent, 会尝试等待当前节点结束后返回,最长 5s,超过 5s 仍未结束,则会返回成功。
|
||||
LLM 节点,流输出时会同时被终止,但 HTTP 请求节点这种可能长时间运行的,不会被终止。`,
|
||||
'/core/chat/recentlyUsed': {
|
||||
get: {
|
||||
summary: '获取最近使用的应用',
|
||||
description: '获取最近使用的应用',
|
||||
tags: [TagsMap.chatPage],
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: StopV2ChatSchema
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: '成功停止工作流',
|
||||
description: '成功返回最近使用的应用',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: StopV2ChatResponseSchema
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'/core/chat/presignChatFilePostUrl': {
|
||||
post: {
|
||||
summary: '获取文件上传 URL',
|
||||
description: '获取文件上传 URL',
|
||||
tags: [TagsMap.chatPage],
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: PresignChatFilePostUrlSchema
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: '成功上传对话文件预签名 URL',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: CreatePostPresignedUrlResultSchema
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'/core/chat/presignChatFileGetUrl': {
|
||||
post: {
|
||||
summary: '获取文件预览地址',
|
||||
description: '获取文件预览地址',
|
||||
tags: [TagsMap.chatPage],
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: PresignChatFileGetUrlSchema
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: '成功获取对话文件预签名 URL',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: z.string()
|
||||
schema: GetRecentlyUsedAppsResponseSchema
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export const openAPIDocument = createDocument({
|
|||
'x-tagGroups': [
|
||||
{
|
||||
name: 'Agent 应用',
|
||||
tags: [TagsMap.appLog]
|
||||
tags: [TagsMap.appLog, TagsMap.publishChannel]
|
||||
},
|
||||
{
|
||||
name: '对话管理',
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ export const TagsMap = {
|
|||
appLog: 'Agent 日志',
|
||||
|
||||
// Chat - home
|
||||
chatPage: '对话页操作',
|
||||
chatPage: '对话页',
|
||||
chatController: '对话框操作',
|
||||
chatHistory: '对话历史管理',
|
||||
chatSetting: '门户页配置',
|
||||
chatFeedback: '对话反馈',
|
||||
|
|
@ -13,6 +14,9 @@ export const TagsMap = {
|
|||
pluginToolTag: '工具标签',
|
||||
pluginTeam: '团队插件管理',
|
||||
|
||||
// Publish Channel
|
||||
publishChannel: '发布渠道',
|
||||
|
||||
/* Support */
|
||||
// Wallet
|
||||
walletBill: '订单',
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { z } from 'zod';
|
||||
import type { HistoryItemType } from '../../core/chat/type.d';
|
||||
import type { OutLinkSchema } from './type.d';
|
||||
import type { OutLinkSchema, PlaygroundVisibilityConfigType } from './type.d';
|
||||
import { PlaygroundVisibilityConfigSchema } from './type.d';
|
||||
|
||||
export type AuthOutLinkInitProps = {
|
||||
outLinkUid: string;
|
||||
|
|
@ -10,3 +12,20 @@ export type AuthOutLinkLimitProps = AuthOutLinkChatProps & { outLink: OutLinkSch
|
|||
export type AuthOutLinkResponse = {
|
||||
uid: string;
|
||||
};
|
||||
|
||||
export const UpdatePlaygroundVisibilityConfigBodySchema = PlaygroundVisibilityConfigSchema.extend({
|
||||
appId: z.string().min(1, 'App ID is required')
|
||||
});
|
||||
export type UpdatePlaygroundVisibilityConfigBody = z.infer<
|
||||
typeof UpdatePlaygroundVisibilityConfigBodySchema
|
||||
>;
|
||||
|
||||
export const PlaygroundVisibilityConfigQuerySchema = z.object({
|
||||
appId: z.string().min(1, 'App ID is required')
|
||||
});
|
||||
export type PlaygroundVisibilityConfigQuery = z.infer<typeof PlaygroundVisibilityConfigQuerySchema>;
|
||||
|
||||
export const PlaygroundVisibilityConfigResponseSchema = PlaygroundVisibilityConfigSchema;
|
||||
export type PlaygroundVisibilityConfigResponse = z.infer<
|
||||
typeof PlaygroundVisibilityConfigResponseSchema
|
||||
>;
|
||||
|
|
|
|||
|
|
@ -5,5 +5,6 @@ export enum PublishChannelEnum {
|
|||
feishu = 'feishu',
|
||||
dingtalk = 'dingtalk',
|
||||
wecom = 'wecom',
|
||||
officialAccount = 'official_account'
|
||||
officialAccount = 'official_account',
|
||||
playground = 'playground'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { z } from 'zod';
|
||||
import { AppSchema } from '../../core/app/type';
|
||||
import type { PublishChannelEnum } from './constant';
|
||||
import { RequireOnlyOne } from '../../common/type/utils';
|
||||
|
|
@ -63,14 +64,14 @@ export type OutLinkSchema<T extends OutlinkAppType = undefined> = {
|
|||
lastTime: Date;
|
||||
type: PublishChannelEnum;
|
||||
|
||||
// whether the response content is detailed
|
||||
responseDetail: boolean;
|
||||
// whether to hide the node status
|
||||
showNodeStatus?: boolean;
|
||||
// wheter to show the full text reader
|
||||
// showFullText?: boolean;
|
||||
// whether to show the complete quote
|
||||
showRawSource?: boolean;
|
||||
// whether to show the quote
|
||||
showCite: boolean;
|
||||
// whether to show the running status
|
||||
showRunningStatus: boolean;
|
||||
// whether to show the full text reader
|
||||
showFullText: boolean;
|
||||
// whether can download source
|
||||
canDownloadSource: boolean;
|
||||
|
||||
// response when request
|
||||
immediateResponse?: string;
|
||||
|
|
@ -93,10 +94,10 @@ export type OutLinkSchema<T extends OutlinkAppType = undefined> = {
|
|||
export type OutLinkEditType<T = undefined> = {
|
||||
_id?: string;
|
||||
name: string;
|
||||
responseDetail?: OutLinkSchema<T>['responseDetail'];
|
||||
showNodeStatus?: OutLinkSchema<T>['showNodeStatus'];
|
||||
// showFullText?: OutLinkSchema<T>['showFullText'];
|
||||
showRawSource?: OutLinkSchema<T>['showRawSource'];
|
||||
showCite?: OutLinkSchema<T>['showCite'];
|
||||
showRunningStatus?: OutLinkSchema<T>['showRunningStatus'];
|
||||
showFullText?: OutLinkSchema<T>['showFullText'];
|
||||
canDownloadSource?: OutLinkSchema<T>['canDownloadSource'];
|
||||
// response when request
|
||||
immediateResponse?: string;
|
||||
// response when error or other situation
|
||||
|
|
@ -106,3 +107,12 @@ export type OutLinkEditType<T = undefined> = {
|
|||
// config for specific platform
|
||||
app?: T;
|
||||
};
|
||||
|
||||
export const PlaygroundVisibilityConfigSchema = z.object({
|
||||
showRunningStatus: z.boolean(),
|
||||
showCite: z.boolean(),
|
||||
showFullText: z.boolean(),
|
||||
canDownloadSource: z.boolean()
|
||||
});
|
||||
|
||||
export type PlaygroundVisibilityConfigType = z.infer<typeof PlaygroundVisibilityConfigSchema>;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ import { getS3ChatSource } from '../../common/s3/sources/chat';
|
|||
import { MongoAppChatLog } from './logs/chatLogsSchema';
|
||||
import { MongoAppRegistration } from '../../support/appRegistration/schema';
|
||||
import { MongoMcpKey } from '../../support/mcp/schema';
|
||||
import { MongoAppRecord } from './record/schema';
|
||||
import { mongoSessionRun } from '../../common/mongo/sessionRun';
|
||||
import { addLog } from '../../common/system/log';
|
||||
|
||||
export const beforeUpdateAppFormat = ({ nodes }: { nodes?: StoreNodeItemType[] }) => {
|
||||
if (!nodes) return;
|
||||
|
|
@ -203,4 +206,29 @@ export const deleteAppsImmediate = async ({
|
|||
'_id'
|
||||
).lean();
|
||||
await Promise.all(evalJobs.map((evalJob) => removeEvaluationJob(evalJob._id)));
|
||||
|
||||
// Remove app record
|
||||
await MongoAppRecord.deleteMany({ teamId, appId: { $in: appIds } });
|
||||
};
|
||||
|
||||
export const updateParentFoldersUpdateTime = ({ parentId }: { parentId?: string | null }) => {
|
||||
mongoSessionRun(async (session) => {
|
||||
const existsId = new Set<string>();
|
||||
while (true) {
|
||||
if (!parentId || existsId.has(parentId)) return;
|
||||
|
||||
existsId.add(parentId);
|
||||
|
||||
const parentApp = await MongoApp.findById(parentId, 'parentId updateTime');
|
||||
if (!parentApp) return;
|
||||
|
||||
parentApp.updateTime = new Date();
|
||||
await parentApp.save({ session });
|
||||
|
||||
// 递归更新上层
|
||||
parentId = parentApp.parentId;
|
||||
}
|
||||
}).catch((err) => {
|
||||
addLog.error('updateParentFoldersUpdateTime error', err);
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
import {
|
||||
TeamCollectionName,
|
||||
TeamMemberCollectionName
|
||||
} from '@fastgpt/global/support/user/team/constant';
|
||||
import { getMongoModel, Schema } from '../../../common/mongo';
|
||||
import { AppCollectionName } from '../schema';
|
||||
import type { AppRecordType } from './type';
|
||||
|
||||
export const AppRecordCollectionName = 'app_records';
|
||||
|
||||
const AppRecordSchema = new Schema(
|
||||
{
|
||||
tmbId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: TeamMemberCollectionName,
|
||||
required: true
|
||||
},
|
||||
teamId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: TeamCollectionName,
|
||||
required: true
|
||||
},
|
||||
appId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: AppCollectionName,
|
||||
required: true
|
||||
},
|
||||
lastUsedTime: {
|
||||
type: Date,
|
||||
default: () => new Date()
|
||||
}
|
||||
},
|
||||
{
|
||||
timestamps: false
|
||||
}
|
||||
);
|
||||
|
||||
AppRecordSchema.index({ tmbId: 1, lastUsedTime: -1 }); // 查询用户最近使用的应用
|
||||
AppRecordSchema.index({ tmbId: 1, appId: 1 }, { unique: true }); // 防止重复记录
|
||||
AppRecordSchema.index({ teamId: 1, appId: 1 }); // 用于清理权限失效的记录
|
||||
|
||||
export const MongoAppRecord = getMongoModel<AppRecordType>(
|
||||
AppRecordCollectionName,
|
||||
AppRecordSchema
|
||||
);
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
export const AppRecordSchemaZod = z.object({
|
||||
_id: z.string(),
|
||||
tmbId: z.string(),
|
||||
teamId: z.string(),
|
||||
appId: z.string(),
|
||||
lastUsedTime: z.date()
|
||||
});
|
||||
|
||||
// TypeScript types inferred from Zod schemas
|
||||
export type AppRecordType = z.infer<typeof AppRecordSchemaZod>;
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import { MongoAppRecord } from './schema';
|
||||
import { addLog } from '../../../common/system/log';
|
||||
|
||||
export const recordAppUsage = async ({
|
||||
appId,
|
||||
tmbId,
|
||||
teamId
|
||||
}: {
|
||||
appId: string;
|
||||
tmbId: string;
|
||||
teamId: string;
|
||||
}) => {
|
||||
await MongoAppRecord.updateOne(
|
||||
{ tmbId, appId },
|
||||
{
|
||||
$set: {
|
||||
teamId,
|
||||
lastUsedTime: new Date()
|
||||
}
|
||||
},
|
||||
{
|
||||
upsert: true
|
||||
}
|
||||
).catch((error) => {
|
||||
addLog.error('recordAppUsage error', error);
|
||||
});
|
||||
};
|
||||
|
|
@ -35,7 +35,6 @@ export type Props = {
|
|||
nodes: StoreNodeItemType[];
|
||||
appChatConfig?: AppChatConfigType;
|
||||
variables?: Record<string, any>;
|
||||
isUpdateUseTime: boolean;
|
||||
newTitle: string;
|
||||
source: `${ChatSourceEnum}`;
|
||||
sourceName?: string;
|
||||
|
|
@ -219,7 +218,6 @@ export async function saveChat(props: Props) {
|
|||
nodes,
|
||||
appChatConfig,
|
||||
variables,
|
||||
isUpdateUseTime,
|
||||
newTitle,
|
||||
source,
|
||||
sourceName,
|
||||
|
|
@ -393,18 +391,6 @@ export async function saveChat(props: Props) {
|
|||
} catch (error) {
|
||||
addLog.error('Push chat log error', error);
|
||||
}
|
||||
|
||||
if (isUpdateUseTime) {
|
||||
await MongoApp.updateOne(
|
||||
{ _id: appId },
|
||||
{
|
||||
updateTime: new Date()
|
||||
},
|
||||
{
|
||||
...writePrimary
|
||||
}
|
||||
).catch();
|
||||
}
|
||||
} catch (error) {
|
||||
addLog.error(`update chat history error`, error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,19 +43,21 @@ const OutLinkSchema = new Schema({
|
|||
type: Date
|
||||
},
|
||||
|
||||
responseDetail: {
|
||||
showRunningStatus: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showNodeStatus: {
|
||||
showCite: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
default: false
|
||||
},
|
||||
// showFullText: {
|
||||
// type: Boolean
|
||||
// },
|
||||
showRawSource: {
|
||||
type: Boolean
|
||||
showFullText: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
canDownloadSource: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
limit: {
|
||||
maxUsagePoints: {
|
||||
|
|
|
|||
|
|
@ -17,12 +17,14 @@ export function useLinkedScroll<
|
|||
pageSize = 10,
|
||||
params = {},
|
||||
currentData,
|
||||
defaultScroll = 'top'
|
||||
defaultScroll = 'top',
|
||||
showErrorToast = true
|
||||
}: {
|
||||
pageSize?: number;
|
||||
params?: Record<string, any>;
|
||||
currentData?: { id: string; anchor?: any };
|
||||
defaultScroll?: 'top' | 'bottom';
|
||||
showErrorToast?: boolean;
|
||||
}
|
||||
) {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -105,7 +107,8 @@ export function useLinkedScroll<
|
|||
onFinally() {
|
||||
isInit.current = true;
|
||||
},
|
||||
manual: false
|
||||
manual: false,
|
||||
errorToast: showErrorToast ? undefined : ''
|
||||
}
|
||||
);
|
||||
useEffect(() => {
|
||||
|
|
@ -153,7 +156,8 @@ export function useLinkedScroll<
|
|||
return response;
|
||||
},
|
||||
{
|
||||
refreshDeps: [hasMorePrev, isLoading, params, pageSize]
|
||||
refreshDeps: [hasMorePrev, isLoading, params, pageSize],
|
||||
errorToast: showErrorToast ? undefined : ''
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -188,7 +192,8 @@ export function useLinkedScroll<
|
|||
return response;
|
||||
},
|
||||
{
|
||||
refreshDeps: [hasMoreNext, isLoading, params, pageSize]
|
||||
refreshDeps: [hasMoreNext, isLoading, params, pageSize],
|
||||
errorToast: showErrorToast ? undefined : ''
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ export function useScrollPagination<
|
|||
} catch (error: any) {
|
||||
if (showErrorToast) {
|
||||
toast({
|
||||
title: getErrText(error, t('common:core.chat.error.data_error')),
|
||||
title: t(getErrText(error, t('common:core.chat.error.data_error'))),
|
||||
status: 'error'
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -301,6 +301,8 @@
|
|||
"pro_modal_subtitle": "Join the business edition now to unlock more premium features",
|
||||
"pro_modal_title": "Business Edition Exclusive!",
|
||||
"pro_modal_unlock_button": "Unlock Now",
|
||||
"publish.chat_desc": "After logging into the portal, users can talk directly to the application",
|
||||
"publish.playground_link": "Redirect Link",
|
||||
"publish_channel": "Publish",
|
||||
"publish_success": "Publish Successful",
|
||||
"question_guide_tip": "After the conversation, 3 guiding questions will be generated for you.",
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@
|
|||
"core.ai.model.Vector Model": "Index model",
|
||||
"core.ai.model.doc_index_and_dialog": "Document Index & Dialog Index",
|
||||
"core.app.Api request": "API Request",
|
||||
"core.app.Api request desc": "Integrate into existing systems through API, or WeChat Work, Feishu, etc.",
|
||||
"core.app.Api request desc": "Connect to existing systems via API",
|
||||
"core.app.App intro": "App Introduction",
|
||||
"core.app.Auto execute": "Auto execute",
|
||||
"core.app.Chat Variable": "Chat Variable",
|
||||
|
|
@ -264,7 +264,7 @@
|
|||
"core.app.Set a name for your app": "Set a Name for Your App",
|
||||
"core.app.Setting ai property": "Click to Configure AI Model Properties",
|
||||
"core.app.Share link": "Login-Free Window",
|
||||
"core.app.Share link desc": "Share the link with other users, they can use it directly without logging in",
|
||||
"core.app.Share link desc": "Create shareable links and support login-free use",
|
||||
"core.app.Share link desc detail": "You can directly share this model with other users for conversation, they can use it directly without logging in. Note, this feature will consume your account balance, please keep the link safe!",
|
||||
"core.app.TTS": "Voice Playback",
|
||||
"core.app.TTS Tip": "After enabling, you can use the voice playback function after each conversation. Using this feature may incur additional costs.",
|
||||
|
|
@ -315,6 +315,7 @@
|
|||
"core.app.share.Amount limit tip": "Up to 10 groups",
|
||||
"core.app.share.Create link": "Create New Link",
|
||||
"core.app.share.Create link tip": "Creation successful. The share address has been copied and can be shared directly.",
|
||||
"core.app.share.Download source": "Download/open source original text",
|
||||
"core.app.share.Ip limit title": "IP Rate Limit (people/minute)",
|
||||
"core.app.share.Is response quote": "Return Quote",
|
||||
"core.app.share.Not share link": "No Share Link Created",
|
||||
|
|
@ -1102,9 +1103,11 @@
|
|||
"support.outlink.Max usage points tip": "The maximum number of points allowed for this link. It cannot be used after exceeding the limit. -1 means unlimited.",
|
||||
"support.outlink.Usage points": "Points Consumption",
|
||||
"support.outlink.share.Chat_quote_reader": "Full text reader",
|
||||
"support.outlink.share.Download source tips": "Download the original file of the knowledge base, or jump to the source website",
|
||||
"support.outlink.share.Full_text tips": "Allows reading of the complete dataset from which the referenced fragment is derived",
|
||||
"support.outlink.share.Response Quote": "Return Quote",
|
||||
"support.outlink.share.Response Quote": "View quoted snippets",
|
||||
"support.outlink.share.Response Quote tips": "Return quoted content in the share link, but do not allow users to download the original document",
|
||||
"support.outlink.share.Show full text tips": "View the complete file to which the quoted content belongs. You cannot view the original file or jump to the source website.",
|
||||
"support.outlink.share.running_node": "Running node",
|
||||
"support.outlink.share.show_complete_quote": "View original source",
|
||||
"support.outlink.share.show_complete_quote_tips": "View and download the complete citation document, or jump to the citation website",
|
||||
|
|
|
|||
|
|
@ -313,6 +313,8 @@
|
|||
"pro_modal_subtitle": "即刻加入商业版,解锁更多高级功能",
|
||||
"pro_modal_title": "商业版专享!",
|
||||
"pro_modal_unlock_button": "去解锁",
|
||||
"publish.chat_desc": "用户登录门户后可直接与应用对话",
|
||||
"publish.playground_link": "跳转链接",
|
||||
"publish_channel": "发布渠道",
|
||||
"publish_channel.wecom.empty": "发布到企业微信机器人,请先 <a>绑定自定义域名</a>,并且通过域名校验。",
|
||||
"publish_success": "发布成功",
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@
|
|||
"core.ai.model.Vector Model": "索引模型",
|
||||
"core.ai.model.doc_index_and_dialog": "文档索引 & 对话索引",
|
||||
"core.app.Api request": "API 访问",
|
||||
"core.app.Api request desc": "通过 API 接入到已有系统中,或企微、飞书等",
|
||||
"core.app.Api request desc": "通过 API 接入已有系统",
|
||||
"core.app.App intro": "应用介绍",
|
||||
"core.app.Auto execute": "自动执行",
|
||||
"core.app.Chat Variable": "对话框变量",
|
||||
|
|
@ -267,7 +267,7 @@
|
|||
"core.app.Set a name for your app": "给应用设置一个名称",
|
||||
"core.app.Setting ai property": "点击配置 AI 模型相关属性",
|
||||
"core.app.Share link": "免登录窗口",
|
||||
"core.app.Share link desc": "分享链接给其他用户,无需登录即可直接进行使用",
|
||||
"core.app.Share link desc": "创建可分享的链接,支持免登录使用",
|
||||
"core.app.Share link desc detail": "可以直接分享该模型给其他用户去进行对话,对方无需登录即可直接进行对话。注意,这个功能会消耗你账号的余额,请保管好链接!",
|
||||
"core.app.TTS": "语音播放",
|
||||
"core.app.TTS Tip": "开启后,每次对话后可使用语音播放功能。使用该功能可能产生额外费用。",
|
||||
|
|
@ -318,10 +318,12 @@
|
|||
"core.app.share.Amount limit tip": "最多创建 10 组",
|
||||
"core.app.share.Create link": "创建新链接",
|
||||
"core.app.share.Create link tip": "创建成功。已复制分享地址,可直接分享使用",
|
||||
"core.app.share.Download source": "下载/打开来源原文",
|
||||
"core.app.share.Ip limit title": "IP 限流(人/分钟)",
|
||||
"core.app.share.Is response quote": "返回引用",
|
||||
"core.app.share.Not share link": "没有创建分享链接",
|
||||
"core.app.share.Role check": "身份校验",
|
||||
"core.app.share.Show full text": "查看引用全文",
|
||||
"core.app.switch_to_template_market": "跳转模板市场",
|
||||
"core.app.tip.Add a intro to app": "快来给应用一个介绍~",
|
||||
"core.app.tip.chatNodeSystemPromptTip": "在此输入提示词",
|
||||
|
|
@ -1110,9 +1112,11 @@
|
|||
"support.outlink.Max usage points tip": "该链接最多允许使用多少积分,超出后将无法使用。-1 代表无限制。",
|
||||
"support.outlink.Usage points": "积分消耗",
|
||||
"support.outlink.share.Chat_quote_reader": "全文阅读器",
|
||||
"support.outlink.share.Download source tips": "下载知识库原文件,或跳转来源网站",
|
||||
"support.outlink.share.Full_text tips": "允许阅读该引用片段来源的完整数据集",
|
||||
"support.outlink.share.Response Quote": "引用内容",
|
||||
"support.outlink.share.Response Quote": "查看引用片段",
|
||||
"support.outlink.share.Response Quote tips": "查看知识库搜索的引用内容,不可查看完整引用文档或跳转引用网站",
|
||||
"support.outlink.share.Show full text tips": "查看引用内容所属的完整文件,不可查看原文件或跳转来来源网站",
|
||||
"support.outlink.share.running_node": "运行节点",
|
||||
"support.outlink.share.show_complete_quote": "查看来源原文",
|
||||
"support.outlink.share.show_complete_quote_tips": "查看及下载完整引用文档,或跳转引用网站",
|
||||
|
|
|
|||
|
|
@ -299,6 +299,8 @@
|
|||
"pro_modal_subtitle": "即刻加入商業版,解鎖更多高級功能",
|
||||
"pro_modal_title": "商業版專享!",
|
||||
"pro_modal_unlock_button": "去解鎖",
|
||||
"publish.chat_desc": "用戶登錄門戶後可直接與應用對話",
|
||||
"publish.playground_link": "跳轉鏈接",
|
||||
"publish_channel": "發布通道",
|
||||
"publish_success": "發布成功",
|
||||
"question_guide_tip": "對話結束後,會為你產生 3 個引導性問題。",
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@
|
|||
"core.ai.model.Vector Model": "索引模型",
|
||||
"core.ai.model.doc_index_and_dialog": "文件索引與對話索引",
|
||||
"core.app.Api request": "API 存取",
|
||||
"core.app.Api request desc": "透過 API 整合到現有系統中,或整合到企業微信、飛書等",
|
||||
"core.app.Api request desc": "通過 API 接入已有系統",
|
||||
"core.app.App intro": "應用程式介紹",
|
||||
"core.app.Auto execute": "自動執行",
|
||||
"core.app.Chat Variable": "對話變數",
|
||||
|
|
@ -264,7 +264,7 @@
|
|||
"core.app.Set a name for your app": "為您的應用程式命名",
|
||||
"core.app.Setting ai property": "點選設定 AI 模型相關屬性",
|
||||
"core.app.Share link": "免登入視窗",
|
||||
"core.app.Share link desc": "分享連結給其他使用者,無需登入即可直接使用",
|
||||
"core.app.Share link desc": "創建可分享的鏈接,支持免登錄使用",
|
||||
"core.app.Share link desc detail": "您可以直接分享此模型給其他使用者進行對話,對方無需登入即可直接使用。請注意,此功能會消耗您帳戶的餘額,請妥善保管連結!",
|
||||
"core.app.TTS": "語音播放",
|
||||
"core.app.TTS Tip": "開啟後,每次對話後可使用語音播放功能。使用此功能可能會產生額外費用。",
|
||||
|
|
@ -315,6 +315,7 @@
|
|||
"core.app.share.Amount limit tip": "最多 10 組",
|
||||
"core.app.share.Create link": "建立新連結",
|
||||
"core.app.share.Create link tip": "建立成功。已複製分享網址,可直接分享使用",
|
||||
"core.app.share.Download source": "下載/打開來源原文",
|
||||
"core.app.share.Ip limit title": "IP 限流(人/分鐘)",
|
||||
"core.app.share.Is response quote": "返回引用",
|
||||
"core.app.share.Not share link": "尚未建立分享連結",
|
||||
|
|
@ -1099,9 +1100,11 @@
|
|||
"support.outlink.Max usage points tip": "此連結最多允許使用多少點數,超出後將無法使用。-1 代表無限制。",
|
||||
"support.outlink.Usage points": "點數消耗",
|
||||
"support.outlink.share.Chat_quote_reader": "全文閱讀器",
|
||||
"support.outlink.share.Download source tips": "下載知識庫原文件,或跳轉來源網站",
|
||||
"support.outlink.share.Full_text tips": "允許閱讀該引用片段來源的完整資料集",
|
||||
"support.outlink.share.Response Quote": "回傳引用",
|
||||
"support.outlink.share.Response Quote": "查看引用片段",
|
||||
"support.outlink.share.Response Quote tips": "在分享連結中回傳引用內容,但不允許使用者下載原始文件",
|
||||
"support.outlink.share.Show full text tips": "查看引用內容所屬的完整文件,不可查看原文件或跳轉來來源網站",
|
||||
"support.outlink.share.running_node": "執行節點",
|
||||
"support.outlink.share.show_complete_quote": "檢視原始內容",
|
||||
"support.outlink.share.show_complete_quote_tips": "檢視及下載完整引用文件,或跳轉至引用網站",
|
||||
|
|
|
|||
|
|
@ -163,12 +163,12 @@ const ChatItem = (props: Props) => {
|
|||
|
||||
const isChatting = useContextSelector(ChatBoxContext, (v) => v.isChatting);
|
||||
const chatType = useContextSelector(ChatBoxContext, (v) => v.chatType);
|
||||
const showNodeStatus = useContextSelector(ChatItemContext, (v) => v.showNodeStatus);
|
||||
const showRunningStatus = useContextSelector(ChatItemContext, (v) => v.showRunningStatus);
|
||||
|
||||
const appId = useContextSelector(WorkflowRuntimeContext, (v) => v.appId);
|
||||
const chatId = useContextSelector(WorkflowRuntimeContext, (v) => v.chatId);
|
||||
const outLinkAuthData = useContextSelector(WorkflowRuntimeContext, (v) => v.outLinkAuthData);
|
||||
const isShowReadRawSource = useContextSelector(ChatItemContext, (v) => v.isShowReadRawSource);
|
||||
const isShowFullText = useContextSelector(ChatItemContext, (v) => v.isShowFullText);
|
||||
|
||||
const { totalQuoteList: quoteList = [] } = useMemo(
|
||||
() => addStatisticalDataToHistoryItem(chat),
|
||||
|
|
@ -258,7 +258,7 @@ const ChatItem = (props: Props) => {
|
|||
setCiteModalData({
|
||||
rawSearch: quoteList,
|
||||
metadata:
|
||||
item?.collectionId && isShowReadRawSource
|
||||
item?.collectionId && isShowFullText
|
||||
? {
|
||||
appId: appId,
|
||||
chatId: chatId,
|
||||
|
|
@ -322,7 +322,7 @@ const ChatItem = (props: Props) => {
|
|||
<ChatAvatar src={avatar} type={type} />
|
||||
|
||||
{/* Workflow status */}
|
||||
{!!chatStatusMap && statusBoxData && isLastChild && showNodeStatus && (
|
||||
{!!chatStatusMap && statusBoxData && isLastChild && showRunningStatus && (
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
px={3}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ const QuoteList = React.memo(function QuoteList({
|
|||
chatId: v.chatId,
|
||||
...(v.outLinkAuthData || {})
|
||||
}));
|
||||
const showRawSource = useContextSelector(ChatItemContext, (v) => v.isShowReadRawSource);
|
||||
const canDownloadSource = useContextSelector(ChatItemContext, (v) => v.canDownloadSource);
|
||||
const showRouteToDatasetDetail = useContextSelector(
|
||||
ChatItemContext,
|
||||
(v) => v.showRouteToDatasetDetail
|
||||
|
|
@ -87,7 +87,7 @@ const QuoteList = React.memo(function QuoteList({
|
|||
>
|
||||
<QuoteItem
|
||||
quoteItem={item}
|
||||
canViewSource={showRawSource}
|
||||
canDownloadSource={canDownloadSource}
|
||||
canEditData={showRouteToDatasetDetail}
|
||||
canEditDataset={showRouteToDatasetDetail}
|
||||
{...RawSourceBoxProps}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { addStatisticalDataToHistoryItem } from '@/global/core/chat/utils';
|
|||
import { useSize } from 'ahooks';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { ChatBoxContext } from '../Provider';
|
||||
import { ChatItemContext } from '@/web/core/chat/context/chatItemContext';
|
||||
|
||||
export type CitationRenderItem = {
|
||||
type: 'dataset' | 'link';
|
||||
|
|
@ -48,12 +49,22 @@ const ResponseTags = ({
|
|||
|
||||
const chatTime = historyItem.time || new Date();
|
||||
const durationSeconds = historyItem.durationSeconds || 0;
|
||||
const isShowCite = useContextSelector(ChatItemContext, (v) => v.isShowCite);
|
||||
const {
|
||||
totalQuoteList: quoteList = [],
|
||||
llmModuleAccount = 0,
|
||||
historyPreviewLength = 0,
|
||||
toolCiteLinks = []
|
||||
} = useMemo(() => addStatisticalDataToHistoryItem(historyItem), [historyItem]);
|
||||
} = useMemo(() => {
|
||||
return {
|
||||
...addStatisticalDataToHistoryItem(historyItem),
|
||||
...(isShowCite
|
||||
? {
|
||||
totalQuoteList: []
|
||||
}
|
||||
: {})
|
||||
};
|
||||
}, [historyItem, isShowCite]);
|
||||
|
||||
const [quoteFolded, setQuoteFolded] = useState<boolean>(true);
|
||||
|
||||
|
|
@ -78,6 +89,7 @@ const ResponseTags = ({
|
|||
: true;
|
||||
|
||||
const citationRenderList: CitationRenderItem[] = useMemo(() => {
|
||||
if (!isShowCite) return [];
|
||||
// Dataset citations
|
||||
const datasetItems = Object.values(
|
||||
quoteList.reduce((acc: Record<string, SearchDataResponseItemType[]>, cur) => {
|
||||
|
|
@ -116,7 +128,7 @@ const ResponseTags = ({
|
|||
}));
|
||||
|
||||
return [...datasetItems, ...linkItems];
|
||||
}, [quoteList, toolCiteLinks, onOpenCiteModal]);
|
||||
}, [quoteList, toolCiteLinks, onOpenCiteModal, isShowCite]);
|
||||
|
||||
const notEmptyTags = notSharePage || quoteList.length > 0 || (isPc && durationSeconds > 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -31,9 +31,13 @@ import { eventBus, EventNameEnum } from '@/web/common/utils/eventbus';
|
|||
import { SelectOptionsComponent, FormInputComponent } from './Interactive/InteractiveComponents';
|
||||
import { extractDeepestInteractive } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { type OnOpenCiteModalProps } from '@/web/core/chat/context/chatItemContext';
|
||||
import {
|
||||
type OnOpenCiteModalProps,
|
||||
ChatItemContext
|
||||
} from '@/web/core/chat/context/chatItemContext';
|
||||
import { WorkflowRuntimeContext } from '../ChatContainer/context/workflowRuntimeContext';
|
||||
import { useCreation } from 'ahooks';
|
||||
import { removeDatasetCiteText } from '@fastgpt/global/core/ai/llm/utils';
|
||||
|
||||
const accordionButtonStyle = {
|
||||
w: 'auto',
|
||||
|
|
@ -102,13 +106,16 @@ const RenderText = React.memo(function RenderText({
|
|||
const appId = useContextSelector(WorkflowRuntimeContext, (v) => v.appId);
|
||||
const chatId = useContextSelector(WorkflowRuntimeContext, (v) => v.chatId);
|
||||
const outLinkAuthData = useContextSelector(WorkflowRuntimeContext, (v) => v.outLinkAuthData);
|
||||
const isShowCite = useContextSelector(ChatItemContext, (v) => v.isShowCite);
|
||||
|
||||
const source = useMemo(() => {
|
||||
if (!text) return '';
|
||||
|
||||
// Remove quote references if not showing response detail
|
||||
return text;
|
||||
}, [text]);
|
||||
if (isShowCite) {
|
||||
return text;
|
||||
}
|
||||
return removeDatasetCiteText(text, isShowCite);
|
||||
}, [text, isShowCite]);
|
||||
|
||||
const chatAuthData = useCreation(() => {
|
||||
return { appId, chatId, chatItemDataId, ...outLinkAuthData };
|
||||
|
|
@ -329,6 +336,8 @@ const AIResponseBox = ({
|
|||
isChatting: boolean;
|
||||
onOpenCiteModal?: (e?: OnOpenCiteModalProps) => void;
|
||||
}) => {
|
||||
const showRunningStatus = useContextSelector(ChatItemContext, (v) => v.showRunningStatus);
|
||||
|
||||
if (value.type === ChatItemValueTypeEnum.text && value.text) {
|
||||
return (
|
||||
<RenderText
|
||||
|
|
@ -348,7 +357,7 @@ const AIResponseBox = ({
|
|||
/>
|
||||
);
|
||||
}
|
||||
if (value.type === ChatItemValueTypeEnum.tool && value.tools) {
|
||||
if (value.type === ChatItemValueTypeEnum.tool && value.tools && showRunningStatus) {
|
||||
return <RenderTool showAnimation={isChatting} tools={value.tools} />;
|
||||
}
|
||||
if (value.type === ChatItemValueTypeEnum.interactive && value.interactive) {
|
||||
|
|
|
|||
|
|
@ -91,13 +91,13 @@ export const formatScore = (score: ScoreItemType[]) => {
|
|||
|
||||
const QuoteItem = ({
|
||||
quoteItem,
|
||||
canViewSource,
|
||||
canDownloadSource,
|
||||
canEditData,
|
||||
canEditDataset,
|
||||
...RawSourceBoxProps
|
||||
}: {
|
||||
quoteItem: SearchDataResponseItemType;
|
||||
canViewSource?: boolean;
|
||||
canDownloadSource?: boolean;
|
||||
canEditData?: boolean;
|
||||
canEditDataset?: boolean;
|
||||
} & Omit<readCollectionSourceBody, 'collectionId'>) => {
|
||||
|
|
@ -208,7 +208,7 @@ const QuoteItem = ({
|
|||
collectionId={quoteItem.collectionId}
|
||||
sourceName={quoteItem.sourceName}
|
||||
sourceId={quoteItem.sourceId}
|
||||
canView={canViewSource}
|
||||
canView={canDownloadSource}
|
||||
{...RawSourceBoxProps}
|
||||
/>
|
||||
<Box flex={1} />
|
||||
|
|
|
|||
|
|
@ -205,10 +205,10 @@ const Render = ({
|
|||
return (
|
||||
<ChatItemContextProvider
|
||||
showRouteToDatasetDetail={true}
|
||||
isShowReadRawSource={true}
|
||||
isResponseDetail={true}
|
||||
// isShowFullText={true}
|
||||
showNodeStatus
|
||||
canDownloadSource={true}
|
||||
isShowCite={true}
|
||||
isShowFullText={true}
|
||||
showRunningStatus={true}
|
||||
>
|
||||
<ChatRecordContextProvider params={chatRecordProviderParams}>
|
||||
<ChatTest
|
||||
|
|
|
|||
|
|
@ -264,10 +264,10 @@ const Render = (props: Props) => {
|
|||
return (
|
||||
<ChatItemContextProvider
|
||||
showRouteToDatasetDetail={true}
|
||||
isShowReadRawSource={true}
|
||||
isResponseDetail={true}
|
||||
// isShowFullText={true}
|
||||
showNodeStatus
|
||||
canDownloadSource={true}
|
||||
isShowCite={true}
|
||||
isShowFullText={true}
|
||||
showRunningStatus={true}
|
||||
>
|
||||
<ChatRecordContextProvider params={params} feedbackRecordId={feedbackRecordId}>
|
||||
<DetailLogsModal
|
||||
|
|
|
|||
|
|
@ -182,10 +182,10 @@ const Render = ({
|
|||
return (
|
||||
<ChatItemContextProvider
|
||||
showRouteToDatasetDetail={true}
|
||||
isShowReadRawSource={true}
|
||||
isResponseDetail={true}
|
||||
// isShowFullText={true}
|
||||
showNodeStatus
|
||||
canDownloadSource={true}
|
||||
isShowCite={true}
|
||||
isShowFullText={true}
|
||||
showRunningStatus={true}
|
||||
>
|
||||
<ChatRecordContextProvider params={chatRecordProviderParams}>
|
||||
<ChatTest currentTool={currentTool} url={url} headerSecret={headerSecret} />
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ const DingTalk = ({ appId }: { appId: string }) => {
|
|||
name: item.name,
|
||||
limit: item.limit,
|
||||
app: item.app,
|
||||
responseDetail: item.responseDetail,
|
||||
showCite: item.showCite,
|
||||
defaultResponse: item.defaultResponse,
|
||||
immediateResponse: item.immediateResponse
|
||||
});
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ const FeiShu = ({ appId }: { appId: string }) => {
|
|||
name: item.name,
|
||||
limit: item.limit,
|
||||
app: item.app,
|
||||
responseDetail: item.responseDetail,
|
||||
showCite: item.showCite,
|
||||
defaultResponse: item.defaultResponse,
|
||||
immediateResponse: item.immediateResponse
|
||||
});
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ const Share = ({ appId }: { appId: string; type: PublishChannelEnum }) => {
|
|||
}`
|
||||
: ''}
|
||||
</Td>
|
||||
<Td>{item.responseDetail ? '✔' : '✖'}</Td>
|
||||
<Td>{item.showCite ? '✔' : '✖'}</Td>
|
||||
{feConfigs?.isPlus && (
|
||||
<>
|
||||
<Td>{item?.limit?.QPM || '-'}</Td>
|
||||
|
|
@ -182,10 +182,10 @@ const Share = ({ appId }: { appId: string; type: PublishChannelEnum }) => {
|
|||
setEditLinkData({
|
||||
_id: item._id,
|
||||
name: item.name,
|
||||
responseDetail: item.responseDetail ?? false,
|
||||
showRawSource: item.showRawSource ?? false,
|
||||
// showFullText: item.showFullText ?? false,
|
||||
showNodeStatus: item.showNodeStatus ?? false,
|
||||
showCite: item.showCite,
|
||||
canDownloadSource: item.canDownloadSource,
|
||||
showFullText: item.showFullText,
|
||||
showRunningStatus: item.showRunningStatus,
|
||||
limit: item.limit
|
||||
})
|
||||
},
|
||||
|
|
@ -281,9 +281,9 @@ function EditLinkModal({
|
|||
defaultValues: defaultData
|
||||
});
|
||||
|
||||
const responseDetail = watch('responseDetail');
|
||||
// const showFullText = watch('showFullText');
|
||||
const showRawSource = watch('showRawSource');
|
||||
const showCite = watch('showCite');
|
||||
const showFullText = watch('showFullText');
|
||||
const canDownloadSource = watch('canDownloadSource');
|
||||
|
||||
const isEdit = useMemo(() => !!defaultData._id, [defaultData]);
|
||||
|
||||
|
|
@ -413,7 +413,7 @@ function EditLinkModal({
|
|||
</Box>
|
||||
<Flex alignItems={'center'} mt={4} justify={'space-between'} height={'36px'}>
|
||||
<FormLabel>{t('publish:show_node')}</FormLabel>
|
||||
<Switch {...register('showNodeStatus')} />
|
||||
<Switch {...register('showRunningStatus')} />
|
||||
</Flex>
|
||||
<Flex alignItems={'center'} mt={4} justify={'space-between'} height={'36px'}>
|
||||
<Flex alignItems={'center'}>
|
||||
|
|
@ -424,56 +424,56 @@ function EditLinkModal({
|
|||
></QuestionTip>
|
||||
</Flex>
|
||||
<Switch
|
||||
{...register('responseDetail', {
|
||||
{...register('showCite', {
|
||||
onChange(e) {
|
||||
if (!e.target.checked) {
|
||||
// setValue('showFullText', false);
|
||||
setValue('showRawSource', false);
|
||||
setValue('showFullText', false);
|
||||
setValue('canDownloadSource', false);
|
||||
}
|
||||
}
|
||||
})}
|
||||
isChecked={responseDetail}
|
||||
isChecked={showCite}
|
||||
/>
|
||||
</Flex>
|
||||
{/* <Flex alignItems={'center'} mt={4} justify={'space-between'} height={'36px'}>
|
||||
<Flex alignItems={'center'} mt={4} justify={'space-between'} height={'36px'}>
|
||||
<Flex alignItems={'center'}>
|
||||
<FormLabel>{t('common:support.outlink.share.Chat_quote_reader')}</FormLabel>
|
||||
<FormLabel>{t('common:core.app.share.Show full text')}</FormLabel>
|
||||
<QuestionTip
|
||||
ml={1}
|
||||
label={t('common:support.outlink.share.Full_text tips')}
|
||||
label={t('common:support.outlink.share.Show full text tips')}
|
||||
></QuestionTip>
|
||||
</Flex>
|
||||
<Switch
|
||||
{...register('showFullText', {
|
||||
onChange(e) {
|
||||
if (e.target.checked) {
|
||||
setValue('responseDetail', true);
|
||||
if (!e.target.checked) {
|
||||
setValue('canDownloadSource', false);
|
||||
} else {
|
||||
setValue('showRawSource', false);
|
||||
setValue('showCite', true);
|
||||
}
|
||||
}
|
||||
})}
|
||||
isChecked={showFullText}
|
||||
/>
|
||||
</Flex> */}
|
||||
</Flex>
|
||||
<Flex alignItems={'center'} mt={4} justify={'space-between'} height={'36px'}>
|
||||
<Flex alignItems={'center'}>
|
||||
<FormLabel>{t('common:support.outlink.share.show_complete_quote')}</FormLabel>
|
||||
<FormLabel>{t('common:core.app.share.Download source')}</FormLabel>
|
||||
<QuestionTip
|
||||
ml={1}
|
||||
label={t('common:support.outlink.share.show_complete_quote_tips')}
|
||||
label={t('common:support.outlink.share.Download source tips')}
|
||||
></QuestionTip>
|
||||
</Flex>
|
||||
<Switch
|
||||
{...register('showRawSource', {
|
||||
{...register('canDownloadSource', {
|
||||
onChange(e) {
|
||||
if (e.target.checked) {
|
||||
setValue('responseDetail', true);
|
||||
// setValue('showFullText', true);
|
||||
setValue('showFullText', true);
|
||||
setValue('showCite', true);
|
||||
}
|
||||
}
|
||||
})}
|
||||
isChecked={showRawSource}
|
||||
isChecked={canDownloadSource}
|
||||
/>
|
||||
</Flex>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ const OffiAccount = ({ appId }: { appId: string }) => {
|
|||
name: item.name,
|
||||
limit: item.limit,
|
||||
app: item.app,
|
||||
responseDetail: item.responseDetail,
|
||||
showCite: item.showCite,
|
||||
defaultResponse: item.defaultResponse,
|
||||
immediateResponse: item.immediateResponse
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,186 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { Box, Flex, Grid, Switch } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
|
||||
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import {
|
||||
getPlaygroundVisibilityConfig,
|
||||
updatePlaygroundVisibilityConfig
|
||||
} from '@/web/support/outLink/api';
|
||||
import type { PlaygroundVisibilityConfigType } from '@fastgpt/global/support/outLink/type';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useCopyData } from '@fastgpt/web/hooks/useCopyData';
|
||||
import { ChatSidebarPaneEnum } from '@/pageComponents/chat/constants';
|
||||
|
||||
const defaultPlaygroundVisibilityForm: PlaygroundVisibilityConfigType = {
|
||||
showRunningStatus: true,
|
||||
showCite: true,
|
||||
showFullText: true,
|
||||
canDownloadSource: true
|
||||
};
|
||||
|
||||
const PlaygroundVisibilityConfig = ({ appId }: { appId: string }) => {
|
||||
const { t } = useTranslation();
|
||||
const { copyData } = useCopyData();
|
||||
|
||||
const { register, watch, setValue, reset } = useForm({
|
||||
defaultValues: defaultPlaygroundVisibilityForm
|
||||
});
|
||||
|
||||
const showCite = watch('showCite');
|
||||
const showFullText = watch('showFullText');
|
||||
const canDownloadSource = watch('canDownloadSource');
|
||||
|
||||
const playgroundLink = useMemo(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
return `${window.location.origin}/chat?appId=${appId}&pane=${ChatSidebarPaneEnum.RECENTLY_USED_APPS}`;
|
||||
}
|
||||
return '';
|
||||
}, [appId]);
|
||||
|
||||
useRequest2(() => getPlaygroundVisibilityConfig({ appId }), {
|
||||
onSuccess: (data) => {
|
||||
reset({
|
||||
showRunningStatus: data.showRunningStatus,
|
||||
showCite: data.showCite,
|
||||
showFullText: data.showFullText,
|
||||
canDownloadSource: data.canDownloadSource
|
||||
});
|
||||
},
|
||||
manual: false
|
||||
});
|
||||
|
||||
const { runAsync: saveConfig } = useRequest2(
|
||||
async (data: PlaygroundVisibilityConfigType) => {
|
||||
return await updatePlaygroundVisibilityConfig({
|
||||
appId,
|
||||
...data
|
||||
});
|
||||
},
|
||||
{
|
||||
successToast: t('common:save_success')
|
||||
}
|
||||
);
|
||||
|
||||
const autoSave = async () => {
|
||||
const values = watch();
|
||||
await saveConfig(values);
|
||||
};
|
||||
|
||||
return (
|
||||
<Flex flexDirection="column" h="100%">
|
||||
<Box fontSize={'sm'} fontWeight={'medium'} color={'myGray.900'} mb={3}>
|
||||
{t('app:publish.playground_link')}
|
||||
</Box>
|
||||
|
||||
<Box borderRadius={'md'} bg={'myGray.100'} overflow={'hidden'} fontSize={'sm'} mb={6}>
|
||||
<Flex
|
||||
p={3}
|
||||
bg={'myWhite.500'}
|
||||
border="base"
|
||||
borderTopLeftRadius={'md'}
|
||||
borderTopRightRadius={'md'}
|
||||
alignItems={'center'}
|
||||
>
|
||||
<Box flex={1} fontSize={'xs'} color={'myGray.600'}>
|
||||
{t('common:core.app.outLink.Link block title')}
|
||||
</Box>
|
||||
<MyIcon
|
||||
name={'copy'}
|
||||
w={'16px'}
|
||||
color={'myGray.600'}
|
||||
cursor={'pointer'}
|
||||
_hover={{ color: 'primary.500' }}
|
||||
onClick={() => copyData(playgroundLink)}
|
||||
/>
|
||||
</Flex>
|
||||
<Box whiteSpace={'nowrap'} p={3} overflowX={'auto'}>
|
||||
{playgroundLink}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box fontSize={'sm'} fontWeight={'medium'} color={'myGray.900'}>
|
||||
{t('publish:private_config')}
|
||||
</Box>
|
||||
|
||||
<Grid templateColumns={'1fr 1fr'} gap={4} mt={4}>
|
||||
<Flex alignItems={'center'}>
|
||||
<FormLabel fontSize={'12px'} flex={'0 0 127px'}>
|
||||
{t('publish:show_node')}
|
||||
</FormLabel>
|
||||
<Switch
|
||||
{...register('showRunningStatus', {
|
||||
onChange: autoSave
|
||||
})}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex alignItems={'center'} flex={'0 0 158px'}>
|
||||
<FormLabel fontSize={'12px'}>
|
||||
{t('common:support.outlink.share.Response Quote')}
|
||||
</FormLabel>
|
||||
<QuestionTip ml={1} label={t('common:support.outlink.share.Response Quote tips')} />
|
||||
</Flex>
|
||||
<Switch
|
||||
{...register('showCite', {
|
||||
onChange(e) {
|
||||
if (!e.target.checked) {
|
||||
setValue('showFullText', false);
|
||||
setValue('canDownloadSource', false);
|
||||
}
|
||||
autoSave();
|
||||
}
|
||||
})}
|
||||
isChecked={showCite}
|
||||
/>
|
||||
</Flex>
|
||||
</Grid>
|
||||
|
||||
<Grid templateColumns={'1fr 1fr'} gap={4} mt={4}>
|
||||
<Flex>
|
||||
<Flex alignItems={'center'} flex={'0 0 127px'}>
|
||||
<FormLabel fontSize={'12px'}>{t('common:core.app.share.Show full text')}</FormLabel>
|
||||
<QuestionTip ml={1} label={t('common:support.outlink.share.Show full text tips')} />
|
||||
</Flex>
|
||||
<Switch
|
||||
{...register('showFullText', {
|
||||
onChange(e) {
|
||||
if (!e.target.checked) {
|
||||
setValue('canDownloadSource', false);
|
||||
} else {
|
||||
setValue('showCite', true);
|
||||
}
|
||||
autoSave();
|
||||
}
|
||||
})}
|
||||
isChecked={showFullText}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex alignItems={'center'} flex={'0 0 158px'}>
|
||||
<FormLabel fontSize={'12px'} fontWeight={'medium'}>
|
||||
{t('common:core.app.share.Download source')}
|
||||
</FormLabel>
|
||||
<QuestionTip ml={1} label={t('common:support.outlink.share.Download source tips')} />
|
||||
</Flex>
|
||||
<Switch
|
||||
{...register('canDownloadSource', {
|
||||
onChange(e) {
|
||||
if (e.target.checked) {
|
||||
setValue('showFullText', true);
|
||||
setValue('showCite', true);
|
||||
}
|
||||
autoSave();
|
||||
}
|
||||
})}
|
||||
isChecked={canDownloadSource}
|
||||
/>
|
||||
</Flex>
|
||||
</Grid>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default PlaygroundVisibilityConfig;
|
||||
|
|
@ -200,7 +200,7 @@ const Wecom = ({ appId }: { appId: string }) => {
|
|||
name: item.name,
|
||||
limit: item.limit,
|
||||
app: item.app,
|
||||
responseDetail: item.responseDetail,
|
||||
showCite: item.showCite,
|
||||
defaultResponse: item.defaultResponse,
|
||||
immediateResponse: item.immediateResponse
|
||||
});
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ const FeiShu = dynamic(() => import('./FeiShu'));
|
|||
const DingTalk = dynamic(() => import('./DingTalk'));
|
||||
const Wecom = dynamic(() => import('./Wecom'));
|
||||
const OffiAccount = dynamic(() => import('./OffiAccount'));
|
||||
const Playground = dynamic(() => import('./Playground'));
|
||||
|
||||
const OutLink = () => {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -85,7 +86,14 @@ const OutLink = () => {
|
|||
isProFn: true
|
||||
}
|
||||
]
|
||||
: [])
|
||||
: []),
|
||||
{
|
||||
icon: 'core/chat/sidebar/home',
|
||||
title: t('common:navbar.Chat'),
|
||||
desc: t('app:publish.chat_desc'),
|
||||
value: PublishChannelEnum.playground,
|
||||
isProFn: false
|
||||
}
|
||||
]);
|
||||
|
||||
const [linkType, setLinkType] = useState<PublishChannelEnum>(PublishChannelEnum.share);
|
||||
|
|
@ -141,6 +149,7 @@ const OutLink = () => {
|
|||
{linkType === PublishChannelEnum.dingtalk && <DingTalk appId={appId} />}
|
||||
{linkType === PublishChannelEnum.wecom && <Wecom appId={appId} />}
|
||||
{linkType === PublishChannelEnum.officialAccount && <OffiAccount appId={appId} />}
|
||||
{linkType === PublishChannelEnum.playground && <Playground appId={appId} />}
|
||||
</Flex>
|
||||
</Box>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -118,10 +118,10 @@ const Render = ({ appForm, setRenderEdit }: Props) => {
|
|||
return (
|
||||
<ChatItemContextProvider
|
||||
showRouteToDatasetDetail={true}
|
||||
isShowReadRawSource={true}
|
||||
isResponseDetail={true}
|
||||
// isShowFullText={true}
|
||||
showNodeStatus
|
||||
canDownloadSource={true}
|
||||
isShowCite={true}
|
||||
isShowFullText={true}
|
||||
showRunningStatus={true}
|
||||
>
|
||||
<ChatRecordContextProvider params={chatRecordProviderParams}>
|
||||
<ChatTest appForm={appForm} setRenderEdit={setRenderEdit} />
|
||||
|
|
|
|||
|
|
@ -206,10 +206,10 @@ const Render = (Props: Props) => {
|
|||
return (
|
||||
<ChatItemContextProvider
|
||||
showRouteToDatasetDetail={true}
|
||||
isShowReadRawSource={true}
|
||||
isResponseDetail={true}
|
||||
// isShowFullText={true}
|
||||
showNodeStatus
|
||||
canDownloadSource={true}
|
||||
isShowCite={true}
|
||||
isShowFullText={true}
|
||||
showRunningStatus={true}
|
||||
>
|
||||
<ChatRecordContextProvider params={chatRecordProviderParams}>
|
||||
<ChatTest {...Props} chatId={chatId} />
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { ChatSettingContext } from '@/web/core/chat/context/chatSettingContext';
|
||||
import { ChatPageContext } from '@/web/core/chat/context/chatPageContext';
|
||||
import { useMemo } from 'react';
|
||||
import Avatar from '@fastgpt/web/components/common/Avatar';
|
||||
import { ChatSettingTabOptionEnum, ChatSidebarPaneEnum } from '@/pageComponents/chat/constants';
|
||||
|
|
@ -41,11 +41,11 @@ const ChatFavouriteApp = () => {
|
|||
|
||||
const onOpenSlider = useContextSelector(ChatContext, (v) => v.onOpenSlider);
|
||||
|
||||
const handlePaneChange = useContextSelector(ChatSettingContext, (v) => v.handlePaneChange);
|
||||
const wideLogoUrl = useContextSelector(ChatSettingContext, (v) => v.chatSettings?.wideLogoUrl);
|
||||
const homeTabTitle = useContextSelector(ChatSettingContext, (v) => v.chatSettings?.homeTabTitle);
|
||||
const handlePaneChange = useContextSelector(ChatPageContext, (v) => v.handlePaneChange);
|
||||
const wideLogoUrl = useContextSelector(ChatPageContext, (v) => v.chatSettings?.wideLogoUrl);
|
||||
const homeTabTitle = useContextSelector(ChatPageContext, (v) => v.chatSettings?.homeTabTitle);
|
||||
|
||||
const tags = useContextSelector(ChatSettingContext, (v) => v.chatSettings?.favouriteTags || []);
|
||||
const tags = useContextSelector(ChatPageContext, (v) => v.chatSettings?.favouriteTags || []);
|
||||
const tagCache = useMemo(() => {
|
||||
return tags.reduce(
|
||||
(acc, tag) => {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import { AppFolderTypeList, AppTypeEnum } from '@fastgpt/global/core/app/constan
|
|||
import { useSystem } from '@fastgpt/web/hooks/useSystem';
|
||||
import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs';
|
||||
import { useRouter } from 'next/router';
|
||||
import { type AppListItemType } from '@fastgpt/global/core/app/type';
|
||||
import {
|
||||
type GetResourceFolderListProps,
|
||||
type GetResourceListItemResponse
|
||||
|
|
@ -24,7 +23,7 @@ import SelectOneResource from '@/components/common/folder/SelectOneResource';
|
|||
import { ChatItemContext } from '@/web/core/chat/context/chatItemContext';
|
||||
import VariablePopover from '@/components/core/chat/ChatContainer/components/VariablePopover';
|
||||
import { useCopyData } from '@fastgpt/web/hooks/useCopyData';
|
||||
import { ChatSettingContext } from '@/web/core/chat/context/chatSettingContext';
|
||||
import { ChatPageContext } from '@/web/core/chat/context/chatPageContext';
|
||||
import {
|
||||
ChatSidebarPaneEnum,
|
||||
DEFAULT_LOGO_BANNER_COLLAPSED_URL
|
||||
|
|
@ -38,7 +37,6 @@ import { ChatTypeEnum } from '@/components/core/chat/ChatContainer/ChatBox/const
|
|||
const ChatHeader = ({
|
||||
history,
|
||||
showHistory,
|
||||
apps,
|
||||
totalRecordsCount,
|
||||
|
||||
pane,
|
||||
|
|
@ -50,18 +48,15 @@ const ChatHeader = ({
|
|||
|
||||
history: ChatItemType[];
|
||||
showHistory?: boolean;
|
||||
apps?: AppListItemType[];
|
||||
totalRecordsCount: number;
|
||||
reserveSpace?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { isPc } = useSystem();
|
||||
const pathname = usePathname();
|
||||
const { source } = useChatStore();
|
||||
|
||||
const chatData = useContextSelector(ChatItemContext, (v) => v.chatBoxData);
|
||||
const isVariableVisible = useContextSelector(ChatItemContext, (v) => v.isVariableVisible);
|
||||
|
||||
const isPlugin = chatData.app.type === AppTypeEnum.workflowTool;
|
||||
const isShare = source === 'share';
|
||||
const chatType = isShare ? ChatTypeEnum.share : ChatTypeEnum.chat;
|
||||
|
|
@ -87,7 +82,6 @@ const ChatHeader = ({
|
|||
</>
|
||||
) : (
|
||||
<MobileHeader
|
||||
apps={apps}
|
||||
appId={chatData.appId}
|
||||
name={
|
||||
pane === ChatSidebarPaneEnum.HOME && !isShare
|
||||
|
|
@ -113,15 +107,7 @@ const ChatHeader = ({
|
|||
);
|
||||
};
|
||||
|
||||
const MobileDrawer = ({
|
||||
onCloseDrawer,
|
||||
appId,
|
||||
apps
|
||||
}: {
|
||||
onCloseDrawer: () => void;
|
||||
appId: string;
|
||||
apps?: AppListItemType[];
|
||||
}) => {
|
||||
const MobileDrawer = ({ onCloseDrawer, appId }: { onCloseDrawer: () => void; appId: string }) => {
|
||||
enum TabEnum {
|
||||
recently = 'recently',
|
||||
app = 'app'
|
||||
|
|
@ -129,6 +115,7 @@ const MobileDrawer = ({
|
|||
const { t } = useTranslation();
|
||||
|
||||
const { setChatId } = useChatStore();
|
||||
const myApps = useContextSelector(ChatPageContext, (v) => v.myApps);
|
||||
|
||||
const [currentTab, setCurrentTab] = useState<TabEnum>(TabEnum.recently);
|
||||
|
||||
|
|
@ -143,7 +130,7 @@ const MobileDrawer = ({
|
|||
);
|
||||
}, []);
|
||||
|
||||
const handlePaneChange = useContextSelector(ChatSettingContext, (v) => v.handlePaneChange);
|
||||
const handlePaneChange = useContextSelector(ChatPageContext, (v) => v.handlePaneChange);
|
||||
|
||||
const onclickApp = (id: string) => {
|
||||
handlePaneChange(ChatSidebarPaneEnum.RECENTLY_USED_APPS, id);
|
||||
|
|
@ -201,22 +188,22 @@ const MobileDrawer = ({
|
|||
{/* history */}
|
||||
{currentTab === TabEnum.recently && (
|
||||
<Box px={3} overflow={'auto'} h={'100%'}>
|
||||
{Array.isArray(apps) &&
|
||||
apps.map((item) => (
|
||||
<Flex justify={'center'} key={item._id}>
|
||||
{Array.isArray(myApps) &&
|
||||
myApps.map((item) => (
|
||||
<Flex justify={'center'} key={item.appId}>
|
||||
<Flex
|
||||
py={2.5}
|
||||
px={2}
|
||||
width={'100%'}
|
||||
borderRadius={'md'}
|
||||
alignItems={'center'}
|
||||
{...(item._id === appId
|
||||
{...(item.appId === appId
|
||||
? {
|
||||
backgroundColor: 'primary.50 !important',
|
||||
color: 'primary.600'
|
||||
}
|
||||
: {
|
||||
onClick: () => onclickApp(item._id)
|
||||
onClick: () => onclickApp(item.appId)
|
||||
})}
|
||||
>
|
||||
<Avatar src={item.avatar} w={'24px'} borderRadius={'sm'} />
|
||||
|
|
@ -247,13 +234,11 @@ const MobileHeader = ({
|
|||
showHistory,
|
||||
name,
|
||||
avatar,
|
||||
appId,
|
||||
apps
|
||||
appId
|
||||
}: {
|
||||
showHistory?: boolean;
|
||||
avatar: string;
|
||||
name: string;
|
||||
apps?: AppListItemType[];
|
||||
appId: string;
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
|
|
@ -290,9 +275,7 @@ const MobileHeader = ({
|
|||
</Flex>
|
||||
</Flex>
|
||||
|
||||
{isOpenDrawer && !isShareChat && (
|
||||
<MobileDrawer apps={apps} appId={appId} onCloseDrawer={onCloseDrawer} />
|
||||
)}
|
||||
{isOpenDrawer && !isShareChat && <MobileDrawer appId={appId} onCloseDrawer={onCloseDrawer} />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import { getCollectionQuote } from '@/web/core/chat/api';
|
|||
import MyIconButton from '@fastgpt/web/components/common/Icon/button';
|
||||
import MyBox from '@fastgpt/web/components/common/MyBox';
|
||||
import { getCollectionSourceAndOpen } from '@/web/core/dataset/hooks/readCollectionSource';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { ChatItemContext } from '@/web/core/chat/context/chatItemContext';
|
||||
|
||||
const CollectionReader = ({
|
||||
rawSearch,
|
||||
|
|
@ -37,6 +39,8 @@ const CollectionReader = ({
|
|||
const router = useRouter();
|
||||
const { userInfo } = useUserStore();
|
||||
|
||||
const canDownloadSource = useContextSelector(ChatItemContext, (v) => v.canDownloadSource);
|
||||
|
||||
const { collectionId, datasetId, chatItemDataId, sourceId, sourceName, quoteId } = metadata;
|
||||
const [quoteIndex, setQuoteIndex] = useState(0);
|
||||
|
||||
|
|
@ -175,11 +179,13 @@ const CollectionReader = ({
|
|||
{sourceName || t('common:unknow_source')}
|
||||
</Box>
|
||||
<Box ml={3}>
|
||||
<DownloadButton
|
||||
canAccessRawData={true}
|
||||
onDownload={handleDownload}
|
||||
onRead={handleRead}
|
||||
/>
|
||||
{canDownloadSource && (
|
||||
<DownloadButton
|
||||
canAccessRawData={true}
|
||||
onDownload={handleDownload}
|
||||
onRead={handleRead}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Flex>
|
||||
<MyIconButton
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import LogChart from '@/pageComponents/app/detail/Logs/LogChart';
|
||||
import { ChatSettingContext } from '@/web/core/chat/context/chatSettingContext';
|
||||
import { ChatPageContext } from '@/web/core/chat/context/chatPageContext';
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import { ChatSourceEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import type { DateRangeType } from '@fastgpt/web/components/common/DateRangePicker';
|
||||
|
|
@ -13,7 +13,7 @@ type Props = {
|
|||
};
|
||||
|
||||
const LogDetails = ({ Header }: Props) => {
|
||||
const appId = useContextSelector(ChatSettingContext, (v) => v.chatSettings?.appId || '');
|
||||
const appId = useContextSelector(ChatPageContext, (v) => v.chatSettings?.appId || '');
|
||||
|
||||
const [dateRange, setDateRange] = useState<DateRangeType>({
|
||||
from: new Date(addDays(new Date(), -6).setHours(0, 0, 0, 0)),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ChatSettingContext } from '@/web/core/chat/context/chatSettingContext';
|
||||
import { ChatPageContext } from '@/web/core/chat/context/chatPageContext';
|
||||
import { AddIcon } from '@chakra-ui/icons';
|
||||
import {
|
||||
Box,
|
||||
|
|
@ -377,10 +377,10 @@ type Props = {
|
|||
const TagManageModal = ({ onClose, onRefresh }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const refreshChatSetting = useContextSelector(ChatSettingContext, (v) => v.refreshChatSetting);
|
||||
const refreshChatSetting = useContextSelector(ChatPageContext, (v) => v.refreshChatSetting);
|
||||
|
||||
// get tags from db
|
||||
const tags = useContextSelector(ChatSettingContext, (v) => v.chatSettings?.favouriteTags || []);
|
||||
const tags = useContextSelector(ChatPageContext, (v) => v.chatSettings?.favouriteTags || []);
|
||||
// local editable tags list
|
||||
const [localTags, setLocalTags] = useState<ChatFavouriteTagType[]>(tags);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,12 @@
|
|||
import { ChatSettingContext } from '@/web/core/chat/context/chatSettingContext';
|
||||
import { ChatPageContext } from '@/web/core/chat/context/chatPageContext';
|
||||
import {
|
||||
Button,
|
||||
ButtonGroup,
|
||||
Flex,
|
||||
HStack,
|
||||
IconButton,
|
||||
Input,
|
||||
InputGroup,
|
||||
InputLeftElement,
|
||||
Table,
|
||||
TableContainer,
|
||||
Tbody,
|
||||
Td,
|
||||
Th,
|
||||
Thead,
|
||||
Tr,
|
||||
useDisclosure
|
||||
} from '@chakra-ui/react';
|
||||
import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||
|
|
@ -68,7 +60,7 @@ const FavouriteAppSetting = ({ Header }: Props) => {
|
|||
|
||||
const searchAppTagValue = watchSearchValue('tag');
|
||||
// apps' tags options
|
||||
const tagOptions = useContextSelector(ChatSettingContext, (v) => {
|
||||
const tagOptions = useContextSelector(ChatPageContext, (v) => {
|
||||
const tags = v.chatSettings?.favouriteTags || [];
|
||||
return [
|
||||
{ label: t('chat:setting.favourite.category_all'), value: '' },
|
||||
|
|
@ -76,7 +68,7 @@ const FavouriteAppSetting = ({ Header }: Props) => {
|
|||
];
|
||||
});
|
||||
// app's tags cache map
|
||||
const tagMap = useContextSelector(ChatSettingContext, (v) =>
|
||||
const tagMap = useContextSelector(ChatPageContext, (v) =>
|
||||
(v.chatSettings?.favouriteTags || []).reduce<Record<string, ChatFavouriteTagType>>(
|
||||
(acc, tag) => {
|
||||
acc[tag.id] = { ...tag };
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import Avatar from '@fastgpt/web/components/common/Avatar';
|
|||
import type { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { useMount } from 'ahooks';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { ChatSettingContext } from '@/web/core/chat/context/chatSettingContext';
|
||||
import { ChatPageContext } from '@/web/core/chat/context/chatPageContext';
|
||||
import {
|
||||
DEFAULT_LOGO_BANNER_COLLAPSED_URL,
|
||||
DEFAULT_LOGO_BANNER_URL
|
||||
|
|
@ -46,8 +46,8 @@ const HomepageSetting = ({ Header, onDiagramShow }: Props) => {
|
|||
const { t } = useTranslation();
|
||||
const { feConfigs } = useSystemStore();
|
||||
|
||||
const chatSettings = useContextSelector(ChatSettingContext, (v) => v.chatSettings);
|
||||
const refreshChatSetting = useContextSelector(ChatSettingContext, (v) => v.refreshChatSetting);
|
||||
const chatSettings = useContextSelector(ChatPageContext, (v) => v.chatSettings);
|
||||
const refreshChatSetting = useContextSelector(ChatPageContext, (v) => v.refreshChatSetting);
|
||||
|
||||
const chatSettings2Form = useCallback(
|
||||
(data?: ChatSettingType) => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import LogTable from '@/pageComponents/app/detail/Logs/LogTable';
|
||||
import { ChatSettingContext } from '@/web/core/chat/context/chatSettingContext';
|
||||
import { ChatPageContext } from '@/web/core/chat/context/chatPageContext';
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import { ChatSourceEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import type { DateRangeType } from '@fastgpt/web/components/common/DateRangePicker';
|
||||
|
|
@ -16,7 +16,7 @@ type Props = {
|
|||
const chatSourceValues = Object.values(ChatSourceEnum);
|
||||
|
||||
const LogDetails = ({ Header }: Props) => {
|
||||
const appId = useContextSelector(ChatSettingContext, (v) => v.chatSettings?.appId || '');
|
||||
const appId = useContextSelector(ChatPageContext, (v) => v.chatSettings?.appId || '');
|
||||
|
||||
const [dateRange, setDateRange] = useState<DateRangeType>({
|
||||
from: new Date(addDays(new Date(), -6).setHours(0, 0, 0, 0)),
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { useContextSelector } from 'use-context-selector';
|
|||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { ChatContext } from '@/web/core/chat/context/chatContext';
|
||||
import NextHead from '@/components/common/NextHead';
|
||||
import { ChatSettingContext } from '@/web/core/chat/context/chatSettingContext';
|
||||
import { ChatPageContext } from '@/web/core/chat/context/chatPageContext';
|
||||
import ChatSliderMobileDrawer from '@/pageComponents/chat/slider/ChatSliderMobileDrawer';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useMount } from 'ahooks';
|
||||
|
|
@ -43,8 +43,8 @@ const ChatSetting = () => {
|
|||
);
|
||||
const onOpenSlider = useContextSelector(ChatContext, (v) => v.onOpenSlider);
|
||||
|
||||
const chatSettings = useContextSelector(ChatSettingContext, (v) => v.chatSettings);
|
||||
const handlePaneChange = useContextSelector(ChatSettingContext, (v) => v.handlePaneChange);
|
||||
const chatSettings = useContextSelector(ChatPageContext, (v) => v.chatSettings);
|
||||
const handlePaneChange = useContextSelector(ChatPageContext, (v) => v.handlePaneChange);
|
||||
|
||||
const handleTabChange = useCallback(
|
||||
(tab: ChatSettingTabOptionEnum) => {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import AppTypeTag from '@/pageComponents/chat/ChatTeamApp/TypeTag';
|
|||
import { formatTimeToChatTime } from '@fastgpt/global/common/string/time';
|
||||
import { useSystem } from '@fastgpt/web/hooks/useSystem';
|
||||
import UserBox from '@fastgpt/web/components/common/UserBox';
|
||||
import { ChatSettingContext } from '@/web/core/chat/context/chatSettingContext';
|
||||
import { ChatPageContext } from '@/web/core/chat/context/chatPageContext';
|
||||
import { ChatSidebarPaneEnum } from '@/pageComponents/chat/constants';
|
||||
|
||||
const List = ({ appType }: { appType: AppTypeEnum | 'all' }) => {
|
||||
|
|
@ -33,7 +33,7 @@ const List = ({ appType }: { appType: AppTypeEnum | 'all' }) => {
|
|||
].includes(app.type)
|
||||
)
|
||||
);
|
||||
const handlePaneChange = useContextSelector(ChatSettingContext, (v) => v.handlePaneChange);
|
||||
const handlePaneChange = useContextSelector(ChatPageContext, (v) => v.handlePaneChange);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import SearchInput from '@fastgpt/web/components/common/Input/SearchInput';
|
|||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { ChatContext } from '@/web/core/chat/context/chatContext';
|
||||
import NextHead from '@/components/common/NextHead';
|
||||
import { ChatSettingContext } from '@/web/core/chat/context/chatSettingContext';
|
||||
import { ChatPageContext } from '@/web/core/chat/context/chatPageContext';
|
||||
import ChatSliderMobileDrawer from '@/pageComponents/chat/slider/ChatSliderMobileDrawer';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
|
||||
|
|
@ -29,7 +29,7 @@ const MyApps = () => {
|
|||
(v) => v
|
||||
);
|
||||
|
||||
const chatSettings = useContextSelector(ChatSettingContext, (v) => v.chatSettings);
|
||||
const chatSettings = useContextSelector(ChatPageContext, (v) => v.chatSettings);
|
||||
|
||||
const onOpenSlider = useContextSelector(ChatContext, (v) => v.onOpenSlider);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import SideBar from '@/components/SideBar';
|
|||
import { ChatContext } from '@/web/core/chat/context/chatContext';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { ChatItemContext } from '@/web/core/chat/context/chatItemContext';
|
||||
import { type AppListItemType } from '@fastgpt/global/core/app/type';
|
||||
import { ChatTypeEnum } from '@/components/core/chat/ChatContainer/ChatBox/constants';
|
||||
import { useCallback } from 'react';
|
||||
import type { StartChatFnProps } from '@/components/core/chat/ChatContainer/type';
|
||||
|
|
@ -20,21 +19,18 @@ import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
|||
import { getInitChatInfo } from '@/web/core/chat/api';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import NextHead from '@/components/common/NextHead';
|
||||
import { ChatSettingContext } from '@/web/core/chat/context/chatSettingContext';
|
||||
import { ChatPageContext } from '@/web/core/chat/context/chatPageContext';
|
||||
import { ChatSidebarPaneEnum } from '../constants';
|
||||
import ChatHistorySidebar from '@/pageComponents/chat/slider/ChatSliderSidebar';
|
||||
import ChatSliderMobileDrawer from '@/pageComponents/chat/slider/ChatSliderMobileDrawer';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { ChatErrEnum } from '@fastgpt/global/common/error/code/chat';
|
||||
import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
|
||||
|
||||
const CustomPluginRunBox = dynamic(() => import('@/pageComponents/chat/CustomPluginRunBox'));
|
||||
|
||||
type Props = {
|
||||
myApps: AppListItemType[];
|
||||
};
|
||||
|
||||
const AppChatWindow = ({ myApps }: Props) => {
|
||||
const AppChatWindow = () => {
|
||||
const { userInfo } = useUserStore();
|
||||
const { chatId, appId, outLinkAuthData } = useChatStore();
|
||||
|
||||
|
|
@ -45,6 +41,7 @@ const AppChatWindow = ({ myApps }: Props) => {
|
|||
const onUpdateHistoryTitle = useContextSelector(ChatContext, (v) => v.onUpdateHistoryTitle);
|
||||
|
||||
const isPlugin = useContextSelector(ChatItemContext, (v) => v.isPlugin);
|
||||
const isShowCite = useContextSelector(ChatItemContext, (v) => v.isShowCite);
|
||||
const onChangeChatId = useContextSelector(ChatContext, (v) => v.onChangeChatId);
|
||||
const chatBoxData = useContextSelector(ChatItemContext, (v) => v.chatBoxData);
|
||||
const datasetCiteData = useContextSelector(ChatItemContext, (v) => v.datasetCiteData);
|
||||
|
|
@ -54,9 +51,10 @@ const AppChatWindow = ({ myApps }: Props) => {
|
|||
const chatRecords = useContextSelector(ChatRecordContext, (v) => v.chatRecords);
|
||||
const totalRecordsCount = useContextSelector(ChatRecordContext, (v) => v.totalRecordsCount);
|
||||
|
||||
const pane = useContextSelector(ChatSettingContext, (v) => v.pane);
|
||||
const chatSettings = useContextSelector(ChatSettingContext, (v) => v.chatSettings);
|
||||
const handlePaneChange = useContextSelector(ChatSettingContext, (v) => v.handlePaneChange);
|
||||
const pane = useContextSelector(ChatPageContext, (v) => v.pane);
|
||||
const chatSettings = useContextSelector(ChatPageContext, (v) => v.chatSettings);
|
||||
const handlePaneChange = useContextSelector(ChatPageContext, (v) => v.handlePaneChange);
|
||||
const refreshRecentlyUsed = useContextSelector(ChatPageContext, (v) => v.refreshRecentlyUsed);
|
||||
|
||||
const { loading } = useRequest2(
|
||||
async () => {
|
||||
|
|
@ -82,6 +80,9 @@ const AppChatWindow = ({ myApps }: Props) => {
|
|||
onChangeChatId();
|
||||
return;
|
||||
}
|
||||
if (e?.statusText === AppErrEnum.unAuthApp) {
|
||||
refreshRecentlyUsed();
|
||||
}
|
||||
handlePaneChange(ChatSidebarPaneEnum.TEAM_APPS);
|
||||
}
|
||||
},
|
||||
|
|
@ -106,7 +107,8 @@ const AppChatWindow = ({ myApps }: Props) => {
|
|||
variables,
|
||||
responseChatItemId,
|
||||
appId,
|
||||
chatId
|
||||
chatId,
|
||||
retainDatasetCite: isShowCite
|
||||
},
|
||||
abortCtrl: controller,
|
||||
onMessage: generatingMessage
|
||||
|
|
@ -120,9 +122,19 @@ const AppChatWindow = ({ myApps }: Props) => {
|
|||
title: newTitle
|
||||
}));
|
||||
|
||||
refreshRecentlyUsed();
|
||||
|
||||
return { responseText, isNewChat: forbidLoadChat.current };
|
||||
},
|
||||
[appId, chatId, onUpdateHistoryTitle, setChatBoxData, forbidLoadChat]
|
||||
[
|
||||
appId,
|
||||
chatId,
|
||||
onUpdateHistoryTitle,
|
||||
setChatBoxData,
|
||||
forbidLoadChat,
|
||||
isShowCite,
|
||||
refreshRecentlyUsed
|
||||
]
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
@ -156,7 +168,6 @@ const AppChatWindow = ({ myApps }: Props) => {
|
|||
pane={pane}
|
||||
chatSettings={chatSettings}
|
||||
showHistory
|
||||
apps={myApps}
|
||||
history={chatRecords}
|
||||
totalRecordsCount={totalRecordsCount}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -36,12 +36,8 @@ import { getDefaultAppForm } from '@fastgpt/global/core/app/utils';
|
|||
import { getToolPreviewNode } from '@/web/core/app/api/tool';
|
||||
import type { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/node';
|
||||
import { getWebLLMModel } from '@/web/common/system/utils';
|
||||
import { ChatSettingContext } from '@/web/core/chat/context/chatSettingContext';
|
||||
import type {
|
||||
AppFileSelectConfigType,
|
||||
AppListItemType,
|
||||
AppWhisperConfigType
|
||||
} from '@fastgpt/global/core/app/type';
|
||||
import { ChatPageContext } from '@/web/core/chat/context/chatPageContext';
|
||||
import type { AppFileSelectConfigType, AppWhisperConfigType } from '@fastgpt/global/core/app/type';
|
||||
import ChatHeader from '@/pageComponents/chat/ChatHeader';
|
||||
import { ChatRecordContext } from '@/web/core/chat/context/chatRecordContext';
|
||||
import { ChatSidebarPaneEnum } from '../constants';
|
||||
|
|
@ -49,10 +45,6 @@ import ChatHistorySidebar from '@/pageComponents/chat/slider/ChatSliderSidebar';
|
|||
import ChatSliderMobileDrawer from '@/pageComponents/chat/slider/ChatSliderMobileDrawer';
|
||||
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
|
||||
|
||||
type Props = {
|
||||
myApps: AppListItemType[];
|
||||
};
|
||||
|
||||
const defaultFileSelectConfig: AppFileSelectConfigType = {
|
||||
maxFiles: 20,
|
||||
canSelectFile: true,
|
||||
|
|
@ -68,7 +60,7 @@ const defaultWhisperConfig: AppWhisperConfigType = {
|
|||
autoTTSResponse: false
|
||||
};
|
||||
|
||||
const HomeChatWindow = ({ myApps }: Props) => {
|
||||
const HomeChatWindow = () => {
|
||||
const { t } = useTranslation();
|
||||
const { isPc } = useSystem();
|
||||
|
||||
|
|
@ -84,11 +76,13 @@ const HomeChatWindow = ({ myApps }: Props) => {
|
|||
const datasetCiteData = useContextSelector(ChatItemContext, (v) => v.datasetCiteData);
|
||||
const setChatBoxData = useContextSelector(ChatItemContext, (v) => v.setChatBoxData);
|
||||
const resetVariables = useContextSelector(ChatItemContext, (v) => v.resetVariables);
|
||||
const isShowCite = useContextSelector(ChatItemContext, (v) => v.isShowCite);
|
||||
|
||||
const pane = useContextSelector(ChatSettingContext, (v) => v.pane);
|
||||
const chatSettings = useContextSelector(ChatSettingContext, (v) => v.chatSettings);
|
||||
const handlePaneChange = useContextSelector(ChatSettingContext, (v) => v.handlePaneChange);
|
||||
const homeAppId = useContextSelector(ChatSettingContext, (v) => v.chatSettings?.appId || '');
|
||||
const pane = useContextSelector(ChatPageContext, (v) => v.pane);
|
||||
const chatSettings = useContextSelector(ChatPageContext, (v) => v.chatSettings);
|
||||
const handlePaneChange = useContextSelector(ChatPageContext, (v) => v.handlePaneChange);
|
||||
const homeAppId = useContextSelector(ChatPageContext, (v) => v.chatSettings?.appId || '');
|
||||
const refreshRecentlyUsed = useContextSelector(ChatPageContext, (v) => v.refreshRecentlyUsed);
|
||||
|
||||
const chatRecords = useContextSelector(ChatRecordContext, (v) => v.chatRecords);
|
||||
const totalRecordsCount = useContextSelector(ChatRecordContext, (v) => v.totalRecordsCount);
|
||||
|
|
@ -216,7 +210,8 @@ const HomeChatWindow = ({ myApps }: Props) => {
|
|||
variables,
|
||||
responseChatItemId,
|
||||
appId,
|
||||
chatId
|
||||
chatId,
|
||||
retainDatasetCite: isShowCite
|
||||
},
|
||||
abortCtrl: controller,
|
||||
onMessage: generatingMessage
|
||||
|
|
@ -230,6 +225,8 @@ const HomeChatWindow = ({ myApps }: Props) => {
|
|||
title: newTitle
|
||||
}));
|
||||
|
||||
refreshRecentlyUsed();
|
||||
|
||||
return { responseText, isNewChat: forbidLoadChat.current };
|
||||
}
|
||||
|
||||
|
|
@ -264,6 +261,7 @@ const HomeChatWindow = ({ myApps }: Props) => {
|
|||
appId,
|
||||
appName: t('chat:home.chat_app'),
|
||||
chatId,
|
||||
retainDatasetCite: isShowCite,
|
||||
...form2AppWorkflow(formData, t)
|
||||
},
|
||||
onMessage: generatingMessage,
|
||||
|
|
@ -278,6 +276,8 @@ const HomeChatWindow = ({ myApps }: Props) => {
|
|||
title: newTitle
|
||||
}));
|
||||
|
||||
refreshRecentlyUsed();
|
||||
|
||||
return { responseText, isNewChat: forbidLoadChat.current };
|
||||
}
|
||||
);
|
||||
|
|
@ -394,7 +394,8 @@ const HomeChatWindow = ({ myApps }: Props) => {
|
|||
setSelectedToolIds,
|
||||
setChatBoxData,
|
||||
isPc,
|
||||
isQuickApp
|
||||
isQuickApp,
|
||||
isShowCite
|
||||
]
|
||||
);
|
||||
|
||||
|
|
@ -445,7 +446,6 @@ const HomeChatWindow = ({ myApps }: Props) => {
|
|||
pane={pane}
|
||||
chatSettings={chatSettings}
|
||||
showHistory
|
||||
apps={myApps}
|
||||
history={chatRecords}
|
||||
totalRecordsCount={totalRecordsCount}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { ChatSettingContext } from '@/web/core/chat/context/chatSettingContext';
|
||||
import { ChatPageContext } from '@/web/core/chat/context/chatPageContext';
|
||||
import { ChatSidebarPaneEnum } from '@/pageComponents/chat/constants';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { ChatContext } from '@/web/core/chat/context/chatContext';
|
||||
|
|
@ -15,8 +15,8 @@ const ChatSliderFooter = () => {
|
|||
const { feConfigs } = useSystemStore();
|
||||
|
||||
const onCloseSlider = useContextSelector(ChatContext, (v) => v.onCloseSlider);
|
||||
const handlePaneChange = useContextSelector(ChatSettingContext, (v) => v.handlePaneChange);
|
||||
const pane = useContextSelector(ChatSettingContext, (v) => v.pane);
|
||||
const handlePaneChange = useContextSelector(ChatPageContext, (v) => v.handlePaneChange);
|
||||
const pane = useContextSelector(ChatPageContext, (v) => v.pane);
|
||||
|
||||
const isAdmin = !!userInfo?.team.permission.hasManagePer;
|
||||
const isSettingPane = pane === ChatSidebarPaneEnum.SETTING;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { GridItem, Grid } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
import { ChatSettingContext } from '@/web/core/chat/context/chatSettingContext';
|
||||
import { ChatPageContext } from '@/web/core/chat/context/chatPageContext';
|
||||
import { ChatSidebarPaneEnum } from '@/pageComponents/chat/constants';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { ChatContext } from '@/web/core/chat/context/chatContext';
|
||||
|
|
@ -24,9 +24,9 @@ const ChatSliderHeader = ({ title, banner }: Props) => {
|
|||
const { isPc } = useSystem();
|
||||
const { setChatId } = useChatStore();
|
||||
|
||||
const pane = useContextSelector(ChatSettingContext, (v) => v.pane);
|
||||
const handlePaneChange = useContextSelector(ChatSettingContext, (v) => v.handlePaneChange);
|
||||
const enableHome = useContextSelector(ChatSettingContext, (v) => v.chatSettings?.enableHome);
|
||||
const pane = useContextSelector(ChatPageContext, (v) => v.pane);
|
||||
const handlePaneChange = useContextSelector(ChatPageContext, (v) => v.handlePaneChange);
|
||||
const enableHome = useContextSelector(ChatPageContext, (v) => v.chatSettings?.enableHome);
|
||||
|
||||
const appName = useContextSelector(ChatItemContext, (v) => v.chatBoxData?.app.name);
|
||||
const appAvatar = useContextSelector(ChatItemContext, (v) => v.chatBoxData?.app.avatar);
|
||||
|
|
|
|||
|
|
@ -17,12 +17,11 @@ import {
|
|||
} from '@/pageComponents/chat/constants';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { ChatSettingContext } from '@/web/core/chat/context/chatSettingContext';
|
||||
import { ChatPageContext } from '@/web/core/chat/context/chatPageContext';
|
||||
import { usePathname } from 'next/navigation';
|
||||
|
||||
type Props = {
|
||||
activeAppId: string;
|
||||
apps: AppListItemType[];
|
||||
};
|
||||
|
||||
const MotionBox = motion(Box);
|
||||
|
|
@ -148,13 +147,13 @@ const AnimatedText: React.FC<AnimatedTextProps> = ({ show, children, className,
|
|||
);
|
||||
|
||||
const LogoSection = () => {
|
||||
const isCollapsed = useContextSelector(ChatSettingContext, (v) => v.collapse === 1);
|
||||
const logos = useContextSelector(ChatSettingContext, (v) => v.logos);
|
||||
const isCollapsed = useContextSelector(ChatPageContext, (v) => v.collapse === 1);
|
||||
const logos = useContextSelector(ChatPageContext, (v) => v.logos);
|
||||
const isHomeActive = useContextSelector(
|
||||
ChatSettingContext,
|
||||
ChatPageContext,
|
||||
(v) => v.pane === ChatSidebarPaneEnum.HOME
|
||||
);
|
||||
const onTriggerCollapse = useContextSelector(ChatSettingContext, (v) => v.onTriggerCollapse);
|
||||
const onTriggerCollapse = useContextSelector(ChatPageContext, (v) => v.onTriggerCollapse);
|
||||
const wideLogoSrc = logos.wideLogoUrl;
|
||||
const squareLogoSrc = logos.squareLogoUrl;
|
||||
|
||||
|
|
@ -256,24 +255,24 @@ const NavigationSection = () => {
|
|||
const { feConfigs } = useSystemStore();
|
||||
|
||||
const isEnableHome = useContextSelector(
|
||||
ChatSettingContext,
|
||||
ChatPageContext,
|
||||
(v) => v.chatSettings?.enableHome ?? true
|
||||
);
|
||||
const isCollapsed = useContextSelector(ChatSettingContext, (v) => v.collapse === 1);
|
||||
const onTriggerCollapse = useContextSelector(ChatSettingContext, (v) => v.onTriggerCollapse);
|
||||
const isCollapsed = useContextSelector(ChatPageContext, (v) => v.collapse === 1);
|
||||
const onTriggerCollapse = useContextSelector(ChatPageContext, (v) => v.onTriggerCollapse);
|
||||
const isHomeActive = useContextSelector(
|
||||
ChatSettingContext,
|
||||
ChatPageContext,
|
||||
(v) => v.pane === ChatSidebarPaneEnum.HOME
|
||||
);
|
||||
const isTeamAppsActive = useContextSelector(
|
||||
ChatSettingContext,
|
||||
ChatPageContext,
|
||||
(v) => v.pane === ChatSidebarPaneEnum.TEAM_APPS
|
||||
);
|
||||
const isFavouriteAppsActive = useContextSelector(
|
||||
ChatSettingContext,
|
||||
ChatPageContext,
|
||||
(v) => v.pane === ChatSidebarPaneEnum.FAVORITE_APPS
|
||||
);
|
||||
const handlePaneChange = useContextSelector(ChatSettingContext, (v) => v.handlePaneChange);
|
||||
const handlePaneChange = useContextSelector(ChatPageContext, (v) => v.handlePaneChange);
|
||||
|
||||
return (
|
||||
<Flex mt={4} flexDirection={'column'} gap={1} px={4}>
|
||||
|
|
@ -365,12 +364,12 @@ const BottomSection = () => {
|
|||
const isAdmin = !!userInfo?.team.permission.hasManagePer;
|
||||
const isShare = pathname === '/chat/share';
|
||||
|
||||
const isCollapsed = useContextSelector(ChatSettingContext, (v) => v.collapse === 1);
|
||||
const isCollapsed = useContextSelector(ChatPageContext, (v) => v.collapse === 1);
|
||||
const isSettingActive = useContextSelector(
|
||||
ChatSettingContext,
|
||||
ChatPageContext,
|
||||
(v) => v.pane === ChatSidebarPaneEnum.SETTING
|
||||
);
|
||||
const onSettingClick = useContextSelector(ChatSettingContext, (v) => v.handlePaneChange);
|
||||
const onSettingClick = useContextSelector(ChatPageContext, (v) => v.handlePaneChange);
|
||||
|
||||
return (
|
||||
<MotionBox mt={'auto'} px={3} py={4} layout={false}>
|
||||
|
|
@ -485,13 +484,14 @@ const BottomSection = () => {
|
|||
);
|
||||
};
|
||||
|
||||
const ChatSlider = ({ apps, activeAppId }: Props) => {
|
||||
const ChatSlider = ({ activeAppId }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const isCollapsed = useContextSelector(ChatSettingContext, (v) => v.collapse === 1);
|
||||
const pane = useContextSelector(ChatSettingContext, (v) => v.pane);
|
||||
const isCollapsed = useContextSelector(ChatPageContext, (v) => v.collapse === 1);
|
||||
const pane = useContextSelector(ChatPageContext, (v) => v.pane);
|
||||
const myApps = useContextSelector(ChatPageContext, (v) => v.myApps);
|
||||
|
||||
const handlePaneChange = useContextSelector(ChatSettingContext, (v) => v.handlePaneChange);
|
||||
const handlePaneChange = useContextSelector(ChatPageContext, (v) => v.handlePaneChange);
|
||||
|
||||
return (
|
||||
<MotionFlex
|
||||
|
|
@ -531,9 +531,9 @@ const ChatSlider = ({ apps, activeAppId }: Props) => {
|
|||
</HStack>
|
||||
|
||||
<MyBox flex={'1 0 0'} h={0} overflow={'overlay'} px={4} position={'relative'}>
|
||||
{apps.map((item) => (
|
||||
{myApps.map((item) => (
|
||||
<Flex
|
||||
key={item._id}
|
||||
key={item.appId}
|
||||
py={2}
|
||||
px={2}
|
||||
mb={3}
|
||||
|
|
@ -541,12 +541,12 @@ const ChatSlider = ({ apps, activeAppId }: Props) => {
|
|||
borderRadius={'md'}
|
||||
alignItems={'center'}
|
||||
fontSize={'sm'}
|
||||
{...(pane === ChatSidebarPaneEnum.RECENTLY_USED_APPS && item._id === activeAppId
|
||||
{...(pane === ChatSidebarPaneEnum.RECENTLY_USED_APPS && item.appId === activeAppId
|
||||
? { bg: 'primary.100', color: 'primary.600' }
|
||||
: {
|
||||
_hover: { bg: 'primary.100' },
|
||||
onClick: () =>
|
||||
handlePaneChange(ChatSidebarPaneEnum.RECENTLY_USED_APPS, item._id)
|
||||
handlePaneChange(ChatSidebarPaneEnum.RECENTLY_USED_APPS, item.appId)
|
||||
})}
|
||||
>
|
||||
<Avatar src={item.avatar} w={'1.5rem'} borderRadius={'md'} />
|
||||
|
|
|
|||
|
|
@ -1,48 +0,0 @@
|
|||
import { getRecentlyUsedApps } from '@/web/core/app/api';
|
||||
import { useChatStore } from '@/web/core/chat/context/useChatStore';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useMount } from 'ahooks';
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
export const useChat = (appId: string) => {
|
||||
const { setSource, setAppId } = useChatStore();
|
||||
const { userInfo, initUserInfo } = useUserStore();
|
||||
|
||||
const [isInitedUser, setIsInitedUser] = useState(false);
|
||||
|
||||
// get app list
|
||||
const { data: myApps = [] } = useRequest2(() => getRecentlyUsedApps({ getRecentlyChat: true }), {
|
||||
manual: false,
|
||||
errorToast: '',
|
||||
refreshDeps: [userInfo],
|
||||
pollingInterval: 30000
|
||||
});
|
||||
|
||||
// initialize user info
|
||||
useMount(async () => {
|
||||
// ensure store has current appId before setting source (avoids fallback to lastChatAppId)
|
||||
if (appId) setAppId(appId);
|
||||
try {
|
||||
await initUserInfo();
|
||||
} catch (error) {
|
||||
console.log('User not logged in:', error);
|
||||
} finally {
|
||||
setSource('online');
|
||||
setIsInitedUser(true);
|
||||
}
|
||||
});
|
||||
|
||||
// sync appId to store as soon as route/appId changes
|
||||
useEffect(() => {
|
||||
if (appId) {
|
||||
setAppId(appId);
|
||||
}
|
||||
}, [appId, setAppId, userInfo]);
|
||||
|
||||
return {
|
||||
isInitedUser,
|
||||
userInfo,
|
||||
myApps
|
||||
};
|
||||
};
|
||||
|
|
@ -449,7 +449,7 @@ const TestResults = React.memo(function TestResults({
|
|||
<Box mt={1} gap={4}>
|
||||
{datasetTestItem?.results.map((item, index) => (
|
||||
<Box key={item.id} p={3} borderRadius={'lg'} bg={'myGray.100'} _notLast={{ mb: 2 }}>
|
||||
<QuoteItem quoteItem={item} canViewSource canEditData />
|
||||
<QuoteItem quoteItem={item} canDownloadSource canEditData />
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -5,36 +5,56 @@ import type { S3MQJobData } from '@fastgpt/service/common/s3/mq';
|
|||
import { addLog } from '@fastgpt/service/common/system/log';
|
||||
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
|
||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||
import { PublishChannelEnum } from '@fastgpt/global/support/outLink/constant';
|
||||
import { connectionMongo } from '@fastgpt/service/common/mongo';
|
||||
|
||||
export type ResponseType = {
|
||||
message: string;
|
||||
retriedCount: number;
|
||||
failedCount: number;
|
||||
shareLinkMigration: {
|
||||
totalRecords: number;
|
||||
updatedRecords: number;
|
||||
updateResults: Array<{
|
||||
operation: string;
|
||||
updated: number;
|
||||
}>;
|
||||
};
|
||||
};
|
||||
|
||||
async function handler(
|
||||
req: ApiRequestProps,
|
||||
res: ApiResponseType<ResponseType>
|
||||
): Promise<ResponseType> {
|
||||
await authCert({ req, authRoot: true });
|
||||
const queue = getQueue<S3MQJobData>(QueueNames.s3FileDelete);
|
||||
/**
|
||||
* 4.14.5 版本数据初始化脚本
|
||||
* 1. 重试所有失败的 S3 删除任务
|
||||
* 2. 为所有 share 类型的 OutLink 记录添加 showFullText 字段
|
||||
* 3. 重命名字段:
|
||||
* - showNodeStatus -> showRunningStatus
|
||||
* - responseDetail -> showCite
|
||||
* - showRawSource -> canDownloadSource
|
||||
*/
|
||||
|
||||
// Get all failed jobs and retry them
|
||||
/**
|
||||
* 功能1: 重试所有失败的 S3 删除任务
|
||||
*/
|
||||
async function retryFailedS3DeleteJobs(): Promise<{
|
||||
retriedCount: number;
|
||||
failedCount: number;
|
||||
}> {
|
||||
const queue = getQueue<S3MQJobData>(QueueNames.s3FileDelete);
|
||||
const failedJobs = await queue.getFailed();
|
||||
console.log(`Found ${failedJobs.length} failed jobs`);
|
||||
console.log(`Found ${failedJobs.length} failed S3 delete jobs`);
|
||||
|
||||
let retriedCount = 0;
|
||||
|
||||
await batchRun(
|
||||
failedJobs,
|
||||
async (job) => {
|
||||
addLog.debug(`Retrying job with 3 new attempts`, { retriedCount });
|
||||
addLog.debug(`Retrying S3 delete job with new attempts`, { retriedCount });
|
||||
try {
|
||||
// Remove old job and recreate with new attempts
|
||||
const jobData = job.data;
|
||||
await job.remove();
|
||||
|
||||
// Add new job with 3 more attempts
|
||||
// Add new job with more attempts
|
||||
await queue.add('delete-s3-files', jobData, {
|
||||
attempts: 10,
|
||||
removeOnFail: {
|
||||
|
|
@ -49,19 +69,217 @@ async function handler(
|
|||
});
|
||||
|
||||
retriedCount++;
|
||||
console.log(`Retried job ${job.id} with 3 new attempts`);
|
||||
console.log(`Retried S3 delete job ${job.id} with new attempts`);
|
||||
} catch (error) {
|
||||
console.error(`Failed to retry job ${job.id}:`, error);
|
||||
console.error(`Failed to retry S3 delete job ${job.id}:`, error);
|
||||
}
|
||||
},
|
||||
100
|
||||
);
|
||||
|
||||
return {
|
||||
message: 'Successfully retried all failed S3 delete jobs with 3 new attempts',
|
||||
retriedCount,
|
||||
failedCount: failedJobs.length
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 功能2和3: 处理 OutLink 记录的数据迁移
|
||||
* - 添加 showFullText 字段
|
||||
* - 重命名现有字段
|
||||
*/
|
||||
async function migrateOutLinkData(): Promise<{
|
||||
totalRecords: number;
|
||||
updatedRecords: number;
|
||||
updateResults: Array<{
|
||||
operation: string;
|
||||
updated: number;
|
||||
}>;
|
||||
}> {
|
||||
let totalUpdated = 0;
|
||||
const updateResults: Array<{
|
||||
operation: string;
|
||||
updated: number;
|
||||
}> = [];
|
||||
|
||||
// 获取 MongoDB 原生集合,绕过 Mongoose 的严格模式
|
||||
const db = connectionMongo.connection.db;
|
||||
if (!db) {
|
||||
throw new Error('Database connection not established');
|
||||
}
|
||||
const outLinkCollection = db.collection('outlinks');
|
||||
|
||||
// 1. 为所有 share 类型的记录添加 showFullText 字段
|
||||
const shareLinks = await outLinkCollection
|
||||
.find({
|
||||
type: PublishChannelEnum.share,
|
||||
showFullText: { $exists: false } // 只查找没有 showFullText 字段的记录
|
||||
})
|
||||
.toArray();
|
||||
|
||||
if (shareLinks.length > 0) {
|
||||
// 批量更新添加 showFullText 字段
|
||||
const showFullTextOps = shareLinks.map((link: any) => ({
|
||||
updateOne: {
|
||||
filter: { _id: link._id },
|
||||
update: { $set: { showFullText: link.showRawSource ?? true } }
|
||||
}
|
||||
}));
|
||||
|
||||
const showFullTextResult = await outLinkCollection.bulkWrite(showFullTextOps);
|
||||
totalUpdated += showFullTextResult.modifiedCount;
|
||||
updateResults.push({
|
||||
operation: 'Add showFullText field',
|
||||
updated: showFullTextResult.modifiedCount
|
||||
});
|
||||
|
||||
console.log(`Added showFullText field to ${showFullTextResult.modifiedCount} share links`);
|
||||
}
|
||||
|
||||
// 2. 重命名字段:showNodeStatus -> showRunningStatus
|
||||
const showNodeStatusLinks = await outLinkCollection
|
||||
.find({
|
||||
showNodeStatus: { $exists: true },
|
||||
showRunningStatus: { $exists: false }
|
||||
})
|
||||
.toArray();
|
||||
|
||||
if (showNodeStatusLinks.length > 0) {
|
||||
const renameNodeStatusOps = showNodeStatusLinks.map((link: any) => ({
|
||||
updateOne: {
|
||||
filter: { _id: link._id },
|
||||
update: [
|
||||
{
|
||||
$set: { showRunningStatus: '$showNodeStatus' }
|
||||
},
|
||||
{
|
||||
$unset: 'showNodeStatus'
|
||||
}
|
||||
]
|
||||
}
|
||||
}));
|
||||
|
||||
const renameNodeStatusResult = await outLinkCollection.bulkWrite(renameNodeStatusOps);
|
||||
totalUpdated += renameNodeStatusResult.modifiedCount;
|
||||
updateResults.push({
|
||||
operation: 'Rename showNodeStatus to showRunningStatus',
|
||||
updated: renameNodeStatusResult.modifiedCount
|
||||
});
|
||||
|
||||
console.log(
|
||||
`Renamed showNodeStatus to showRunningStatus for ${renameNodeStatusResult.modifiedCount} links`
|
||||
);
|
||||
}
|
||||
|
||||
// 3. 重命名字段:responseDetail -> showCite
|
||||
const responseDetailLinks = await outLinkCollection
|
||||
.find({
|
||||
responseDetail: { $exists: true },
|
||||
showCite: { $exists: false }
|
||||
})
|
||||
.toArray();
|
||||
|
||||
if (responseDetailLinks.length > 0) {
|
||||
const renameResponseDetailOps = responseDetailLinks.map((link: any) => ({
|
||||
updateOne: {
|
||||
filter: { _id: link._id },
|
||||
update: [
|
||||
{
|
||||
$set: { showCite: '$responseDetail' }
|
||||
},
|
||||
{
|
||||
$unset: 'responseDetail'
|
||||
}
|
||||
]
|
||||
}
|
||||
}));
|
||||
|
||||
const renameResponseDetailResult = await outLinkCollection.bulkWrite(renameResponseDetailOps);
|
||||
totalUpdated += renameResponseDetailResult.modifiedCount;
|
||||
updateResults.push({
|
||||
operation: 'Rename responseDetail to showCite',
|
||||
updated: renameResponseDetailResult.modifiedCount
|
||||
});
|
||||
|
||||
console.log(
|
||||
`Renamed responseDetail to showCite for ${renameResponseDetailResult.modifiedCount} links`
|
||||
);
|
||||
}
|
||||
|
||||
// 4. 重命名字段:showRawSource -> canDownloadSource
|
||||
const showRawSourceLinks = await outLinkCollection
|
||||
.find({
|
||||
showRawSource: { $exists: true },
|
||||
canDownloadSource: { $exists: false }
|
||||
})
|
||||
.toArray();
|
||||
|
||||
if (showRawSourceLinks.length > 0) {
|
||||
const renameRawSourceOps = showRawSourceLinks.map((link: any) => ({
|
||||
updateOne: {
|
||||
filter: { _id: link._id },
|
||||
update: [
|
||||
{
|
||||
$set: { canDownloadSource: '$showRawSource' }
|
||||
},
|
||||
{
|
||||
$unset: 'showRawSource'
|
||||
}
|
||||
]
|
||||
}
|
||||
}));
|
||||
|
||||
const renameRawSourceResult = await outLinkCollection.bulkWrite(renameRawSourceOps);
|
||||
totalUpdated += renameRawSourceResult.modifiedCount;
|
||||
updateResults.push({
|
||||
operation: 'Rename showRawSource to canDownloadSource',
|
||||
updated: renameRawSourceResult.modifiedCount
|
||||
});
|
||||
|
||||
console.log(
|
||||
`Renamed showRawSource to canDownloadSource for ${renameRawSourceResult.modifiedCount} links`
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
totalRecords: totalUpdated,
|
||||
updatedRecords: totalUpdated,
|
||||
updateResults
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 主处理函数
|
||||
*/
|
||||
async function handler(
|
||||
req: ApiRequestProps,
|
||||
_res: ApiResponseType<ResponseType>
|
||||
): Promise<ResponseType> {
|
||||
await authCert({ req, authRoot: true });
|
||||
|
||||
// 执行功能1: 重试 S3 删除任务
|
||||
const s3JobResult = await retryFailedS3DeleteJobs();
|
||||
|
||||
// 执行功能2&3: OutLink 数据迁移
|
||||
let shareLinkMigration = {
|
||||
totalRecords: 0,
|
||||
updatedRecords: 0,
|
||||
updateResults: [] as Array<{ operation: string; updated: number }>
|
||||
};
|
||||
|
||||
try {
|
||||
shareLinkMigration = await migrateOutLinkData();
|
||||
} catch (error) {
|
||||
console.error('Failed to migrate outLink data:', error);
|
||||
// 即使迁移失败,也继续返回 S3 任务处理的结果
|
||||
}
|
||||
|
||||
return {
|
||||
message: `Completed v4.14.5 initialization: S3 job retries and outLink migration`,
|
||||
retriedCount: s3JobResult.retriedCount,
|
||||
failedCount: s3JobResult.failedCount,
|
||||
shareLinkMigration
|
||||
};
|
||||
}
|
||||
|
||||
export default NextAPI(handler);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import { isS3ObjectKey } from '@fastgpt/service/common/s3/utils';
|
|||
import { MongoAppTemplate } from '@fastgpt/service/core/app/templates/templateSchema';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import path from 'node:path';
|
||||
import { updateParentFoldersUpdateTime } from '@fastgpt/service/core/app/controller';
|
||||
|
||||
export type CreateAppBody = {
|
||||
parentId?: ParentIdType;
|
||||
|
|
@ -243,6 +244,10 @@ export const onCreateApp = async ({
|
|||
|
||||
await getS3AvatarSource().refreshAvatar(_avatar, undefined, session);
|
||||
|
||||
updateParentFoldersUpdateTime({
|
||||
parentId
|
||||
});
|
||||
|
||||
(async () => {
|
||||
addAuditLog({
|
||||
tmbId,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { MongoApp } from '@fastgpt/service/core/app/schema';
|
|||
import type { StoreSecretValueType } from '@fastgpt/global/common/secret/type';
|
||||
import { storeSecretValue } from '@fastgpt/service/common/secret/utils';
|
||||
import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema';
|
||||
import { updateParentFoldersUpdateTime } from '@fastgpt/service/core/app/controller';
|
||||
|
||||
export type UpdateHttpPluginBody = {
|
||||
appId: string;
|
||||
|
|
@ -50,6 +51,7 @@ async function handler(req: ApiRequestProps<UpdateHttpPluginBody>, res: NextApiR
|
|||
},
|
||||
{ session }
|
||||
);
|
||||
|
||||
await MongoAppVersion.updateOne(
|
||||
{ appId },
|
||||
{
|
||||
|
|
@ -60,6 +62,9 @@ async function handler(req: ApiRequestProps<UpdateHttpPluginBody>, res: NextApiR
|
|||
{ session }
|
||||
);
|
||||
});
|
||||
updateParentFoldersUpdateTime({
|
||||
parentId: app.parentId
|
||||
});
|
||||
}
|
||||
|
||||
export default NextAPI(handler);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import { sumPer } from '@fastgpt/global/support/permission/utils';
|
|||
export type ListAppBody = {
|
||||
parentId?: ParentIdType;
|
||||
type?: AppTypeEnum | AppTypeEnum[];
|
||||
getRecentlyChat?: boolean;
|
||||
searchKey?: string;
|
||||
};
|
||||
|
||||
|
|
@ -38,7 +37,7 @@ export type ListAppBody = {
|
|||
*/
|
||||
|
||||
async function handler(req: ApiRequestProps<ListAppBody>): Promise<AppListItemType[]> {
|
||||
const { parentId, type, getRecentlyChat, searchKey } = req.body;
|
||||
const { parentId, type, searchKey } = req.body;
|
||||
|
||||
// Auth user permission
|
||||
const [{ tmbId, teamId, permission: teamPer }] = await Promise.all([
|
||||
|
|
@ -94,14 +93,6 @@ async function handler(req: ApiRequestProps<ListAppBody>): Promise<AppListItemTy
|
|||
);
|
||||
|
||||
const findAppsQuery = (() => {
|
||||
if (getRecentlyChat) {
|
||||
return {
|
||||
// get all chat app, excluding hidden apps and deleted apps
|
||||
teamId,
|
||||
type: { $in: [AppTypeEnum.workflow, AppTypeEnum.simple, AppTypeEnum.workflowTool] }
|
||||
};
|
||||
}
|
||||
|
||||
// Filter apps by permission, if not owner, only get apps that I have permission to access
|
||||
const idList = { _id: { $in: myPerList.map((item) => item.resourceId) } };
|
||||
const appPerQuery = teamPer.isOwner
|
||||
|
|
@ -153,7 +144,6 @@ async function handler(req: ApiRequestProps<ListAppBody>): Promise<AppListItemTy
|
|||
};
|
||||
})();
|
||||
const limit = (() => {
|
||||
if (getRecentlyChat) return 15;
|
||||
if (searchKey) return 50;
|
||||
return;
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { getMCPToolSetRuntimeNode } from '@fastgpt/global/core/app/tool/mcpTool/
|
|||
import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema';
|
||||
import { type StoreSecretValueType } from '@fastgpt/global/common/secret/type';
|
||||
import { storeSecretValue } from '@fastgpt/service/common/secret/utils';
|
||||
import { updateParentFoldersUpdateTime } from '@fastgpt/service/core/app/controller';
|
||||
|
||||
export type updateMCPToolsQuery = {};
|
||||
|
||||
|
|
@ -51,6 +52,7 @@ async function handler(
|
|||
},
|
||||
{ session }
|
||||
);
|
||||
|
||||
await MongoAppVersion.updateOne(
|
||||
{ appId },
|
||||
{
|
||||
|
|
@ -61,6 +63,9 @@ async function handler(
|
|||
{ session }
|
||||
);
|
||||
});
|
||||
updateParentFoldersUpdateTime({
|
||||
parentId: app.parentId
|
||||
});
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import { AuditEventEnum } from '@fastgpt/global/support/user/audit/constants';
|
|||
import { getI18nAppType } from '@fastgpt/service/support/user/audit/util';
|
||||
import { i18nT } from '@fastgpt/web/i18n/utils';
|
||||
import { getS3AvatarSource } from '@fastgpt/service/common/s3/sources/avatar';
|
||||
import { updateParentFoldersUpdateTime } from '@fastgpt/service/core/app/controller';
|
||||
|
||||
export type AppUpdateQuery = {
|
||||
appId: string;
|
||||
|
|
@ -117,7 +118,7 @@ async function handler(req: ApiRequestProps<AppUpdateBody, AppUpdateQuery>) {
|
|||
|
||||
await getS3AvatarSource().refreshAvatar(avatar, app.avatar, session);
|
||||
|
||||
return MongoApp.findByIdAndUpdate(
|
||||
const result = await MongoApp.findByIdAndUpdate(
|
||||
appId,
|
||||
{
|
||||
...parseParentIdInMongo(parentId),
|
||||
|
|
@ -133,10 +134,28 @@ async function handler(req: ApiRequestProps<AppUpdateBody, AppUpdateQuery>) {
|
|||
edges
|
||||
}),
|
||||
...(chatConfig && { chatConfig }),
|
||||
...(isMove && { inheritPermission: true })
|
||||
...(isMove && { inheritPermission: true }),
|
||||
updateTime: new Date()
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
|
||||
if (isMove) {
|
||||
// Update both old and new parent folders
|
||||
updateParentFoldersUpdateTime({
|
||||
parentId: app.parentId
|
||||
});
|
||||
updateParentFoldersUpdateTime({
|
||||
parentId
|
||||
});
|
||||
} else {
|
||||
// Update current parent folder
|
||||
updateParentFoldersUpdateTime({
|
||||
parentId: parentId || app.parentId
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
// Move
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { addAuditLog } from '@fastgpt/service/support/user/audit/util';
|
|||
import { AuditEventEnum } from '@fastgpt/global/support/user/audit/constants';
|
||||
import { getI18nAppType } from '@fastgpt/service/support/user/audit/util';
|
||||
import { i18nT } from '@fastgpt/web/i18n/utils';
|
||||
import { updateParentFoldersUpdateTime } from '@fastgpt/service/core/app/controller';
|
||||
|
||||
async function handler(req: ApiRequestProps<PostPublishAppProps>, res: NextApiResponse<any>) {
|
||||
const { appId } = req.query as { appId: string };
|
||||
|
|
@ -28,6 +29,9 @@ async function handler(req: ApiRequestProps<PostPublishAppProps>, res: NextApiRe
|
|||
beforeUpdateAppFormat({
|
||||
nodes
|
||||
});
|
||||
updateParentFoldersUpdateTime({
|
||||
parentId: app.parentId
|
||||
});
|
||||
|
||||
if (autoSave) {
|
||||
await mongoSessionRun(async (session) => {
|
||||
|
|
|
|||
|
|
@ -248,7 +248,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||
nodes,
|
||||
appChatConfig: chatConfig,
|
||||
variables: newVariables,
|
||||
isUpdateUseTime: false, // owner update use time
|
||||
newTitle,
|
||||
source: ChatSourceEnum.test,
|
||||
userContent: userQuestion,
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ async function handler(
|
|||
};
|
||||
}
|
||||
|
||||
const [app, { responseDetail, showNodeStatus, authType }] = await Promise.all([
|
||||
const [app, { showCite, showRunningStatus, authType }] = await Promise.all([
|
||||
MongoApp.findById(appId, 'type').lean(),
|
||||
authChatCrud({
|
||||
req,
|
||||
|
|
@ -81,16 +81,16 @@ async function handler(
|
|||
if (item.obj === ChatRoleEnum.AI) {
|
||||
item.responseData = filterPublicNodeResponseData({
|
||||
nodeRespones: item.responseData,
|
||||
responseDetail
|
||||
responseDetail: showCite
|
||||
});
|
||||
|
||||
if (showNodeStatus === false) {
|
||||
if (showRunningStatus === false) {
|
||||
item.value = item.value.filter((v) => v.type !== ChatItemValueTypeEnum.tool);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!responseDetail) {
|
||||
if (!showCite) {
|
||||
histories.forEach((item) => {
|
||||
if (item.obj === ChatRoleEnum.AI) {
|
||||
item.value = removeAIResponseCite(item.value, false);
|
||||
|
|
@ -99,7 +99,7 @@ async function handler(
|
|||
}
|
||||
|
||||
return {
|
||||
list: isPlugin ? histories : transformPreviewHistories(histories, responseDetail),
|
||||
list: isPlugin ? histories : transformPreviewHistories(histories, showCite),
|
||||
total
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ async function handler(
|
|||
};
|
||||
}
|
||||
|
||||
const [app, { responseDetail, showNodeStatus, authType }] = await Promise.all([
|
||||
const [app, { showCite, showRunningStatus, authType }] = await Promise.all([
|
||||
MongoApp.findById(appId, 'type').lean(),
|
||||
authChatCrud({
|
||||
req,
|
||||
|
|
@ -93,16 +93,16 @@ async function handler(
|
|||
if (item.obj === ChatRoleEnum.AI) {
|
||||
item.responseData = filterPublicNodeResponseData({
|
||||
nodeRespones: item.responseData,
|
||||
responseDetail
|
||||
responseDetail: showCite
|
||||
});
|
||||
|
||||
if (showNodeStatus === false) {
|
||||
if (showRunningStatus === false) {
|
||||
item.value = item.value.filter((v) => v.type !== ChatItemValueTypeEnum.tool);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!responseDetail) {
|
||||
if (!showCite) {
|
||||
result.histories.forEach((item) => {
|
||||
if (item.obj === ChatRoleEnum.AI) {
|
||||
item.value = removeAIResponseCite(item.value, false);
|
||||
|
|
@ -110,9 +110,7 @@ async function handler(
|
|||
});
|
||||
}
|
||||
|
||||
const list = isPlugin
|
||||
? result.histories
|
||||
: transformPreviewHistories(result.histories, responseDetail);
|
||||
const list = isPlugin ? result.histories : transformPreviewHistories(result.histories, showCite);
|
||||
|
||||
return {
|
||||
list: list.map((item) => ({
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ async function handler(
|
|||
return [];
|
||||
}
|
||||
|
||||
const [{ responseDetail }, chatData, nodeResponses] = await Promise.all([
|
||||
const [{ showCite }, chatData, nodeResponses] = await Promise.all([
|
||||
authChatCrud({
|
||||
req,
|
||||
authToken: true,
|
||||
|
|
@ -57,7 +57,7 @@ async function handler(
|
|||
const flowResponses = chatData.responseData?.length ? chatData.responseData : nodeResponses;
|
||||
return req.query.shareId
|
||||
? filterPublicNodeResponseData({
|
||||
responseDetail,
|
||||
responseDetail: showCite,
|
||||
nodeRespones: flowResponses
|
||||
})
|
||||
: flowResponses;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ import { NextAPI } from '@/service/middleware/entry';
|
|||
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { presignVariablesFileUrls } from '@fastgpt/service/core/chat/utils';
|
||||
import { MongoAppRecord } from '@fastgpt/service/core/app/record/schema';
|
||||
import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
|
||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||
|
||||
async function handler(
|
||||
req: NextApiRequest,
|
||||
|
|
@ -25,57 +28,74 @@ async function handler(
|
|||
});
|
||||
}
|
||||
|
||||
// auth app permission
|
||||
const [{ app, tmbId }, chat] = await Promise.all([
|
||||
authApp({
|
||||
req,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
appId,
|
||||
per: ReadPermissionVal
|
||||
}),
|
||||
chatId ? MongoChat.findOne({ appId, chatId }) : undefined
|
||||
]);
|
||||
|
||||
// auth chat permission
|
||||
if (chat && !app.permission.hasReadChatLogPer && String(tmbId) !== String(chat?.tmbId)) {
|
||||
return Promise.reject(ChatErrEnum.unAuthChat);
|
||||
}
|
||||
|
||||
// get app and history
|
||||
const { nodes, chatConfig } = await getAppLatestVersion(app._id, app);
|
||||
const pluginInputs =
|
||||
chat?.pluginInputs ??
|
||||
nodes?.find((node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput)?.inputs ??
|
||||
[];
|
||||
|
||||
const variables = await presignVariablesFileUrls({
|
||||
variables: chat?.variables,
|
||||
variableConfig: chat?.variableList
|
||||
});
|
||||
|
||||
return {
|
||||
chatId,
|
||||
appId,
|
||||
title: chat?.title,
|
||||
userAvatar: undefined,
|
||||
variables,
|
||||
app: {
|
||||
chatConfig: getAppChatConfig({
|
||||
chatConfig,
|
||||
systemConfigNode: getGuideModule(nodes),
|
||||
storeVariables: chat?.variableList,
|
||||
storeWelcomeText: chat?.welcomeText,
|
||||
isPublicFetch: false
|
||||
try {
|
||||
// auth app permission
|
||||
const [{ app, tmbId }, chat] = await Promise.all([
|
||||
authApp({
|
||||
req,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
appId,
|
||||
per: ReadPermissionVal
|
||||
}),
|
||||
chatModels: getChatModelNameListByModules(nodes),
|
||||
name: app.name,
|
||||
avatar: app.avatar,
|
||||
intro: app.intro,
|
||||
type: app.type,
|
||||
pluginInputs
|
||||
chatId ? MongoChat.findOne({ appId, chatId }) : undefined
|
||||
]);
|
||||
|
||||
// auth chat permission
|
||||
if (chat && !app.permission.hasReadChatLogPer && String(tmbId) !== String(chat?.tmbId)) {
|
||||
return Promise.reject(ChatErrEnum.unAuthChat);
|
||||
}
|
||||
};
|
||||
|
||||
// get app and history
|
||||
const { nodes, chatConfig } = await getAppLatestVersion(app._id, app);
|
||||
const pluginInputs =
|
||||
chat?.pluginInputs ??
|
||||
nodes?.find((node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput)?.inputs ??
|
||||
[];
|
||||
|
||||
const variables = await presignVariablesFileUrls({
|
||||
variables: chat?.variables,
|
||||
variableConfig: chat?.variableList
|
||||
});
|
||||
|
||||
return {
|
||||
chatId,
|
||||
appId,
|
||||
title: chat?.title,
|
||||
userAvatar: undefined,
|
||||
variables,
|
||||
app: {
|
||||
chatConfig: getAppChatConfig({
|
||||
chatConfig,
|
||||
systemConfigNode: getGuideModule(nodes),
|
||||
storeVariables: chat?.variableList,
|
||||
storeWelcomeText: chat?.welcomeText,
|
||||
isPublicFetch: false
|
||||
}),
|
||||
chatModels: getChatModelNameListByModules(nodes),
|
||||
name: app.name,
|
||||
avatar: app.avatar,
|
||||
intro: app.intro,
|
||||
type: app.type,
|
||||
pluginInputs
|
||||
}
|
||||
};
|
||||
} catch (error: any) {
|
||||
if (error === AppErrEnum.unAuthApp && appId) {
|
||||
const { tmbId } = await authCert({
|
||||
req,
|
||||
authToken: true,
|
||||
authApiKey: true
|
||||
});
|
||||
|
||||
await MongoAppRecord.deleteOne({
|
||||
tmbId,
|
||||
appId
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
export default NextAPI(handler);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { ApiRequestProps } from '@fastgpt/service/type/next';
|
|||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { getS3ChatSource } from '@fastgpt/service/common/s3/sources/chat';
|
||||
import { authChatCrud } from '@/service/support/permission/auth/chat';
|
||||
import type { PresignChatFileGetUrlParams } from '@fastgpt/global/openapi/core/chat/api';
|
||||
import type { PresignChatFileGetUrlParams } from '@fastgpt/global/openapi/core/chat/controler/api';
|
||||
|
||||
async function handler(req: ApiRequestProps<PresignChatFileGetUrlParams>): Promise<string> {
|
||||
const { key, appId, outLinkAuthData } = req.body;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { getS3ChatSource } from '@fastgpt/service/common/s3/sources/chat';
|
|||
import { authChatCrud } from '@/service/support/permission/auth/chat';
|
||||
import { authFrequencyLimit } from '@/service/common/frequencyLimit/api';
|
||||
import { addSeconds } from 'date-fns';
|
||||
import type { PresignChatFilePostUrlParams } from '@fastgpt/global/openapi/core/chat/api';
|
||||
import type { PresignChatFilePostUrlParams } from '@fastgpt/global/openapi/core/chat/controler/api';
|
||||
|
||||
const authUploadLimit = (tmbId: string) => {
|
||||
if (!global.feConfigs.uploadFileMaxAmount) return;
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ async function handler(
|
|||
|
||||
const limitedPageSize = Math.min(pageSize, 30);
|
||||
|
||||
const [collection, { chat, showRawSource }, chatItem] = await Promise.all([
|
||||
const [collection, { chat, showFullText }, chatItem] = await Promise.all([
|
||||
getCollectionWithDataset(collectionId),
|
||||
authChatCrud({
|
||||
req,
|
||||
|
|
@ -73,7 +73,7 @@ async function handler(
|
|||
authCollectionInChat({ appId, chatId, chatItemDataId, collectionIds: [collectionId] })
|
||||
]);
|
||||
|
||||
if (!showRawSource || !chat || !chatItem || initialAnchor === undefined) {
|
||||
if (!showFullText || !chat || !chatItem || initialAnchor === undefined) {
|
||||
return Promise.reject(ChatErrEnum.unAuthChat);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ async function handler(req: ApiRequestProps<GetQuoteProps>): Promise<GetQuotesRe
|
|||
datasetDataIdList
|
||||
} = req.body;
|
||||
|
||||
const [{ chat, responseDetail }, chatItem] = await Promise.all([
|
||||
const [{ chat, showCite }, chatItem] = await Promise.all([
|
||||
authChatCrud({
|
||||
req,
|
||||
authToken: true,
|
||||
|
|
@ -53,7 +53,7 @@ async function handler(req: ApiRequestProps<GetQuoteProps>): Promise<GetQuotesRe
|
|||
MongoChatItem.findOne({ appId, chatId, dataId: chatItemDataId }, 'time').lean(),
|
||||
authCollectionInChat({ appId, chatId, chatItemDataId, collectionIds: collectionIdList })
|
||||
]);
|
||||
if (!chat || !chatItem || !responseDetail) return Promise.reject(ChatErrEnum.unAuthChat);
|
||||
if (!chat || !chatItem || !showCite) return Promise.reject(ChatErrEnum.unAuthChat);
|
||||
|
||||
const list = await MongoDatasetData.find(
|
||||
{ _id: { $in: datasetDataIdList }, collectionId: { $in: collectionIdList } },
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
|
||||
import { MongoAppRecord } from '@fastgpt/service/core/app/record/schema';
|
||||
import { MongoApp } from '@fastgpt/service/core/app/schema';
|
||||
import type { GetRecentlyUsedAppsResponseType } from '@fastgpt/global/openapi/core/chat/api';
|
||||
|
||||
async function handler(
|
||||
req: ApiRequestProps<{}, {}>,
|
||||
_res: ApiResponseType
|
||||
): Promise<GetRecentlyUsedAppsResponseType> {
|
||||
const { tmbId } = await authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
authApiKey: true
|
||||
});
|
||||
|
||||
const recentRecords = await MongoAppRecord.find(
|
||||
{ tmbId },
|
||||
{ appId: 1 },
|
||||
{ sort: { lastUsedTime: -1 }, limit: 20 }
|
||||
).lean();
|
||||
|
||||
if (!recentRecords.length) return [];
|
||||
|
||||
const apps = await MongoApp.find(
|
||||
{ _id: { $in: recentRecords.map((record) => record.appId) } },
|
||||
'_id name avatar'
|
||||
).lean();
|
||||
|
||||
const appMap = new Map(apps.map((app) => [String(app._id), app]));
|
||||
|
||||
return recentRecords
|
||||
.map((record) => appMap.get(String(record.appId)))
|
||||
.filter((app) => app != null)
|
||||
.map((app) => ({
|
||||
appId: String(app._id),
|
||||
name: app.name,
|
||||
avatar: app.avatar
|
||||
}));
|
||||
}
|
||||
|
||||
export default NextAPI(handler);
|
||||
|
|
@ -67,7 +67,7 @@ async function handler(req: ApiRequestProps<ExportCollectionBody, {}>, res: Next
|
|||
authCollectionInChat({ appId, chatId, chatItemDataId, collectionIds: [collectionId] })
|
||||
]);
|
||||
|
||||
if (!authRes.showRawSource) {
|
||||
if (!authRes.canDownloadSource) {
|
||||
return Promise.reject(DatasetErrEnum.unAuthDatasetFile);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ async function handler(
|
|||
authCollectionInChat({ appId, chatId, chatItemDataId, collectionIds: [collectionId] })
|
||||
]);
|
||||
|
||||
if (!authRes.showRawSource) {
|
||||
if (!authRes.canDownloadSource) {
|
||||
return Promise.reject(DatasetErrEnum.unAuthDatasetFile);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ async function handler(req: ApiRequestProps<GetQuoteDataProps>): Promise<GetQuot
|
|||
return Promise.reject(i18nT('common:data_not_found'));
|
||||
}
|
||||
|
||||
const [collection, { responseDetail }] = await Promise.all([
|
||||
const [collection, { showCite }] = await Promise.all([
|
||||
MongoDatasetCollection.findById(datasetData.collectionId).lean(),
|
||||
authChatCrud({
|
||||
req,
|
||||
|
|
@ -73,7 +73,7 @@ async function handler(req: ApiRequestProps<GetQuoteDataProps>): Promise<GetQuot
|
|||
if (!collection) {
|
||||
return Promise.reject('Can not find the collection');
|
||||
}
|
||||
if (!responseDetail) {
|
||||
if (!showCite) {
|
||||
return Promise.reject(ChatErrEnum.unAuthChat);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
import { MongoOutLink } from '@fastgpt/service/support/outLink/schema';
|
||||
import { authApp } from '@fastgpt/service/support/permission/app/auth';
|
||||
import { PublishChannelEnum } from '@fastgpt/global/support/outLink/constant';
|
||||
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import type { ApiRequestProps } from '@fastgpt/service/type/next';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import {
|
||||
type PlaygroundVisibilityConfigQuery,
|
||||
type PlaygroundVisibilityConfigResponse,
|
||||
PlaygroundVisibilityConfigQuerySchema,
|
||||
PlaygroundVisibilityConfigResponseSchema
|
||||
} from '@fastgpt/global/support/outLink/api.d';
|
||||
|
||||
async function handler(
|
||||
req: ApiRequestProps<{}, PlaygroundVisibilityConfigQuery>
|
||||
): Promise<PlaygroundVisibilityConfigResponse> {
|
||||
const { appId } = PlaygroundVisibilityConfigQuerySchema.parse(req.query);
|
||||
|
||||
await authApp({
|
||||
req,
|
||||
authToken: true,
|
||||
appId,
|
||||
per: WritePermissionVal
|
||||
});
|
||||
|
||||
const existingConfig = await MongoOutLink.findOne(
|
||||
{
|
||||
appId,
|
||||
type: PublishChannelEnum.playground
|
||||
},
|
||||
'showRunningStatus showCite showFullText canDownloadSource'
|
||||
).lean();
|
||||
|
||||
return PlaygroundVisibilityConfigResponseSchema.parse({
|
||||
showRunningStatus: existingConfig?.showRunningStatus ?? true,
|
||||
showCite: existingConfig?.showCite ?? true,
|
||||
showFullText: existingConfig?.showFullText ?? true,
|
||||
canDownloadSource: existingConfig?.canDownloadSource ?? true
|
||||
});
|
||||
}
|
||||
|
||||
export default NextAPI(handler);
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
import { MongoOutLink } from '@fastgpt/service/support/outLink/schema';
|
||||
import { authApp } from '@fastgpt/service/support/permission/app/auth';
|
||||
import { PublishChannelEnum } from '@fastgpt/global/support/outLink/constant';
|
||||
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import type { ApiRequestProps } from '@fastgpt/service/type/next';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import {
|
||||
type UpdatePlaygroundVisibilityConfigBody,
|
||||
UpdatePlaygroundVisibilityConfigBodySchema
|
||||
} from '@fastgpt/global/support/outLink/api.d';
|
||||
|
||||
async function handler(req: ApiRequestProps<UpdatePlaygroundVisibilityConfigBody, {}>) {
|
||||
const { appId, showRunningStatus, showCite, showFullText, canDownloadSource } =
|
||||
UpdatePlaygroundVisibilityConfigBodySchema.parse(req.body);
|
||||
|
||||
const { teamId, tmbId } = await authApp({
|
||||
req,
|
||||
authToken: true,
|
||||
appId,
|
||||
per: WritePermissionVal
|
||||
});
|
||||
|
||||
await MongoOutLink.updateOne(
|
||||
{ appId, type: PublishChannelEnum.playground },
|
||||
{
|
||||
$setOnInsert: {
|
||||
shareId: `playground-${appId}`,
|
||||
teamId,
|
||||
tmbId,
|
||||
name: 'Playground Chat'
|
||||
},
|
||||
$set: {
|
||||
appId,
|
||||
type: PublishChannelEnum.playground,
|
||||
showRunningStatus: showRunningStatus,
|
||||
showCite: showCite,
|
||||
showFullText: showFullText,
|
||||
canDownloadSource: canDownloadSource
|
||||
}
|
||||
},
|
||||
{ upsert: true }
|
||||
);
|
||||
}
|
||||
|
||||
export default NextAPI(handler);
|
||||
|
|
@ -26,7 +26,8 @@ export type OutLinkUpdateResponse = string;
|
|||
async function handler(
|
||||
req: ApiRequestProps<OutLinkUpdateBody, OutLinkUpdateQuery>
|
||||
): Promise<OutLinkUpdateResponse> {
|
||||
const { _id, name, responseDetail, limit, app, showRawSource, showNodeStatus } = req.body;
|
||||
const { _id, name, showCite, limit, app, canDownloadSource, showRunningStatus, showFullText } =
|
||||
req.body;
|
||||
|
||||
if (!_id) {
|
||||
return Promise.reject(CommonErrEnum.missingParams);
|
||||
|
|
@ -46,10 +47,10 @@ async function handler(
|
|||
|
||||
const doc = await MongoOutLink.findByIdAndUpdate(_id, {
|
||||
name,
|
||||
responseDetail,
|
||||
showRawSource,
|
||||
showNodeStatus,
|
||||
// showFullText,
|
||||
showCite,
|
||||
canDownloadSource,
|
||||
showRunningStatus,
|
||||
showFullText,
|
||||
limit,
|
||||
app
|
||||
});
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import {
|
|||
} from '@fastgpt/service/core/chat/saveChat';
|
||||
import { responseWrite } from '@fastgpt/service/common/response';
|
||||
import { authOutLinkChatStart } from '@/service/support/permission/auth/outLink';
|
||||
import { recordAppUsage } from '@fastgpt/service/core/app/record/utils';
|
||||
import { pushResult2Remote, addOutLinkUsage } from '@fastgpt/service/support/outLink/tools';
|
||||
import { getUsageSourceByAuthType } from '@fastgpt/global/support/wallet/usage/tools';
|
||||
import { authTeamSpaceToken } from '@/service/support/permission/auth/team';
|
||||
|
|
@ -91,8 +92,8 @@ type AuthResponseType = {
|
|||
teamId: string;
|
||||
tmbId: string;
|
||||
app: AppSchema;
|
||||
responseDetail?: boolean;
|
||||
showNodeStatus?: boolean;
|
||||
showCite?: boolean;
|
||||
showRunningStatus?: boolean;
|
||||
authType: `${AuthUserTypeEnum}`;
|
||||
apikey?: string;
|
||||
responseAllData: boolean;
|
||||
|
|
@ -157,13 +158,13 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||
teamId,
|
||||
tmbId,
|
||||
app,
|
||||
responseDetail,
|
||||
showCite,
|
||||
authType,
|
||||
sourceName,
|
||||
apikey,
|
||||
responseAllData,
|
||||
outLinkUserId = customUid,
|
||||
showNodeStatus
|
||||
showRunningStatus
|
||||
} = await (async () => {
|
||||
// share chat
|
||||
if (shareId && outLinkUid) {
|
||||
|
|
@ -205,7 +206,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||
|
||||
pushTrack.teamChatQPM({ teamId });
|
||||
|
||||
retainDatasetCite = retainDatasetCite && !!responseDetail;
|
||||
retainDatasetCite = retainDatasetCite && !!showCite;
|
||||
const isPlugin = app.type === AppTypeEnum.workflowTool;
|
||||
|
||||
// Check message type
|
||||
|
|
@ -275,7 +276,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||
detail,
|
||||
streamResponse: stream,
|
||||
id: chatId,
|
||||
showNodeStatus
|
||||
showNodeStatus: showRunningStatus
|
||||
});
|
||||
|
||||
const saveChatId = chatId || getNanoid(24);
|
||||
|
|
@ -326,7 +327,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||
})();
|
||||
|
||||
// save chat
|
||||
const isOwnerUse = !shareId && !spaceTeamId && String(tmbId) === String(app.tmbId);
|
||||
const source = (() => {
|
||||
if (shareId) {
|
||||
return ChatSourceEnum.share;
|
||||
|
|
@ -363,7 +363,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||
nodes,
|
||||
appChatConfig: chatConfig,
|
||||
variables: newVariables,
|
||||
isUpdateUseTime: isOwnerUse && source === ChatSourceEnum.online, // owner update use time
|
||||
newTitle,
|
||||
shareId,
|
||||
outLinkUid: outLinkUserId,
|
||||
|
|
@ -383,12 +382,21 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||
await saveChat(params);
|
||||
}
|
||||
|
||||
const isOwnerUse = !shareId && !spaceTeamId && String(tmbId) === String(app.tmbId);
|
||||
if (isOwnerUse && source === ChatSourceEnum.online) {
|
||||
await recordAppUsage({
|
||||
appId: app._id,
|
||||
tmbId,
|
||||
teamId
|
||||
});
|
||||
}
|
||||
|
||||
addLog.info(`completions running time: ${(Date.now() - startTime) / 1000}s`);
|
||||
|
||||
/* select fe response field */
|
||||
const feResponseData = responseAllData
|
||||
? flowResponses
|
||||
: filterPublicNodeResponseData({ nodeRespones: flowResponses, responseDetail });
|
||||
: filterPublicNodeResponseData({ nodeRespones: flowResponses, responseDetail: showCite });
|
||||
|
||||
if (stream) {
|
||||
workflowResponseWrite({
|
||||
|
|
@ -508,7 +516,7 @@ const authShareChat = async ({
|
|||
shareId: string;
|
||||
chatId?: string;
|
||||
}): Promise<AuthResponseType> => {
|
||||
const { teamId, tmbId, appId, authType, responseDetail, showNodeStatus, uid, sourceName } =
|
||||
const { teamId, tmbId, appId, authType, showCite, showRunningStatus, uid, sourceName } =
|
||||
await authOutLinkChatStart(data);
|
||||
const app = await MongoApp.findById(appId).lean();
|
||||
|
||||
|
|
@ -530,9 +538,9 @@ const authShareChat = async ({
|
|||
apikey: '',
|
||||
authType,
|
||||
responseAllData: false,
|
||||
responseDetail,
|
||||
showCite,
|
||||
outLinkUserId: uid,
|
||||
showNodeStatus
|
||||
showRunningStatus
|
||||
};
|
||||
};
|
||||
const authTeamSpaceChat = async ({
|
||||
|
|
@ -569,7 +577,7 @@ const authTeamSpaceChat = async ({
|
|||
authType: AuthUserTypeEnum.outLink,
|
||||
apikey: '',
|
||||
responseAllData: false,
|
||||
responseDetail: true,
|
||||
showCite: true,
|
||||
outLinkUserId: uid
|
||||
};
|
||||
};
|
||||
|
|
@ -651,7 +659,7 @@ const authHeaderRequest = async ({
|
|||
authType,
|
||||
sourceName,
|
||||
responseAllData: true,
|
||||
responseDetail: true
|
||||
showCite: true
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import {
|
|||
} from '@fastgpt/service/core/chat/saveChat';
|
||||
import { responseWrite } from '@fastgpt/service/common/response';
|
||||
import { authOutLinkChatStart } from '@/service/support/permission/auth/outLink';
|
||||
import { recordAppUsage } from '@fastgpt/service/core/app/record/utils';
|
||||
import { pushResult2Remote, addOutLinkUsage } from '@fastgpt/service/support/outLink/tools';
|
||||
import { getUsageSourceByAuthType } from '@fastgpt/global/support/wallet/usage/tools';
|
||||
import { authTeamSpaceToken } from '@/service/support/permission/auth/team';
|
||||
|
|
@ -92,8 +93,8 @@ type AuthResponseType = {
|
|||
teamId: string;
|
||||
tmbId: string;
|
||||
app: AppSchema;
|
||||
responseDetail?: boolean;
|
||||
showNodeStatus?: boolean;
|
||||
showCite?: boolean;
|
||||
showRunningStatus?: boolean;
|
||||
authType: `${AuthUserTypeEnum}`;
|
||||
apikey?: string;
|
||||
responseAllData: boolean;
|
||||
|
|
@ -158,13 +159,13 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||
teamId,
|
||||
tmbId,
|
||||
app,
|
||||
responseDetail,
|
||||
showCite,
|
||||
authType,
|
||||
sourceName,
|
||||
apikey,
|
||||
responseAllData,
|
||||
outLinkUserId = customUid,
|
||||
showNodeStatus
|
||||
showRunningStatus
|
||||
} = await (async () => {
|
||||
// share chat
|
||||
if (shareId && outLinkUid) {
|
||||
|
|
@ -206,7 +207,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||
|
||||
pushTrack.teamChatQPM({ teamId });
|
||||
|
||||
retainDatasetCite = retainDatasetCite && !!responseDetail;
|
||||
retainDatasetCite = retainDatasetCite && !!showCite;
|
||||
const isPlugin = app.type === AppTypeEnum.workflowTool;
|
||||
|
||||
// Check message type
|
||||
|
|
@ -275,7 +276,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||
detail,
|
||||
streamResponse: stream,
|
||||
id: chatId,
|
||||
showNodeStatus
|
||||
showNodeStatus: showRunningStatus
|
||||
});
|
||||
|
||||
const saveChatId = chatId || getNanoid(24);
|
||||
|
|
@ -321,14 +322,13 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||
maxRunTimes: WORKFLOW_MAX_RUN_TIMES,
|
||||
workflowStreamResponse: workflowResponseWrite,
|
||||
responseAllData,
|
||||
responseDetail
|
||||
responseDetail: showCite
|
||||
});
|
||||
}
|
||||
return Promise.reject('您的工作流版本过低,请重新发布一次');
|
||||
})();
|
||||
|
||||
// save chat
|
||||
const isOwnerUse = !shareId && !spaceTeamId && String(tmbId) === String(app.tmbId);
|
||||
const source = (() => {
|
||||
if (shareId) {
|
||||
return ChatSourceEnum.share;
|
||||
|
|
@ -365,7 +365,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||
nodes,
|
||||
appChatConfig: chatConfig,
|
||||
variables: newVariables,
|
||||
isUpdateUseTime: isOwnerUse && source === ChatSourceEnum.online, // owner update use time
|
||||
newTitle,
|
||||
shareId,
|
||||
outLinkUid: outLinkUserId,
|
||||
|
|
@ -385,12 +384,21 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||
await saveChat(params);
|
||||
}
|
||||
|
||||
const isOwnerUse = !shareId && !spaceTeamId && String(tmbId) === String(app.tmbId);
|
||||
if (isOwnerUse && source === ChatSourceEnum.online) {
|
||||
await recordAppUsage({
|
||||
appId: app._id,
|
||||
tmbId,
|
||||
teamId
|
||||
});
|
||||
}
|
||||
|
||||
addLog.info(`completions running time: ${(Date.now() - startTime) / 1000}s`);
|
||||
|
||||
/* select fe response field */
|
||||
const feResponseData = responseAllData
|
||||
? flowResponses
|
||||
: filterPublicNodeResponseData({ nodeRespones: flowResponses, responseDetail });
|
||||
: filterPublicNodeResponseData({ nodeRespones: flowResponses, responseDetail: showCite });
|
||||
|
||||
if (stream) {
|
||||
workflowResponseWrite({
|
||||
|
|
@ -503,7 +511,7 @@ const authShareChat = async ({
|
|||
shareId: string;
|
||||
chatId?: string;
|
||||
}): Promise<AuthResponseType> => {
|
||||
const { teamId, tmbId, appId, authType, responseDetail, showNodeStatus, uid, sourceName } =
|
||||
const { teamId, tmbId, appId, authType, showCite, showRunningStatus, uid, sourceName } =
|
||||
await authOutLinkChatStart(data);
|
||||
const app = await MongoApp.findById(appId).lean();
|
||||
|
||||
|
|
@ -525,9 +533,9 @@ const authShareChat = async ({
|
|||
apikey: '',
|
||||
authType,
|
||||
responseAllData: false,
|
||||
responseDetail,
|
||||
showCite,
|
||||
outLinkUserId: uid,
|
||||
showNodeStatus
|
||||
showRunningStatus
|
||||
};
|
||||
};
|
||||
const authTeamSpaceChat = async ({
|
||||
|
|
@ -564,7 +572,7 @@ const authTeamSpaceChat = async ({
|
|||
authType: AuthUserTypeEnum.outLink,
|
||||
apikey: '',
|
||||
responseAllData: false,
|
||||
responseDetail: true,
|
||||
showCite: true,
|
||||
outLinkUserId: uid
|
||||
};
|
||||
};
|
||||
|
|
@ -646,7 +654,7 @@ const authHeaderRequest = async ({
|
|||
authType,
|
||||
sourceName,
|
||||
responseAllData: true,
|
||||
responseDetail: true
|
||||
showCite: true
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,10 @@ import {
|
|||
setAgentRuntimeStop,
|
||||
waitForWorkflowComplete
|
||||
} from '@fastgpt/service/core/workflow/dispatch/workflowStatus';
|
||||
import { StopV2ChatSchema, type StopV2ChatResponse } from '@fastgpt/global/openapi/core/chat/api';
|
||||
import {
|
||||
StopV2ChatSchema,
|
||||
type StopV2ChatResponse
|
||||
} from '@fastgpt/global/openapi/core/chat/controler/api';
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse): Promise<StopV2ChatResponse> {
|
||||
const { appId, chatId, outLinkAuthData } = StopV2ChatSchema.parse(req.body);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import { serviceSideProps } from '@/web/common/i18n/utils';
|
|||
import { ChatSidebarPaneEnum } from '@/pageComponents/chat/constants';
|
||||
import { GetChatTypeEnum } from '@/global/core/chat/constants';
|
||||
import ChatContextProvider from '@/web/core/chat/context/chatContext';
|
||||
import { type AppListItemType } from '@fastgpt/global/core/app/type';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { useSystem } from '@fastgpt/web/hooks/useSystem';
|
||||
import { ChatSourceEnum } from '@fastgpt/global/core/chat/constants';
|
||||
|
|
@ -18,19 +17,18 @@ import ChatQuoteList from '@/pageComponents/chat/ChatQuoteList';
|
|||
import LoginModal from '@/pageComponents/login/LoginModal';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import ChatSetting from '@/pageComponents/chat/ChatSetting';
|
||||
import { useChat } from '@/pageComponents/chat/useChat';
|
||||
import AppChatWindow from '@/pageComponents/chat/ChatWindow/AppChatWindow';
|
||||
import HomeChatWindow from '@/pageComponents/chat/ChatWindow/HomeChatWindow';
|
||||
import {
|
||||
ChatSettingContext,
|
||||
ChatSettingContextProvider
|
||||
} from '@/web/core/chat/context/chatSettingContext';
|
||||
import { ChatPageContext, ChatPageContextProvider } from '@/web/core/chat/context/chatPageContext';
|
||||
import ChatTeamApp from '@/pageComponents/chat/ChatTeamApp';
|
||||
import ChatFavouriteApp from '@/pageComponents/chat/ChatFavouriteApp';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import type { LoginSuccessResponse } from '@/global/support/api/userRes';
|
||||
import { MongoOutLink } from '@fastgpt/service/support/outLink/schema';
|
||||
import { addLog } from '@fastgpt/service/common/system/log';
|
||||
import { PublishChannelEnum } from '@fastgpt/global/support/outLink/constant';
|
||||
|
||||
const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
|
||||
const Chat = () => {
|
||||
const { isPc } = useSystem();
|
||||
|
||||
const { appId } = useChatStore();
|
||||
|
|
@ -38,8 +36,8 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
|
|||
const datasetCiteData = useContextSelector(ChatItemContext, (v) => v.datasetCiteData);
|
||||
const setCiteModalData = useContextSelector(ChatItemContext, (v) => v.setCiteModalData);
|
||||
|
||||
const collapse = useContextSelector(ChatSettingContext, (v) => v.collapse);
|
||||
const pane = useContextSelector(ChatSettingContext, (v) => v.pane);
|
||||
const collapse = useContextSelector(ChatPageContext, (v) => v.collapse);
|
||||
const pane = useContextSelector(ChatPageContext, (v) => v.pane);
|
||||
|
||||
return (
|
||||
<Flex h={'100%'}>
|
||||
|
|
@ -52,14 +50,14 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
|
|||
overflow={'hidden'}
|
||||
transition={'width 0.1s ease-in-out'}
|
||||
>
|
||||
<ChatSlider apps={myApps} activeAppId={appId} />
|
||||
<ChatSlider activeAppId={appId} />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{(!datasetCiteData || isPc) && (
|
||||
<PageContainer flex="1 0 0" w={0} position="relative">
|
||||
{/* home chat window */}
|
||||
{pane === ChatSidebarPaneEnum.HOME && <HomeChatWindow myApps={myApps} />}
|
||||
{pane === ChatSidebarPaneEnum.HOME && <HomeChatWindow />}
|
||||
|
||||
{/* favourite apps */}
|
||||
{pane === ChatSidebarPaneEnum.FAVORITE_APPS && <ChatFavouriteApp />}
|
||||
|
|
@ -68,7 +66,7 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
|
|||
{pane === ChatSidebarPaneEnum.TEAM_APPS && <ChatTeamApp />}
|
||||
|
||||
{/* recently used apps chat window */}
|
||||
{pane === ChatSidebarPaneEnum.RECENTLY_USED_APPS && <AppChatWindow myApps={myApps} />}
|
||||
{pane === ChatSidebarPaneEnum.RECENTLY_USED_APPS && <AppChatWindow />}
|
||||
|
||||
{/* setting */}
|
||||
{pane === ChatSidebarPaneEnum.SETTING && <ChatSetting />}
|
||||
|
|
@ -88,12 +86,23 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
|
|||
);
|
||||
};
|
||||
|
||||
const Render = (props: { appId: string; isStandalone?: string }) => {
|
||||
type ChatPageProps = {
|
||||
appId: string;
|
||||
isStandalone?: string;
|
||||
showRunningStatus: boolean;
|
||||
showCite: boolean;
|
||||
showFullText: boolean;
|
||||
canDownloadSource: boolean;
|
||||
};
|
||||
|
||||
const ChatContent = (props: ChatPageProps) => {
|
||||
const { appId, isStandalone } = props;
|
||||
const { chatId } = useChatStore();
|
||||
const { setUserInfo } = useUserStore();
|
||||
const { feConfigs } = useSystemStore();
|
||||
const { isInitedUser, userInfo, myApps } = useChat(appId);
|
||||
|
||||
const isInitedUser = useContextSelector(ChatPageContext, (v) => v.isInitedUser);
|
||||
const userInfo = useContextSelector(ChatPageContext, (v) => v.userInfo);
|
||||
|
||||
const chatHistoryProviderParams = useMemo(
|
||||
() => ({ appId, source: ChatSourceEnum.online }),
|
||||
|
|
@ -134,31 +143,62 @@ const Render = (props: { appId: string; isStandalone?: string }) => {
|
|||
|
||||
// show main chat interface
|
||||
return (
|
||||
<ChatSettingContextProvider>
|
||||
<ChatContextProvider params={chatHistoryProviderParams}>
|
||||
<ChatItemContextProvider
|
||||
showRouteToDatasetDetail={isStandalone !== '1'}
|
||||
isShowReadRawSource={true}
|
||||
isResponseDetail={true}
|
||||
showNodeStatus
|
||||
>
|
||||
<ChatRecordContextProvider params={chatRecordProviderParams}>
|
||||
<Chat myApps={myApps} />
|
||||
</ChatRecordContextProvider>
|
||||
</ChatItemContextProvider>
|
||||
</ChatContextProvider>
|
||||
</ChatSettingContextProvider>
|
||||
<ChatContextProvider params={chatHistoryProviderParams}>
|
||||
<ChatItemContextProvider
|
||||
showRouteToDatasetDetail={isStandalone !== '1'}
|
||||
showRunningStatus={props.showRunningStatus}
|
||||
canDownloadSource={props.canDownloadSource}
|
||||
isShowCite={props.showCite}
|
||||
isShowFullText={props.showFullText}
|
||||
>
|
||||
<ChatRecordContextProvider params={chatRecordProviderParams}>
|
||||
<Chat />
|
||||
</ChatRecordContextProvider>
|
||||
</ChatItemContextProvider>
|
||||
</ChatContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
const Render = (props: ChatPageProps) => {
|
||||
return (
|
||||
<ChatPageContextProvider appId={props.appId}>
|
||||
<ChatContent {...props} />
|
||||
</ChatPageContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default Render;
|
||||
|
||||
export async function getServerSideProps(context: any) {
|
||||
const appId = context?.query?.appId || '';
|
||||
|
||||
const chatQuoteReaderConfig = await (async () => {
|
||||
try {
|
||||
if (!appId) return null;
|
||||
|
||||
const config = await MongoOutLink.findOne(
|
||||
{
|
||||
appId,
|
||||
type: PublishChannelEnum.playground
|
||||
},
|
||||
'showRunningStatus showCite showFullText canDownloadSource'
|
||||
).lean();
|
||||
|
||||
return config;
|
||||
} catch (error) {
|
||||
addLog.error('getServerSideProps', error);
|
||||
return null;
|
||||
}
|
||||
})();
|
||||
|
||||
return {
|
||||
props: {
|
||||
appId: context?.query?.appId || '',
|
||||
isStandalone: context?.query?.isStandalone || '',
|
||||
...(await serviceSideProps(context, ['file', 'app', 'chat', 'workflow', 'user', 'login']))
|
||||
appId,
|
||||
showRunningStatus: chatQuoteReaderConfig?.showRunningStatus ?? true,
|
||||
showCite: chatQuoteReaderConfig?.showCite ?? true,
|
||||
showFullText: chatQuoteReaderConfig?.showFullText ?? true,
|
||||
canDownloadSource: chatQuoteReaderConfig?.canDownloadSource ?? true,
|
||||
...(await serviceSideProps(context, ['file', 'app', 'chat', 'workflow']))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default Render;
|
||||
|
|
|
|||
|
|
@ -53,10 +53,10 @@ type Props = {
|
|||
shareId: string;
|
||||
authToken: string;
|
||||
customUid: string;
|
||||
showRawSource: boolean;
|
||||
responseDetail: boolean;
|
||||
// showFullText: boolean;
|
||||
showNodeStatus: boolean;
|
||||
canDownloadSource: boolean;
|
||||
isShowCite: boolean;
|
||||
isShowFullText: boolean;
|
||||
showRunningStatus: boolean;
|
||||
};
|
||||
|
||||
const OutLink = (props: Props) => {
|
||||
|
|
@ -95,7 +95,7 @@ const OutLink = (props: Props) => {
|
|||
const setChatBoxData = useContextSelector(ChatItemContext, (v) => v.setChatBoxData);
|
||||
const datasetCiteData = useContextSelector(ChatItemContext, (v) => v.datasetCiteData);
|
||||
const setCiteModalData = useContextSelector(ChatItemContext, (v) => v.setCiteModalData);
|
||||
const isResponseDetail = useContextSelector(ChatItemContext, (v) => v.isResponseDetail);
|
||||
const isShowCite = useContextSelector(ChatItemContext, (v) => v.isShowCite);
|
||||
|
||||
const chatRecords = useContextSelector(ChatRecordContext, (v) => v.chatRecords);
|
||||
const totalRecordsCount = useContextSelector(ChatRecordContext, (v) => v.totalRecordsCount);
|
||||
|
|
@ -175,7 +175,7 @@ const OutLink = (props: Props) => {
|
|||
responseChatItemId,
|
||||
chatId: completionChatId,
|
||||
...outLinkAuthData,
|
||||
retainDatasetCite: isResponseDetail
|
||||
retainDatasetCite: isShowCite
|
||||
},
|
||||
onMessage: generatingMessage,
|
||||
abortCtrl: controller
|
||||
|
|
@ -213,7 +213,7 @@ const OutLink = (props: Props) => {
|
|||
chatId,
|
||||
customVariables,
|
||||
outLinkAuthData,
|
||||
isResponseDetail,
|
||||
isShowCite,
|
||||
onUpdateHistoryTitle,
|
||||
setChatBoxData,
|
||||
forbidLoadChat,
|
||||
|
|
@ -388,10 +388,10 @@ const Render = (props: Props) => {
|
|||
<ChatContextProvider params={chatHistoryProviderParams}>
|
||||
<ChatItemContextProvider
|
||||
showRouteToDatasetDetail={false}
|
||||
isShowReadRawSource={props.showRawSource}
|
||||
isResponseDetail={props.responseDetail}
|
||||
// isShowFullText={props.showFullText}
|
||||
showNodeStatus={props.showNodeStatus}
|
||||
canDownloadSource={props.canDownloadSource}
|
||||
isShowCite={props.isShowCite}
|
||||
isShowFullText={props.isShowFullText}
|
||||
showRunningStatus={props.showRunningStatus}
|
||||
>
|
||||
<ChatRecordContextProvider params={chatRecordProviderParams}>
|
||||
<OutLink {...props} />
|
||||
|
|
@ -416,7 +416,7 @@ export async function getServerSideProps(context: any) {
|
|||
{
|
||||
shareId
|
||||
},
|
||||
'appId showRawSource showNodeStatus responseDetail'
|
||||
'appId canDownloadSource showCite showFullText showRunningStatus'
|
||||
)
|
||||
.populate<{ associatedApp: AppSchema }>('associatedApp', 'name avatar intro')
|
||||
.lean();
|
||||
|
|
@ -432,10 +432,10 @@ export async function getServerSideProps(context: any) {
|
|||
appName: app?.associatedApp?.name ?? 'AI',
|
||||
appAvatar: app?.associatedApp?.avatar ?? '',
|
||||
appIntro: app?.associatedApp?.intro ?? 'AI',
|
||||
showRawSource: app?.showRawSource ?? false,
|
||||
responseDetail: app?.responseDetail ?? false,
|
||||
// showFullText: app?.showFullText ?? false,
|
||||
showNodeStatus: app?.showNodeStatus ?? false,
|
||||
canDownloadSource: app?.canDownloadSource ?? false,
|
||||
isShowCite: app?.showCite ?? false,
|
||||
isShowFullText: app?.showFullText ?? false,
|
||||
showRunningStatus: app?.showRunningStatus ?? false,
|
||||
shareId: shareId ?? '',
|
||||
authToken: authToken ?? '',
|
||||
customUid,
|
||||
|
|
|
|||
|
|
@ -101,7 +101,6 @@ export const getScheduleTriggerApp = async () => {
|
|||
nodes,
|
||||
appChatConfig: chatConfig,
|
||||
variables: {},
|
||||
isUpdateUseTime: false, // owner update use time
|
||||
newTitle: 'Cron Job',
|
||||
source: ChatSourceEnum.cronJob,
|
||||
userContent: {
|
||||
|
|
|
|||
|
|
@ -257,7 +257,6 @@ export const callMcpServerTool = async ({ key, toolName, inputs }: toolCallProps
|
|||
nodes,
|
||||
appChatConfig: chatConfig,
|
||||
variables: newVariables,
|
||||
isUpdateUseTime: false, // owner update use time
|
||||
newTitle,
|
||||
source: ChatSourceEnum.mcp,
|
||||
userContent: userQuestion,
|
||||
|
|
|
|||
|
|
@ -24,9 +24,10 @@ import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
|||
Chat没有读写的权限之分,鉴权过了,都可以操作。
|
||||
*/
|
||||
export const defaultResponseShow = {
|
||||
responseDetail: true,
|
||||
showNodeStatus: true,
|
||||
showRawSource: true
|
||||
showCite: true,
|
||||
showRunningStatus: true,
|
||||
showFullText: true,
|
||||
canDownloadSource: true
|
||||
};
|
||||
type AuthChatCommonProps = {
|
||||
appId: string;
|
||||
|
|
@ -54,9 +55,10 @@ export async function authChatCrud({
|
|||
tmbId: string;
|
||||
uid: string;
|
||||
chat?: ChatSchemaType;
|
||||
responseDetail: boolean;
|
||||
showNodeStatus: boolean;
|
||||
showRawSource: boolean;
|
||||
showCite: boolean;
|
||||
showRunningStatus: boolean;
|
||||
showFullText: boolean;
|
||||
canDownloadSource: boolean;
|
||||
authType?: `${AuthUserTypeEnum}`;
|
||||
}> {
|
||||
if (!appId) return Promise.reject(ChatErrEnum.unAuthChat);
|
||||
|
|
@ -109,9 +111,11 @@ export async function authChatCrud({
|
|||
teamId: String(outLinkConfig.teamId),
|
||||
tmbId: String(outLinkConfig.tmbId),
|
||||
uid,
|
||||
responseDetail: outLinkConfig.responseDetail,
|
||||
showNodeStatus: outLinkConfig.showNodeStatus ?? true,
|
||||
showRawSource: outLinkConfig.showRawSource ?? false,
|
||||
|
||||
showCite: outLinkConfig.showCite ?? false,
|
||||
showRunningStatus: outLinkConfig.showRunningStatus ?? true,
|
||||
showFullText: outLinkConfig.showFullText ?? false,
|
||||
canDownloadSource: outLinkConfig.canDownloadSource ?? false,
|
||||
authType: AuthUserTypeEnum.outLink
|
||||
};
|
||||
}
|
||||
|
|
@ -123,9 +127,10 @@ export async function authChatCrud({
|
|||
teamId: String(outLinkConfig.teamId),
|
||||
tmbId: String(outLinkConfig.tmbId),
|
||||
uid,
|
||||
responseDetail: outLinkConfig.responseDetail,
|
||||
showNodeStatus: outLinkConfig.showNodeStatus ?? true,
|
||||
showRawSource: outLinkConfig.showRawSource ?? false,
|
||||
showCite: outLinkConfig.showCite ?? false,
|
||||
showRunningStatus: outLinkConfig.showRunningStatus ?? true,
|
||||
showFullText: outLinkConfig.showFullText ?? false,
|
||||
canDownloadSource: outLinkConfig.canDownloadSource ?? false,
|
||||
authType: AuthUserTypeEnum.outLink
|
||||
};
|
||||
}
|
||||
|
|
@ -135,9 +140,10 @@ export async function authChatCrud({
|
|||
tmbId: String(outLinkConfig.tmbId),
|
||||
chat,
|
||||
uid,
|
||||
responseDetail: outLinkConfig.responseDetail,
|
||||
showNodeStatus: outLinkConfig.showNodeStatus ?? true,
|
||||
showRawSource: outLinkConfig.showRawSource ?? false,
|
||||
showCite: outLinkConfig.showCite ?? false,
|
||||
showRunningStatus: outLinkConfig.showRunningStatus ?? true,
|
||||
showFullText: outLinkConfig.showFullText ?? false,
|
||||
canDownloadSource: outLinkConfig.canDownloadSource ?? false,
|
||||
authType: AuthUserTypeEnum.outLink
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,8 +63,10 @@ export async function authOutLinkChatStart({
|
|||
teamId: outLinkConfig.teamId,
|
||||
tmbId: outLinkConfig.tmbId,
|
||||
authType: AuthUserTypeEnum.token,
|
||||
responseDetail: outLinkConfig.responseDetail,
|
||||
showNodeStatus: outLinkConfig.showNodeStatus,
|
||||
showCite: outLinkConfig.showCite,
|
||||
showRunningStatus: outLinkConfig.showRunningStatus,
|
||||
showFullText: outLinkConfig.showFullText,
|
||||
canDownloadSource: outLinkConfig.canDownloadSource,
|
||||
appId,
|
||||
uid
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,11 +14,6 @@ export const getMyApps = (data?: ListAppBody) =>
|
|||
maxQuantity: 1
|
||||
});
|
||||
|
||||
export const getRecentlyUsedApps = (data?: ListAppBody) =>
|
||||
POST<AppListItemType[]>('/core/app/list?t=0', data, {
|
||||
maxQuantity: 1
|
||||
});
|
||||
|
||||
/**
|
||||
* 创建一个应用
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -26,10 +26,10 @@ export const defaultApp: AppDetailType = {
|
|||
|
||||
export const defaultOutLinkForm: OutLinkEditType = {
|
||||
name: '',
|
||||
showNodeStatus: true,
|
||||
responseDetail: false,
|
||||
// showFullText: false,
|
||||
showRawSource: false,
|
||||
showRunningStatus: true,
|
||||
showCite: false,
|
||||
showFullText: false,
|
||||
canDownloadSource: false,
|
||||
limit: {
|
||||
QPM: 100,
|
||||
maxUsagePoints: -1
|
||||
|
|
|
|||
|
|
@ -24,7 +24,11 @@ import type {
|
|||
UpdateFavouriteAppParamsType
|
||||
} from '@fastgpt/global/openapi/core/chat/favourite/api';
|
||||
import type { ChatFavouriteAppType } from '@fastgpt/global/core/chat/favouriteApp/type';
|
||||
import type { StopV2ChatParams } from '@fastgpt/global/openapi/core/chat/api';
|
||||
import type { StopV2ChatParams } from '@fastgpt/global/openapi/core/chat/controler/api';
|
||||
import type { GetRecentlyUsedAppsResponseType } from '@fastgpt/global/openapi/core/chat/api';
|
||||
|
||||
export const getRecentlyUsedApps = () =>
|
||||
GET<GetRecentlyUsedAppsResponseType>('/core/chat/recentlyUsed', undefined, { maxQuantity: 1 });
|
||||
|
||||
/**
|
||||
* 获取初始化聊天内容
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue