Compare commits

...

5 Commits

Author SHA1 Message Date
archer 8544e14110
perf: init shell 2025-12-24 20:26:16 +08:00
heheer d8cc4a0d52
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>
2025-12-24 20:11:50 +08:00
heheer 4fbe27f2df
add plan activity config (#6139)
Some checks failed
Build FastGPT images in Personal warehouse / get-vars (push) Has been cancelled
Build FastGPT images in Personal warehouse / build-fastgpt-images (map[arch:amd64 runs-on:ubuntu-24.04]) (push) Has been cancelled
Build FastGPT images in Personal warehouse / build-fastgpt-images (map[arch:arm64 runs-on:ubuntu-24.04-arm]) (push) Has been cancelled
Build FastGPT images in Personal warehouse / release-fastgpt-images (push) Has been cancelled
* activity points

* modal

* ui

* fix

* pref: zod schema

* perf: ad api with zod

* perf: plan year switch

* perf: plan

* i18n

* fix: hook

* fix: activity checker

* fix: i18n

* fix clear token

* fix

* back

* can close modal in pay

* ad token

* rename

* fix

* total points

* eng i18n

---------

Co-authored-by: archer <545436317@qq.com>
2025-12-24 18:22:25 +08:00
Archer e53242e8bc
4.14.5 dev (#6146)
Some checks failed
Build FastGPT images in Personal warehouse / get-vars (push) Waiting to run
Build FastGPT images in Personal warehouse / build-fastgpt-images (map[arch:amd64 runs-on:ubuntu-24.04]) (push) Blocked by required conditions
Build FastGPT images in Personal warehouse / build-fastgpt-images (map[arch:arm64 runs-on:ubuntu-24.04-arm]) (push) Blocked by required conditions
Build FastGPT images in Personal warehouse / release-fastgpt-images (push) Blocked by required conditions
Document deploy / sync-images (push) Has been cancelled
Document deploy / generate-timestamp (push) Has been cancelled
Document deploy / build-images (map[domain:https://fastgpt.cn suffix:cn]) (push) Has been cancelled
Document deploy / build-images (map[domain:https://fastgpt.io suffix:io]) (push) Has been cancelled
Document deploy / update-images (map[deployment:fastgpt-docs domain:https://fastgpt.cn kube_config:KUBE_CONFIG_CN suffix:cn]) (push) Has been cancelled
Document deploy / update-images (map[deployment:fastgpt-docs domain:https://fastgpt.io kube_config:KUBE_CONFIG_IO suffix:io]) (push) Has been cancelled
* stop design doc

* remove invalid doc

* action
2025-12-24 17:09:26 +08:00
heheer f175a1a30c
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>
2025-12-24 14:28:42 +08:00
156 changed files with 3684 additions and 1083 deletions

View File

@ -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 版本工作流运行

View File

@ -73,7 +73,6 @@ jobs:
--label "org.opencontainers.image.description=${{ steps.config.outputs.DESCRIPTION }}" \
--push \
--cache-from=type=local,src=/tmp/.buildx-cache \
--cache-to=type=local,dest=/tmp/.buildx-cache \
-t ${{ steps.config.outputs.DOCKER_REPO_TAGGED }} \
.

View File

@ -7,6 +7,8 @@ description: 'FastGPT V4.14.5 更新说明'
## 🚀 新增内容
1. 对话记录使用侧改成软删除,增加从日志管理里删除对话记录。
2. 更新Agent/工具时,会更新其上层所有目录的更新时间,以便其会排在列表前面。
3. 门户页支持配置单个应用运行可见度配。
## ⚙️ 优化

View File

@ -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",

View File

@ -3,7 +3,8 @@ export enum SystemConfigsTypeEnum {
fastgptPro = 'fastgptPro',
systemMsgModal = 'systemMsgModal',
license = 'license',
operationalAd = 'operationalAd'
operationalAd = 'operationalAd',
activityAd = 'activityAd'
}
export const SystemConfigsTypeMap = {
@ -21,5 +22,8 @@ export const SystemConfigsTypeMap = {
},
[SystemConfigsTypeEnum.operationalAd]: {
label: 'operationalAd'
},
[SystemConfigsTypeEnum.activityAd]: {
label: 'activityAd'
}
};

View File

@ -1,6 +1,7 @@
import { createDocument } from 'zod-openapi';
import { DashboardPath } from './admin/core/dashboard';
import { TagsMap } from './tag';
import { AdminSupportPath } from './admin/support';
export const adminOpenAPIDocument = createDocument({
openapi: '3.1.0',
@ -10,13 +11,18 @@ export const adminOpenAPIDocument = createDocument({
description: 'FastGPT Admin API 文档'
},
paths: {
...DashboardPath
...DashboardPath,
...AdminSupportPath
},
servers: [{ url: '/api' }],
'x-tagGroups': [
{
name: '仪表盘',
tags: [TagsMap.adminDashboard]
},
{
name: '系统配置',
tags: [TagsMap.adminInform]
}
]
});

View File

@ -13,8 +13,6 @@ import {
} from './api';
import { TagsMap } from '../../../tag';
export * from './api';
export const DashboardPath: OpenAPIPath = {
'/admin/core/dashboard/getUserStats': {
get: {

View File

@ -0,0 +1,6 @@
import { AdminUserPath } from './user';
import type { OpenAPIPath } from '../../type';
export const AdminSupportPath: OpenAPIPath = {
...AdminUserPath
};

View File

@ -0,0 +1,6 @@
import { AdminInformPath } from './inform';
import type { OpenAPIPath } from '../../../type';
export const AdminUserPath: OpenAPIPath = {
...AdminInformPath
};

View File

@ -0,0 +1,57 @@
import { z } from 'zod';
import { InformLevelEnum } from '../../../../../support/user/inform/constants';
// Send system inform
export const SendSystemInformBodySchema = z.object({
title: z.string().meta({ description: '通知标题' }),
content: z.string().meta({ description: '通知内容' }),
level: z.enum(InformLevelEnum).meta({ description: '通知等级' })
});
export type SendSystemInformBodyType = z.infer<typeof SendSystemInformBodySchema>;
// Update system modal
export const UpdateSystemModalBodySchema = z.object({
content: z.string().meta({ description: '系统弹窗内容' })
});
export type UpdateSystemModalBodyType = z.infer<typeof UpdateSystemModalBodySchema>;
// Update operational ad
export const UpdateOperationalAdBodySchema = z.object({
operationalAdImage: z.string().meta({ description: '活动图片URL' }),
operationalAdLink: z.string().meta({ description: '活动链接' })
});
export type UpdateOperationalAdBodyType = z.infer<typeof UpdateOperationalAdBodySchema>;
// Update activity ad
export const UpdateActivityAdBodySchema = z.object({
activityAdImage: z.string().meta({ description: '底部广告图片URL' }),
activityAdLink: z.string().meta({ description: '底部广告链接' })
});
export type UpdateActivityAdBodyType = z.infer<typeof UpdateActivityAdBodySchema>;
// Response schemas
export const SystemMsgModalResponseSchema = z
.object({
id: z.string().meta({ description: '弹窗ID' }),
content: z.string().meta({ description: '弹窗内容' })
})
.optional();
export type SystemMsgModalValueType = z.infer<typeof SystemMsgModalResponseSchema>;
export const OperationalAdResponseSchema = z
.object({
id: z.string().meta({ description: '广告ID' }),
operationalAdImage: z.string().meta({ description: '广告图片URL' }),
operationalAdLink: z.string().meta({ description: '广告链接' })
})
.optional();
export type OperationalAdResponseType = z.infer<typeof OperationalAdResponseSchema>;
export const ActivityAdResponseSchema = z
.object({
id: z.string().meta({ description: '广告ID' }),
activityAdImage: z.string().meta({ description: '广告图片URL' }),
activityAdLink: z.string().meta({ description: '广告链接' })
})
.optional();
export type ActivityAdResponseType = z.infer<typeof ActivityAdResponseSchema>;

View File

@ -0,0 +1,161 @@
import type { OpenAPIPath } from '../../../../type';
import {
SendSystemInformBodySchema,
UpdateSystemModalBodySchema,
UpdateOperationalAdBodySchema,
UpdateActivityAdBodySchema,
SystemMsgModalResponseSchema,
OperationalAdResponseSchema,
ActivityAdResponseSchema
} from './api';
import { TagsMap } from '../../../../tag';
export const AdminInformPath: OpenAPIPath = {
'/admin/support/user/inform/sendSystemInform': {
post: {
summary: '发送系统通知给所有用户',
description: '向所有用户发送系统通知消息',
tags: [TagsMap.adminInform],
requestBody: {
content: {
'application/json': {
schema: SendSystemInformBodySchema
}
}
},
responses: {
200: {
description: '成功发送系统通知',
content: {
'application/json': {
schema: {}
}
}
}
}
}
},
'/support/user/inform/getSystemMsgModal': {
get: {
summary: '获取系统弹窗内容',
description: '获取系统消息弹窗的内容',
tags: [TagsMap.adminInform],
responses: {
200: {
description: '成功获取系统弹窗内容',
content: {
'application/json': {
schema: SystemMsgModalResponseSchema
}
}
}
}
}
},
'/admin/support/user/inform/updateSystemModal': {
post: {
summary: '更新系统弹窗内容',
description: '更新系统消息弹窗的内容',
tags: [TagsMap.adminInform],
requestBody: {
content: {
'application/json': {
schema: UpdateSystemModalBodySchema
}
}
},
responses: {
200: {
description: '成功更新系统弹窗',
content: {
'application/json': {
schema: {}
}
}
}
}
}
},
'/support/user/inform/getOperationalAd': {
get: {
summary: '获取运营广告',
description: '获取运营广告的图片和链接',
tags: [TagsMap.adminInform],
responses: {
200: {
description: '成功获取运营广告',
content: {
'application/json': {
schema: OperationalAdResponseSchema
}
}
}
}
}
},
'/admin/support/user/inform/updateOperationalAd': {
post: {
summary: '更新运营广告',
description: '更新运营广告的图片和链接',
tags: [TagsMap.adminInform],
requestBody: {
content: {
'application/json': {
schema: UpdateOperationalAdBodySchema
}
}
},
responses: {
200: {
description: '成功更新运营广告',
content: {
'application/json': {
schema: {}
}
}
}
}
}
},
'/support/user/inform/getActivityAd': {
get: {
summary: '获取活动广告',
description: '获取活动广告的图片和链接',
tags: [TagsMap.adminInform],
responses: {
200: {
description: '成功获取活动广告',
content: {
'application/json': {
schema: ActivityAdResponseSchema
}
}
}
}
}
},
'/admin/support/user/inform/updateActivityAd': {
post: {
summary: '更新活动广告',
description: '更新活动广告的图片和链接',
tags: [TagsMap.adminInform],
requestBody: {
content: {
'application/json': {
schema: UpdateActivityAdBodySchema
}
}
},
responses: {
200: {
description: '成功更新活动广告',
content: {
'application/json': {
schema: {}
}
}
}
}
}
}
};

View File

@ -1,6 +1,8 @@
import type { OpenAPIPath } from '../../type';
import { AppLogPath } from './log';
import { PublishChannelPath } from './publishChannel';
export const AppPath: OpenAPIPath = {
...AppLogPath
...AppLogPath,
...PublishChannelPath
};

View File

@ -0,0 +1,5 @@
import { PlaygroundPath } from './playground';
export const PublishChannelPath = {
...PlaygroundPath
};

View File

@ -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
>;

View File

@ -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()
})
}
}
}
}
}
}
};

View File

@ -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>;

View File

@ -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>;

View File

@ -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()
}
}
}
}
}
}
};

View File

@ -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
}
}
}

View File

