From 3ef362508a6b954f2b6ae7272050292a1f606324 Mon Sep 17 00:00:00 2001 From: gjd Date: Fri, 6 Jun 2025 17:09:14 +0800 Subject: [PATCH 1/9] =?UTF-8?q?feat(ai):=20=E6=B7=BB=E5=8A=A0=20AI=20?= =?UTF-8?q?=E5=AF=B9=E8=AF=9D=E8=81=8A=E5=A4=A9=E5=92=8C=20API=20=E5=AF=86?= =?UTF-8?q?=E9=92=A5=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 AI 对话聊天管理页面,包括对话列表和消息列表 - 新增 API 密钥管理页面,包括密钥列表和表单 - 添加相关 API 接口和数据模型 - 集成表单和表格组件,实现基本的 CRUD 操作 --- .../src/api/ai/chat/conversation/index.ts | 75 +++++ .../web-antd/src/api/ai/chat/message/index.ts | 96 ++++++ .../src/api/ai/knowledge/knowledge/index.ts | 50 ++++ .../web-antd/src/api/ai/model/apiKey/index.ts | 50 ++++ .../src/api/ai/model/chatRole/index.ts | 85 ++++++ apps/web-antd/src/api/ai/model/model/index.ts | 55 ++++ apps/web-antd/src/api/ai/model/tool/index.ts | 43 +++ apps/web-antd/src/utils/constants.ts | 8 + apps/web-antd/src/utils/dict.ts | 2 +- .../src/views/ai/chat/manager/data.ts | 196 +++++++++++++ .../src/views/ai/chat/manager/index.vue | 39 ++- .../manager/modules/ChatConversationList.vue | 113 +++++++ .../chat/manager/modules/ChatMessageList.vue | 110 +++++++ .../src/views/ai/model/apiKey/data.ts | 126 ++++++++ .../src/views/ai/model/apiKey/index.vue | 140 +++++++-- .../views/ai/model/apiKey/modules/form.vue | 82 ++++++ .../src/views/ai/model/chatRole/data.ts | 277 ++++++++++++++++++ .../src/views/ai/model/chatRole/index.vue | 151 ++++++++-- .../views/ai/model/chatRole/modules/form.vue | 88 ++++++ .../web-antd/src/views/ai/model/model/data.ts | 248 ++++++++++++++++ .../src/views/ai/model/model/index.vue | 154 ++++++++-- .../src/views/ai/model/model/modules/form.vue | 83 ++++++ apps/web-antd/src/views/ai/model/tool/data.ts | 111 +++++++ .../src/views/ai/model/tool/index.vue | 140 +++++++-- .../src/views/ai/model/tool/modules/form.vue | 82 ++++++ packages/effects/request/package.json | 1 + packages/effects/request/src/index.ts | 1 + pnpm-lock.yaml | 8 + 28 files changed, 2509 insertions(+), 105 deletions(-) create mode 100644 apps/web-antd/src/api/ai/chat/conversation/index.ts create mode 100644 apps/web-antd/src/api/ai/chat/message/index.ts create mode 100644 apps/web-antd/src/api/ai/knowledge/knowledge/index.ts create mode 100644 apps/web-antd/src/api/ai/model/apiKey/index.ts create mode 100644 apps/web-antd/src/api/ai/model/chatRole/index.ts create mode 100644 apps/web-antd/src/api/ai/model/model/index.ts create mode 100644 apps/web-antd/src/api/ai/model/tool/index.ts create mode 100644 apps/web-antd/src/views/ai/chat/manager/data.ts create mode 100644 apps/web-antd/src/views/ai/chat/manager/modules/ChatConversationList.vue create mode 100644 apps/web-antd/src/views/ai/chat/manager/modules/ChatMessageList.vue create mode 100644 apps/web-antd/src/views/ai/model/apiKey/data.ts create mode 100644 apps/web-antd/src/views/ai/model/apiKey/modules/form.vue create mode 100644 apps/web-antd/src/views/ai/model/chatRole/data.ts create mode 100644 apps/web-antd/src/views/ai/model/chatRole/modules/form.vue create mode 100644 apps/web-antd/src/views/ai/model/model/data.ts create mode 100644 apps/web-antd/src/views/ai/model/model/modules/form.vue create mode 100644 apps/web-antd/src/views/ai/model/tool/data.ts create mode 100644 apps/web-antd/src/views/ai/model/tool/modules/form.vue diff --git a/apps/web-antd/src/api/ai/chat/conversation/index.ts b/apps/web-antd/src/api/ai/chat/conversation/index.ts new file mode 100644 index 000000000..c15f80893 --- /dev/null +++ b/apps/web-antd/src/api/ai/chat/conversation/index.ts @@ -0,0 +1,75 @@ +import type { PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace AiChatConversationApi { + export interface ChatConversationVO { + id: number; // ID 编号 + userId: number; // 用户编号 + title: string; // 对话标题 + pinned: boolean; // 是否置顶 + roleId: number; // 角色编号 + modelId: number; // 模型编号 + model: string; // 模型标志 + temperature: number; // 温度参数 + maxTokens: number; // 单条回复的最大 Token 数量 + maxContexts: number; // 上下文的最大 Message 数量 + createTime?: Date; // 创建时间 + // 额外字段 + systemMessage?: string; // 角色设定 + modelName?: string; // 模型名字 + roleAvatar?: string; // 角色头像 + modelMaxTokens?: string; // 模型的单条回复的最大 Token 数量 + modelMaxContexts?: string; // 模型的上下文的最大 Message 数量 + } +} + +// 获得【我的】聊天对话 +export function getChatConversationMy(id: number) { + return requestClient.get< + PageResult + >(`/ai/chat/conversation/get-my?id=${id}`); +} + +// 新增【我的】聊天对话 +export function createChatConversationMy( + data: AiChatConversationApi.ChatConversationVO, +) { + return requestClient.post('/ai/chat/conversation/create-my', data); +} + +// 更新【我的】聊天对话 +export function updateChatConversationMy( + data: AiChatConversationApi.ChatConversationVO, +) { + return requestClient.put(`/ai/chat/conversation/update-my`, data); +} + +// 删除【我的】聊天对话 +export function deleteChatConversationMy(id: string) { + return requestClient.delete(`/ai/chat/conversation/delete-my?id=${id}`); +} + +// 删除【我的】所有对话,置顶除外 +export function deleteChatConversationMyByUnpinned() { + return requestClient.delete(`/ai/chat/conversation/delete-by-unpinned`); +} + +// 获得【我的】聊天对话列表 +export function getChatConversationMyList() { + return requestClient.get( + `/ai/chat/conversation/my-list`, + ); +} + +// 获得【我的】聊天对话列表 +export function getChatConversationPage(params: any) { + return requestClient.get< + PageResult + >(`/ai/chat/conversation/page`, { params }); +} + +// 管理员删除消息 +export function deleteChatConversationByAdmin(id: number) { + return requestClient.delete(`/ai/chat/conversation/delete-by-admin?id=${id}`); +} diff --git a/apps/web-antd/src/api/ai/chat/message/index.ts b/apps/web-antd/src/api/ai/chat/message/index.ts new file mode 100644 index 000000000..2232c7f1d --- /dev/null +++ b/apps/web-antd/src/api/ai/chat/message/index.ts @@ -0,0 +1,96 @@ +import type { PageResult } from '@vben/request'; + +import { fetchEventSource } from '@vben/request'; +import { useAccessStore } from '@vben/stores'; + +import { requestClient } from '#/api/request'; + +const accessStore = useAccessStore(); +export namespace AiChatMessageApi { + export interface ChatMessageVO { + id: number; // 编号 + conversationId: number; // 对话编号 + type: string; // 消息类型 + userId: string; // 用户编号 + roleId: string; // 角色编号 + model: number; // 模型标志 + modelId: number; // 模型编号 + content: string; // 聊天内容 + tokens: number; // 消耗 Token 数量 + segmentIds?: number[]; // 段落编号 + segments?: { + content: string; // 段落内容 + documentId: number; // 文档编号 + documentName: string; // 文档名称 + id: number; // 段落编号 + }[]; + createTime: Date; // 创建时间 + roleAvatar: string; // 角色头像 + userAvatar: string; // 用户头像 + } +} + +// 消息列表 +export function getChatMessageListByConversationId( + conversationId: null | number, +) { + return requestClient.get( + `/ai/chat/message/list-by-conversation-id?conversationId=${conversationId}`, + ); +} + +// 发送 Stream 消息 +export function sendChatMessageStream( + conversationId: number, + content: string, + ctrl: any, + enableContext: boolean, + onMessage: any, + onError: any, + onClose: any, +) { + const token = accessStore.accessToken; + return fetchEventSource( + `${import.meta.env.VITE_BASE_URL}/ai/chat/message/send-stream`, + { + method: 'post', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + openWhenHidden: true, + body: JSON.stringify({ + conversationId, + content, + useContext: enableContext, + }), + onmessage: onMessage, + onerror: onError, + onclose: onClose, + signal: ctrl.signal, + }, + ); +} + +// 删除消息 +export function deleteChatMessage(id: string) { + return requestClient.delete(`/ai/chat/message/delete?id=${id}`); +} + +// 删除指定对话的消息 +export function deleteByConversationId(conversationId: number) { + return requestClient.delete( + `/ai/chat/message/delete-by-conversation-id?conversationId=${conversationId}`, + ); +} +// 获得消息分页 +export function getChatMessagePage(params: any) { + return requestClient.get>( + '/ai/chat/message/page', + { params }, + ); +} +// 管理员删除消息 +export function deleteChatMessageByAdmin(id: number) { + return requestClient.delete(`/ai/chat/message/delete-by-admin?id=${id}`); +} diff --git a/apps/web-antd/src/api/ai/knowledge/knowledge/index.ts b/apps/web-antd/src/api/ai/knowledge/knowledge/index.ts new file mode 100644 index 000000000..0ff7281fb --- /dev/null +++ b/apps/web-antd/src/api/ai/knowledge/knowledge/index.ts @@ -0,0 +1,50 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace AiKnowledgeKnowledgeApi { + export interface KnowledgeVO { + id: number; // 编号 + name: string; // 知识库名称 + description: string; // 知识库描述 + embeddingModelId: number; // 嵌入模型编号,高质量模式时维护 + topK: number; // topK + similarityThreshold: number; // 相似度阈值 + } +} + +// 查询知识库分页 +export function getKnowledgePage(params: PageParam) { + return requestClient.get>( + '/ai/knowledge/page', + { params }, + ); +} + +// 查询知识库详情 +export function getKnowledge(id: number) { + return requestClient.get( + `/ai/knowledge/get?id=${id}`, + ); +} +// 新增知识库 +export function createKnowledge(data: AiKnowledgeKnowledgeApi.KnowledgeVO) { + return requestClient.post('/ai/knowledge/create', data); +} + +// 修改知识库 +export function updateKnowledge(data: AiKnowledgeKnowledgeApi.KnowledgeVO) { + return requestClient.put('/ai/knowledge/update', data); +} + +// 删除知识库 +export function deleteKnowledge(id: number) { + return requestClient.delete(`/ai/knowledge/delete?id=${id}`); +} + +// 获取知识库简单列表 +export function getSimpleKnowledgeList() { + return requestClient.get( + '/ai/knowledge/simple-list', + ); +} diff --git a/apps/web-antd/src/api/ai/model/apiKey/index.ts b/apps/web-antd/src/api/ai/model/apiKey/index.ts new file mode 100644 index 000000000..6ae5a1fac --- /dev/null +++ b/apps/web-antd/src/api/ai/model/apiKey/index.ts @@ -0,0 +1,50 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace AiModelApiKeyApi { + export interface ApiKeyVO { + id: number; // 编号 + name: string; // 名称 + apiKey: string; // 密钥 + platform: string; // 平台 + url: string; // 自定义 API 地址 + status: number; // 状态 + } +} + +// 查询 API 密钥分页 +export function getApiKeyPage(params: PageParam) { + return requestClient.get>( + '/ai/api-key/page', + { params }, + ); +} + +// 获得 API 密钥列表 +export function getApiKeySimpleList() { + return requestClient.get( + '/ai/api-key/simple-list', + ); +} + +// 查询 API 密钥详情 +export function getApiKey(id: number) { + return requestClient.get( + `/ai/api-key/get?id=${id}`, + ); +} +// 新增 API 密钥 +export function createApiKey(data: AiModelApiKeyApi.ApiKeyVO) { + return requestClient.post('/ai/api-key/create', data); +} + +// 修改 API 密钥 +export function updateApiKey(data: AiModelApiKeyApi.ApiKeyVO) { + return requestClient.put('/ai/api-key/update', data); +} + +// 删除 API 密钥 +export function deleteApiKey(id: number) { + return requestClient.delete(`/ai/api-key/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/ai/model/chatRole/index.ts b/apps/web-antd/src/api/ai/model/chatRole/index.ts new file mode 100644 index 000000000..1c6306c33 --- /dev/null +++ b/apps/web-antd/src/api/ai/model/chatRole/index.ts @@ -0,0 +1,85 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace AiModelChatRoleApi { + export interface ChatRoleVO { + id: number; // 角色编号 + modelId: number; // 模型编号 + name: string; // 角色名称 + avatar: string; // 角色头像 + category: string; // 角色类别 + sort: number; // 角色排序 + description: string; // 角色描述 + systemMessage: string; // 角色设定 + welcomeMessage: string; // 角色设定 + publicStatus: boolean; // 是否公开 + status: number; // 状态 + knowledgeIds?: number[]; // 引用的知识库 ID 列表 + toolIds?: number[]; // 引用的工具 ID 列表 + } + + // AI 聊天角色 分页请求 vo + export interface ChatRolePageReqVO { + name?: string; // 角色名称 + category?: string; // 角色类别 + publicStatus: boolean; // 是否公开 + pageNo: number; // 是否公开 + pageSize: number; // 是否公开 + } +} + +// 查询聊天角色分页 +export function getChatRolePage(params: PageParam) { + return requestClient.get>( + '/ai/chat-role/page', + { params }, + ); +} + +// 查询聊天角色详情 +export function getChatRole(id: number) { + return requestClient.get( + `/ai/chat-role/get?id=${id}`, + ); +} +// 新增聊天角色 +export function createChatRole(data: AiModelChatRoleApi.ChatRoleVO) { + return requestClient.post('/ai/chat-role/create', data); +} + +// 修改聊天角色 +export function updateChatRole(data: AiModelChatRoleApi.ChatRoleVO) { + return requestClient.put('/ai/chat-role/update', data); +} + +// 删除聊天角色 +export function deleteChatRole(id: number) { + return requestClient.delete(`/ai/chat-role/delete?id=${id}`); +} + +// ======= chat 聊天 +// 获取 my role +export function getMyPage(params: AiModelChatRoleApi.ChatRolePageReqVO) { + return requestClient.get('/ai/chat-role/my-page', { params }); +} + +// 获取角色分类 +export function getCategoryList() { + return requestClient.get('/ai/chat-role/category-list'); +} + +// 创建角色 +export function createMy(data: AiModelChatRoleApi.ChatRoleVO) { + return requestClient.post('/ai/chat-role/create-my', data); +} + +// 更新角色 +export function updateMy(data: AiModelChatRoleApi.ChatRoleVO) { + return requestClient.put('/ai/chat-role/update', data); +} + +// 删除角色 my +export function deleteMy(id: number) { + return requestClient.delete(`/ai/chat-role/delete-my?id=${id}`); +} diff --git a/apps/web-antd/src/api/ai/model/model/index.ts b/apps/web-antd/src/api/ai/model/model/index.ts new file mode 100644 index 000000000..eefa0878f --- /dev/null +++ b/apps/web-antd/src/api/ai/model/model/index.ts @@ -0,0 +1,55 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace AiModelModelApi { + export interface ModelVO { + id: number; // 编号 + keyId: number; // API 秘钥编号 + name: string; // 模型名字 + model: string; // 模型标识 + platform: string; // 模型平台 + type: number; // 模型类型 + sort: number; // 排序 + status: number; // 状态 + temperature?: number; // 温度参数 + maxTokens?: number; // 单条回复的最大 Token 数量 + maxContexts?: number; // 上下文的最大 Message 数量 + } +} + +// 查询模型分页 +export function getModelPage(params: PageParam) { + return requestClient.get>( + '/ai/model/page', + { params }, + ); +} + +// 获得模型列表 +export function getModelSimpleList(type?: number) { + return requestClient.get('/ai/model/simple-list', { + params: { + type, + }, + }); +} + +// 查询模型详情 +export function getModel(id: number) { + return requestClient.get(`/ai/model/get?id=${id}`); +} +// 新增模型 +export function createModel(data: AiModelModelApi.ModelVO) { + return requestClient.post('/ai/model/create', data); +} + +// 修改模型 +export function updateModel(data: AiModelModelApi.ModelVO) { + return requestClient.put('/ai/model/update', data); +} + +// 删除模型 +export function deleteModel(id: number) { + return requestClient.delete(`/ai/model/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/ai/model/tool/index.ts b/apps/web-antd/src/api/ai/model/tool/index.ts new file mode 100644 index 000000000..a6a878f92 --- /dev/null +++ b/apps/web-antd/src/api/ai/model/tool/index.ts @@ -0,0 +1,43 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace AiModelToolApi { + export interface ToolVO { + id: number; // 工具编号 + name: string; // 工具名称 + description: string; // 工具描述 + status: number; // 状态 + } +} + +// 查询工具分页 +export function getToolPage(params: PageParam) { + return requestClient.get>('/ai/tool/page', { + params, + }); +} + +// 查询工具详情 +export function getTool(id: number) { + return requestClient.get(`/ai/tool/get?id=${id}`); +} +// 新增工具 +export function createTool(data: AiModelToolApi.ToolVO) { + return requestClient.post('/ai/tool/create', data); +} + +// 修改工具 +export function updateTool(data: AiModelToolApi.ToolVO) { + return requestClient.put('/ai/tool/update', data); +} + +// 删除工具 +export function deleteTool(id: number) { + return requestClient.delete(`/ai/tool/delete?id=${id}`); +} + +// 获取工具简单列表 +export function getToolSimpleList() { + return requestClient.get('/ai/tool/simple-list'); +} diff --git a/apps/web-antd/src/utils/constants.ts b/apps/web-antd/src/utils/constants.ts index ed4f97a8e..611d992d9 100644 --- a/apps/web-antd/src/utils/constants.ts +++ b/apps/web-antd/src/utils/constants.ts @@ -5,6 +5,14 @@ * 枚举类 */ +export const AiModelTypeEnum = { + CHAT: 1, // 聊天 + IMAGE: 2, // 图像 + VOICE: 3, // 音频 + VIDEO: 4, // 视频 + EMBEDDING: 5, // 向量 + RERANK: 6, // 重排 +}; // ========== COMMON 模块 ========== // 全局通用状态枚举 export const CommonStatusEnum = { diff --git a/apps/web-antd/src/utils/dict.ts b/apps/web-antd/src/utils/dict.ts index 3393f9fa7..1571f04da 100644 --- a/apps/web-antd/src/utils/dict.ts +++ b/apps/web-antd/src/utils/dict.ts @@ -143,10 +143,10 @@ export const getBoolDictOptions = (dictType: string) => { enum DICT_TYPE { AI_GENERATE_MODE = 'ai_generate_mode', // AI 生成模式 AI_IMAGE_STATUS = 'ai_image_status', // AI 图片状态 + AI_MODEL_TYPE = 'ai_model_type', // AI 模型类型 AI_MUSIC_STATUS = 'ai_music_status', // AI 音乐状态 // ========== AI - 人工智能模块 ========== AI_PLATFORM = 'ai_platform', // AI 平台 - AI_WRITE_FORMAT = 'ai_write_format', // AI 写作格式 AI_WRITE_LANGUAGE = 'ai_write_language', // AI 写作语言 AI_WRITE_LENGTH = 'ai_write_length', // AI 写作长度 diff --git a/apps/web-antd/src/views/ai/chat/manager/data.ts b/apps/web-antd/src/views/ai/chat/manager/data.ts new file mode 100644 index 000000000..5e1f844e8 --- /dev/null +++ b/apps/web-antd/src/views/ai/chat/manager/data.ts @@ -0,0 +1,196 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { getSimpleUserList } from '#/api/system/user'; +import { DICT_TYPE } from '#/utils'; + +/** 列表的搜索表单 */ +export function useGridFormSchemaConversation(): VbenFormSchema[] { + return [ + { + fieldName: 'userId', + label: '用户编号', + component: 'Input', + }, + { + fieldName: 'title', + label: '聊天标题', + component: 'Input', + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + placeholder: ['开始时间', '结束时间'], + valueFormat: 'YYYY-MM-DD HH:mm:ss', + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumnsConversation(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '对话编号', + fixed: 'left', + minWidth: 180, + }, + { + field: 'title', + title: '对话标题', + minWidth: 180, + fixed: 'left', + }, + { + title: '用户', + width: 180, + slots: { default: 'userId' }, + }, + { + field: 'roleName', + title: '角色', + minWidth: 180, + }, + { + field: 'model', + title: '模型标识', + minWidth: 180, + }, + { + field: 'messageCount', + title: '消息数', + minWidth: 180, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'temperature', + title: '温度参数', + minWidth: 80, + }, + { + title: '回复数 Token 数', + field: 'maxTokens', + minWidth: 120, + }, + { + title: '上下文数量', + field: 'maxContexts', + minWidth: 120, + }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchemaMessage(): VbenFormSchema[] { + return [ + { + fieldName: 'conversationId', + label: '对话编号', + component: 'Input', + }, + { + fieldName: 'userId', + label: '用户编号', + component: 'ApiSelect', + componentProps: { + api: getSimpleUserList, + labelField: 'nickname', + valueField: 'id', + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + placeholder: ['开始时间', '结束时间'], + valueFormat: 'YYYY-MM-DD HH:mm:ss', + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumnsMessage(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '消息编号', + fixed: 'left', + minWidth: 180, + }, + { + field: 'conversationId', + title: '对话编号', + minWidth: 180, + fixed: 'left', + }, + { + title: '用户', + width: 180, + slots: { default: 'userId' }, + }, + { + field: 'roleName', + title: '角色', + minWidth: 180, + }, + { + field: 'type', + title: '消息类型', + minWidth: 100, + }, + { + field: 'model', + title: '模型标识', + minWidth: 180, + }, + { + field: 'content', + title: '消息内容', + minWidth: 300, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'replyId', + title: '回复消息编号', + minWidth: 180, + }, + { + title: '携带上下文', + field: 'useContext', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + minWidth: 100, + }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/ai/chat/manager/index.vue b/apps/web-antd/src/views/ai/chat/manager/index.vue index 9bc7fbd0c..b892dd23a 100644 --- a/apps/web-antd/src/views/ai/chat/manager/index.vue +++ b/apps/web-antd/src/views/ai/chat/manager/index.vue @@ -1,31 +1,30 @@ diff --git a/apps/web-antd/src/views/ai/chat/manager/modules/ChatConversationList.vue b/apps/web-antd/src/views/ai/chat/manager/modules/ChatConversationList.vue new file mode 100644 index 000000000..7b23f7912 --- /dev/null +++ b/apps/web-antd/src/views/ai/chat/manager/modules/ChatConversationList.vue @@ -0,0 +1,113 @@ + + + diff --git a/apps/web-antd/src/views/ai/chat/manager/modules/ChatMessageList.vue b/apps/web-antd/src/views/ai/chat/manager/modules/ChatMessageList.vue new file mode 100644 index 000000000..0752b6bca --- /dev/null +++ b/apps/web-antd/src/views/ai/chat/manager/modules/ChatMessageList.vue @@ -0,0 +1,110 @@ + + + diff --git a/apps/web-antd/src/views/ai/model/apiKey/data.ts b/apps/web-antd/src/views/ai/model/apiKey/data.ts new file mode 100644 index 000000000..03b5ccc92 --- /dev/null +++ b/apps/web-antd/src/views/ai/model/apiKey/data.ts @@ -0,0 +1,126 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { z } from '#/adapter/form'; +import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils'; +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'platform', + label: '所属平台', + component: 'Select', + componentProps: { + placeholder: '请选择所属平台', + options: getDictOptions(DICT_TYPE.AI_PLATFORM, 'string'), + allowClear: true, + }, + rules: z.string().min(1, { message: '请输入平台' }), + }, + { + component: 'Input', + fieldName: 'name', + label: '名称', + rules: 'required', + }, + { + component: 'Input', + fieldName: 'apiKey', + label: '密钥', + rules: 'required', + }, + { + component: 'Input', + fieldName: 'url', + label: '自定义 API URL', + }, + { + fieldName: 'status', + label: '状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '名称', + component: 'Input', + }, + { + fieldName: 'platform', + label: '平台', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.AI_PLATFORM, 'string'), + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'platform', + title: '所属平台', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.AI_PLATFORM }, + }, + }, + { + field: 'name', + title: '名称', + }, + { + field: 'apiKey', + title: '密钥', + }, + { + field: 'url', + title: '自定义 API URL', + }, + { + field: 'status', + title: '状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/ai/model/apiKey/index.vue b/apps/web-antd/src/views/ai/model/apiKey/index.vue index 2d916433a..ce3749e63 100644 --- a/apps/web-antd/src/views/ai/model/apiKey/index.vue +++ b/apps/web-antd/src/views/ai/model/apiKey/index.vue @@ -1,31 +1,129 @@ diff --git a/apps/web-antd/src/views/ai/model/apiKey/modules/form.vue b/apps/web-antd/src/views/ai/model/apiKey/modules/form.vue new file mode 100644 index 000000000..68376f41f --- /dev/null +++ b/apps/web-antd/src/views/ai/model/apiKey/modules/form.vue @@ -0,0 +1,82 @@ + + + diff --git a/apps/web-antd/src/views/ai/model/chatRole/data.ts b/apps/web-antd/src/views/ai/model/chatRole/data.ts new file mode 100644 index 000000000..a20434ba6 --- /dev/null +++ b/apps/web-antd/src/views/ai/model/chatRole/data.ts @@ -0,0 +1,277 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { z } from '#/adapter/form'; +import { getSimpleKnowledgeList } from '#/api/ai/knowledge/knowledge'; +import { getModelSimpleList } from '#/api/ai/model/model'; +import { getToolSimpleList } from '#/api/ai/model/tool'; +import { + AiModelTypeEnum, + CommonStatusEnum, + DICT_TYPE, + getDictOptions, +} from '#/utils'; +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + component: 'Input', + fieldName: 'formType', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + component: 'Input', + fieldName: 'name', + label: '角色名称', + rules: 'required', + }, + { + component: 'ImageUpload', + fieldName: 'avatar', + label: '角色头像', + componentProps: { + maxSize: 1, + }, + rules: 'required', + }, + { + fieldName: 'modelId', + label: '绑定模型', + component: 'ApiSelect', + componentProps: { + placeholder: '请选择绑定模型', + api: () => getModelSimpleList(AiModelTypeEnum.CHAT), + labelField: 'name', + valueField: 'id', + allowClear: true, + }, + dependencies: { + triggerFields: ['formType'], + show: (values) => { + return values.formType === 'create' || values.formType === 'update'; + }, + }, + }, + { + component: 'Input', + fieldName: 'category', + label: '角色类别', + rules: 'required', + dependencies: { + triggerFields: ['formType'], + show: (values) => { + return values.formType === 'create' || values.formType === 'update'; + }, + }, + }, + { + component: 'Textarea', + fieldName: 'description', + label: '角色描述', + componentProps: { + placeholder: '请输入角色描述', + }, + rules: 'required', + }, + { + fieldName: 'systemMessage', + label: '角色设定', + component: 'Textarea', + componentProps: { + placeholder: '请输入角色设定', + }, + rules: 'required', + }, + { + fieldName: 'knowledgeIds', + label: '引用知识库', + component: 'ApiSelect', + componentProps: { + placeholder: '请选择引用知识库', + api: getSimpleKnowledgeList, + labelField: 'name', + mode: 'multiple', + valueField: 'id', + allowClear: true, + }, + }, + { + fieldName: 'toolIds', + label: '引用工具', + component: 'ApiSelect', + componentProps: { + placeholder: '请选择引用工具', + api: getToolSimpleList, + mode: 'multiple', + labelField: 'name', + valueField: 'id', + allowClear: true, + }, + }, + { + fieldName: 'publicStatus', + label: '是否公开', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), + buttonStyle: 'solid', + optionType: 'button', + }, + defaultValue: true, + dependencies: { + triggerFields: ['formType'], + show: (values) => { + return values.formType === 'create' || values.formType === 'update'; + }, + }, + rules: 'required', + }, + { + fieldName: 'sort', + label: '角色排序', + component: 'InputNumber', + componentProps: { + controlsPosition: 'right', + placeholder: '请输入角色排序', + class: 'w-full', + }, + dependencies: { + triggerFields: ['formType'], + show: (values) => { + return values.formType === 'create' || values.formType === 'update'; + }, + }, + rules: 'required', + }, + { + fieldName: 'status', + label: '开启状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + dependencies: { + triggerFields: ['formType'], + show: (values) => { + return values.formType === 'create' || values.formType === 'update'; + }, + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '角色名称', + component: 'Input', + }, + { + fieldName: 'category', + label: '角色类别', + component: 'Input', + }, + { + fieldName: 'publicStatus', + label: '是否公开', + component: 'Select', + componentProps: { + placeholder: '请选择是否公开', + options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), + allowClear: true, + }, + defaultValue: true, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'name', + title: '角色名称', + minWidth: 100, + }, + { + title: '绑定模型', + field: 'modelName', + minWidth: 100, + }, + { + title: '角色头像', + slots: { default: 'avatar' }, + minWidth: 140, + }, + { + title: '角色类别', + field: 'category', + minWidth: 100, + }, + { + title: '角色描述', + field: 'description', + minWidth: 100, + }, + { + title: '角色设定', + field: 'systemMessage', + minWidth: 100, + }, + { + title: '知识库', + slots: { default: 'knowledgeIds' }, + minWidth: 100, + }, + { + title: '工具', + slots: { default: 'toolIds' }, + minWidth: 100, + }, + { + field: 'publicStatus', + title: '是否公开', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + minWidth: 80, + }, + { + field: 'status', + title: '状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + minWidth: 80, + }, + { + title: '角色排序', + field: 'sort', + minWidth: 80, + }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/ai/model/chatRole/index.vue b/apps/web-antd/src/views/ai/model/chatRole/index.vue index 45f09d3ea..0e9ad1557 100644 --- a/apps/web-antd/src/views/ai/model/chatRole/index.vue +++ b/apps/web-antd/src/views/ai/model/chatRole/index.vue @@ -1,31 +1,140 @@ diff --git a/apps/web-antd/src/views/ai/model/chatRole/modules/form.vue b/apps/web-antd/src/views/ai/model/chatRole/modules/form.vue new file mode 100644 index 000000000..56773a16a --- /dev/null +++ b/apps/web-antd/src/views/ai/model/chatRole/modules/form.vue @@ -0,0 +1,88 @@ + + + diff --git a/apps/web-antd/src/views/ai/model/model/data.ts b/apps/web-antd/src/views/ai/model/model/data.ts new file mode 100644 index 000000000..54fa41905 --- /dev/null +++ b/apps/web-antd/src/views/ai/model/model/data.ts @@ -0,0 +1,248 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { z } from '#/adapter/form'; +import { getApiKeySimpleList } from '#/api/ai/model/apiKey'; +import { + AiModelTypeEnum, + CommonStatusEnum, + DICT_TYPE, + getDictOptions, +} from '#/utils'; +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'platform', + label: '所属平台', + component: 'Select', + componentProps: { + placeholder: '请选择所属平台', + options: getDictOptions(DICT_TYPE.AI_PLATFORM, 'string'), + allowClear: true, + }, + rules: z.string().min(1, { message: '请输入平台' }), + }, + { + fieldName: 'type', + label: '模型类型', + component: 'Select', + componentProps: (values) => { + return { + placeholder: '请输入模型类型', + disabled: !!values.id, + options: getDictOptions(DICT_TYPE.AI_MODEL_TYPE, 'number'), + allowClear: true, + }; + }, + rules: 'required', + }, + { + fieldName: 'keyId', + label: 'API 秘钥', + component: 'ApiSelect', + componentProps: { + placeholder: '请选择API 秘钥', + api: getApiKeySimpleList, + labelField: 'name', + valueField: 'id', + allowClear: true, + }, + rules: 'required', + }, + { + component: 'Input', + fieldName: 'name', + label: '模型名字', + rules: 'required', + }, + { + component: 'Input', + fieldName: 'model', + label: '模型标识', + rules: 'required', + }, + { + fieldName: 'sort', + label: '模型排序', + component: 'InputNumber', + componentProps: { + controlsPosition: 'right', + placeholder: '请输入模型排序', + class: 'w-full', + }, + rules: 'required', + }, + { + fieldName: 'status', + label: '开启状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + { + fieldName: 'temperature', + label: '温度参数', + component: 'InputNumber', + componentProps: { + controlsPosition: 'right', + placeholder: '请输入温度参数', + class: 'w-full', + min: 0, + max: 2, + }, + dependencies: { + triggerFields: ['type'], + show: (values) => { + return [AiModelTypeEnum.CHAT].includes(values.type); + }, + }, + rules: 'required', + }, + { + fieldName: 'maxTokens', + label: '回复数 Token 数', + component: 'InputNumber', + componentProps: { + min: 0, + max: 8192, + controlsPosition: 'right', + placeholder: '请输入回复数 Token 数', + class: 'w-full', + }, + dependencies: { + triggerFields: ['type'], + show: (values) => { + return [AiModelTypeEnum.CHAT].includes(values.type); + }, + }, + rules: 'required', + }, + { + fieldName: 'maxContexts', + label: '上下文数量', + component: 'InputNumber', + componentProps: { + min: 0, + max: 20, + controlsPosition: 'right', + placeholder: '请输入上下文数量', + class: 'w-full', + }, + dependencies: { + triggerFields: ['type'], + show: (values) => { + return [AiModelTypeEnum.CHAT].includes(values.type); + }, + }, + rules: 'required', + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '模型名字', + component: 'Input', + }, + { + fieldName: 'model', + label: '模型标识', + component: 'Input', + }, + { + fieldName: 'platform', + label: '模型平台', + component: 'Input', + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'platform', + title: '所属平台', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.AI_PLATFORM }, + }, + minWidth: 100, + }, + { + field: 'type', + title: '模型类型', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.AI_MODEL_TYPE }, + }, + minWidth: 100, + }, + { + field: 'name', + title: '模型名字', + minWidth: 180, + }, + { + title: '模型标识', + field: 'model', + minWidth: 180, + }, + { + title: 'API 秘钥', + slots: { default: 'keyId' }, + minWidth: 140, + }, + { + title: '排序', + field: 'sort', + minWidth: 80, + }, + { + field: 'status', + title: '状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + minWidth: 80, + }, + { + field: 'temperature', + title: '温度参数', + minWidth: 80, + }, + { + title: '回复数 Token 数', + field: 'maxTokens', + minWidth: 140, + }, + { + title: '上下文数量', + field: 'maxContexts', + minWidth: 100, + }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/ai/model/model/index.vue b/apps/web-antd/src/views/ai/model/model/index.vue index 827703350..80fd45f49 100644 --- a/apps/web-antd/src/views/ai/model/model/index.vue +++ b/apps/web-antd/src/views/ai/model/model/index.vue @@ -1,31 +1,143 @@ diff --git a/apps/web-antd/src/views/ai/model/model/modules/form.vue b/apps/web-antd/src/views/ai/model/model/modules/form.vue new file mode 100644 index 000000000..c88857648 --- /dev/null +++ b/apps/web-antd/src/views/ai/model/model/modules/form.vue @@ -0,0 +1,83 @@ + + + diff --git a/apps/web-antd/src/views/ai/model/tool/data.ts b/apps/web-antd/src/views/ai/model/tool/data.ts new file mode 100644 index 000000000..df1eba38c --- /dev/null +++ b/apps/web-antd/src/views/ai/model/tool/data.ts @@ -0,0 +1,111 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils'; +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + + { + component: 'Input', + fieldName: 'name', + label: '工具名称', + rules: 'required', + }, + { + component: 'Textarea', + fieldName: 'description', + label: '工具描述', + componentProps: { + placeholder: '请输入工具描述', + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + defaultValue: CommonStatusEnum.ENABLE, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '工具名称', + component: 'Input', + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + placeholder: ['开始时间', '结束时间'], + valueFormat: 'YYYY-MM-DD HH:mm:ss', + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '工具编号', + }, + { + field: 'name', + title: '工具名称', + }, + { + field: 'description', + title: '工具描述', + }, + { + field: 'status', + title: '状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/ai/model/tool/index.vue b/apps/web-antd/src/views/ai/model/tool/index.vue index daf18f8cc..54fc5a08a 100644 --- a/apps/web-antd/src/views/ai/model/tool/index.vue +++ b/apps/web-antd/src/views/ai/model/tool/index.vue @@ -1,34 +1,132 @@ diff --git a/apps/web-antd/src/views/ai/model/tool/modules/form.vue b/apps/web-antd/src/views/ai/model/tool/modules/form.vue new file mode 100644 index 000000000..de16dc275 --- /dev/null +++ b/apps/web-antd/src/views/ai/model/tool/modules/form.vue @@ -0,0 +1,82 @@ + + + diff --git a/packages/effects/request/package.json b/packages/effects/request/package.json index 527f6d904..08e672b39 100644 --- a/packages/effects/request/package.json +++ b/packages/effects/request/package.json @@ -20,6 +20,7 @@ } }, "dependencies": { + "@microsoft/fetch-event-source": "^2.0.1", "@vben/locales": "workspace:*", "@vben/utils": "workspace:*", "axios": "catalog:", diff --git a/packages/effects/request/src/index.ts b/packages/effects/request/src/index.ts index fae1b058d..d4a3ed157 100644 --- a/packages/effects/request/src/index.ts +++ b/packages/effects/request/src/index.ts @@ -1,2 +1,3 @@ export * from './request-client'; +export * from '@microsoft/fetch-event-source'; export * from 'axios'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dabf51bdb..493986cbe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1824,6 +1824,9 @@ importers: packages/effects/request: dependencies: + '@microsoft/fetch-event-source': + specifier: ^2.0.1 + version: 2.0.1 '@vben/locales': specifier: workspace:* version: link:../../locales @@ -3915,6 +3918,9 @@ packages: resolution: {integrity: sha512-cszYIcjiNscDoMB1CIKZ3My61+JOhpERGlGr54i6bocvGLrcL/wo9o+RNXMBrb7XgLtKaizZWUpqRduQuHQLdg==} hasBin: true + '@microsoft/fetch-event-source@2.0.1': + resolution: {integrity: sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA==} + '@microsoft/tsdoc-config@0.17.1': resolution: {integrity: sha512-UtjIFe0C6oYgTnad4q1QP4qXwLhe6tIpNTRStJ2RZEPIkqQPREAwE5spzVxsdn9UaEMUqhh0AqSx3X4nWAKXWw==} @@ -13780,6 +13786,8 @@ snapshots: transitivePeerDependencies: - '@types/node' + '@microsoft/fetch-event-source@2.0.1': {} + '@microsoft/tsdoc-config@0.17.1': dependencies: '@microsoft/tsdoc': 0.15.1 -- Gitee From 1b236e89bf36b1a8bd391ca8c19eea05c256b67e Mon Sep 17 00:00:00 2001 From: gjd Date: Mon, 9 Jun 2025 16:20:34 +0800 Subject: [PATCH 2/9] =?UTF-8?q?feat(ai):=20=E6=B7=BB=E5=8A=A0=20AI=20?= =?UTF-8?q?=E7=BB=98=E5=9B=BE=E5=92=8C=E6=80=9D=E7=BB=B4=E5=AF=BC=E5=9B=BE?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 AI 绘图管理页面,包括绘画列表、搜索筛选和操作功能 - 实现 AI 思维导图生成功能,支持流式生成和已有内容生成 - 添加 AI 音乐和写作相关的 API 接口 - 更新常量文件,增加 AI 平台、图像生成状态等枚举 - 优化 AI 绘图和思维导图的组件结构,提高可维护性 --- apps/web-antd/src/api/ai/image/index.ts | 112 +++++++++++ apps/web-antd/src/api/ai/mindmap/index.ts | 65 +++++++ apps/web-antd/src/api/ai/music/index.ts | 44 +++++ apps/web-antd/src/api/ai/write/index.ts | 90 +++++++++ apps/web-antd/src/utils/constants.ts | 121 ++++++++++++ .../src/views/ai/image/manager/data.ts | 146 ++++++++++++++ .../src/views/ai/image/manager/index.vue | 146 ++++++++++++-- .../src/views/ai/mindmap/index/index.vue | 99 ++++++++-- .../views/ai/mindmap/index/modules/Left.vue | 77 ++++++++ .../views/ai/mindmap/index/modules/Right.vue | 167 ++++++++++++++++ .../src/views/ai/mindmap/manager/data.ts | 84 ++++++++ .../src/views/ai/mindmap/manager/index.vue | 117 ++++++++++-- .../src/views/ai/music/manager/data.ts | 175 +++++++++++++++++ .../src/views/ai/music/manager/index.vue | 180 ++++++++++++++++-- .../src/views/ai/write/manager/data.ts | 157 +++++++++++++++ .../src/views/ai/write/manager/index.vue | 117 ++++++++++-- 16 files changed, 1794 insertions(+), 103 deletions(-) create mode 100644 apps/web-antd/src/api/ai/image/index.ts create mode 100644 apps/web-antd/src/api/ai/mindmap/index.ts create mode 100644 apps/web-antd/src/api/ai/music/index.ts create mode 100644 apps/web-antd/src/api/ai/write/index.ts create mode 100644 apps/web-antd/src/views/ai/image/manager/data.ts create mode 100644 apps/web-antd/src/views/ai/mindmap/index/modules/Left.vue create mode 100644 apps/web-antd/src/views/ai/mindmap/index/modules/Right.vue create mode 100644 apps/web-antd/src/views/ai/mindmap/manager/data.ts create mode 100644 apps/web-antd/src/views/ai/music/manager/data.ts create mode 100644 apps/web-antd/src/views/ai/write/manager/data.ts diff --git a/apps/web-antd/src/api/ai/image/index.ts b/apps/web-antd/src/api/ai/image/index.ts new file mode 100644 index 000000000..24699ac77 --- /dev/null +++ b/apps/web-antd/src/api/ai/image/index.ts @@ -0,0 +1,112 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace AiImageApi { + export interface ImageMidjourneyButtonsVO { + customId: string; // MJ::JOB::upsample::1::85a4b4c1-8835-46c5-a15c-aea34fad1862 动作标识 + emoji: string; // 图标 emoji + label: string; // Make Variations 文本 + style: number; // 样式: 2(Primary)、3(Green) + } + // AI 绘图 VO + export interface ImageVO { + id: number; // 编号 + platform: string; // 平台 + model: string; // 模型 + prompt: string; // 提示词 + width: number; // 图片宽度 + height: number; // 图片高度 + status: number; // 状态 + publicStatus: boolean; // 公开状态 + picUrl: string; // 任务地址 + errorMessage: string; // 错误信息 + options: any; // 配置 Map + taskId: number; // 任务编号 + buttons: ImageMidjourneyButtonsVO[]; // mj 操作按钮 + createTime: Date; // 创建时间 + finishTime: Date; // 完成时间 + } + + export interface ImageDrawReqVO { + prompt: string; // 提示词 + modelId: number; // 模型 + style: string; // 图像生成的风格 + width: string; // 图片宽度 + height: string; // 图片高度 + options: object; // 绘制参数,Map + } + + export interface ImageMidjourneyImagineReqVO { + prompt: string; // 提示词 + modelId: number; // 模型 + base64Array: string[]; // size不能为空 + width: string; // 图片宽度 + height: string; // 图片高度 + version: string; // 版本 + } + + export interface ImageMidjourneyActionVO { + id: number; // 图片编号 + customId: string; // MJ::JOB::upsample::1::85a4b4c1-8835-46c5-a15c-aea34fad1862 动作标识 + } +} + +// 获取【我的】绘图分页 +export function getImagePageMy(params: PageParam) { + return requestClient.get>( + '/ai/image/my-page', + { params }, + ); +} + +// 获取【我的】绘图记录 +export function getImageMy(id: number) { + return requestClient.get(`/ai/image/get-my?id=${id}`); +} + +// 获取【我的】绘图记录列表 +export function getImageListMyByIds(ids: number[]) { + return requestClient.get(`/ai/image/my-list-by-ids`, { + params: { ids: ids.join(',') }, + }); +} + +// 生成图片 +export function drawImage(data: AiImageApi.ImageDrawReqVO) { + return requestClient.post(`/ai/image/draw`, data); +} + +// 删除【我的】绘画记录 +export function deleteImageMy(id: number) { + return requestClient.delete(`/ai/image/delete-my?id=${id}`); +} + +// ================ midjourney 专属 ================ +// 【Midjourney】生成图片 +export function midjourneyImagine( + data: AiImageApi.ImageMidjourneyImagineReqVO, +) { + return requestClient.post(`/ai/image/midjourney/imagine`, data); +} + +// 【Midjourney】Action 操作(二次生成图片) +export function midjourneyAction(data: AiImageApi.ImageMidjourneyActionVO) { + return requestClient.post(`/ai/image/midjourney/action`, data); +} + +// ================ 绘图管理 ================ +// 查询绘画分页 +export function getImagePage(params: any) { + return requestClient.get(`/ai/image/page`, { params }); +} + +// 更新绘画发布状态 +export function updateImage(data: any) { + return requestClient.put(`/ai/image/update`, data); +} + +// 删除绘画 +export function deleteImage(id: number) { + return requestClient.delete(`/ai/image/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/ai/mindmap/index.ts b/apps/web-antd/src/api/ai/mindmap/index.ts new file mode 100644 index 000000000..496199ed0 --- /dev/null +++ b/apps/web-antd/src/api/ai/mindmap/index.ts @@ -0,0 +1,65 @@ +import { fetchEventSource } from '@vben/request'; +import { useAccessStore } from '@vben/stores'; + +import { requestClient } from '#/api/request'; + +const accessStore = useAccessStore(); +export namespace AiMindmapApi { + // AI 思维导图 VO + export interface MindMapVO { + id: number; // 编号 + userId: number; // 用户编号 + prompt: string; // 生成内容提示 + generatedContent: string; // 生成的思维导图内容 + platform: string; // 平台 + model: string; // 模型 + errorMessage: string; // 错误信息 + } + + // AI 思维导图生成 VO + export interface AiMindMapGenerateReqVO { + prompt: string; + } +} + +export function generateMindMap({ + data, + onClose, + onMessage, + onError, + ctrl, +}: { + ctrl: AbortController; + data: AiMindmapApi.AiMindMapGenerateReqVO; + onClose?: (...args: any[]) => void; + onError?: (...args: any[]) => void; + onMessage?: (res: any) => void; +}) { + const token = accessStore.accessToken; + return fetchEventSource( + `${import.meta.env.VITE_BASE_URL}/ai/mind-map/generate-stream`, + { + method: 'post', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + openWhenHidden: true, + body: JSON.stringify(data), + onmessage: onMessage, + onerror: onError, + onclose: onClose, + signal: ctrl.signal, + }, + ); +} + +// 查询思维导图分页 +export function getMindMapPage(params: any) { + return requestClient.get(`/ai/mind-map/page`, { params }); +} + +// 删除思维导图 +export function deleteMindMap(id: number) { + return requestClient.delete(`/ai/mind-map/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/ai/music/index.ts b/apps/web-antd/src/api/ai/music/index.ts new file mode 100644 index 000000000..a3a60ffc2 --- /dev/null +++ b/apps/web-antd/src/api/ai/music/index.ts @@ -0,0 +1,44 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace AiMusicApi { + // AI 音乐 VO + export interface MusicVO { + id: number; // 编号 + userId: number; // 用户编号 + title: string; // 音乐名称 + lyric: string; // 歌词 + imageUrl: string; // 图片地址 + audioUrl: string; // 音频地址 + videoUrl: string; // 视频地址 + status: number; // 音乐状态 + gptDescriptionPrompt: string; // 描述词 + prompt: string; // 提示词 + platform: string; // 模型平台 + model: string; // 模型 + generateMode: number; // 生成模式 + tags: string; // 音乐风格标签 + duration: number; // 音乐时长 + publicStatus: boolean; // 是否发布 + taskId: string; // 任务id + errorMessage: string; // 错误信息 + } +} + +// 查询音乐分页 +export function getMusicPage(params: PageParam) { + return requestClient.get>(`/ai/music/page`, { + params, + }); +} + +// 更新音乐 +export function updateMusic(data: any) { + return requestClient.put('/ai/music/update', data); +} + +// 删除音乐 +export function deleteMusic(id: number) { + return requestClient.delete(`/ai/music/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/ai/write/index.ts b/apps/web-antd/src/api/ai/write/index.ts new file mode 100644 index 000000000..21585cbda --- /dev/null +++ b/apps/web-antd/src/api/ai/write/index.ts @@ -0,0 +1,90 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import type { AiWriteTypeEnum } from '#/utils/constants'; + +import { fetchEventSource } from '@vben/request'; +import { useAccessStore } from '@vben/stores'; + +import { requestClient } from '#/api/request'; + +const accessStore = useAccessStore(); +export namespace AiWriteApi { + export interface WriteVO { + type: AiWriteTypeEnum.REPLY | AiWriteTypeEnum.WRITING; // 1:撰写 2:回复 + prompt: string; // 写作内容提示 1。撰写 2回复 + originalContent: string; // 原文 + length: number; // 长度 + format: number; // 格式 + tone: number; // 语气 + language: number; // 语言 + userId?: number; // 用户编号 + platform?: string; // 平台 + model?: string; // 模型 + generatedContent?: string; // 生成的内容 + errorMessage?: string; // 错误信息 + createTime?: Date; // 创建时间 + } + + export interface AiWritePageReqVO extends PageParam { + userId?: number; // 用户编号 + type?: AiWriteTypeEnum; // 写作类型 + platform?: string; // 平台 + createTime?: [string, string]; // 创建时间 + } + + export interface AiWriteRespVo { + id: number; + userId: number; + type: number; + platform: string; + model: string; + prompt: string; + generatedContent: string; + originalContent: string; + length: number; + format: number; + tone: number; + language: number; + errorMessage: string; + createTime: string; + } +} + +export function writeStream( + data: any, + onClose: any, + onMessage: any, + onError: any, + ctrl: any, +) { + const token = accessStore.accessToken; + return fetchEventSource( + `${import.meta.env.VITE_BASE_URL}/ai/write/generate-stream`, + { + method: 'post', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + openWhenHidden: true, + body: JSON.stringify(data), + onmessage: onMessage, + onerror: onError, + onclose: onClose, + signal: ctrl.signal, + }, + ); +} + +// 获取写作列表 +export function getWritePage(params: any) { + return requestClient.get>( + `/ai/write/page`, + { params }, + ); +} + +// 删除音乐 +export function deleteWrite(id: number) { + return requestClient.delete(`/ai/write/delete`, { params: { id } }); +} diff --git a/apps/web-antd/src/utils/constants.ts b/apps/web-antd/src/utils/constants.ts index 611d992d9..761df6fdf 100644 --- a/apps/web-antd/src/utils/constants.ts +++ b/apps/web-antd/src/utils/constants.ts @@ -5,6 +5,23 @@ * 枚举类 */ +/** + * AI 平台的枚举 + */ +export const AiPlatformEnum = { + TONG_YI: 'TongYi', // 阿里 + YI_YAN: 'YiYan', // 百度 + DEEP_SEEK: 'DeepSeek', // DeepSeek + ZHI_PU: 'ZhiPu', // 智谱 AI + XING_HUO: 'XingHuo', // 讯飞 + SiliconFlow: 'SiliconFlow', // 硅基流动 + OPENAI: 'OpenAI', + Ollama: 'Ollama', + STABLE_DIFFUSION: 'StableDiffusion', // Stability AI + MIDJOURNEY: 'Midjourney', // Midjourney + SUNO: 'Suno', // Suno AI +}; + export const AiModelTypeEnum = { CHAT: 1, // 聊天 IMAGE: 2, // 图像 @@ -13,6 +30,31 @@ export const AiModelTypeEnum = { EMBEDDING: 5, // 向量 RERANK: 6, // 重排 }; + +/** + * AI 图像生成状态的枚举 + */ +export const AiImageStatusEnum = { + IN_PROGRESS: 10, // 进行中 + SUCCESS: 20, // 已完成 + FAIL: 30, // 已失败 +}; +/** + * AI 音乐生成状态的枚举 + */ +export const AiMusicStatusEnum = { + IN_PROGRESS: 10, // 进行中 + SUCCESS: 20, // 已完成 + FAIL: 30, // 已失败 +}; + +/** + * AI 写作类型的枚举 + */ +export enum AiWriteTypeEnum { + WRITING = 1, // 撰写 + REPLY, // 回复 +} // ========== COMMON 模块 ========== // 全局通用状态枚举 export const CommonStatusEnum = { @@ -733,3 +775,82 @@ OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.DELEGATE, '委派'); OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.ADD_SIGN, '加签'); OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.RETURN, '退回'); OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.COPY, '抄送'); + +// ========== 【写作 UI】相关的枚举 ========== + +/** 写作点击示例时的数据 */ +export const WriteExample = { + write: { + prompt: 'vue', + data: 'Vue.js 是一种用于构建用户界面的渐进式 JavaScript 框架。它的核心库只关注视图层,易于上手,同时也便于与其他库或已有项目整合。\n\nVue.js 的特点包括:\n- 响应式的数据绑定:Vue.js 会自动将数据与 DOM 同步,使得状态管理变得更加简单。\n- 组件化:Vue.js 允许开发者通过小型、独立和通常可复用的组件构建大型应用。\n- 虚拟 DOM:Vue.js 使用虚拟 DOM 实现快速渲染,提高了性能。\n\n在 Vue.js 中,一个典型的应用结构可能包括:\n1. 根实例:每个 Vue 应用都需要一个根实例作为入口点。\n2. 组件系统:可以创建自定义的可复用组件。\n3. 指令:特殊的带有前缀 v- 的属性,为 DOM 元素提供特殊的行为。\n4. 插值:用于文本内容,将数据动态地插入到 HTML。\n5. 计算属性和侦听器:用于处理数据的复杂逻辑和响应数据变化。\n6. 条件渲染:根据条件决定元素的渲染。\n7. 列表渲染:用于显示列表数据。\n8. 事件处理:响应用户交互。\n9. 表单输入绑定:处理表单输入和验证。\n10. 组件生命周期钩子:在组件的不同阶段执行特定的函数。\n\nVue.js 还提供了官方的路由器 Vue Router 和状态管理库 Vuex,以支持构建复杂的单页应用(SPA)。\n\n在开发过程中,开发者通常会使用 Vue CLI,这是一个强大的命令行工具,用于快速生成 Vue 项目脚手架,集成了诸如 Babel、Webpack 等现代前端工具,以及热重载、代码检测等开发体验优化功能。\n\nVue.js 的生态系统还包括大量的第三方库和插件,如 Vuetify(UI 组件库)、Vue Test Utils(测试工具)等,这些都极大地丰富了 Vue.js 的开发生态。\n\n总的来说,Vue.js 是一个灵活、高效的前端框架,适合从小型项目到大型企业级应用的开发。它的易用性、灵活性和强大的社区支持使其成为许多开发者的首选框架之一。', + }, + reply: { + originalContent: '领导,我想请假', + prompt: '不批', + data: '您的请假申请已收悉,经核实和考虑,暂时无法批准您的请假申请。\n\n如有特殊情况或紧急事务,请及时与我联系。\n\n祝工作顺利。\n\n谢谢。', + }, +}; + +// ========== 【思维导图 UI】相关的枚举 ========== + +/** 思维导图已有内容生成示例 */ +export const MindMapContentExample = `# Java 技术栈 + +## 核心技术 +### Java SE +### Java EE + +## 框架 +### Spring +#### Spring Boot +#### Spring MVC +#### Spring Data +### Hibernate +### MyBatis + +## 构建工具 +### Maven +### Gradle + +## 版本控制 +### Git +### SVN + +## 测试工具 +### JUnit +### Mockito +### Selenium + +## 应用服务器 +### Tomcat +### Jetty +### WildFly + +## 数据库 +### MySQL +### PostgreSQL +### Oracle +### MongoDB + +## 消息队列 +### Kafka +### RabbitMQ +### ActiveMQ + +## 微服务 +### Spring Cloud +### Dubbo + +## 容器化 +### Docker +### Kubernetes + +## 云服务 +### AWS +### Azure +### Google Cloud + +## 开发工具 +### IntelliJ IDEA +### Eclipse +### Visual Studio Code`; diff --git a/apps/web-antd/src/views/ai/image/manager/data.ts b/apps/web-antd/src/views/ai/image/manager/data.ts new file mode 100644 index 000000000..ec6fabee2 --- /dev/null +++ b/apps/web-antd/src/views/ai/image/manager/data.ts @@ -0,0 +1,146 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { getSimpleUserList } from '#/api/system/user'; +import { DICT_TYPE, getDictOptions } from '#/utils'; + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'userId', + label: '用户编号', + component: 'ApiSelect', + componentProps: { + api: getSimpleUserList, + labelField: 'nickname', + valueField: 'id', + }, + }, + { + fieldName: 'platform', + label: '平台', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.AI_PLATFORM, 'string'), + }, + }, + { + fieldName: 'status', + label: '绘画状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.AI_IMAGE_STATUS, 'number'), + }, + }, + { + fieldName: 'publicStatus', + label: '是否发布', + component: 'Select', + componentProps: { + options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), + allowClear: true, + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + placeholder: ['开始时间', '结束时间'], + valueFormat: 'YYYY-MM-DD HH:mm:ss', + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + minWidth: 180, + fixed: 'left', + }, + { + title: '图片', + minWidth: 110, + fixed: 'left', + slots: { default: 'picUrl' }, + }, + { + minWidth: 180, + title: '用户', + slots: { default: 'userId' }, + }, + { + field: 'platform', + title: '平台', + minWidth: 120, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.AI_PLATFORM }, + }, + }, + { + field: 'model', + title: '模型', + minWidth: 180, + }, + { + field: 'status', + title: '绘画状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.AI_IMAGE_STATUS }, + }, + }, + { + minWidth: 100, + title: '是否发布', + slots: { default: 'publicStatus' }, + }, + { + field: 'prompt', + title: '提示词', + minWidth: 180, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'width', + title: '宽度', + minWidth: 180, + }, + { + field: 'height', + title: '高度', + minWidth: 180, + }, + { + field: 'errorMessage', + title: '错误信息', + minWidth: 180, + }, + { + field: 'taskId', + title: '任务编号', + minWidth: 180, + }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/ai/image/manager/index.vue b/apps/web-antd/src/views/ai/image/manager/index.vue index 3411ad599..3baafb34d 100644 --- a/apps/web-antd/src/views/ai/image/manager/index.vue +++ b/apps/web-antd/src/views/ai/image/manager/index.vue @@ -1,31 +1,135 @@ diff --git a/apps/web-antd/src/views/ai/mindmap/index/index.vue b/apps/web-antd/src/views/ai/mindmap/index/index.vue index cf47ebd8c..12ace1b87 100644 --- a/apps/web-antd/src/views/ai/mindmap/index/index.vue +++ b/apps/web-antd/src/views/ai/mindmap/index/index.vue @@ -1,28 +1,85 @@ diff --git a/apps/web-antd/src/views/ai/mindmap/index/modules/Left.vue b/apps/web-antd/src/views/ai/mindmap/index/modules/Left.vue new file mode 100644 index 000000000..750514c90 --- /dev/null +++ b/apps/web-antd/src/views/ai/mindmap/index/modules/Left.vue @@ -0,0 +1,77 @@ + + - diff --git a/apps/web-antd/src/views/ai/image/index/components/dall3/index.vue b/apps/web-antd/src/views/ai/image/index/components/dall3/index.vue index f48bf0944..425bd0cad 100644 --- a/apps/web-antd/src/views/ai/image/index/components/dall3/index.vue +++ b/apps/web-antd/src/views/ai/image/index/components/dall3/index.vue @@ -151,19 +151,18 @@ defineExpose({ settingValues }); v-model:value="prompt" :maxlength="1024" :rows="5" - class="w-100% mt-[15px]" + class="mt-[15px] w-full" placeholder="例如:童话里的小屋应该是什么样子?" show-count /> -
-
- 随机热词 -
- + +
+
随机热词
+
-
-
- 模型选择 -
- + +
+
模型选择
+
-
-
- 风格选择 -
- + +
+
风格选择
+
@@ -215,35 +216,41 @@ defineExpose({ settingValues }); fit="contain" @click="handleStyleClick(imageStyle)" /> -
{{ imageStyle.name }}
+
+ {{ imageStyle.name }} +
-
-
- 画面比例 -
- + +
+
画面比例
+
-
{{ imageSize.name }}
+
+ {{ imageSize.name }} +
-
+ +
- diff --git a/apps/web-antd/src/views/ai/image/index/components/midjourney/index.vue b/apps/web-antd/src/views/ai/image/index/components/midjourney/index.vue index b82c0b14d..f231d6683 100644 --- a/apps/web-antd/src/views/ai/image/index/components/midjourney/index.vue +++ b/apps/web-antd/src/views/ai/image/index/components/midjourney/index.vue @@ -150,19 +150,18 @@ defineExpose({ settingValues }); v-model:value="prompt" :maxlength="1024" :rows="5" - class="w-100% mt-[15px]" + class="mt-[15px] w-full" placeholder="例如:童话里的小屋应该是什么样子?" show-count />
-
-
- 随机热词 -
- + +
+
随机热词
+
-
-
- 尺寸 -
- + +
+
尺寸
+
-
{{ imageSize.key }}
+
{{ imageSize.key }}
-
-
- 模型 -
- + +
+
模型
+
-
{{ model.name }}
+
{{ model.name }}
-
-
- 版本 -
- + +
+
版本
+
-
-
- 参考图 -
- + +
+
参考图
+
-
+ +
- diff --git a/apps/web-antd/src/views/ai/image/index/components/stableDiffusion/index.vue b/apps/web-antd/src/views/ai/image/index/components/stableDiffusion/index.vue index cdd2f47bb..337b0dd8c 100644 --- a/apps/web-antd/src/views/ai/image/index/components/stableDiffusion/index.vue +++ b/apps/web-antd/src/views/ai/image/index/components/stableDiffusion/index.vue @@ -9,7 +9,6 @@ import { alert, confirm } from '@vben/common-ui'; import { Button, - Input, InputNumber, message, Select, @@ -139,19 +138,19 @@ defineExpose({ settingValues }); v-model:value="prompt" :maxlength="1024" :rows="5" - class="w-100% mt-[15px]" + class="mt-[15px] w-full" placeholder="例如:童话里的小屋应该是什么样子?" show-count />
-
-
- 随机热词 -
- + + +
+
随机热词
+
-
-
- 采样方法 -
- + + +
+
采样方法
+
-
-
- 风格 -
- + + +
+
风格
+ - + + +
+
图片尺寸
+ + +
-
-
- 迭代步数 -
- + + +
+
迭代步数
+
-
-
- 引导系数 -
- + + +
+
引导系数
+
-
-
- 随机因子 -
- + + +
+
随机因子
+
-
+ + +
- diff --git a/apps/web-antd/src/views/ai/image/index/index.vue b/apps/web-antd/src/views/ai/image/index/index.vue index e63e7d23e..23dee0a81 100644 --- a/apps/web-antd/src/views/ai/image/index/index.vue +++ b/apps/web-antd/src/views/ai/image/index/index.vue @@ -90,15 +90,16 @@ onMounted(async () => { - - diff --git a/apps/web-antd/src/views/ai/image/square/index.vue b/apps/web-antd/src/views/ai/image/square/index.vue index 6cf489844..517c2bea4 100644 --- a/apps/web-antd/src/views/ai/image/square/index.vue +++ b/apps/web-antd/src/views/ai/image/square/index.vue @@ -45,72 +45,44 @@ onMounted(async () => { - diff --git a/apps/web-antd/src/views/ai/mindmap/index/modules/Left.vue b/apps/web-antd/src/views/ai/mindmap/index/modules/Left.vue index 750514c90..d56add1ed 100644 --- a/apps/web-antd/src/views/ai/mindmap/index/modules/Left.vue +++ b/apps/web-antd/src/views/ai/mindmap/index/modules/Left.vue @@ -24,7 +24,11 @@ defineExpose({ - - diff --git a/apps/web-antd/src/views/ai/mindmap/index/modules/Right.vue b/apps/web-antd/src/views/ai/mindmap/index/modules/Right.vue index b20f826c0..d912f9bde 100644 --- a/apps/web-antd/src/views/ai/mindmap/index/modules/Right.vue +++ b/apps/web-antd/src/views/ai/mindmap/index/modules/Right.vue @@ -120,7 +120,7 @@ defineExpose({