mirror of
https://github.com/labring/FastGPT.git
synced 2026-02-28 01:02:28 +08:00
chat log soft delete (#6110)
* chat log soft delete * perf: history api * add history test * Update packages/web/i18n/en/app.json Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * zod parse error * fix: ts --------- Co-authored-by: archer <545436317@qq.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
2
packages/global/common/file/api.d.ts
vendored
2
packages/global/common/file/api.d.ts
vendored
@@ -1,4 +1,4 @@
|
||||
import type { OutLinkChatAuthProps } from '../../support/permission/chat.d';
|
||||
import type { OutLinkChatAuthProps } from '../../support/permission/chat';
|
||||
|
||||
export type preUploadImgProps = OutLinkChatAuthProps & {
|
||||
// expiredTime?: Date;
|
||||
|
||||
@@ -37,7 +37,7 @@ export const AppLogKeysEnumMap = {
|
||||
};
|
||||
|
||||
export const DefaultAppLogKeys = [
|
||||
{ key: AppLogKeysEnum.SOURCE, enable: true },
|
||||
{ key: AppLogKeysEnum.SOURCE, enable: false },
|
||||
{ key: AppLogKeysEnum.USER, enable: true },
|
||||
{ key: AppLogKeysEnum.TITLE, enable: true },
|
||||
{ key: AppLogKeysEnum.SESSION_ID, enable: false },
|
||||
|
||||
4
packages/global/core/chat/type.d.ts
vendored
4
packages/global/core/chat/type.d.ts
vendored
@@ -51,6 +51,8 @@ export type ChatSchemaType = {
|
||||
hasBadFeedback?: boolean;
|
||||
hasUnreadGoodFeedback?: boolean;
|
||||
hasUnreadBadFeedback?: boolean;
|
||||
|
||||
deleteTime?: Date | null;
|
||||
};
|
||||
|
||||
export type ChatWithAppSchema = Omit<ChatSchemaType, 'appId'> & {
|
||||
@@ -197,7 +199,7 @@ export type HistoryItemType = {
|
||||
};
|
||||
export type ChatHistoryItemType = HistoryItemType & {
|
||||
appId: string;
|
||||
top: boolean;
|
||||
top?: boolean;
|
||||
};
|
||||
|
||||
/* ------- response data ------------ */
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const PaginationSchema = z.object({
|
||||
pageSize: z.union([z.number(), z.string()]),
|
||||
pageSize: z.union([z.number(), z.string()]).optional(),
|
||||
offset: z.union([z.number(), z.string()]).optional(),
|
||||
pageNum: z.union([z.number(), z.string()]).optional()
|
||||
});
|
||||
export type PaginationType = z.infer<typeof PaginationSchema>;
|
||||
|
||||
export const PaginationResponseSchema = <T extends z.ZodTypeAny>(itemSchema: T) =>
|
||||
z.object({
|
||||
total: z.number().optional().default(0),
|
||||
list: z.array(itemSchema).optional().default([])
|
||||
});
|
||||
export type PaginationResponseType<T extends z.ZodTypeAny> = z.infer<
|
||||
ReturnType<typeof PaginationResponseSchema<T>>
|
||||
>;
|
||||
|
||||
@@ -34,7 +34,7 @@ export const ChatLogItemSchema = z.object({
|
||||
title: z.string().optional().meta({ example: '用户对话', description: '对话标题' }),
|
||||
customTitle: z.string().nullish().meta({ example: '自定义标题', description: '自定义对话标题' }),
|
||||
source: z.enum(ChatSourceEnum).meta({ example: ChatSourceEnum.api, description: '对话来源' }),
|
||||
sourceName: z.string().optional().meta({ example: 'API调用', description: '来源名称' }),
|
||||
sourceName: z.string().nullish().meta({ example: 'API调用', description: '来源名称' }),
|
||||
updateTime: z.date().meta({ example: '2024-01-01T00:30:00.000Z', description: '更新时间' }),
|
||||
createTime: z.date().meta({ example: '2024-01-01T00:00:00.000Z', description: '创建时间' }),
|
||||
messageCount: z.int().nullish().meta({ example: 10, description: '消息数量' }),
|
||||
@@ -50,7 +50,7 @@ export const ChatLogItemSchema = z.object({
|
||||
totalPoints: z.number().nullish().meta({ example: 150.5, description: '总积分消耗' }),
|
||||
outLinkUid: z.string().nullish().meta({ example: 'outLink123', description: '外链用户 ID' }),
|
||||
tmbId: z.string().nullish().meta({ example: 'tmb123', description: '团队成员 ID' }),
|
||||
sourceMember: SourceMemberSchema.optional().meta({ description: '来源成员信息' }),
|
||||
sourceMember: SourceMemberSchema.nullish().meta({ description: '来源成员信息' }),
|
||||
versionName: z.string().nullish().meta({ example: 'v1.0.0', description: '版本名称' }),
|
||||
region: z.string().nullish().meta({ example: '中国', description: '区域' })
|
||||
});
|
||||
|
||||
@@ -105,11 +105,11 @@ export const UpdateUserFeedbackBodySchema = z.object({
|
||||
example: 'data123',
|
||||
description: '消息数据 ID'
|
||||
}),
|
||||
userGoodFeedback: z.string().optional().nullable().meta({
|
||||
userGoodFeedback: z.string().nullish().meta({
|
||||
example: '回答很好',
|
||||
description: '用户好评反馈内容'
|
||||
}),
|
||||
userBadFeedback: z.string().optional().nullable().meta({
|
||||
userBadFeedback: z.string().nullish().meta({
|
||||
example: '回答不准确',
|
||||
description: '用户差评反馈内容'
|
||||
})
|
||||
|
||||
73
packages/global/openapi/core/chat/history/api.ts
Normal file
73
packages/global/openapi/core/chat/history/api.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import z from 'zod';
|
||||
import { ObjectIdSchema } from '../../../../common/type/mongo';
|
||||
import { OutLinkChatAuthSchema } from '../../../../support/permission/chat';
|
||||
import { ChatSourceEnum } from '../../../../core/chat/constants';
|
||||
import { PaginationSchema, PaginationResponseSchema } from '../../../api';
|
||||
|
||||
// Get chat histories schema
|
||||
export const GetHistoriesBodySchema = PaginationSchema.and(
|
||||
OutLinkChatAuthSchema.and(
|
||||
z.object({
|
||||
appId: ObjectIdSchema.optional().describe('应用ID'),
|
||||
source: z.enum(ChatSourceEnum).optional().describe('对话来源'),
|
||||
startCreateTime: z.string().optional().describe('创建时间开始'),
|
||||
endCreateTime: z.string().optional().describe('创建时间结束'),
|
||||
startUpdateTime: z.string().optional().describe('更新时间开始'),
|
||||
endUpdateTime: z.string().optional().describe('更新时间结束')
|
||||
})
|
||||
)
|
||||
);
|
||||
export type GetHistoriesBodyType = z.infer<typeof GetHistoriesBodySchema>;
|
||||
export const GetHistoriesResponseSchema = PaginationResponseSchema(
|
||||
z.object({
|
||||
chatId: z.string(),
|
||||
updateTime: z.date(),
|
||||
appId: z.string(),
|
||||
customTitle: z.string().optional(),
|
||||
title: z.string(),
|
||||
top: z.boolean().optional()
|
||||
})
|
||||
);
|
||||
export type GetHistoriesResponseType = z.infer<typeof GetHistoriesResponseSchema>;
|
||||
|
||||
// Update chat history schema
|
||||
export const UpdateHistoryBodySchema = OutLinkChatAuthSchema.and(
|
||||
z.object({
|
||||
appId: ObjectIdSchema.describe('应用ID'),
|
||||
chatId: z.string().min(1).describe('对话ID'),
|
||||
title: z.string().optional().describe('标题'),
|
||||
customTitle: z.string().optional().describe('自定义标题'),
|
||||
top: z.boolean().optional().describe('是否置顶')
|
||||
})
|
||||
);
|
||||
export type UpdateHistoryBodyType = z.infer<typeof UpdateHistoryBodySchema>;
|
||||
|
||||
// Delete single chat history schema
|
||||
export const DelChatHistorySchema = OutLinkChatAuthSchema.and(
|
||||
z.object({
|
||||
appId: ObjectIdSchema.describe('应用ID'),
|
||||
chatId: z.string().min(1).describe('对话ID')
|
||||
})
|
||||
);
|
||||
export type DelChatHistoryType = z.infer<typeof DelChatHistorySchema>;
|
||||
|
||||
// Clear all chat histories schema
|
||||
export const ClearChatHistoriesSchema = OutLinkChatAuthSchema.and(
|
||||
z.object({
|
||||
appId: ObjectIdSchema.describe('应用ID')
|
||||
})
|
||||
);
|
||||
export type ClearChatHistoriesType = z.infer<typeof ClearChatHistoriesSchema>;
|
||||
|
||||
// Batch delete chat histories schema (for log manager)
|
||||
export const ChatBatchDeleteBodySchema = z.object({
|
||||
appId: ObjectIdSchema,
|
||||
chatIds: z
|
||||
.array(z.string().min(1))
|
||||
.min(1)
|
||||
.meta({
|
||||
description: '对话ID列表',
|
||||
example: ['chat_123456', 'chat_789012']
|
||||
})
|
||||
});
|
||||
export type ChatBatchDeleteBodyType = z.infer<typeof ChatBatchDeleteBodySchema>;
|
||||
109
packages/global/openapi/core/chat/history/index.ts
Normal file
109
packages/global/openapi/core/chat/history/index.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import type { OpenAPIPath } from '../../../type';
|
||||
import { TagsMap } from '../../../tag';
|
||||
import {
|
||||
GetHistoriesBodySchema,
|
||||
GetHistoriesResponseSchema,
|
||||
UpdateHistoryBodySchema,
|
||||
ChatBatchDeleteBodySchema,
|
||||
DelChatHistorySchema,
|
||||
ClearChatHistoriesSchema
|
||||
} from './api';
|
||||
|
||||
export const ChatHistoryPath: OpenAPIPath = {
|
||||
'/core/chat/history/getHistories': {
|
||||
post: {
|
||||
summary: '获取对话历史列表',
|
||||
description: '分页获取指定应用的对话历史记录',
|
||||
tags: [TagsMap.chatHistory],
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: GetHistoriesBodySchema
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: '成功获取对话历史列表',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: GetHistoriesResponseSchema
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'/core/chat/history/updateHistory': {
|
||||
put: {
|
||||
summary: '修改对话历史',
|
||||
description: '修改对话历史的标题、自定义标题或置顶状态',
|
||||
tags: [TagsMap.chatHistory],
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: UpdateHistoryBodySchema
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: '成功修改对话历史'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'/core/chat/history/delHistory': {
|
||||
delete: {
|
||||
summary: '删除单个对话历史',
|
||||
description: '软删除指定的单个对话记录',
|
||||
tags: [TagsMap.chatHistory],
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: DelChatHistorySchema
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: '成功删除对话'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'/core/chat/history/clearHistories': {
|
||||
delete: {
|
||||
summary: '清空应用对话历史',
|
||||
description: '清空指定应用的所有对话记录(软删除)',
|
||||
tags: [TagsMap.chatHistory],
|
||||
requestParams: {
|
||||
query: ClearChatHistoriesSchema
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: '成功清空对话历史'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'/core/chat/history/batchDelete': {
|
||||
post: {
|
||||
summary: '批量删除对话历史',
|
||||
description: '批量删除指定应用的多个对话记录(真实删除),需应用日志权限。',
|
||||
tags: [TagsMap.chatHistory],
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: ChatBatchDeleteBodySchema
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: '成功删除对话'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -2,6 +2,7 @@ import type { OpenAPIPath } from '../../type';
|
||||
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 } from '../../../core/chat/api';
|
||||
@@ -11,6 +12,7 @@ export const ChatPath: OpenAPIPath = {
|
||||
...ChatSettingPath,
|
||||
...ChatFavouriteAppPath,
|
||||
...ChatFeedbackPath,
|
||||
...ChatHistoryPath,
|
||||
|
||||
'/core/chat/presignChatFileGetUrl': {
|
||||
post: {
|
||||
|
||||
@@ -30,7 +30,7 @@ export const openAPIDocument = createDocument({
|
||||
},
|
||||
{
|
||||
name: '对话管理',
|
||||
tags: [TagsMap.chatSetting, TagsMap.chatPage, TagsMap.chatFeedback]
|
||||
tags: [TagsMap.chatHistory, TagsMap.chatPage, TagsMap.chatFeedback, TagsMap.chatSetting]
|
||||
},
|
||||
{
|
||||
name: '插件系统',
|
||||
|
||||
@@ -4,7 +4,8 @@ export const TagsMap = {
|
||||
appLog: 'Agent 日志',
|
||||
|
||||
// Chat - home
|
||||
chatPage: '对话页',
|
||||
chatPage: '对话页操作',
|
||||
chatHistory: '对话历史管理',
|
||||
chatSetting: '门户页配置',
|
||||
chatFeedback: '对话反馈',
|
||||
|
||||
|
||||
9
packages/global/support/permission/chat.d.ts
vendored
9
packages/global/support/permission/chat.d.ts
vendored
@@ -1,9 +0,0 @@
|
||||
type ShareChatAuthProps = {
|
||||
shareId?: string;
|
||||
outLinkUid?: string;
|
||||
};
|
||||
type TeamChatAuthProps = {
|
||||
teamId?: string;
|
||||
teamToken?: string;
|
||||
};
|
||||
export type OutLinkChatAuthProps = ShareChatAuthProps & TeamChatAuthProps;
|
||||
16
packages/global/support/permission/chat.ts
Normal file
16
packages/global/support/permission/chat.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import z from 'zod';
|
||||
|
||||
export const ShareChatAuthSchema = z.object({
|
||||
shareId: z.string().optional().describe('分享链接ID'),
|
||||
outLinkUid: z.string().optional().describe('外链用户ID')
|
||||
});
|
||||
export type ShareChatAuthProps = z.infer<typeof ShareChatAuthSchema>;
|
||||
|
||||
export const TeamChatAuthSchema = z.object({
|
||||
teamId: z.string().optional().describe('团队ID'),
|
||||
teamToken: z.string().optional().describe('团队Token')
|
||||
});
|
||||
export type TeamChatAuthProps = z.infer<typeof TeamChatAuthSchema>;
|
||||
|
||||
export const OutLinkChatAuthSchema = ShareChatAuthSchema.and(TeamChatAuthSchema);
|
||||
export type OutLinkChatAuthProps = z.infer<typeof OutLinkChatAuthSchema>;
|
||||
@@ -38,9 +38,7 @@ export type UserType = {
|
||||
|
||||
export const SourceMemberSchema = z.object({
|
||||
name: z.string().meta({ example: '张三', description: '成员名称' }),
|
||||
avatar: z
|
||||
.string()
|
||||
.meta({ example: 'https://cloud.fastgpt.cn/avatar.png', description: '成员头像' }),
|
||||
avatar: z.string().nullish().meta({ description: '成员头像' }),
|
||||
status: z
|
||||
.enum(TeamMemberStatusEnum)
|
||||
.meta({ example: TeamMemberStatusEnum.active, description: '成员状态' })
|
||||
|
||||
Reference in New Issue
Block a user