@ -1,11 +1,9 @@
import { createDocument } from 'zod-openapi';
import { ChatPath } from './core/chat';
import { ApiKeyPath } from './support/openapi';
import { TagsMap } from './tag';
import { PluginPath } from './core/plugin';
import { WalletPath } from './support/wallet';
import { CustomDomainPath } from './support/customDomain';
import { AppPath } from './core/app';
import { SupportPath } from './support';
export const openAPIDocument = createDocument({
openapi: '3.1.0',
@ -17,16 +15,14 @@ export const openAPIDocument = createDocument({
paths: {
...AppPath,
...ChatPath,
...ApiKeyPath,
...PluginPath,
...WalletPath,
...CustomDomainPath
...SupportPath
},
servers: [{ url: '/api' }],
'x-tagGroups': [
{
name: 'Agent 应用',
tags: [TagsMap.appLog]
tags: [TagsMap.appLog, TagsMap.publishChannel]
},
{
name: '对话管理',
@ -37,8 +33,8 @@ export const openAPIDocument = createDocument({
tags: [TagsMap.pluginToolTag, TagsMap.pluginTeam]
},
{
name: '支付系统',
tags: [TagsMap.walletBill, TagsMap.walletDiscountCoupon]
name: '用户体系',
tags: [TagsMap.userInform, TagsMap.walletBill, TagsMap.walletDiscountCoupon]
},
{
name: '通用-辅助功能',

View File

@ -0,0 +1,12 @@
import { UserPath } from './user';
import type { OpenAPIPath } from '../type';
import { WalletPath } from './wallet';
import { ApiKeyPath } from './openapi';
import { CustomDomainPath } from './customDomain';
export const SupportPath: OpenAPIPath = {
...UserPath,
...WalletPath,
...ApiKeyPath,
...CustomDomainPath
};

View File

@ -0,0 +1,6 @@
import { UserInformPath } from './inform';
import type { OpenAPIPath } from '../../type';
export const UserPath: OpenAPIPath = {
...UserInformPath
};

View File

@ -0,0 +1,61 @@
import type { OpenAPIPath } from '../../../type';
import {
SystemMsgModalResponseSchema,
OperationalAdResponseSchema,
ActivityAdResponseSchema
} from '../../../admin/support/user/inform/api';
import { TagsMap } from '../../../tag';
export const UserInformPath: OpenAPIPath = {
'/proApi/support/user/inform/getSystemMsgModal': {
get: {
summary: '获取系统弹窗内容',
description: '获取系统消息弹窗的内容',
tags: [TagsMap.userInform],
responses: {
200: {
description: '成功获取系统弹窗内容',
content: {
'application/json': {
schema: SystemMsgModalResponseSchema
}
}
}
}
}
},
'/proApi/support/user/inform/getOperationalAd': {
get: {
summary: '获取运营广告',
description: '获取运营广告的图片和链接',
tags: [TagsMap.userInform],
responses: {
200: {
description: '成功获取运营广告',
content: {
'application/json': {
schema: OperationalAdResponseSchema
}
}
}
}
}
},
'/proApi/support/user/inform/getActivityAd': {
get: {
summary: '获取活动广告',
description: '获取活动广告的图片和链接',
tags: [TagsMap.userInform],
responses: {
200: {
description: '成功获取活动广告',
content: {
'application/json': {
schema: ActivityAdResponseSchema
}
}
}
}
}
}
};

View File

@ -25,6 +25,32 @@ export const BillListResponseSchema = z.object({
});
export type GetBillListResponseType = z.infer<typeof BillListResponseSchema>;
// Bill detail
export const BillDetailQuerySchema = z.object({
billId: ObjectIdSchema.meta({ description: '订单 ID' })
});
export type BillDetailQueryType = z.infer<typeof BillDetailQuerySchema>;
export const BillDetailResponseSchema = BillSchema.safeExtend({
discountCouponName: z.string().optional(),
couponDetail: z
.object({
key: z.string(),
type: z.enum(CouponTypeEnum),
subscriptions: z.array(
z.object({
type: z.enum(SubTypeEnum),
durationDay: z.number(),
totalPoints: z.number().optional(),
level: z.enum(StandardSubLevelEnum).optional(),
extraDatasetSize: z.number().optional(),
customConfig: z.record(z.string(), z.any()).optional()
})
)
})
.optional()
});
export type BillDetailResponseType = z.infer<typeof BillDetailResponseSchema>;
// Create
export const CreateStandPlanBillSchema = z
.object({
@ -88,30 +114,14 @@ export const CheckPayResultResponseSchema = z.object({
});
export type CheckPayResultResponseType = z.infer<typeof CheckPayResultResponseSchema>;
// Bill detail
export const BillDetailResponseSchema = BillSchema.safeExtend({
discountCouponName: z.string().optional(),
couponDetail: z
.object({
key: z.string(),
type: z.enum(CouponTypeEnum),
subscriptions: z.array(
z.object({
type: z.enum(SubTypeEnum),
durationDay: z.number(),
totalPoints: z.number().optional(),
level: z.enum(StandardSubLevelEnum).optional(),
extraDatasetSize: z.number().optional(),
customConfig: z.record(z.string(), z.any()).optional()
})
)
})
.optional()
});
export type BillDetailResponseType = z.infer<typeof BillDetailResponseSchema>;
// Cancel bill
export const CancelBillPropsSchema = z.object({
billId: ObjectIdSchema.meta({ description: '订单 ID' })
});
export type CancelBillPropsType = z.infer<typeof CancelBillPropsSchema>;
// Check pay result
export const CheckPayResultQuerySchema = z.object({
payId: ObjectIdSchema.meta({ description: '订单 ID' })
});
export type CheckPayResultQueryType = z.infer<typeof CheckPayResultQuerySchema>;

View File

@ -8,7 +8,9 @@ import {
CheckPayResultResponseSchema,
BillDetailResponseSchema,
BillListQuerySchema,
CancelBillPropsSchema
CancelBillPropsSchema,
CheckPayResultQuerySchema,
BillDetailQuerySchema
} from './api';
import { TagsMap } from '../../../tag';
import { ObjectIdSchema } from '../../../../common/type/mongo';
@ -68,11 +70,7 @@ export const BillPath: OpenAPIPath = {
description: '检查订单的支付状态,用于轮询支付结果',
tags: [TagsMap.walletBill],
requestParams: {
query: z.object({
payId: ObjectIdSchema.meta({
description: '订单 ID'
})
})
query: CheckPayResultQuerySchema
},
responses: {
200: {
@ -92,11 +90,7 @@ export const BillPath: OpenAPIPath = {
description: '根据订单 ID 获取订单详细信息,包括优惠券名称等',
tags: [TagsMap.walletBill],
requestParams: {
query: z.object({
billId: ObjectIdSchema.meta({
description: '订单 ID'
})
})
query: BillDetailQuerySchema
},
responses: {
200: {

View File

@ -4,7 +4,8 @@ export const TagsMap = {
appLog: 'Agent 日志',
// Chat - home
chatPage: '对话页操作',
chatPage: '对话页',
chatController: '对话框操作',
chatHistory: '对话历史管理',
chatSetting: '门户页配置',
chatFeedback: '对话反馈',
@ -13,11 +14,16 @@ export const TagsMap = {
pluginToolTag: '工具标签',
pluginTeam: '团队插件管理',
// Publish Channel
publishChannel: '发布渠道',
/* Support */
// Wallet
walletBill: '订单',
walletDiscountCoupon: '优惠券',
customDomain: '自定义域名',
// User
userInform: '用户通知',
/* Common */
// APIKey
@ -29,5 +35,7 @@ export const TagsMap = {
pluginAdmin: '管理员插件管理',
pluginToolAdmin: '管理员系统工具管理',
// Data
adminDashboard: '管理员仪表盘'
adminDashboard: '管理员仪表盘',
// Inform
adminInform: '管理员通知管理'
};

View File

@ -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
>;

View File

@ -5,5 +5,6 @@ export enum PublishChannelEnum {
feishu = 'feishu',
dingtalk = 'dingtalk',
wecom = 'wecom',
officialAccount = 'official_account'
officialAccount = 'official_account',
playground = 'playground'
}

View File

@ -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;
@ -87,16 +88,21 @@ export type OutLinkSchema<T extends OutlinkAppType = undefined> = {
};
app: T;
//@deprecated
responseDetail?: boolean;
showNodeStatus?: boolean;
showRawSource?: boolean;
};
// Edit the Outlink
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 +112,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>;

View File

@ -2,8 +2,7 @@ import type { auditLogMap, adminAuditLogMap } from '../../../../web/support/user
export enum AdminAuditEventEnum {
ADMIN_LOGIN = 'ADMIN_LOGIN',
ADMIN_UPDATE_SYSTEM_MODAL = 'ADMIN_UPDATE_SYSTEM_MODAL',
ADMIN_SEND_SYSTEM_INFORM = 'ADMIN_SEND_SYSTEM_INFORM',
ADMIN_ADD_USER = 'ADMIN_ADD_USER',
ADMIN_UPDATE_USER = 'ADMIN_UPDATE_USER',
ADMIN_UPDATE_TEAM = 'ADMIN_UPDATE_TEAM',
@ -21,7 +20,13 @@ export enum AdminAuditEventEnum {
ADMIN_DELETE_PLUGIN = 'ADMIN_DELETE_PLUGIN',
ADMIN_CREATE_PLUGIN_GROUP = 'ADMIN_CREATE_PLUGIN_GROUP',
ADMIN_UPDATE_PLUGIN_GROUP = 'ADMIN_UPDATE_PLUGIN_GROUP',
ADMIN_DELETE_PLUGIN_GROUP = 'ADMIN_DELETE_PLUGIN_GROUP'
ADMIN_DELETE_PLUGIN_GROUP = 'ADMIN_DELETE_PLUGIN_GROUP',
// Inform
ADMIN_UPDATE_SYSTEM_MODAL = 'ADMIN_UPDATE_SYSTEM_MODAL',
ADMIN_SEND_SYSTEM_INFORM = 'ADMIN_SEND_SYSTEM_INFORM',
ADMIN_UPDATE_ACTIVITY_AD = 'ADMIN_UPDATE_ACTIVITY_AD',
ADMIN_UPDATE_OPERATIONAL_AD = 'ADMIN_UPDATE_OPERATIONAL_AD'
}
export enum AuditEventEnum {

View File

@ -1,5 +1,4 @@
import type { StandardSubLevelEnum, SubModeEnum } from './constants';
import { TeamSubSchema } from './type.d';
export type StandardSubPlanParams = {
level: `${StandardSubLevelEnum}`;

View File

@ -1,103 +0,0 @@
import type { StandardSubLevelEnum, SubModeEnum, SubTypeEnum } from './constants';
// Content of plan
export type TeamStandardSubPlanItemType = {
name?: string;
desc?: string; // Plan description
price: number; // read price / month
pointPrice: number; // read price/ one thousand
totalPoints: number; // n
maxTeamMember: number;
maxAppAmount: number; // max app or plugin amount
maxDatasetAmount: number;
maxDatasetSize: number;
requestsPerMinute?: number;
appRegistrationCount?: number;
chatHistoryStoreDuration: number; // n day
websiteSyncPerDataset?: number;
auditLogStoreDuration?: number;
ticketResponseTime?: number;
customDomain?: number;
// Custom plan specific fields
priceDescription?: string;
customFormUrl?: string;
customDescriptions?: string[];
};
export type StandSubPlanLevelMapType = Record<
`${StandardSubLevelEnum}`,
TeamStandardSubPlanItemType
>;
export type PointsPackageItem = {
points: number;
month: number;
price: number;
};
export type SubPlanType = {
[SubTypeEnum.standard]?: StandSubPlanLevelMapType;
planDescriptionUrl?: string;
appRegistrationUrl?: string;
communitySupportTip?: string;
[SubTypeEnum.extraDatasetSize]: {
price: number;
};
[SubTypeEnum.extraPoints]: {
packages: PointsPackageItem[];
};
};
export type TeamSubSchema = {
_id: string;
teamId: string;
type: `${SubTypeEnum}`;
startTime: Date;
expiredTime: Date;
currentMode: `${SubModeEnum}`;
nextMode: `${SubModeEnum}`;
currentSubLevel: StandardSubLevelEnum;
nextSubLevel: StandardSubLevelEnum;
maxTeamMember?: number;
maxApp?: number;
maxDataset?: number;
// custom level configurations
requestsPerMinute?: number;
chatHistoryStoreDuration?: number;
maxDatasetSize?: number;
websiteSyncPerDataset?: number;
appRegistrationCount?: number;
auditLogStoreDuration?: number;
ticketResponseTime?: number;
customDomain?: number;
totalPoints: number;
surplusPoints: number;
currentExtraDatasetSize: number;
};
export type TeamPlanStatusType = {
[SubTypeEnum.standard]?: TeamSubSchema;
standardConstants?: TeamStandardSubPlanItemType;
totalPoints: number;
usedPoints: number;
// standard + extra
datasetMaxSize: number;
};
export type ClientTeamPlanStatusType = TeamPlanStatusType & {
usedMember: number;
usedAppAmount: number;
usedDatasetSize: number;
usedDatasetIndexSize: number;
usedRegistrationCount: number;
};

View File

@ -0,0 +1,111 @@
import z from 'zod';
import { StandardSubLevelEnum, SubModeEnum, SubTypeEnum } from './constants';
import { ObjectIdSchema } from '../../../common/type/mongo';
// Content of plan
export const TeamStandardSubPlanItemSchema = z.object({
name: z.string().optional(),
desc: z.string().optional(),
price: z.number(),
totalPoints: z.int(), // 总积分
maxTeamMember: z.int(),
maxAppAmount: z.int(),
maxDatasetAmount: z.int(),
maxDatasetSize: z.int(),
requestsPerMinute: z.int().optional(), // QPM
appRegistrationCount: z.int().optional(), // 应用备案数量
chatHistoryStoreDuration: z.int(), // 历史记录保留天数
websiteSyncPerDataset: z.int().optional(), // 站点同步最大页面
auditLogStoreDuration: z.int().optional(), // 审计日志保留天数
ticketResponseTime: z.int().optional(), // 工单支持时间
customDomain: z.int().optional(), // 自定义域名数量
// 定制套餐
priceDescription: z.string().optional(), // 价格描述
customFormUrl: z.string().optional(), // 自定义表单 URL
customDescriptions: z.array(z.string()).optional(), // 自定义描述
// Active
annualBonusPoints: z.int().optional(), // 年度赠送积分
// @deprecated
pointPrice: z.number().optional()
});
export type TeamStandardSubPlanItemType = z.infer<typeof TeamStandardSubPlanItemSchema>;
export const StandSubPlanLevelMapSchema = z.record(
z.enum(StandardSubLevelEnum),
TeamStandardSubPlanItemSchema
);
export type StandSubPlanLevelMapType = z.infer<typeof StandSubPlanLevelMapSchema>;
export const PointsPackageItemSchema = z.object({
points: z.int(),
month: z.int(),
price: z.number(),
activityBonusPoints: z.int().optional() // 活动赠送积分
});
export type PointsPackageItem = z.infer<typeof PointsPackageItemSchema>;
export const SubPlanSchema = z.object({
[SubTypeEnum.standard]: StandSubPlanLevelMapSchema.optional(),
[SubTypeEnum.extraDatasetSize]: z.object({ price: z.number() }).optional(),
[SubTypeEnum.extraPoints]: z.object({ packages: PointsPackageItemSchema.array() }).optional(),
planDescriptionUrl: z.string().optional(),
appRegistrationUrl: z.string().optional(),
communitySupportTip: z.string().optional(),
activityExpirationTime: z.date().optional()
});
export type SubPlanType = z.infer<typeof SubPlanSchema>;
export const TeamSubSchema = z.object({
_id: ObjectIdSchema,
teamId: ObjectIdSchema,
type: z.enum(SubTypeEnum),
startTime: z.date(),
expiredTime: z.date(),
currentMode: z.enum(SubModeEnum),
nextMode: z.enum(SubModeEnum),
currentSubLevel: z.enum(StandardSubLevelEnum),
nextSubLevel: z.enum(StandardSubLevelEnum),
maxTeamMember: z.int().optional(),
maxApp: z.int().optional(),
maxDataset: z.int().optional(),
totalPoints: z.int(),
annualBonusPoints: z.int().optional(),
surplusPoints: z.int(),
currentExtraDatasetSize: z.int(),
// 定制版特有属性
requestsPerMinute: z.int().optional(),
chatHistoryStoreDuration: z.int().optional(),
maxDatasetSize: z.int().optional(),
websiteSyncPerDataset: z.int().optional(),
appRegistrationCount: z.int().optional(),
auditLogStoreDuration: z.int().optional(),
ticketResponseTime: z.int().optional(),
customDomain: z.int().optional()
});
export type TeamSubSchemaType = z.infer<typeof TeamSubSchema>;
export const TeamPlanStatusSchema = z.object({
[SubTypeEnum.standard]: TeamSubSchema.optional(),
standardConstants: TeamStandardSubPlanItemSchema.optional(),
totalPoints: z.int(),
usedPoints: z.int(),
datasetMaxSize: z.int()
});
export type TeamPlanStatusType = z.infer<typeof TeamPlanStatusSchema>;
export const ClientTeamPlanStatusSchema = TeamPlanStatusSchema.extend({
usedMember: z.int(),
usedAppAmount: z.int(),
usedDatasetSize: z.int(),
usedDatasetIndexSize: z.int(),
usedRegistrationCount: z.int()
});
export type ClientTeamPlanStatusType = z.infer<typeof ClientTeamPlanStatusSchema>;

View File

@ -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);
});
};

View File

@ -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
);

View File

@ -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>;

View File

@ -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);
});
};

View File

@ -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);
}

View File

@ -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: {
@ -83,7 +85,12 @@ const OutLinkSchema = new Schema({
},
defaultResponse: {
type: String
}
},
//@deprecated
responseDetail: Boolean,
showNodeStatus: Boolean,
showRawSource: Boolean
});
OutLinkSchema.virtual('associatedApp', {

View File

@ -1,4 +0,0 @@
export type SystemMsgModalValueType = {
id: string;
content: string;
};

View File

@ -11,7 +11,7 @@ import {
SubModeEnum,
SubTypeEnum
} from '@fastgpt/global/support/wallet/sub/constants';
import type { TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type';
import type { TeamSubSchemaType } from '@fastgpt/global/support/wallet/sub/type';
export const subCollectionName = 'team_subscriptions';
@ -100,4 +100,4 @@ try {
console.log(error);
}
export const MongoTeamSub = getMongoModel<TeamSubSchema>(subCollectionName, SubSchema);
export const MongoTeamSub = getMongoModel<TeamSubSchemaType>(subCollectionName, SubSchema);

View File

@ -7,8 +7,8 @@ import {
import { MongoTeamSub } from './schema';
import {
type TeamPlanStatusType,
type TeamSubSchema
} from '@fastgpt/global/support/wallet/sub/type.d';
type TeamSubSchemaType
} from '@fastgpt/global/support/wallet/sub/type';
import dayjs from 'dayjs';
import { type ClientSession } from '../../../common/mongo';
import { addMonths } from 'date-fns';
@ -29,7 +29,7 @@ export const getStandardPlanConfig = (level: `${StandardSubLevelEnum}`) => {
return global.subPlans?.standard?.[level];
};
export const sortStandPlans = (plans: TeamSubSchema[]) => {
export const sortStandPlans = (plans: TeamSubSchemaType[]) => {
return plans.sort(
(a, b) =>
standardSubLevelMap[b.currentSubLevel].weight - standardSubLevelMap[a.currentSubLevel].weight

View File

@ -8,7 +8,17 @@ import { imageBaseUrl } from '@fastgpt/global/common/file/image/constants';
export const useUploadAvatar = (
api: (params: { filename: string }) => Promise<CreatePostPresignedUrlResult>,
{ onSuccess }: { onSuccess?: (avatar: string) => void } = {}
{
onSuccess,
maxW = 300,
maxH = 300,
maxSize = 1024 * 500 // 500KB
}: {
onSuccess?: (avatar: string) => void;
maxW?: number;
maxH?: number;
maxSize?: number;
} = {}
) => {
const { toast } = useToast();
const { t } = useTranslation();
@ -32,8 +42,9 @@ export const useUploadAvatar = (
const compressed = base64ToFile(
await compressBase64Img({
base64Img: await fileToBase64(file),
maxW: 300,
maxH: 300
maxW,
maxH,
maxSize
}),
file.name
);

View File

@ -1,5 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path fill-rule="evenodd" clip-rule="evenodd"
d="M12.6262 3.29289C13.0167 2.90237 13.6499 2.90237 14.0404 3.29289C14.4309 3.68342 14.4309 4.31658 14.0404 4.70711L6.70707 12.0404C6.31654 12.431 5.68338 12.431 5.29285 12.0404L1.95952 8.70711C1.56899 8.31658 1.56899 7.68342 1.95952 7.29289C2.35004 6.90237 2.98321 6.90237 3.37373 7.29289L5.99996 9.91912L12.6262 3.29289Z"
fill="#3370FF" />
<svg viewBox="0 0 16 16" fill="none">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.6261 3.29289C13.0166 2.90237 13.6498 2.90237 14.0403 3.29289C14.4308 3.68342 14.4308 4.31658 14.0403 4.70711L6.70694 12.0404C6.31642 12.431 5.68325 12.431 5.29273 12.0404L1.9594 8.70711C1.56887 8.31658 1.56887 7.68342 1.9594 7.29289C2.34992 6.90237 2.98309 6.90237 3.37361 7.29289L5.99984 9.91912L12.6261 3.29289Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 475 B

After

Width:  |  Height:  |  Size: 416 B

View File

@ -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 : ''
}
);

View File

@ -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'
});
}

View File

@ -19,7 +19,9 @@
"admin_login": "Administrator login",
"admin_save_template_type": "Update template classification",
"admin_send_system_inform": "Send system notifications",
"admin_update_activity_ad": "Bottom advertising configuration",
"admin_update_app_template": "Update templates",
"admin_update_operational_ad": "Full screen ad configuration",
"admin_update_plan": "Editorial Team Package",
"admin_update_plugin": "Plugin Update",
"admin_update_plugin_group": "Plugin group update",
@ -128,7 +130,9 @@
"log_admin_login": "【{{name}}】Logined in the administrator background",
"log_admin_save_template_type": "【{{name}}】Added template classification called [{{typeName}}]",
"log_admin_send_system_inform": "【{{name}}】Sent a system notification titled [{{informTitle}}], with the level of [{{level}}]",
"log_admin_update_activity_ad": "[{{name}}] has configured bottom ads",
"log_admin_update_app_template": "【{{name}}】Updated template information named [{{templateName}}]",
"log_admin_update_operational_ad": "[{{name}}] has configured the event page",
"log_admin_update_plan": "【{{name}}】Edited the package information of the team with the team id [{{teamId}}]",
"log_admin_update_plugin": "【{{name}}】Updated plugin information called [{{pluginName}}]",
"log_admin_update_plugin_group": "【{{name}}】Updated plug-in grouping called [{{groupName}}]",

View File

@ -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.",

View File

@ -98,6 +98,10 @@
"Warning": "Warning",
"Website": "Website",
"action_confirm": "Confirm",
"activity_ad.desc": "More points, same annual package price. Get up to 1.66M bonus points.",
"activity_ad.join_now": "Get Started",
"activity_ad.later": "Maybe later",
"activity_ad.title": "Festival Special · Limited Time",
"add_new": "add_new",
"add_new_param": "Add new param",
"add_success": "Added Successfully",
@ -234,7 +238,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 +268,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 +319,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",
@ -949,7 +954,7 @@
"n_ai_points": "{{amount}} points",
"n_chat_records_retain": "{{amount}} Days of Chat History Retention",
"n_custom_domain_amount": "{{amount}} Custom domains",
"n_custom_domain_amount tip": "The number of custom domain names that the team can configure, which can currently be used to access Wecom intelligent robots",
"n_custom_domain_amount_tip": "The number of custom domain names that the team can configure, which can currently be used to access Wecom intelligent robots",
"n_dataset_amount": "{{amount}} Dataset limit",
"n_dataset_size": "{{amount}} Dataset Indexes",
"n_team_audit_day": "{{amount}} days team operation log records",
@ -1102,9 +1107,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",
@ -1205,6 +1212,7 @@
"support.wallet.subscription.AI points": "AI Points",
"support.wallet.subscription.AI points usage": "AI Points Usage",
"support.wallet.subscription.AI points usage tip": "Each time the AI model is called, a certain amount of AI points will be consumed. For specific calculation standards, please refer to the 'Pricing' above.",
"support.wallet.subscription.Activity expiration time": "Activity ends on {{month}}/{{day}}/{{year}} at {{hour}}:{{minute}}",
"support.wallet.subscription.Ai points": "AI Points Calculation Standards",
"support.wallet.subscription.Current plan": "Current Package",
"support.wallet.subscription.Dataset size": "Knowledge Base Index",
@ -1256,6 +1264,7 @@
"support.wallet.subscription.status.inactive": "Inactive",
"support.wallet.subscription.team_operation_log": "Record team operation logs",
"support.wallet.subscription.token_compute": "Click to View Online Tokens Calculator",
"support.wallet.subscription.total_points": "Total points",
"support.wallet.subscription.type.balance": "Balance Recharge",
"support.wallet.subscription.type.extraDatasetSize": "Dataset Expansion",
"support.wallet.subscription.type.extraPoints": "AI Points Package",

View File

@ -19,7 +19,9 @@
"admin_login": "管理员登录",
"admin_save_template_type": "更新模板分类",
"admin_send_system_inform": "发送系统通知",
"admin_update_activity_ad": "底部广告配置",
"admin_update_app_template": "更新模板",
"admin_update_operational_ad": "全屏广告配置",
"admin_update_plan": "编辑团队套餐",
"admin_update_plugin": "插件更新",
"admin_update_plugin_group": "插件分组更新",
@ -130,7 +132,9 @@
"log_admin_login": "【{{name}}】登录了管理员后台",
"log_admin_save_template_type": "【{{name}}】添加了名为【{{typeName}}】的模板分类",
"log_admin_send_system_inform": "【{{name}}】发送了标题为【{{informTitle}}】的系统通知,等级为【{{level}}】",
"log_admin_update_activity_ad": "【{{name}}】进行了底部广告配置",
"log_admin_update_app_template": "【{{name}}】更新了名为【{{templateName}}】的模板信息",
"log_admin_update_operational_ad": "【{{name}}】进行了活动页配置",
"log_admin_update_plan": "【{{name}}】编辑了团队id为【{{teamId}}】的团队的套餐信息",
"log_admin_update_plugin": "【{{name}}】更新了名为【{{pluginName}}】的插件信息",
"log_admin_update_plugin_group": "【{{name}}】更新了名为【{{groupName}}】的插件分组",

View File

@ -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": "发布成功",

View File

@ -99,6 +99,10 @@
"Warning": "警告",
"Website": "网站",
"action_confirm": "操作确认",
"activity_ad.desc": "充值最高可得额外166万积分年费套餐旧价享新量",
"activity_ad.join_now": "立即参与",
"activity_ad.later": "稍等一会儿",
"activity_ad.title": "双节献礼 · 限时升级",
"add_new": "新增",
"add_new_param": "新增参数",
"add_success": "添加成功",
@ -237,7 +241,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 +271,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 +322,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": "在此输入提示词",
@ -955,7 +961,7 @@
"n_app_registration_amount": "{{amount}} 个应用备案",
"n_chat_records_retain": "{{amount}} 天对话记录保留",
"n_custom_domain_amount": "{{amount}} 个自定义域名",
"n_custom_domain_amount tip": "团队可以配置的自定义域名数量,目前可用于接入企微智能机器人",
"n_custom_domain_amount_tip": "团队可以配置的自定义域名数量,目前可用于接入企微智能机器人",
"n_dataset_amount": "{{amount}} 个知识库",
"n_dataset_size": "{{amount}} 组知识库索引",
"n_team_audit_day": "{{amount}} 天团队操作日志记录",
@ -1110,9 +1116,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": "查看及下载完整引用文档,或跳转引用网站",
@ -1213,6 +1221,7 @@
"support.wallet.subscription.AI points": "AI 积分",
"support.wallet.subscription.AI points usage": "AI 积分使用量",
"support.wallet.subscription.AI points usage tip": "每次调用 AI 模型时,都会消耗一定的 AI 积分。具体的计算标准可参考上方的“计费标准”",
"support.wallet.subscription.Activity expiration time": "活动截至{{year}}年{{month}}月{{day}}日{{hour}}:{{minute}}",
"support.wallet.subscription.Ai points": "AI 积分计算标准",
"support.wallet.subscription.Current plan": "当前套餐",
"support.wallet.subscription.Dataset size": "知识库索引量",
@ -1265,6 +1274,7 @@
"support.wallet.subscription.status.inactive": "待使用",
"support.wallet.subscription.team_operation_log": "记录团队操作日志",
"support.wallet.subscription.token_compute": "点击查看在线 Tokens 计算器",
"support.wallet.subscription.total_points": "总积分",
"support.wallet.subscription.type.balance": "余额充值",
"support.wallet.subscription.type.extraDatasetSize": "知识库扩容",
"support.wallet.subscription.type.extraPoints": "AI 积分套餐",

View File

@ -19,7 +19,9 @@
"admin_login": "管理員登錄",
"admin_save_template_type": "更新模板分類",
"admin_send_system_inform": "發送系統通知",
"admin_update_activity_ad": "底部廣告配置",
"admin_update_app_template": "更新模板",
"admin_update_operational_ad": "全屏廣告配置",
"admin_update_plan": "編輯團隊套餐",
"admin_update_plugin": "插件更新",
"admin_update_plugin_group": "插件分組更新",
@ -128,7 +130,9 @@
"log_admin_login": "【{{name}}】登錄了管理員後台",
"log_admin_save_template_type": "【{{name}}】添加了名為【{{typeName}}】的模板分類",
"log_admin_send_system_inform": "【{{name}}】發送了標題為【{{informTitle}}】的系統通知,等級為【{{level}}】",
"log_admin_update_activity_ad": "【{{name}}】進行了底部廣告配置",
"log_admin_update_app_template": "【{{name}}】更新了名為【{{templateName}}】的模板信息",
"log_admin_update_operational_ad": "【{{name}}】進行了活動頁配置",
"log_admin_update_plan": "【{{name}}】編輯了團隊id為【{{teamId}}】的團隊的套餐信息",
"log_admin_update_plugin": "【{{name}}】更新了名為【{{pluginName}}】的插件信息",
"log_admin_update_plugin_group": "【{{name}}】更新了名為【{{groupName}}】的插件分組",

View File

@ -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 個引導性問題。",

View File

@ -98,6 +98,10 @@
"Warning": "警告",
"Website": "網站",
"action_confirm": "確認",
"activity_ad.desc": "充值最高可得額外166萬積分年費套餐舊價享新量",
"activity_ad.join_now": "立即參與",
"activity_ad.later": "稍等一會兒",
"activity_ad.title": "雙節獻禮 · 限時升級",
"add_new": "新增",
"add_new_param": "新增參數",
"add_success": "新增成功",
@ -234,7 +238,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 +268,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 +319,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": "尚未建立分享連結",
@ -947,7 +952,7 @@
"n_ai_points": "{{amount}} 積分",
"n_chat_records_retain": "{{amount}} 天對話紀錄保留",
"n_custom_domain_amount": "{{amount}} 個自定義域名",
"n_custom_domain_amount tip": "團隊可以配置的自定義域名數量,目前可用於接入企微智能機器人",
"n_custom_domain_amount_tip": "團隊可以配置的自定義域名數量,目前可用於接入企微智能機器人",
"n_dataset_amount": "{{amount}} 個知識庫",
"n_dataset_size": "{{amount}} 組知識庫索引",
"n_team_audit_day": "{{amount}} 天團隊操作日誌記錄",
@ -1099,9 +1104,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": "檢視及下載完整引用文件,或跳轉至引用網站",
@ -1202,6 +1209,7 @@
"support.wallet.subscription.AI points": "AI 點數",
"support.wallet.subscription.AI points usage": "AI 點數使用量",
"support.wallet.subscription.AI points usage tip": "每次呼叫 AI 模型時,都會消耗一定的 AI 點數。具體的計算標準可參考上方的「計費標準」",
"support.wallet.subscription.Activity expiration time": "活動截至{{year}}年{{month}}月{{day}}日{{hour}}:{{minute}}",
"support.wallet.subscription.Ai points": "AI 點數計算標準",
"support.wallet.subscription.Current plan": "目前方案",
"support.wallet.subscription.Dataset size": "知識庫索引量",
@ -1253,6 +1261,7 @@
"support.wallet.subscription.status.inactive": "未使用",
"support.wallet.subscription.team_operation_log": "記錄團隊操作日誌",
"support.wallet.subscription.token_compute": "點選檢視線上 Token 計算機",
"support.wallet.subscription.total_points": "總積分",
"support.wallet.subscription.type.balance": "餘額儲值",
"support.wallet.subscription.type.extraDatasetSize": "知識庫擴充容量",
"support.wallet.subscription.type.extraPoints": "AI 點數方案",

View File

@ -7,16 +7,6 @@ export const adminAuditLogMap = {
typeLabel: i18nT('account_team:admin_login'),
params: {} as { name?: string }
},
[AdminAuditEventEnum.ADMIN_UPDATE_SYSTEM_MODAL]: {
content: i18nT('account_team:log_admin_update_system_modal'),
typeLabel: i18nT('account_team:admin_update_system_modal'),
params: {} as { name?: string }
},
[AdminAuditEventEnum.ADMIN_SEND_SYSTEM_INFORM]: {
content: i18nT('account_team:log_admin_send_system_inform'),
typeLabel: i18nT('account_team:admin_send_system_inform'),
params: {} as { name?: string; informTitle?: string; level?: string }
},
[AdminAuditEventEnum.ADMIN_ADD_USER]: {
content: i18nT('account_team:log_admin_add_user'),
typeLabel: i18nT('account_team:admin_add_user'),
@ -108,6 +98,28 @@ export const adminAuditLogMap = {
content: i18nT('account_team:log_admin_delete_plugin_group'),
typeLabel: i18nT('account_team:admin_delete_plugin_group'),
params: {} as { name?: string; groupName: string }
},
// Inform
[AdminAuditEventEnum.ADMIN_UPDATE_SYSTEM_MODAL]: {
content: i18nT('account_team:log_admin_update_system_modal'),
typeLabel: i18nT('account_team:admin_update_system_modal'),
params: {} as { name?: string }
},
[AdminAuditEventEnum.ADMIN_SEND_SYSTEM_INFORM]: {
content: i18nT('account_team:log_admin_send_system_inform'),
typeLabel: i18nT('account_team:admin_send_system_inform'),
params: {} as { name?: string; informTitle?: string; level?: string }
},
[AdminAuditEventEnum.ADMIN_UPDATE_ACTIVITY_AD]: {
content: i18nT('account_team:log_admin_update_activity_ad'),
typeLabel: i18nT('account_team:admin_update_activity_ad'),
params: {}
},
[AdminAuditEventEnum.ADMIN_UPDATE_OPERATIONAL_AD]: {
content: i18nT('account_team:log_admin_update_operational_ad'),
typeLabel: i18nT('account_team:admin_update_operational_ad'),
params: {}
}
};

View File

@ -0,0 +1,61 @@
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40" fill="none">
<g opacity="0.13">
<path d="M19.375 1.1875L18.4375 2.8125V37.1875L19.375 38.8125L20.3125 37.1875V2.8125L19.375 1.1875Z" fill="url(#paint0_linear_30901_98056)"/>
<path d="M19.375 9.375L15.625 6.875V5L19.375 7.5V9.375ZM19.375 13.125L14.375 10V8.125L19.375 11.25V13.125ZM19.375 9.375L23.125 6.875V5L19.375 7.5V9.375ZM19.375 13.125L24.375 10V8.125L19.375 11.25V13.125ZM19.375 30.625L15.625 33.125V35L19.375 32.5V30.625ZM19.375 26.875L14.375 30V31.875L19.375 28.75V26.875ZM19.375 30.625L23.125 33.125V35L19.375 32.5V30.625ZM19.375 26.875L24.375 30V31.875L19.375 28.75V26.875Z" fill="url(#paint1_linear_30901_98056)"/>
<path d="M3.09375 29.4063H4.96875L34.7188 12.2188L35.6562 10.5938H33.7812L4.03125 27.7813L3.09375 29.4063Z" fill="url(#paint2_linear_30901_98056)"/>
<path d="M10.1563 25.3125L9.875 29.8125L8.25 30.75L8.53125 26.25L10.1563 25.3125ZM13.4063 23.4375L13.1875 29.3438L11.5625 30.2813L11.7813 24.375L13.4063 23.4375Z" fill="url(#paint3_linear_30901_98056)"/>
<path d="M10.1563 25.3125L6.125 23.3125L4.5 24.25L8.53125 26.25L10.1563 25.3125ZM13.4063 23.4375L8.1875 20.6875L6.5625 21.625L11.7813 24.375L13.4063 23.4375ZM28.5625 14.6875L32.5938 16.6875L34.2188 15.75L30.1875 13.75L28.5625 14.6875ZM25.3125 16.5625L30.5312 19.3438L32.1562 18.4063L26.9375 15.625L25.3125 16.5625Z" fill="url(#paint4_linear_30901_98056)"/>
<path d="M28.5625 14.6875L28.8438 10.1875L30.4688 9.25L30.1875 13.75L28.5625 14.6875ZM25.3125 16.5625L25.5312 10.6875L27.1562 9.75L26.9375 15.625L25.3125 16.5625Z" fill="url(#paint5_linear_30901_98056)"/>
<path d="M35.6562 29.4063H33.7812L4.03125 12.2188L3.09375 10.5938H4.96875L34.7188 27.7813L35.6562 29.4063Z" fill="url(#paint6_linear_30901_98056)"/>
<path d="M28.5938 25.3125L28.875 29.8125L30.5 30.75L30.2188 26.25L28.5938 25.3125ZM25.3438 23.4375L25.5625 29.3438L27.1875 30.2813L26.9688 24.375L25.3438 23.4375Z" fill="url(#paint7_linear_30901_98056)"/>
<path d="M28.5938 25.3125L32.625 23.3125L34.25 24.25L30.2188 26.25L28.5938 25.3125ZM25.3438 23.4375L30.5625 20.6875L32.1875 21.625L26.9688 24.375L25.3438 23.4375ZM10.1875 14.6875L6.15625 16.6875L4.53125 15.75L8.5625 13.75L10.1875 14.6875ZM13.4375 16.5625L8.21875 19.3438L6.59375 18.4063L11.8125 15.625L13.4375 16.5625ZM10.1875 14.6875L9.90625 10.1875L8.28125 9.25L8.5625 13.75L10.1875 14.6875Z" fill="url(#paint8_linear_30901_98056)"/>
<path d="M13.4375 16.5625L13.2188 10.6875L11.5938 9.75L11.8125 15.625L13.4375 16.5625Z" fill="url(#paint9_linear_30901_98056)"/>
<path d="M19.375 25.9063L14.25 22.9688V17.0625L19.375 14.0938L24.5 17.0313V22.9375L19.375 25.9063ZM15.8125 22.0625L19.375 24.0938L22.9375 22.0313V17.9688L19.375 15.9063L15.8125 17.9688V22.0625Z" fill="url(#paint10_linear_30901_98056)"/>
</g>
<defs>
<linearGradient id="paint0_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint1_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint2_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint3_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint4_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint5_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint6_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint7_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint8_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint9_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint10_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -0,0 +1,61 @@
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 25 25" fill="none">
<g opacity="0.24">
<path d="M12.1094 0.742188L11.5234 1.75781V23.2422L12.1094 24.2578L12.6953 23.2422V1.75781L12.1094 0.742188Z" fill="url(#paint0_linear_30901_98201)"/>
<path d="M12.1094 5.85938L9.76562 4.29688V3.125L12.1094 4.6875V5.85938ZM12.1094 8.20313L8.98438 6.25V5.07813L12.1094 7.03125V8.20313ZM12.1094 5.85938L14.4531 4.29688V3.125L12.1094 4.6875V5.85938ZM12.1094 8.20313L15.2344 6.25V5.07813L12.1094 7.03125V8.20313ZM12.1094 19.1406L9.76562 20.7031V21.875L12.1094 20.3125V19.1406ZM12.1094 16.7969L8.98438 18.75V19.9219L12.1094 17.9688V16.7969ZM12.1094 19.1406L14.4531 20.7031V21.875L12.1094 20.3125V19.1406ZM12.1094 16.7969L15.2344 18.75V19.9219L12.1094 17.9688V16.7969Z" fill="url(#paint1_linear_30901_98201)"/>
<path d="M1.93359 18.3789H3.10547L21.6992 7.63672L22.2852 6.6211H21.1133L2.51953 17.3633L1.93359 18.3789Z" fill="url(#paint2_linear_30901_98201)"/>
<path d="M6.34766 15.8203L6.17188 18.6328L5.15625 19.2188L5.33203 16.4063L6.34766 15.8203ZM8.37891 14.6484L8.24219 18.3398L7.22656 18.9258L7.36328 15.2344L8.37891 14.6484Z" fill="url(#paint3_linear_30901_98201)"/>
<path d="M6.34766 15.8203L3.82813 14.5703L2.8125 15.1563L5.33203 16.4063L6.34766 15.8203ZM8.37891 14.6484L5.11719 12.9297L4.10156 13.5156L7.36328 15.2344L8.37891 14.6484ZM17.8516 9.17969L20.3711 10.4297L21.3867 9.84375L18.8672 8.59375L17.8516 9.17969ZM15.8203 10.3516L19.082 12.0898L20.0977 11.5039L16.8359 9.76563L15.8203 10.3516Z" fill="url(#paint4_linear_30901_98201)"/>
<path d="M17.8516 9.17969L18.0273 6.36719L19.043 5.78125L18.8672 8.59375L17.8516 9.17969ZM15.8203 10.3516L15.957 6.67969L16.9727 6.09375L16.8359 9.76563L15.8203 10.3516Z" fill="url(#paint5_linear_30901_98201)"/>
<path d="M22.2852 18.3789H21.1133L2.51953 7.63672L1.93359 6.6211H3.10547L21.6992 17.3633L22.2852 18.3789Z" fill="url(#paint6_linear_30901_98201)"/>
<path d="M17.8711 15.8203L18.0469 18.6328L19.0625 19.2188L18.8867 16.4063L17.8711 15.8203ZM15.8398 14.6484L15.9766 18.3398L16.9922 18.9258L16.8555 15.2344L15.8398 14.6484Z" fill="url(#paint7_linear_30901_98201)"/>
<path d="M17.8711 15.8203L20.3906 14.5703L21.4062 15.1563L18.8867 16.4063L17.8711 15.8203ZM15.8398 14.6484L19.1016 12.9297L20.1172 13.5156L16.8555 15.2344L15.8398 14.6484ZM6.36719 9.17969L3.84766 10.4297L2.83203 9.84375L5.35156 8.59375L6.36719 9.17969ZM8.39844 10.3516L5.13672 12.0898L4.12109 11.5039L7.38281 9.76563L8.39844 10.3516ZM6.36719 9.17969L6.19141 6.36719L5.17578 5.78125L5.35156 8.59375L6.36719 9.17969Z" fill="url(#paint8_linear_30901_98201)"/>
<path d="M8.39844 10.3516L8.26172 6.67969L7.24609 6.09375L7.38281 9.76563L8.39844 10.3516Z" fill="url(#paint9_linear_30901_98201)"/>
<path d="M12.1094 16.1914L8.90625 14.3555V10.6641L12.1094 8.80859L15.3125 10.6445V14.3359L12.1094 16.1914ZM9.88281 13.7891L12.1094 15.0586L14.3359 13.7695V11.2305L12.1094 9.94141L9.88281 11.2305V13.7891Z" fill="url(#paint10_linear_30901_98201)"/>
</g>
<defs>
<linearGradient id="paint0_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint1_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint2_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint3_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint4_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint5_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint6_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint7_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint8_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint9_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint10_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -0,0 +1,61 @@
<svg xmlns="http://www.w3.org/2000/svg" width="67" height="67" viewBox="0 0 67 67" fill="none">
<g opacity="0.24">
<path d="M32.4532 1.98901L30.8829 4.71089V62.289L32.4532 65.0109L34.0235 62.289V4.71089L32.4532 1.98901Z" fill="url(#paint0_linear_30901_96540)"/>
<path d="M32.4532 15.7031L26.172 11.5156V8.37495L32.4532 12.5625V15.7031ZM32.4532 21.9843L24.0782 16.75V13.6093L32.4532 18.8437V21.9843ZM32.4532 15.7031L38.7345 11.5156V8.37495L32.4532 12.5625V15.7031ZM32.4532 21.9843L40.8282 16.75V13.6093L32.4532 18.8437V21.9843ZM32.4532 51.2968L26.172 55.4843V58.625L32.4532 54.4375V51.2968ZM32.4532 45.0156L24.0782 50.25V53.3906L32.4532 48.1562V45.0156ZM32.4532 51.2968L38.7345 55.4843V58.625L32.4532 54.4375V51.2968ZM32.4532 45.0156L40.8282 50.25V53.3906L32.4532 48.1562V45.0156Z" fill="url(#paint1_linear_30901_96540)"/>
<path d="M5.18213 49.2554H8.32275L58.154 20.4664L59.7243 17.7445H56.5837L6.75244 46.5336L5.18213 49.2554Z" fill="url(#paint2_linear_30901_96540)"/>
<path d="M17.0118 42.3984L16.5407 49.9359L13.8188 51.5062L14.2899 43.9687L17.0118 42.3984ZM22.4556 39.2578L22.0892 49.1507L19.3673 50.721L19.7337 40.8281L22.4556 39.2578Z" fill="url(#paint3_linear_30901_96540)"/>
<path d="M17.0118 42.3984L10.2595 39.0484L7.5376 40.6187L14.2899 43.9687L17.0118 42.3984ZM22.4556 39.2578L13.7142 34.6515L10.9923 36.2218L19.7337 40.8281L22.4556 39.2578ZM47.8423 24.6015L54.5946 27.9515L57.3165 26.3812L50.5642 23.0312L47.8423 24.6015ZM42.3985 27.7421L51.1399 32.4007L53.8618 30.8304L45.1204 26.1718L42.3985 27.7421Z" fill="url(#paint4_linear_30901_96540)"/>
<path d="M47.8423 24.6015L48.3134 17.064L51.0353 15.4937L50.5642 23.0312L47.8423 24.6015ZM42.3985 27.7421L42.7649 17.9015L45.4868 16.3312L45.1204 26.1718L42.3985 27.7421Z" fill="url(#paint5_linear_30901_96540)"/>
<path d="M59.7243 49.2554H56.5837L6.75244 20.4664L5.18213 17.7445H8.32275L58.154 46.5336L59.7243 49.2554Z" fill="url(#paint6_linear_30901_96540)"/>
<path d="M47.8946 42.3984L48.3657 49.9359L51.0876 51.5062L50.6165 43.9687L47.8946 42.3984ZM42.4509 39.2578L42.8173 49.1507L45.5392 50.721L45.1728 40.8281L42.4509 39.2578Z" fill="url(#paint7_linear_30901_96540)"/>
<path d="M47.8946 42.3984L54.647 39.0484L57.3688 40.6187L50.6165 43.9687L47.8946 42.3984ZM42.4509 39.2578L51.1923 34.6515L53.9142 36.2218L45.1728 40.8281L42.4509 39.2578ZM17.0642 24.6015L10.3118 27.9515L7.58994 26.3812L14.3423 23.0312L17.0642 24.6015ZM22.5079 27.7421L13.7665 32.4007L11.0446 30.8304L19.786 26.1718L22.5079 27.7421ZM17.0642 24.6015L16.5931 17.064L13.8712 15.4937L14.3423 23.0312L17.0642 24.6015Z" fill="url(#paint8_linear_30901_96540)"/>
<path d="M22.5079 27.7421L22.1415 17.9015L19.4196 16.3312L19.786 26.1718L22.5079 27.7421Z" fill="url(#paint9_linear_30901_96540)"/>
<path d="M32.4532 43.3929L23.8688 38.4726V28.5796L32.4532 23.607L41.0376 28.5273V38.4203L32.4532 43.3929ZM26.486 36.9546L32.4532 40.357L38.4204 36.9023V30.0976L32.4532 26.6429L26.486 30.0976V36.9546Z" fill="url(#paint10_linear_30901_96540)"/>
</g>
<defs>
<linearGradient id="paint0_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint1_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint2_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint3_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint4_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint5_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint6_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint7_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint8_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint9_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint10_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -0,0 +1,27 @@
<svg width="29" height="12" viewBox="0 0 29 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_di_30901_97735)">
<path d="M23 1.59997L1 1.59998" stroke="url(#paint0_linear_30901_97735)" stroke-width="2" stroke-linecap="round" shape-rendering="crispEdges"/>
</g>
<defs>
<filter id="filter0_di_30901_97735" x="-4.6" y="-2.43187e-05" width="33.2" height="11.2" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2.3"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.500815 0 0 0 0 0.168025 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_30901_97735"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_30901_97735" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.724544 0 0 0 0 0.338905 0 0 0 0.36 0"/>
<feBlend mode="normal" in2="shape" result="effect2_innerShadow_30901_97735"/>
</filter>
<linearGradient id="paint0_linear_30901_97735" x1="1" y1="2.09998" x2="23" y2="2.09997" gradientUnits="userSpaceOnUse">
<stop stop-color="#BB182C"/>
<stop offset="1" stop-color="#BB182C" stop-opacity="0.1"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,30 @@
<svg width="136" height="170" viewBox="0 0 136 170" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_di_30901_97737)">
<path d="M166.6 83.1323L5.6001 83.1323" stroke="url(#paint0_linear_30901_97737)" stroke-width="2" stroke-linecap="round"/>
<path d="M58.6001 94.2076C63.9919 93.5518 77.6171 90.3167 88.9836 82.6225M88.9836 82.6225C86.142 70.1629 70.8409 53.9874 62.3161 62.5125C53.7912 71.0376 63.1904 82.6225 88.9836 82.6225Z" stroke="#BB182C" stroke-width="2"/>
<path d="M119.6 94.3567C114.336 93.698 101.035 90.4488 89.939 82.7209M89.939 82.7209C92.7131 70.2068 107.65 53.9605 115.972 62.5229C124.295 71.0853 115.119 82.7209 89.939 82.7209Z" stroke="#BB182C" stroke-width="2"/>
<path d="M139.6 160.132L39.6001 1.13232" stroke="#BB182C" stroke-width="2"/>
</g>
<defs>
<filter id="filter0_di_30901_97737" x="9.77516e-05" y="-2.43187e-05" width="172.2" height="169.265" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2.3"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.500815 0 0 0 0 0.168025 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_30901_97737"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_30901_97737" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.724544 0 0 0 0 0.338905 0 0 0 0.36 0"/>
<feBlend mode="normal" in2="shape" result="effect2_innerShadow_30901_97737"/>
</filter>
<linearGradient id="paint0_linear_30901_97737" x1="5.6001" y1="83.6323" x2="29.2468" y2="83.1261" gradientUnits="userSpaceOnUse">
<stop stop-color="#BB182C" stop-opacity="0.1"/>
<stop offset="1" stop-color="#BB182C"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,61 @@
<svg width="78" height="81" viewBox="0 0 78 81" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.24">
<path d="M40.203 2.46411L38.2577 5.83599V77.1641L40.203 80.536L42.1483 77.1641V5.83599L40.203 2.46411Z" fill="url(#paint0_linear_30901_97724)"/>
<path d="M40.203 19.4532L32.4218 14.2657V10.375L40.203 15.5625V19.4532ZM40.203 27.2344L29.828 20.75V16.8594L40.203 23.3438V27.2344ZM40.203 19.4532L47.9843 14.2657V10.375L40.203 15.5625V19.4532ZM40.203 27.2344L50.578 20.75V16.8594L40.203 23.3438V27.2344ZM40.203 63.5469L32.4218 68.7344V72.625L40.203 67.4375V63.5469ZM40.203 55.7657L29.828 62.25V66.1407L40.203 59.6563V55.7657ZM40.203 63.5469L47.9843 68.7344V72.625L40.203 67.4375V63.5469ZM40.203 55.7657L50.578 62.25V66.1407L40.203 59.6563V55.7657Z" fill="url(#paint1_linear_30901_97724)"/>
<path d="M6.41943 61.018H10.3101L72.0413 25.354L73.9866 21.9821H70.096L8.36475 57.6461L6.41943 61.018Z" fill="url(#paint2_linear_30901_97724)"/>
<path d="M21.0741 52.5235L20.4905 61.861L17.1187 63.8063L17.7022 54.4688L21.0741 52.5235ZM27.8179 48.6329L27.364 60.8883L23.9921 62.8336L24.446 50.5782L27.8179 48.6329Z" fill="url(#paint3_linear_30901_97724)"/>
<path d="M21.0741 52.5235L12.7093 48.3735L9.3374 50.3188L17.7022 54.4688L21.0741 52.5235ZM27.8179 48.6329L16.989 42.9266L13.6171 44.8719L24.446 50.5782L27.8179 48.6329ZM59.2671 30.4766L67.6319 34.6266L71.0038 32.6813L62.639 28.5313L59.2671 30.4766ZM52.5233 34.3672L63.3522 40.1383L66.7241 38.193L55.8952 32.4219L52.5233 34.3672Z" fill="url(#paint4_linear_30901_97724)"/>
<path d="M59.2671 30.4766L59.8507 21.1391L63.2226 19.1938L62.639 28.5313L59.2671 30.4766ZM52.5233 34.3672L52.9772 22.1766L56.3491 20.2313L55.8952 32.4219L52.5233 34.3672Z" fill="url(#paint5_linear_30901_97724)"/>
<path d="M73.9866 61.018H70.096L8.36475 25.354L6.41943 21.9821H10.3101L72.0413 57.6461L73.9866 61.018Z" fill="url(#paint6_linear_30901_97724)"/>
<path d="M59.3319 52.5235L59.9155 61.861L63.2874 63.8063L62.7038 54.4688L59.3319 52.5235ZM52.5882 48.6329L53.0421 60.8883L56.414 62.8336L55.9601 50.5782L52.5882 48.6329Z" fill="url(#paint7_linear_30901_97724)"/>
<path d="M59.3319 52.5235L67.6968 48.3735L71.0687 50.3188L62.7038 54.4688L59.3319 52.5235ZM52.5882 48.6329L63.4171 42.9266L66.789 44.8719L55.9601 50.5782L52.5882 48.6329ZM21.139 30.4766L12.7741 34.6266L9.40225 32.6813L17.7671 28.5313L21.139 30.4766ZM27.8827 34.3672L17.0538 40.1383L13.6819 38.193L24.5108 32.4219L27.8827 34.3672ZM21.139 30.4766L20.5554 21.1391L17.1835 19.1938L17.7671 28.5313L21.139 30.4766Z" fill="url(#paint8_linear_30901_97724)"/>
<path d="M27.8827 34.3672L27.4288 22.1766L24.0569 20.2313L24.5108 32.4219L27.8827 34.3672Z" fill="url(#paint9_linear_30901_97724)"/>
<path d="M40.203 53.7555L29.5687 47.6602V35.4047L40.203 29.2446L50.8374 35.3399V47.5954L40.203 53.7555ZM32.8108 45.7797L40.203 49.9946L47.5952 45.7149V37.2852L40.203 33.0055L32.8108 37.2852V45.7797Z" fill="url(#paint10_linear_30901_97724)"/>
</g>
<defs>
<linearGradient id="paint0_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint1_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint2_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint3_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint4_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint5_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint6_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint7_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint8_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint9_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint10_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -0,0 +1,3 @@
<svg width="27" height="28" viewBox="0 0 27 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.62226 -2.00591C6.23794 -1.79022 5.95648 -1.43496 5.83917 -1.01752L4.96831 1.85934L2.0224 1.00889C1.80798 0.943838 1.58239 0.921415 1.35895 0.942944C1.13551 0.964473 0.91876 1.02952 0.721498 1.13423C0.427919 1.2902 0.188641 1.52812 0.0342524 1.81759C-0.120136 2.10705 -0.182618 2.4349 -0.145207 2.75922C-0.107796 3.08355 0.0278096 3.38961 0.244271 3.63827C0.460734 3.88694 0.748218 4.06691 1.06997 4.15519L4.95928 5.27799L8.02483 10.7845L1.82406 10.5278L-1.60572 7.39941C-1.76707 7.2523 -1.95652 7.13767 -2.16324 7.06205C-2.36996 6.98644 -2.5899 6.95133 -2.81052 6.95873C-3.03114 6.96612 -3.2481 7.01588 -3.44902 7.10516C-3.64995 7.19444 -3.83089 7.3215 -3.98154 7.47907C-4.13218 7.63664 -4.24957 7.82165 -4.32699 8.02352C-4.40442 8.2254 -4.44038 8.44019 -4.4328 8.65563C-4.42523 8.87108 -4.37427 9.08296 -4.28285 9.27917C-4.19143 9.47538 -4.06132 9.65209 -3.89997 9.79921L-1.24539 12.2195L-3.72375 14.8118C-4.02798 15.1301 -4.19031 15.5533 -4.17501 15.9884C-4.15972 16.4235 -3.96805 16.8349 -3.64218 17.132C-3.31631 17.4291 -2.88293 17.5876 -2.43738 17.5727C-1.99183 17.5577 -1.5706 17.3706 -1.26636 17.0523L1.83225 13.8097L8.04926 14.0687L4.89153 19.305L0.420006 20.0815C-0.0189056 20.1578 -0.408794 20.4013 -0.663889 20.7583C-0.790198 20.9351 -0.879614 21.1345 -0.927029 21.345C-0.974445 21.5555 -0.978932 21.7731 -0.940233 21.9854C-0.901536 22.1976 -0.820411 22.4003 -0.701492 22.5819C-0.582571 22.7636 -0.428188 22.9205 -0.24715 23.0439C0.11847 23.293 0.570451 23.3901 1.00936 23.3137L4.5848 22.692L5.22145 26.1837C5.26012 26.3959 5.34122 26.5987 5.46013 26.7803C5.57903 26.962 5.73342 27.119 5.91447 27.2423C6.09551 27.3657 6.29967 27.4531 6.51529 27.4994C6.7309 27.5457 6.95375 27.5501 7.1711 27.5123C7.38845 27.4745 7.59605 27.3953 7.78204 27.2791C7.96803 27.163 8.12877 27.0122 8.25508 26.8353C8.38139 26.6585 8.47079 26.4591 8.51818 26.2486C8.56557 26.038 8.57003 25.8204 8.53129 25.6081L7.70753 21.0961L10.8584 15.8744L13.924 21.3809L12.7742 25.1791C12.7065 25.3871 12.682 25.6062 12.7021 25.8236C12.7222 26.041 12.7865 26.2523 12.8912 26.4451C12.996 26.638 13.1391 26.8084 13.3122 26.9466C13.4852 27.0847 13.6848 27.1877 13.8991 27.2496C14.1135 27.3115 14.3383 27.331 14.5605 27.307C14.7826 27.2829 14.9977 27.2158 15.1929 27.1096C15.3882 27.0034 15.5598 26.8602 15.6977 26.6884C15.8356 26.5167 15.937 26.3197 15.996 26.1092L16.8669 23.2323L19.8128 24.0828C20.0258 24.1489 20.2502 24.1729 20.4728 24.1532C20.6955 24.1336 20.9118 24.0708 21.1093 23.9685C21.3067 23.8662 21.4813 23.7265 21.6227 23.5575C21.7642 23.3884 21.8697 23.1936 21.9331 22.9842C21.9964 22.7749 22.0164 22.5553 21.9918 22.3384C21.9672 22.1214 21.8985 21.9115 21.7897 21.7208C21.6809 21.5301 21.5343 21.3625 21.3584 21.2278C21.1825 21.0931 20.9808 20.9941 20.7652 20.9365L16.8759 19.8137L13.8104 14.3071L20.0112 14.5638L23.4409 17.6922C23.6023 17.8394 23.7917 17.9541 23.9985 18.0298C24.2052 18.1054 24.4252 18.1406 24.6458 18.1332C24.8665 18.1258 25.0835 18.0761 25.2844 17.9868C25.4854 17.8975 25.6664 17.7704 25.817 17.6128C25.9677 17.4553 26.0851 17.2702 26.1625 17.0683C26.2399 16.8664 26.2759 16.6516 26.2683 16.4361C26.2607 16.2206 26.2097 16.0087 26.1182 15.8125C26.0268 15.6163 25.8966 15.4396 25.7352 15.2925L23.0806 12.8722L25.559 10.2798C25.7097 10.1223 25.8271 9.93724 25.9046 9.73535C25.9821 9.53346 26.018 9.31864 26.0105 9.10316C26.0029 8.88769 25.952 8.67577 25.8606 8.47952C25.7691 8.28328 25.639 8.10654 25.4777 7.9594C25.3163 7.81227 25.1268 7.69762 24.92 7.62201C24.7133 7.5464 24.4933 7.5113 24.2727 7.51872C24.052 7.52614 23.835 7.57594 23.6341 7.66527C23.4331 7.7546 23.2522 7.8817 23.1016 8.03933L20.003 11.282L13.786 11.023L16.9437 5.7867L21.4152 5.01018C21.6326 4.97243 21.8402 4.89323 22.0262 4.77711C22.2122 4.66099 22.373 4.51022 22.4993 4.33342C22.6257 4.15662 22.7151 3.95724 22.7626 3.74667C22.81 3.53611 22.8145 3.31848 22.7758 3.10622C22.7371 2.89396 22.6559 2.69122 22.537 2.50959C22.418 2.32795 22.2636 2.17098 22.0826 2.04763C21.9015 1.92429 21.6973 1.83698 21.4817 1.7907C21.266 1.74442 21.0432 1.74008 20.8258 1.77792L17.2504 2.39965L16.6138 -1.09199C16.5356 -1.52062 16.2863 -1.90137 15.9207 -2.15048C15.5551 -2.3996 15.1031 -2.49667 14.6642 -2.42035C14.2253 -2.34403 13.8354 -2.10056 13.5803 -1.74351C13.3252 -1.38646 13.2258 -0.945071 13.3039 -0.516447L14.1277 3.99557L10.9768 9.21726L7.91123 3.71074L9.06098 -0.0874187C9.16328 -0.402515 9.16573 -0.740436 9.06802 -1.05692C8.97031 -1.3734 8.77699 -1.65368 8.51339 -1.86104C8.2498 -2.06841 7.92821 -2.19319 7.59076 -2.21903C7.25331 -2.24488 6.91574 -2.1706 6.62226 -2.00591Z" fill="white" fill-opacity="0.2"/>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="23" height="24" viewBox="0 0 23 24" fill="none">
<path d="M15.3871 0.000406097C15.0178 0.0095006 14.667 0.170233 14.4109 0.44759L12.6008 2.33317L10.7906 0.44759C10.6602 0.30789 10.5041 0.196845 10.3318 0.121017C10.1594 0.0451883 9.97422 0.00611411 9.78712 0.00610271C9.50861 0.0061789 9.23645 0.0927728 9.00544 0.254814C8.77443 0.416854 8.59506 0.646979 8.49026 0.915768C8.38546 1.18456 8.35999 1.47979 8.41712 1.76374C8.47424 2.04768 8.61136 2.30742 8.81095 2.50976L11.2008 4.99919V10.5705L6.76564 7.79907L5.5297 3.93392C5.47153 3.75213 5.37955 3.58406 5.25902 3.4393C5.1385 3.29454 4.99178 3.17593 4.82724 3.09024C4.66271 3.00454 4.48358 2.95344 4.30009 2.93986C4.1166 2.92627 3.93234 2.95047 3.75782 3.01107C3.58331 3.07166 3.42196 3.16747 3.28299 3.29302C3.14402 3.41857 3.03015 3.5714 2.94789 3.74279C2.86562 3.91418 2.81657 4.10077 2.80353 4.29191C2.79048 4.48304 2.81371 4.67498 2.87189 4.85677L3.82892 7.84749L0.957823 8.8444C0.605375 8.96678 0.314032 9.22999 0.147887 9.57612C-0.0182588 9.92226 -0.0455975 10.323 0.0718851 10.6901C0.189368 11.0572 0.442048 11.3607 0.774339 11.5338C1.10663 11.7069 1.49131 11.7353 1.84376 11.613L5.43399 10.3654L9.88009 13.1453L5.43399 15.9253L1.84376 14.6777C1.49131 14.5554 1.10663 14.5838 0.774339 14.7569C0.609805 14.8426 0.463086 14.9612 0.342559 15.106C0.222032 15.2507 0.130057 15.4188 0.0718851 15.6006C0.0137136 15.7824 -0.00951502 15.9743 0.00352535 16.1654C0.0165657 16.3566 0.0656195 16.5432 0.147886 16.7146C0.314032 17.0607 0.605375 17.3239 0.957823 17.4463L3.82892 18.4432L2.87189 21.4339C2.81368 21.6157 2.79042 21.8077 2.80343 21.9988C2.81645 22.19 2.86549 22.3766 2.94775 22.548C3.03001 22.7194 3.14389 22.8723 3.28287 22.9979C3.42185 23.1234 3.58321 23.2193 3.75774 23.2799C3.93228 23.3405 4.11656 23.3647 4.30008 23.3511C4.48359 23.3375 4.66273 23.2864 4.82728 23.2006C4.99182 23.1149 5.13854 22.9963 5.25907 22.8515C5.37959 22.7067 5.47155 22.5386 5.5297 22.3568L6.76564 18.4916L11.2008 15.7202V21.2915L8.81095 23.7809C8.67658 23.9153 8.56931 24.0763 8.49541 24.2544C8.42151 24.4325 8.38247 24.6241 8.38058 24.8182C8.37868 25.0122 8.41397 25.2046 8.48437 25.3843C8.55478 25.5639 8.65889 25.7271 8.7906 25.8643C8.92231 26.0015 9.07897 26.1099 9.25142 26.1833C9.42387 26.2566 9.60863 26.2934 9.79489 26.2914C9.98115 26.2894 10.1652 26.2488 10.3361 26.1718C10.5071 26.0948 10.6616 25.9831 10.7906 25.8431L12.6008 23.9575L14.4109 25.8431C14.5399 25.9831 14.6945 26.0948 14.8654 26.1718C15.0364 26.2488 15.2204 26.2894 15.4067 26.2914C15.5929 26.2934 15.7777 26.2566 15.9502 26.1833C16.1226 26.1099 16.2793 26.0015 16.411 25.8643C16.5427 25.7271 16.6468 25.5639 16.7172 25.3843C16.7876 25.2046 16.8229 25.0122 16.821 24.8182C16.8191 24.6241 16.7801 24.4325 16.7062 24.2544C16.6323 24.0763 16.525 23.9153 16.3906 23.7809L14.0008 21.2915V15.7202L18.4359 18.4916L19.6719 22.3568C19.73 22.5386 19.822 22.7067 19.9425 22.8515C20.063 22.9963 20.2097 23.115 20.3743 23.2007C20.5388 23.2864 20.718 23.3375 20.9015 23.3511C21.085 23.3647 21.2693 23.3405 21.4439 23.2799C21.6184 23.2193 21.7798 23.1235 21.9188 22.9979C22.0577 22.8724 22.1716 22.7195 22.2539 22.5481C22.3361 22.3766 22.3852 22.19 22.3982 21.9988C22.4112 21.8077 22.3879 21.6157 22.3297 21.4339L21.3727 18.4432L24.2438 17.4463C24.4183 17.3857 24.5797 17.2899 24.7187 17.1644C24.8577 17.0389 24.9716 16.886 25.0539 16.7146C25.1362 16.5432 25.1853 16.3566 25.1984 16.1654C25.2114 15.9743 25.1882 15.7823 25.13 15.6005C25.0718 15.4187 24.9798 15.2506 24.8593 15.1058C24.7387 14.961 24.592 14.8424 24.4274 14.7567C24.2628 14.671 24.0837 14.62 23.9002 14.6064C23.7166 14.5928 23.5323 14.6171 23.3578 14.6777L19.7676 15.9253L15.3215 13.1453L19.7676 10.3654L23.3578 11.613C23.5323 11.6736 23.7166 11.6978 23.9001 11.6843C24.0837 11.6707 24.2628 11.6196 24.4274 11.5339C24.5919 11.4483 24.7387 11.3296 24.8592 11.1849C24.9798 11.0401 25.0718 10.872 25.13 10.6902C25.1881 10.5084 25.2114 10.3164 25.1983 10.1253C25.1853 9.9341 25.1362 9.74749 25.0539 9.57608C24.9716 9.40468 24.8577 9.25184 24.7187 9.1263C24.5797 9.00076 24.4183 8.90497 24.2438 8.8444L21.3727 7.84749L22.3297 4.85677C22.4472 4.48964 22.4198 4.08893 22.2537 3.74279C22.0875 3.39665 21.7962 3.13344 21.4438 3.01107C21.0913 2.88869 20.7066 2.91717 20.3743 3.09023C20.042 3.2633 19.7894 3.56679 19.6719 3.93392L18.4359 7.79907L14.0008 10.5705V4.99919L16.3906 2.50976C16.594 2.30611 16.7335 2.04323 16.7909 1.75556C16.8484 1.4679 16.8211 1.16887 16.7126 0.897634C16.6042 0.626403 16.4196 0.395623 16.1831 0.235524C15.9465 0.0754252 15.6691 -0.00652579 15.3871 0.000406097Z" fill="white" fill-opacity="0.2"/>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -40,6 +40,9 @@ const ManualCopyModal = dynamic(
() => import('@fastgpt/web/hooks/useCopyData').then((mod) => mod.ManualCopyModal),
{ ssr: false }
);
const ActivityAdModal = dynamic(() => import('@/components/support/activity/ActivityAdModal'), {
ssr: false
});
const pcUnShowLayoutRoute: Record<string, boolean> = {
'/': true,
@ -187,6 +190,7 @@ const Layout = ({ children }: { children: JSX.Element }) => {
)}
<ManualCopyModal />
<ActivityAdModal />
<Loading loading={loading} zIndex={999999} />
</>
);

View File

@ -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}

View File

@ -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}

View File

@ -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);

View File

@ -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) {

View File

@ -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} />

View File

@ -0,0 +1,209 @@
import React, { useCallback, useMemo } from 'react';
import { useDisclosure } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import { getActivityAd } from '@/web/common/system/api';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import {
Box,
Flex,
Button,
Image,
Modal,
ModalOverlay,
ModalContent,
ModalCloseButton
} from '@chakra-ui/react';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useLocalStorageState } from 'ahooks';
import { useRouter } from 'next/router';
import { useUserStore } from '@/web/support/user/useUserStore';
const CLOSED_AD_KEY = 'logout-activity-ad';
const CLOSED_AD_DURATION = 24 * 60 * 60 * 1000; // 24 hours
const ActivityAdModal = () => {
const { isOpen, onOpen, onClose } = useDisclosure();
const { t } = useTranslation();
const { feConfigs } = useSystemStore();
const router = useRouter();
const { userInfo } = useUserStore();
// Check if ad was recently closed
const [closedData, setClosedData] = useLocalStorageState<string>(CLOSED_AD_KEY, {
listenStorageChange: true
});
const { data } = useRequest2(
async () => {
if (!feConfigs?.isPlus || !userInfo) return;
return getActivityAd();
},
{
manual: false,
onSuccess(res) {
const shouldShowAd = (() => {
if (!res?.id) return false;
if (!closedData) return true;
try {
const { timestamp, adId } = JSON.parse(closedData) as {
timestamp: number;
adId: string;
};
// 不同的广告 id一定展示
if (adId && res.id !== adId) return true;
const now = Date.now();
// Show if 24 hours passed
return now - timestamp > CLOSED_AD_DURATION;
} catch {
return true;
}
})();
if (res?.activityAdImage && shouldShowAd) {
onOpen();
}
},
refreshDeps: [userInfo]
}
);
const handleClose = useCallback(() => {
if (data?.id) {
setClosedData(JSON.stringify({ timestamp: Date.now(), adId: data.id }));
}
onClose();
}, [data?.id, onClose, setClosedData]);
const handleJoin = useCallback(() => {
if (data?.activityAdLink) {
if (data.activityAdLink.startsWith('/')) {
router.push(data.activityAdLink);
handleClose();
} else {
window.open(data.activityAdLink, '_blank');
}
}
}, [data?.activityAdLink, handleClose, router]);
if (!data?.activityAdImage || !userInfo) {
return null;
}
return isOpen ? (
<Modal
isOpen={isOpen}
onClose={handleClose}
isCentered
size="xl"
closeOnOverlayClick={false}
blockScrollOnMount
>
<ModalOverlay bg="blackAlpha.600" />
<ModalContent
maxW="400px"
bg="white"
borderRadius="10px"
overflow="hidden"
position="relative"
p={0}
>
<ModalCloseButton
position="absolute"
top={1}
right={1}
zIndex={10}
bg={'rgba(244, 246, 248, 0.40)'}
borderRadius={'full'}
boxSize={9}
display={'flex'}
alignItems={'center'}
justifyContent="center"
color={'white'}
_hover={{ bg: 'rgba(244, 246, 248, 0.60)' }}
/>
<Flex direction="column">
{/* Activity Image */}
<Box position="relative">
<Image
src={data.activityAdImage}
alt="Activity"
w="100%"
h="auto"
objectFit="cover"
userSelect="none"
draggable={false}
/>
{/* Gradient overlay for smooth transition */}
<Box
position="absolute"
bottom={0}
left={0}
right={0}
h={10}
bg="linear-gradient(180deg, rgba(255, 255, 255, 0.00) 0%, #FFF 100%)"
pointerEvents="none"
/>
</Box>
<Flex
mt={6}
justifyContent={'center'}
color={'black'}
fontSize="20px"
fontWeight={'medium'}
>
{t('common:activity_ad.title')}
</Flex>
<Flex mt={6} color={'black'} justifyContent={'center'} fontSize={'14px'} px={8}>
{t('common:activity_ad.desc')}
</Flex>
<Flex direction="column" align="center" p={8} bg="white">
<Flex direction="column" width="100%" gap={3}>
<Button
width={'100%'}
bg={'#ED372C'}
color={'white'}
borderRadius={'6px'}
h={10}
sx={{
'&::before': {
content: '""',
position: 'absolute',
left: '0',
top: '0',
width: '30px',
height: '30px',
backgroundImage: `url('/imgs/system/snowflakeLeft.svg')`,
backgroundRepeat: 'no-repeat'
},
'&::after': {
content: '""',
position: 'absolute',
right: '0',
bottom: '0',
width: '25px',
height: '25px',
backgroundImage: `url('/imgs/system/snowflakeRight.svg')`
}
}}
_hover={{ bg: '#DE0D00' }}
onClick={handleJoin}
>
{t('common:activity_ad.join_now')}
</Button>
<Button width="100%" variant="whiteBase" h={10} onClick={handleClose}>
{t('common:activity_ad.later')}
</Button>
</Flex>
</Flex>
</Flex>
</ModalContent>
</Modal>
) : null;
};
export default React.memo(ActivityAdModal);

View File

@ -135,7 +135,7 @@ export const RechargeModal = ({
<Box
fontSize={'14px'}
fontWeight={'medium'}
>{`${teamPlanStatus?.usedPoints || 0} / ${teamPlanStatus?.totalPoints ?? t('common:Unlimited')}`}</Box>
>{`${Math.round(teamPlanStatus?.usedPoints || 0)} / ${teamPlanStatus?.totalPoints ?? t('common:Unlimited')}`}</Box>
</Flex>
<Flex h={2} w={'full'} p={0.5} bg={'primary.50'} borderRadius={'md'}>
<Box

View File

@ -47,6 +47,27 @@ const QRCodePayModal = ({
const isWxConfigured = feConfigs.payConfig?.wx;
const isBankConfigured = feConfigs.payConfig?.bank;
const MIN_QR_SIZE = 150;
const [dynamicQRSize, setDynamicQRSize] = useState(QR_CODE_SIZE);
useEffect(() => {
const calculateQRSize = () => {
const windowHeight = window.innerHeight;
const reservedSpace = 470 + (tip ? 60 : 0) + (discountCouponName ? 30 : 0);
const availableHeight = windowHeight - reservedSpace;
const newSize = Math.min(QR_CODE_SIZE, Math.max(MIN_QR_SIZE, availableHeight));
setDynamicQRSize(newSize);
};
window.addEventListener('resize', calculateQRSize);
return () => {
window.removeEventListener('resize', calculateQRSize);
};
}, [tip, discountCouponName]);
const [payWayRenderData, setPayWayRenderData] = useState<{
qrCode?: string;
iframeCode?: string;
@ -99,7 +120,7 @@ const QRCodePayModal = ({
const canvas = document.createElement('canvas');
QRCode.toCanvas(canvas, payWayRenderData.qrCode, {
width: QR_CODE_SIZE,
width: dynamicQRSize,
margin: 0,
color: {
dark: '#000000',
@ -113,7 +134,7 @@ const QRCodePayModal = ({
}
})
.catch(console.error);
}, [payWayRenderData.qrCode]);
}, [payWayRenderData.qrCode, dynamicQRSize]);
useEffect(() => {
drawCode();
}, [drawCode]);
@ -140,15 +161,15 @@ const QRCodePayModal = ({
});
const renderPaymentContent = () => {
if (payWayRenderData.qrCode) {
return <Box ref={canvasRef} display={'inline-block'} h={`${QR_CODE_SIZE}px`} />;
return <Box ref={canvasRef} display={'inline-block'} h={`${dynamicQRSize}px`} />;
}
if (payWayRenderData.iframeCode) {
return (
<iframe
srcDoc={payWayRenderData.iframeCode}
style={{
width: QR_CODE_SIZE + 5,
height: QR_CODE_SIZE + 5,
width: dynamicQRSize + 5,
height: dynamicQRSize + 5,
border: 'none',
display: 'inline-block'
}}
@ -169,6 +190,7 @@ const QRCodePayModal = ({
iconSrc="/imgs/modal/wallet.svg"
w={'600px'}
onClose={onClose}
closeOnOverlayClick={false}
>
<ModalBody textAlign={'center'} padding={['16px 24px', '32px 52px']}>
{tip && <LightTip text={tip} mb={6} textAlign={'left'} />}

View File

@ -3,12 +3,12 @@ import type { StandardSubLevelEnum } from '@fastgpt/global/support/wallet/sub/co
import { SubModeEnum } from '@fastgpt/global/support/wallet/sub/constants';
import React, { useMemo } from 'react';
import { standardSubLevelMap } from '@fastgpt/global/support/wallet/sub/constants';
import { Box, Flex, Grid } from '@chakra-ui/react';
import { Box, Flex, Grid, Text } from '@chakra-ui/react';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useTranslation } from 'next-i18next';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import dynamic from 'next/dynamic';
import type { TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type';
import type { TeamSubSchemaType } from '@fastgpt/global/support/wallet/sub/type';
import Markdown from '@/components/Markdown';
import MyPopover from '@fastgpt/web/components/common/MyPopover';
@ -23,7 +23,7 @@ const StandardPlanContentList = ({
}: {
level: `${StandardSubLevelEnum}`;
mode: `${SubModeEnum}`;
standplan?: TeamSubSchema;
standplan?: TeamSubSchemaType;
}) => {
const { t } = useTranslation();
const { subPlans } = useSystemStore();
@ -38,6 +38,8 @@ const StandardPlanContentList = ({
...standardSubLevelMap[level as `${StandardSubLevelEnum}`],
totalPoints:
standplan?.totalPoints ?? plan.totalPoints * (mode === SubModeEnum.month ? 1 : 12),
annualBonusPoints:
mode === SubModeEnum.month ? 0 : standplan?.annualBonusPoints ?? plan.annualBonusPoints,
requestsPerMinute: standplan?.requestsPerMinute ?? plan.requestsPerMinute,
maxTeamMember: standplan?.maxTeamMember ?? plan.maxTeamMember,
maxAppAmount: standplan?.maxApp ?? plan.maxAppAmount,
@ -56,6 +58,7 @@ const StandardPlanContentList = ({
level,
mode,
standplan?.totalPoints,
standplan?.annualBonusPoints,
standplan?.requestsPerMinute,
standplan?.maxTeamMember,
standplan?.maxApp,
@ -72,13 +75,31 @@ const StandardPlanContentList = ({
return planContent ? (
<Grid gap={4} fontSize={'sm'} fontWeight={500}>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon
name={'price/right'}
w={'16px'}
mr={3}
color={planContent.annualBonusPoints ? '#BB182C' : 'primary.600'}
/>
<Flex alignItems={'center'}>
<Box fontWeight={'bold'} color={'myGray.600'}>
{t('common:n_ai_points', {
amount: planContent.totalPoints
})}
</Box>
{planContent.annualBonusPoints ? (
<>
<Text fontWeight={'bold'} color={'myGray.600'} textDecoration={'line-through'} mr={1}>
{planContent.totalPoints}
</Text>
<Text fontWeight={'bold'} color={'#DF531E'}>
{planContent.totalPoints + planContent.annualBonusPoints}
</Text>
<Text color={'myGray.600'} ml={1}>
{t('common:support.wallet.subscription.point')}
</Text>
</>
) : (
<Box fontWeight={'bold'} color={'myGray.600'} display={'flex'}>
<Text>{planContent.totalPoints}</Text>
<Text ml={1}>{t('common:support.wallet.subscription.point')}</Text>
</Box>
)}
<ModelPriceModal>
{({ onOpen }) => (
<QuestionTip ml={1} label={t('common:aipoint_desc')} onClick={onOpen} />
@ -87,7 +108,7 @@ const StandardPlanContentList = ({
</Flex>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box fontWeight={'bold'} color={'myGray.600'}>
{t('common:n_dataset_size', {
amount: planContent.maxDatasetSize
@ -95,7 +116,7 @@ const StandardPlanContentList = ({
</Box>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{t('common:n_team_members', {
amount: planContent.maxTeamMember
@ -103,7 +124,7 @@ const StandardPlanContentList = ({
</Box>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{t('common:n_agent_amount', {
amount: planContent.maxAppAmount
@ -111,7 +132,7 @@ const StandardPlanContentList = ({
</Box>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{t('common:n_dataset_amount', {
amount: planContent.maxDatasetAmount
@ -119,7 +140,7 @@ const StandardPlanContentList = ({
</Box>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{t('common:n_chat_records_retain', {
amount: planContent.chatHistoryStoreDuration
@ -128,7 +149,7 @@ const StandardPlanContentList = ({
</Flex>
{!!planContent.auditLogStoreDuration && (
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{t('common:n_team_audit_day', {
amount: planContent.auditLogStoreDuration
@ -137,7 +158,7 @@ const StandardPlanContentList = ({
</Flex>
)}
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{t('common:n_team_qpm', {
amount: planContent.requestsPerMinute
@ -147,7 +168,7 @@ const StandardPlanContentList = ({
</Flex>
{!!planContent.websiteSyncPerDataset && (
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box fontWeight={'bold'} color={'myGray.600'}>
{t('common:n_website_sync_max_pages', {
amount: planContent.websiteSyncPerDataset
@ -156,7 +177,7 @@ const StandardPlanContentList = ({
</Flex>
)}
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{planContent.ticketResponseTime
? t('common:worker_order_support_time', {
@ -185,7 +206,7 @@ const StandardPlanContentList = ({
</Flex>
{!!planContent.appRegistrationCount && (
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{t('common:n_app_registration_amount', {
amount: planContent.appRegistrationCount
@ -195,13 +216,13 @@ const StandardPlanContentList = ({
)}
{planContent.customDomain !== undefined && (
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{t('common:n_custom_domain_amount', {
amount: planContent.customDomain
})}
</Box>
<QuestionTip ml={1} label={t('common:n_custom_domain_amount tip')} />
<QuestionTip ml={1} label={t('common:n_custom_domain_amount_tip')} />
</Flex>
)}
</Grid>

View File

@ -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

View File

@ -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

View File

@ -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} />

View File

@ -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
});

View File

@ -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
});

View File

@ -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>

View File

@ -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
});

View File

@ -0,0 +1,183 @@
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} w={'400px'}>
<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>
<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;

View File

@ -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
});

View File

@ -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>
);

View File

@ -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} />

View File

@ -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} />

View File

@ -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) => {

View File

@ -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} />}
</>
);
};

View File

@ -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

View File

@ -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)),

View File

@ -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);

View File

@ -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 };

View File

@ -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) => {

View File

@ -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)),

View File

@ -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) => {

View File

@ -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 (
<>

View File

@ -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);

View File

@ -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}
/>

View File

@ -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}
/>

View File

@ -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;

Some files were not shown because too many files have changed in this diff Show More