fix: 对接朋友圈、ai模块
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
Target Server Version : 80030 (8.0.30)
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 28/10/2025 17:10:28
|
||||
Date: 31/10/2025 19:00:36
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
@@ -23,6 +23,8 @@ SET FOREIGN_KEY_CHECKS = 0;
|
||||
DROP TABLE IF EXISTS `ai_api_key`;
|
||||
CREATE TABLE `ai_api_key` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
|
||||
`user_id` bigint NOT NULL COMMENT '创建模型的uid',
|
||||
`public_status` bit(1) NOT NULL DEFAULT b'1' COMMENT '公开、私有',
|
||||
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '名称',
|
||||
`api_key` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '密钥',
|
||||
`platform` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '平台',
|
||||
@@ -35,33 +37,12 @@ CREATE TABLE `ai_api_key` (
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 23 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI API 密钥表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90154862069761 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI API 密钥表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of ai_api_key
|
||||
-- ----------------------------
|
||||
INSERT INTO `ai_api_key` VALUES (1, '【OpenAI】ChatGPT', 'sk-aN6nWn3fILjrgLFT0fC4Aa60B72e4253826c77B29dC94f17', 'OpenAI', 'https://api.holdai.top', 0, '', '2024-05-10 01:37:55', '1', '2025-02-23 16:58:46', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (2, '呵呵', '123321', 'OpenAI', NULL, 0, '1', '2024-05-11 16:46:18', '1', '2024-05-17 15:15:08', b'1', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (3, '【Meta】Ollama', ' ', 'Ollama', 'http://127.0.0.1:11434', 0, '1', '2024-05-17 23:04:13', '1', '2024-07-05 01:30:10', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (4, '【百度】文心一言', 'x0cuLZ7XsaTCU08vuJWO87Lg|R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK', 'YiYan', NULL, 0, '1', '2024-05-18 09:26:02', '1', '2024-07-05 01:30:10', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (5, '【讯飞】星火', '75b161ed2aef4719b275d6e7f2a4d4cd|YWYxYWI2MTA4ODI2NGZlYTQyNjAzZTcz', 'XingHuo', NULL, 0, '1', '2024-05-18 10:09:42', '1', '2025-02-23 18:35:06', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (6, '【阿里】通义千问', 'sk-7d903764249848cfa912733146da12d1', 'TongYi', NULL, 0, '1', '2024-05-18 10:33:12', '1', '2025-02-24 10:24:50', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (7, 'StableDiffusion', 'sk-e53UqbboF8QJCscYvzJscJxJXoFcFg4iJjl1oqgE7baJETmx', 'StableDiffusion', NULL, 0, '1', '2024-06-01 15:11:18', '1', '2024-07-05 01:30:10', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (8, '【本地】Ollama', 'null', 'Ollama', 'http://localhost:11434', 0, '1', '2024-06-01 20:04:43', '1', '2025-02-24 09:21:16', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (9, 'Suno', 'Suno', 'Suno', 'http://127.0.0.1:3001', 0, '1', '2024-06-29 09:14:28', '1', '2024-07-05 01:30:10', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (10, 'Midjourney', 'sk-dZEPiVaNcT3FHhef51996bAa0bC74806BeAb620dA5Da10Bf', 'Midjourney', 'https://api.holdai.top/mj', 0, '1', '2024-06-29 09:40:20', '1', '2024-07-05 01:30:10', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (11, 'DeepSeek', 'sk-5b612c071f904fd59808dc07c9a4f1b8', 'DeepSeek', NULL, 0, '1', '2024-07-06 12:06:04', '1', '2025-03-13 21:18:31', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (12, '智谱', '2f35fb6ca4ea41fab898729b7fac086c.6ESSfPcCkxaKEUlR', 'ZhiPu', NULL, 0, '1', '2024-07-06 18:01:15', '1', '2025-03-11 07:47:46', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (13, '【微软 OpenAI】ChatGPT', 'XXX', 'AzureOpenAI', 'https://eastusprejade.openai.azure.com', 0, '1', '2024-08-10 14:09:27', '1', '2024-08-10 15:08:27', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (14, '字节豆包', '5c1b5747-26d2-4ebd-a4e0-dd0e8d8b4272', 'DouBao', NULL, 0, '1', '2025-02-23 19:52:37', '1', '2025-02-23 19:52:37', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (15, '腾讯混元', 'sk-bcd', 'HunYuan', NULL, 0, '1', '2025-02-23 20:59:10', '1', '2025-02-24 09:20:04', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (16, '腾讯知识引擎', 'sk-abc', 'HunYuan', 'https://api.lkeap.cloud.tencent.com', 0, '1', '2025-02-23 20:59:49', '1', '2025-02-24 09:20:00', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (17, '【本地】deepseek-r1', 'null', 'Ollama', 'http://localhost:11434', 0, '1', '2025-02-24 09:20:31', '1', '2025-02-24 09:21:40', b'1', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (18, '硅基流动', 'sk-epsakfenqnyzoxhmbucsxlhkdqlcbnimslqoivkshalvdozz', 'SiliconFlow', '', 0, '1', '2025-02-24 20:34:19', '1', '2025-02-24 20:34:19', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (19, 'MiniMax', 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJHcm91cE5hbWUiOiLnjovmlofmlowiLCJVc2VyTmFtZSI6IueOi-aWh-aWjCIsIkFjY291bnQiOiIiLCJTdWJqZWN0SUQiOiIxODk3Mjg3MjQ5NDU2ODA4MzQ2IiwiUGhvbmUiOiIxNTYwMTY5MTM5OSIsIkdyb3VwSUQiOiIxODk3Mjg3MjQ5NDQ4NDE5NzM4IiwiUGFnZU5hbWUiOiIiLCJNYWlsIjoiIiwiQ3JlYXRlVGltZSI6IjIwMjUtMDMtMTEgMTI6NTI6MDIiLCJUb2tlblR5cGUiOjEsImlzcyI6Im1pbmltYXgifQ.aAuB7gWW_oA4IYhh-CF7c9MfWWxKN49B_HK-DYjXaDwwffhiG-H1571z1WQhp9QytWG-DqgLejneeSxkiq1wQIe3FsEP2wz4BmGBct31LehbJu8ehLxg_vg75Uod1nFAHbm5mZz6JSVLNIlSo87Xr3UtSzJhAXlapEkcqlA4YOzOpKrZ8l5_OJPTORTCmHWZYgJcRS-faNiH62ZnUEHUozesTFhubJHo5GfJCw_edlnmfSUocERV1BjWvenhZ9My-aYXNktcW9WaSj9l6gayV7A0Ium_PL55T9ln1PcI8gayiVUKJGJDoqNyF1AF9_aF9NOKtTnQzwNqnZdlTYH6hw', 'MiniMax', NULL, 0, '1', '2025-03-11 20:06:35', '1', '2025-03-11 20:06:35', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (20, '月之暗灭', 'sk-g9ZpHUj5nEBwY9JJCyUxaxKOwC5M8cvpQFg211ksPJ64yIlm', 'Moonshot', NULL, 0, '1', '2025-03-11 20:07:27', '1', '2025-10-28 09:03:46', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (21, 'FastGPT', 'fastgpt-aqcc61kFtF8CeaglnGAfQOCIDWwjGdJVJHv6hIlMo28otFlva2aZNK', 'OpenAI', 'https://cloud.fastgpt.cn/api', 0, '1', '2025-03-12 13:51:06', '1', '2025-03-12 20:06:12', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (22, 'Dify', 'app-4hy2d7fJauSbrKbzTKX1afuP', 'OpenAI', 'http://127.0.0.1:3000', 0, '1', '2025-03-12 21:26:34', '1', '2025-03-12 21:50:29', b'0', 1);
|
||||
INSERT INTO `ai_api_key` VALUES (90154862069760, 20901198351872, b'1', 'kimi', 'sk-HD0GKyxX3bYuycGuV5de202U418gczeAYcZVYZucwWrBEu2V', 'Moonshot', NULL, 0, NULL, '2025-10-30 18:43:15', NULL, '2025-10-30 11:26:16', b'0', 1);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for ai_chat_conversation
|
||||
@@ -87,15 +68,14 @@ CREATE TABLE `ai_chat_conversation` (
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NULL DEFAULT NULL COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1781604279872581774 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 聊天对话表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90190392010241 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 聊天对话表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of ai_chat_conversation
|
||||
-- ----------------------------
|
||||
INSERT INTO `ai_chat_conversation` VALUES (1781604279872581684, 20901198351872, 10, '新对话', 53, 'qwen-72b-chat', b'0', NULL, '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议!!!!', 1, 20, 2, '1', '2024-05-20 22:22:39', '1', '2025-10-28 03:38:52', b'1', 1);
|
||||
INSERT INTO `ai_chat_conversation` VALUES (1781604279872581685, 20901198351872, 10, 'gpt测试', 53, 'gpt-3.5-turbo', b'1', '2024-05-21 16:26:29', '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议!!!!', 1, 20, 20, '1', '2024-05-21 09:37:38', '1', '2025-10-28 03:38:52', b'1', 1);
|
||||
INSERT INTO `ai_chat_conversation` VALUES (1781604279872581686, 20901198351872, 10, '新的gpt测试', 53, 'gpt-3.5-turbo', b'0', NULL, '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议!!!!', 1, 20, 20, '1', '2024-05-21 14:43:32', '1', '2025-10-28 03:38:52', b'1', 1);
|
||||
INSERT INTO `ai_chat_conversation` VALUES (1781604279872581687, 20901198351872, 10, '新对话', 53, 'gpt-3.5-turbo', b'0', NULL, '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议!!!!', 1, 20, 20, '1', '2024-05-21 16:37:12', '1', '2025-10-28 03:38:52', b'1', 1);
|
||||
INSERT INTO `ai_chat_conversation` VALUES (90159593245184, 20901198351872, 90159576467968, 'Hula官方角色', 90158209124864, 'moonshot-v1-128k', b'0', NULL, '我是Hula官方机器人,非常聪明', 0.8, 4096, 10, NULL, '2025-10-30 19:02:02', NULL, '2025-10-30 19:02:02', b'0', 1);
|
||||
INSERT INTO `ai_chat_conversation` VALUES (90160268528128, 20901198351872, 90159576467968, 'Hula官方角色', 90158209124864, 'moonshot-v1-128k', b'0', NULL, '我是Hula官方机器人,非常聪明', 0.8, 4096, 10, NULL, '2025-10-30 19:04:43', NULL, '2025-10-30 19:04:43', b'0', 1);
|
||||
INSERT INTO `ai_chat_conversation` VALUES (90190392010240, 10937855681024, 90190358455808, '测试HuLa', 90158209124864, 'moonshot-v1-128k', b'0', NULL, '你是一个vue专家', 0.8, 4096, 10, NULL, '2025-10-30 21:04:26', NULL, '2025-10-30 21:04:26', b'0', 1);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for ai_chat_message
|
||||
@@ -118,17 +98,13 @@ CREATE TABLE `ai_chat_message` (
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NULL DEFAULT NULL COMMENT '租户编号',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 2737 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 聊天消息表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90190480090626 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 聊天消息表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of ai_chat_message
|
||||
-- ----------------------------
|
||||
INSERT INTO `ai_chat_message` VALUES (1481, 1781604279872581686, NULL, 1, 10, 'user', 'gpt-3.5-turbo', 11, '测试小苹果?', b'0', NULL, '1', '2024-05-21 14:47:37', '1', '2024-07-05 01:30:39', b'0', 1);
|
||||
INSERT INTO `ai_chat_message` VALUES (1482, 1781604279872581686, 1481, 1, 10, 'assistant', 'gpt-3.5-turbo', 11, '很,我抱无法提供果歉关于\"测试小苹\"的信息。请问您有其他问题或者需要帮助吗?我会尽力回答提或者供帮助。', b'0', NULL, '1', '2024-05-21 14:47:37', NULL, '2024-07-05 01:30:39', b'0', 1);
|
||||
INSERT INTO `ai_chat_message` VALUES (1483, 1781604279872581686, NULL, 1, 10, 'user', 'gpt-3.5-turbo', 11, '真的么?', b'0', NULL, '1', '2024-05-21 14:47:59', '1', '2024-07-05 01:30:39', b'0', 1);
|
||||
INSERT INTO `ai_chat_message` VALUES (1484, 1781604279872581686, 1483, 1, 10, 'assistant', 'gpt-3.5-turbo', 11, '', b'0', NULL, '1', '2024-05-21 14:47:59', '1', '2024-07-05 01:30:39', b'0', 1);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for ai_chat_role
|
||||
@@ -155,19 +131,13 @@ CREATE TABLE `ai_chat_role` (
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 聊天角色表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90190358455809 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 聊天角色表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of ai_chat_role
|
||||
-- ----------------------------
|
||||
INSERT INTO `ai_chat_role` VALUES (10, NULL, 11, '通用 AI 助手', 'http://test.yudao.iocoder.cn/eaef5f41acb911dd718429a0702dcc3c61160d16e57ba1d543132fab58934f9f.png', '助手', 1, '默认角色', '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议!!!!', NULL, NULL, b'1', 0, '1', '2024-05-13 20:44:48', '1', '2024-07-05 01:30:30', b'0', 1);
|
||||
INSERT INTO `ai_chat_role` VALUES (11, NULL, 14, 'Python 专家', 'http://test.yudao.iocoder.cn/5c5528504c307d34af504f39bc4e7007d2f6f31ee00dab699cc91584d1af8aca.png', '编程开发', 2, 'Python', '我希望你能作为一名 python 专家。我将向你提供有关我的技术问题的所有信息,而你的角色是解决我的问题。你应该用你的计算机科学、网络基础设施和 IT 安全知识来解决我的问题。在你的回答中,使用聪明的、简单的、为各种层次的人所理解的语言会有帮助。逐步解释你的解决方案并使用要点是很有帮助的。尽量避免过多的技术细节,但在必要时使用它们。我希望你用解决方案来回答,而不是写任何解释。', NULL, '17', b'1', 0, '1', '2024-05-17 23:23:20', '1', '2025-03-14 21:10:47', b'0', 1);
|
||||
INSERT INTO `ai_chat_role` VALUES (12, 1, NULL, '小可爱角色', 'http://test.yudao.iocoder.cn/5752750225f522ba794b16ad0b0e73d268093760546ebc2519b1a5dfc5b064d1.jpg', NULL, 0, '卡比兽,爱睡觉', '你好,我是宠物小精灵大师!', NULL, NULL, b'0', 0, '1', '2024-05-25 13:25:46', '1', '2024-07-05 01:30:30', b'0', 1);
|
||||
INSERT INTO `ai_chat_role` VALUES (13, NULL, 17, '写作助手', 'http://test.yudao.iocoder.cn/2a124ba5743f9572fcbd2718a64ba599618c96ddba6c7391ad35906cd3f37f94.png', '写作', 10, '一个厉害的写手高手', '你是一个非常会写作的人!', NULL, NULL, b'1', 0, '1', '2024-07-10 22:55:58', '1', '2024-07-10 22:56:04', b'0', 1);
|
||||
INSERT INTO `ai_chat_role` VALUES (14, NULL, 17, '脑图助手', 'http://test.yudao.iocoder.cn/7401c394a43280732e6aaa715fbfefadc33eeb8fab8f45f6b53f1acf6b22ae29.png', '写作', 11, '一个厉害的思维大师!', '你是一位非常优秀的思维导图助手,你会把用户的所有提问都总结成思维导图,然后以 Markdown 格式输出。markdown 只需要输出一级标题,二级标题,三级标题,四级标题,最多输出四级,除此之外不要输出任何其他 markdown 标记。下面是一个合格的例子:\n # Geek-AI 助手\n ## 完整的开源系统\n ### 前端开源\n ### 后端开源\n ## 支持各种大模型\n ### OpenAI\n ### Azure\n ### 文心一言\n ### 通义千问\n ## 集成多种收费方式\n ### 支付宝\n ### 微信\n 除此之外不要任何解释性语句。', NULL, NULL, b'1', 0, '1', '2024-07-29 21:47:20', '1', '2024-07-29 21:48:00', b'0', 1);
|
||||
INSERT INTO `ai_chat_role` VALUES (15, NULL, 26, '测试知识库', 'http://test.yudao.iocoder.cn/d3a7656aae53c8f063d4578c7a65f9045ef25420ff32cc32dd121a60abcf9127.png', '助手', 10, '我只是个小助手', '一个问答助手', '3', NULL, b'1', 0, '1', '2025-03-09 17:35:36', '1', '2025-03-09 18:32:34', b'1', 1);
|
||||
INSERT INTO `ai_chat_role` VALUES (16, 1, 21, '测试知识库', 'http://test.yudao.iocoder.cn/a2cfbf52d157911ecfb29c4a26b4a19247f6bb2c97a5104c46c970fc235880ef.png', '助手', 0, '测试一下', '一个小助手', '2', NULL, b'0', 0, '1', '2025-03-09 18:33:01', '1', '2025-03-09 18:51:04', b'0', 1);
|
||||
INSERT INTO `ai_chat_role` VALUES (17, 1, NULL, '一个可以查询天气的小助手', 'http://test.yudao.iocoder.cn/de74fdbe9ad40173345d4cd1e2b684fcbb5e797f7b7cc37b42dcbaa20dcf6bb3.png', NULL, 0, '查查查天气', '天气小助手', '', '18', b'0', 0, '1', '2025-03-14 20:03:27', '1', '2025-03-14 20:03:27', b'0', 1);
|
||||
INSERT INTO `ai_chat_role` VALUES (90159576467968, 20901198351872, 90158209124864, 'Hula官方角色', 'https://cdn.hulaspark.com/avatar/1046762075/43de7a13eda6b8c29622f5b4ca429156.webp', NULL, 0, '我是Hula官方机器人', '我是Hula官方机器人,非常聪明', NULL, NULL, b'0', 0, NULL, '2025-10-30 19:01:58', NULL, '2025-10-30 19:01:58', b'0', 1);
|
||||
INSERT INTO `ai_chat_role` VALUES (90190358455808, NULL, 90158209124864, '测试HuLa', 'https://cdn.hulaspark.com/avatar/2439646234/993c2cfc546fabc1ee127037102378d9.webp', '0', 0, '测试', '你是一个vue专家', NULL, NULL, b'1', 0, NULL, '2025-10-30 21:04:17', NULL, '2025-10-30 21:04:17', b'0', 1);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for ai_image
|
||||
@@ -356,6 +326,7 @@ INSERT INTO `ai_mind_map` VALUES (3, 1, '生成一个 Vue 核心关键点', '# V
|
||||
DROP TABLE IF EXISTS `ai_model`;
|
||||
CREATE TABLE `ai_model` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
|
||||
`user_id` bigint NOT NULL COMMENT '创建模型的uid',
|
||||
`key_id` bigint NOT NULL COMMENT 'API 秘钥编号',
|
||||
`name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型名字',
|
||||
`model` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型标识',
|
||||
@@ -363,6 +334,7 @@ CREATE TABLE `ai_model` (
|
||||
`type` tinyint NOT NULL COMMENT '模型类型',
|
||||
`sort` int NOT NULL COMMENT '排序',
|
||||
`status` tinyint NOT NULL COMMENT '状态',
|
||||
`public_status` bit(1) NOT NULL DEFAULT b'1' COMMENT '公开、私有',
|
||||
`temperature` double NULL DEFAULT NULL COMMENT '温度参数',
|
||||
`max_tokens` int NULL DEFAULT NULL COMMENT '单条回复的最大 Token 数量',
|
||||
`max_contexts` int NULL DEFAULT NULL COMMENT '上下文的最大 Message 数量',
|
||||
@@ -372,59 +344,16 @@ CREATE TABLE `ai_model` (
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 56 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 模型表' ROW_FORMAT = Dynamic;
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_user_id`(`user_id` ASC) USING BTREE,
|
||||
INDEX `idx_public_status`(`public_status` ASC) USING BTREE,
|
||||
INDEX `idx_user_public`(`user_id` ASC, `public_status` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90158209124865 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 模型表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of ai_model
|
||||
-- ----------------------------
|
||||
INSERT INTO `ai_model` VALUES (9, 4, 'ernie-tiny-8k', 'ernie-tiny-8k', 'YiYan', 1, 100, 0, NULL, NULL, NULL, '', '2024-05-10 01:38:04', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (10, 4, 'ERNIE 4.0', 'ERNIE 4.0', 'YiYan', 1, 100, 0, 1, 4096, 10, '', '2024-05-10 01:38:04', '1', '2025-03-03 01:26:22', b'1', 1);
|
||||
INSERT INTO `ai_model` VALUES (11, 1, 'gpt-3.5-turbo', 'gpt-3.5-turbo', 'OpenAI', 1, 0, 0, 1, 4096, 20, '1', '2024-05-11 17:57:56', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (12, 3, 'llama3', 'llama3', 'Ollama', 1, 1, 0, 1, 4096, 10, '1', '2024-05-17 23:16:38', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (13, 5, '星火大模型3.5', 'generalv3.5', 'XingHuo', 1, 5, 0, NULL, NULL, NULL, '1', '2024-05-18 10:10:21', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (14, 6, 'qwen-72b-chat', 'qwen-72b-chat', 'TongYi', 1, 6, 0, 1, 2000, 20, '1', '2024-05-18 10:33:47', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (15, 6, 'Qwen-7B', 'Qwen-7B', 'TongYi', 1, 1000, 0, 1, 4096, 20, '1', '2024-06-01 20:05:14', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (16, 4, 'ernie_speed', 'ernie_speed', 'YiYan', 1, 2000, 0, 1, 4096, 10, '1', '2024-06-02 09:00:21', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (17, 11, 'deepseek-chat', 'deepseek-chat', 'DeepSeek', 1, 300, 0, 0.75, 4096, 20, '1', '2024-07-06 12:06:47', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (18, 11, 'deepseek-reasoner', 'deepseek-reasoner', 'DeepSeek', 1, 301, 0, 1, 4096, 20, '1', '2024-07-06 12:07:25', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (19, 12, 'GLM-4', 'GLM-4', 'ZhiPu', 1, 400, 0, 0.75, 2000, 20, '1', '2024-07-06 18:01:45', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (20, 13, '【微软】gpt-35-turbo', 'gpt-35-turbo', 'AzureOpenAI', 1, 2000, 0, 1, 4096, 20, '1', '2024-08-10 14:10:07', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (21, 8, 'qwen:4b', 'qwen:4b', 'Ollama', 1, 9999, 0, NULL, NULL, NULL, '1', '2025-02-23 19:05:00', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (22, 14, 'doubao-1-5-lite-32k', 'doubao-1-5-lite-32k-250115', 'DouBao', 1, 350, 0, NULL, NULL, NULL, '1', '2025-02-23 19:53:24', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (23, 14, 'deepseek-r1-zijie', 'deepseek-r1-250120', 'DouBao', 1, 351, 0, NULL, NULL, NULL, '1', '2025-02-23 19:58:32', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (24, 15, 'hunyuan-turbo', 'hunyuan-turbo', 'HunYuan', 1, 380, 0, NULL, NULL, NULL, '1', '2025-02-23 21:00:37', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (25, 16, 'deepseek-r1-tengxun', 'deepseek-r1', 'HunYuan', 1, 381, 0, NULL, NULL, NULL, '1', '2025-02-23 21:01:20', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (26, 8, 'deepseek-r1-local', 'deepseek-r1', 'Ollama', 1, 10000, 0, NULL, NULL, NULL, '1', '2025-02-24 09:22:32', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (27, 6, 'deepseek-r1-aliyun', 'deepseek-r1', 'TongYi', 1, 7, 0, NULL, NULL, NULL, '1', '2025-02-24 10:05:51', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (28, 6, 'deepseek-v3-aliyun', 'deepseek-v3', 'TongYi', 1, 8, 0, NULL, NULL, NULL, '1', '2025-02-24 10:24:29', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (29, 18, 'deepseek-r1-siliconflow', 'deepseek-ai/DeepSeek-R1', 'SiliconFlow', 1, 12000, 0, NULL, NULL, NULL, '1', '2025-02-24 20:35:18', '1', '2025-03-03 01:26:22', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (30, 8, 'nomic-embed-text', 'nomic-embed-text', 'Ollama', 5, 20000, 0, NULL, NULL, NULL, '1', '2025-02-24 20:35:18', '1', '2025-03-03 01:51:28', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (31, 6, 'wanx-v1', 'wanx-v1', 'TongYi', 2, 3005, 0, NULL, NULL, NULL, '1', '2025-03-03 20:08:49', '1', '2025-03-03 21:36:24', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (32, 6, 'wanx-sketch-to-image-v1', 'wanx-sketch-to-image-v1', 'TongYi', 2, 3005, 0, NULL, NULL, NULL, '1', '2025-03-03 20:09:05', '1', '2025-03-03 21:36:20', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (33, 4, 'sd_xl', 'sd_xl', 'YiYan', 2, 3004, 0, NULL, NULL, NULL, '1', '2025-03-03 20:30:49', '1', '2025-03-03 21:36:14', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (34, 12, 'cogview-3', 'cogview-3', 'ZhiPu', 2, 3003, 0, NULL, NULL, NULL, '1', '2025-03-03 20:31:40', '1', '2025-03-03 21:36:07', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (35, 1, 'dall-e-3', 'dall-e-3', 'OpenAI', 2, 3002, 0, NULL, NULL, NULL, '1', '2025-03-03 20:56:55', '1', '2025-03-03 21:36:02', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (36, 1, 'dall-e-2', 'dall-e-2', 'OpenAI', 2, 3002, 0, NULL, NULL, NULL, '1', '2025-03-03 20:57:57', '1', '2025-03-03 21:35:58', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (37, 7, 'stable-diffusion-v1-6', 'stable-diffusion-v1-6', 'StableDiffusion', 2, 3001, 0, NULL, NULL, NULL, '1', '2025-03-03 21:30:59', '1', '2025-03-03 21:35:48', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (38, 10, 'midjourney', 'midjourney', 'Midjourney', 2, 3000, 0, NULL, NULL, NULL, '1', '2025-03-03 21:35:01', '1', '2025-03-03 21:35:01', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (39, 10, 'niji', 'niji', 'Midjourney', 2, 3000, 0, NULL, NULL, NULL, '1', '2025-03-03 21:35:23', '1', '2025-03-03 21:35:23', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (40, 8, 'mxbai-embed-large', 'mxbai-embed-large', 'Ollama', 5, 20000, 0, NULL, NULL, NULL, '1', '2025-03-10 09:10:33', '1', '2025-03-10 09:10:33', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (41, 6, 'text-embedding-v3', 'text-embedding-v3', 'TongYi', 5, 20000, 0, NULL, NULL, NULL, '1', '2025-03-10 22:04:30', '1', '2025-03-10 22:04:30', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (42, 12, 'embedding-3', 'embedding-3', 'ZhiPu', 5, 20000, 0, NULL, NULL, NULL, '1', '2025-03-11 07:48:21', '1', '2025-03-11 07:48:21', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (43, 1, 'text-embedding-ada-002 ', 'text-embedding-ada-002 ', 'OpenAI', 5, 20000, 0, NULL, NULL, NULL, '1', '2025-03-11 09:38:09', '1', '2025-03-11 09:40:54', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (44, 19, 'abab6.5g-chat', 'abab6.5g-chat', 'MiniMax', 1, 500, 0, NULL, NULL, NULL, '1', '2025-03-11 20:08:03', '1', '2025-03-11 20:08:15', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (45, 19, 'embo-01', 'embo-01', 'MiniMax', 5, 20000, 0, NULL, NULL, NULL, '1', '2025-03-11 20:08:47', '1', '2025-03-11 20:15:17', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (46, 20, 'moonshot-v1-8k', 'moonshot-v1-8k', 'Moonshot', 1, 600, 0, NULL, NULL, NULL, '1', '2025-03-11 20:10:24', '1', '2025-03-11 20:10:24', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (47, 21, 'FastGPT', 'FastGPT', 'OpenAI', 1, 8888, 0, NULL, NULL, NULL, '1', '2025-03-12 13:51:46', '1', '2025-03-12 13:51:46', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (48, 22, 'Dify', 'Dify', 'OpenAI', 1, 8888, 0, NULL, NULL, NULL, '1', '2025-03-12 21:27:34', '1', '2025-03-12 21:27:34', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (49, 1, 'gpt-4o-mini', 'gpt-4o-mini', 'OpenAI', 1, 0, 0, 1, 4096, 20, '1', '2025-03-13 12:46:02', '1', '2025-03-13 12:47:02', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (50, 8, 'qwen2.5', 'qwen2.5', 'Ollama', 1, 9999, 0, NULL, NULL, NULL, '1', '2025-03-13 15:05:15', '1', '2025-03-13 20:38:28', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (51, 19, 'MiniMax-Text-01', 'MiniMax-Text-01', 'MiniMax', 1, 500, 0, NULL, NULL, NULL, '1', '2025-03-13 20:37:48', '1', '2025-03-13 20:38:06', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (52, 18, 'deepseek-v3-siliconflow-vip', 'Pro/deepseek-ai/DeepSeek-V3', 'SiliconFlow', 1, 12000, 0, NULL, NULL, NULL, '1', '2025-03-13 21:06:01', '1', '2025-03-13 21:06:01', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (53, 20, 'moonshot-v1-128k', 'moonshot-v1-128k', 'Moonshot', 1, 600, 0, NULL, NULL, NULL, '1', '2025-03-13 21:15:16', '1', '2025-03-13 21:15:16', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (54, 6, 'qwen-max-latest', 'qwen-max-latest', 'TongYi', 1, 6, 0, NULL, NULL, NULL, '1', '2025-03-13 21:32:27', '1', '2025-03-13 21:34:12', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (55, 5, '4.0Ultra', '4.0Ultra', 'XingHuo', 1, 5, 0, NULL, NULL, NULL, '1', '2025-03-14 11:24:14', '1', '2025-03-14 11:24:14', b'0', 1);
|
||||
INSERT INTO `ai_model` VALUES (90158209124864, 20901198351872, 90154862069760, 'Hula小模型', 'moonshot-v1-128k', 'Moonshot', 1, 0, 0, b'1', 0.8, 4096, 10, NULL, '2025-10-30 18:56:33', NULL, '2025-10-30 11:05:33', b'0', 1);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for ai_music
|
||||
@@ -2302,8 +2231,8 @@ CREATE TABLE `def_user` (
|
||||
-- ----------------------------
|
||||
-- Records of def_user
|
||||
-- ----------------------------
|
||||
INSERT INTO `def_user` VALUES (61170828519936, 2, 'bot', 'HuLa小管家', '', '022', NULL, NULL, '', NULL, b'0', '', '', '1', b'1', '', '2025-08-11 11:11:03.139', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"120.231.232.41\", \"createIpDetail\": null, \"updateIpDetail\": null}', '2025-08-19 10:05:05', 1, NULL, 'a4d5c225e6709ba025272a31c7e90e0121d5e5ba16695afe0b61370bedb677d0', 'Dawn', '2025-07-07 15:27:02', 1, '2025-03-27 04:23:08', NULL, '2025-07-16 12:26:15', 0, 1);
|
||||
INSERT INTO `def_user` VALUES (61170828519937, 2, '2439646234', 'Dawn', '2439646234@qq.com', 'https://cdn.hulaspark.com/avatar/2439646234/6ec99d37b8ba1296c325d2d36b46a14d.webp', NULL, NULL, '', NULL, b'0', '', '', '1', b'1', '', '2025-08-11 11:11:03.189', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"183.15.179.234\", \"createIpDetail\": null, \"updateIpDetail\": {\"ip\": \"183.15.179.234\", \"isp\": \"电信\", \"area\": \"\", \"city\": \"深圳\", \"isp_id\": \"100017\", \"region\": \"广东\", \"city_id\": \"440300\", \"country\": \"中国\", \"region_id\": \"440000\", \"country_id\": \"CN\"}}', NULL, 0, NULL, 'a4d5c225e6709ba025272a31c7e90e0121d5e5ba16695afe0b61370bedb677d0', 'Dawn', '2025-10-28 16:38:01', 1, '2025-03-27 04:23:08', NULL, '2025-10-28 16:55:55', 0, 1);
|
||||
INSERT INTO `def_user` VALUES (61170828519936, 2, 'bot', 'HuLa小管家', '', '022', NULL, NULL, '', NULL, b'0', '', '', '1', b'1', '', '2025-08-11 11:11:03.139', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"120.231.232.41\", \"createIpDetail\": null, \"updateIpDetail\": null}', '2025-10-28 17:08:01', 2, NULL, 'a4d5c225e6709ba025272a31c7e90e0121d5e5ba16695afe0b61370bedb677d0', 'Dawn', '2025-07-07 15:27:02', 1, '2025-03-27 04:23:08', NULL, '2025-07-16 12:26:15', 0, 1);
|
||||
INSERT INTO `def_user` VALUES (61170828519937, 2, '2439646234', 'Dawn', '2439646234@qq.com', 'https://cdn.hulaspark.com/avatar/2439646234/6ec99d37b8ba1296c325d2d36b46a14d.webp', NULL, NULL, '', NULL, b'0', '', '', '1', b'1', '', '2025-08-11 11:11:03.189', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"183.15.179.234\", \"createIpDetail\": null, \"updateIpDetail\": {\"ip\": \"183.15.179.234\", \"isp\": \"电信\", \"area\": \"\", \"city\": \"深圳\", \"isp_id\": \"100017\", \"region\": \"广东\", \"city_id\": \"440300\", \"country\": \"中国\", \"region_id\": \"440000\", \"country_id\": \"CN\"}}', NULL, 0, NULL, 'a4d5c225e6709ba025272a31c7e90e0121d5e5ba16695afe0b61370bedb677d0', 'Dawn', '2025-10-31 18:11:19', 1, '2025-03-27 04:23:08', NULL, '2025-10-31 18:36:18', 0, 1);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for def_user_application
|
||||
@@ -2388,7 +2317,7 @@ CREATE TABLE `extend_interface_log` (
|
||||
-- Records of extend_interface_log
|
||||
-- ----------------------------
|
||||
INSERT INTO `extend_interface_log` VALUES (66567882983426, 244439130119864323, '阿里短信', 0, 1, '2025-08-26 16:37:01', '2025-08-26 16:37:00', NULL, '2025-08-26 16:37:00', NULL, 0, 0);
|
||||
INSERT INTO `extend_interface_log` VALUES (655249535051914248, 244881451621810192, '腾讯邮件', 576, 56, '2025-10-28 16:44:42', '2025-07-16 18:41:01', NULL, '2025-07-16 18:41:01', NULL, 0, 0);
|
||||
INSERT INTO `extend_interface_log` VALUES (655249535051914248, 244881451621810192, '腾讯邮件', 624, 57, '2025-10-31 17:41:02', '2025-07-16 18:41:01', NULL, '2025-07-16 18:41:01', NULL, 0, 0);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for extend_interface_logging
|
||||
@@ -2602,7 +2531,7 @@ CREATE TABLE `worker_node` (
|
||||
`created` timestamp NULL DEFAULT NULL COMMENT '创建时间',
|
||||
`is_del` tinyint(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 891 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'DB;WorkerID Assigner for UID Generator' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 921 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'DB;WorkerID Assigner for UID Generator' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of worker_node
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
Target Server Version : 80030 (8.0.30)
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 28/10/2025 17:10:36
|
||||
Date: 31/10/2025 19:00:29
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
@@ -151,7 +151,7 @@ CREATE TABLE `im_contact` (
|
||||
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
|
||||
INDEX `idx_update_time`(`update_time` ASC) USING BTREE,
|
||||
INDEX `idx_contact_room_uid_hide`(`room_id` ASC, `uid` ASC, `hide` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 69082079590943 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会话列表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 69082079592702 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会话列表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of im_contact
|
||||
@@ -168,7 +168,7 @@ CREATE TABLE `im_feed` (
|
||||
`id` bigint NOT NULL,
|
||||
`uid` bigint NOT NULL COMMENT '用户id',
|
||||
`content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_ci NOT NULL COMMENT '朋友圈文案',
|
||||
`permission` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_ci NOT NULL DEFAULT '1' COMMENT 'privacy -> 私密 open -> 公开 partVisible -> 部分可见 notAnyone -> 不给谁看',
|
||||
`permission` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_ci NOT NULL DEFAULT '1' COMMENT 'privacy -> 私密 open -> 公开 partVisible -> 部分可见 notAnyone -> 不给谁看',
|
||||
`media_type` tinyint NULL DEFAULT NULL COMMENT '朋友圈内容类型(0: 纯文字 1: 图片, 2: 视频)',
|
||||
`create_time` datetime NOT NULL COMMENT '创建时间',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 1,
|
||||
@@ -183,6 +183,8 @@ CREATE TABLE `im_feed` (
|
||||
-- ----------------------------
|
||||
-- Records of im_feed
|
||||
-- ----------------------------
|
||||
INSERT INTO `im_feed` VALUES (90012511218176, 43329605667840, 'Kkk', 'open', 0, '2025-10-30 09:17:35', 1, 43329605667840, 0, 1, NULL);
|
||||
INSERT INTO `im_feed` VALUES (90191368924672, 10937855681024, '你好,测试一下朋友圈吧🤯', 'open', 0, '2025-10-30 21:08:18', 1, 10937855681024, 0, 1, NULL);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for im_feed_media
|
||||
@@ -277,7 +279,7 @@ CREATE TABLE `im_group_member` (
|
||||
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
|
||||
INDEX `idx_update_time`(`update_time` ASC) USING BTREE,
|
||||
INDEX `idx_group_member_uid_isdel_groupid`(`uid` ASC, `is_del` ASC, `group_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 89400339964930 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '群成员表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90516414902273 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '群成员表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of im_group_member
|
||||
@@ -340,7 +342,7 @@ CREATE TABLE `im_message` (
|
||||
INDEX `idx_from_uid`(`from_uid` ASC) USING BTREE,
|
||||
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
|
||||
INDEX `idx_update_time`(`update_time` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 89403284366339 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90516414902274 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of im_message
|
||||
@@ -370,7 +372,7 @@ CREATE TABLE `im_message_mark` (
|
||||
INDEX `idx_uid`(`uid` ASC) USING BTREE,
|
||||
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
|
||||
INDEX `idx_update_time`(`update_time` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 89397676581889 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息标记表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90188940422657 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息标记表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of im_message_mark
|
||||
@@ -402,7 +404,7 @@ CREATE TABLE `im_notice` (
|
||||
INDEX `idx_receiver_type`(`receiver_id` ASC, `event_type` ASC) USING BTREE,
|
||||
INDEX `idx_sender`(`sender_id` ASC) USING BTREE,
|
||||
INDEX `idx_related`(`apply_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 89403246617603 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '统一通知表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90516389736451 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '统一通知表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of im_notice
|
||||
@@ -452,12 +454,12 @@ CREATE TABLE `im_room` (
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
|
||||
INDEX `idx_update_time`(`update_time` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 89400339964931 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '房间表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90505799118849 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '房间表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of im_room
|
||||
-- ----------------------------
|
||||
INSERT INTO `im_room` VALUES (1, 1, 1, '2025-10-28 16:45:02.174', 89400339964935, NULL, '2024-07-10 11:17:15.521', '2025-10-28 08:45:02.398', 1, 1, NULL, 0);
|
||||
INSERT INTO `im_room` VALUES (1, 1, 1, '2025-10-31 17:41:26.004', 90501697089536, NULL, '2024-07-10 11:17:15.521', '2025-10-31 09:41:26.041', 1, 1, NULL, 0);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for im_room_friend
|
||||
@@ -482,7 +484,7 @@ CREATE TABLE `im_room_friend` (
|
||||
INDEX `idx_room_id`(`room_id` ASC) USING BTREE,
|
||||
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
|
||||
INDEX `idx_update_time`(`update_time` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 89400339964932 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '单聊房间表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90505799118850 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '单聊房间表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of im_room_friend
|
||||
@@ -511,7 +513,7 @@ CREATE TABLE `im_room_group` (
|
||||
INDEX `idx_room_id`(`room_id` ASC) USING BTREE,
|
||||
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
|
||||
INDEX `idx_update_time`(`update_time` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 89398838404099 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '群聊房间表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90207575715331 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '群聊房间表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of im_room_group
|
||||
@@ -594,13 +596,13 @@ CREATE TABLE `im_user` (
|
||||
INDEX `idx_update_time`(`update_time` ASC) USING BTREE,
|
||||
INDEX `idx_active_status_last_opt_time`(`last_opt_time` ASC) USING BTREE,
|
||||
INDEX `account_UNIQUE`(`account` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 89400339964929 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90501692895233 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of im_user
|
||||
-- ----------------------------
|
||||
INSERT INTO `im_user` VALUES (1, 61170828519936, 2, 'HuLa小管家', '022', '', 'bot', NULL, '', 0, '2025-07-07 15:27:01.711', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"120.231.232.41\", \"createIpDetail\": {\"ip\": \"206.237.119.215\", \"isp\": \"\", \"area\": \"\", \"city\": \"\", \"isp_id\": \"\", \"region\": \"\", \"city_id\": \"\", \"country\": \"美国\", \"region_id\": \"\", \"country_id\": \"US\"}, \"updateIpDetail\": {\"ip\": \"120.231.232.41\", \"isp\": \"移动\", \"area\": \"\", \"city\": \"\", \"isp_id\": \"100025\", \"region\": \"广东\", \"city_id\": \"\", \"country\": \"中国\", \"region_id\": \"440000\", \"country_id\": \"CN\"}}', 6, 0, '', '2025-03-27 04:23:08.393', '2025-10-11 10:14:24.150', 'k.23772439646234', 0, NULL, 0, '2025-05-09 18:24:37.089', 99978, 0, 1);
|
||||
INSERT INTO `im_user` VALUES (10937855681024, 61170828519937, 3, 'Dawn', 'https://cdn.hulaspark.com/avatar/2439646234/97320189485dca88dcc7a70054445a56.webp', '2439646234@qq.com', '2439646234', NULL, '', 15, '2025-07-30 15:31:57.651', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"183.15.179.234\", \"createIpDetail\": null, \"updateIpDetail\": {\"ip\": \"183.15.179.234\", \"isp\": \"电信\", \"area\": \"\", \"city\": \"深圳\", \"isp_id\": \"100017\", \"region\": \"广东\", \"city_id\": \"440300\", \"country\": \"中国\", \"region_id\": \"440000\", \"country_id\": \"CN\"}}', 6, 0, '', '2025-03-27 04:23:08.393', '2025-10-28 16:08:55.831', 'k.2439646234', 0, NULL, 0, '2025-09-20 21:35:31.415', 99978, 0, 1);
|
||||
INSERT INTO `im_user` VALUES (10937855681024, 61170828519937, 3, 'Dawn', 'https://cdn.hulaspark.com/avatar/2439646234/97320189485dca88dcc7a70054445a56.webp', '2439646234@qq.com', '2439646234', NULL, '', 15, '2025-07-30 15:31:57.651', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"183.15.179.234\", \"createIpDetail\": null, \"updateIpDetail\": {\"ip\": \"183.15.179.234\", \"isp\": \"电信\", \"area\": \"\", \"city\": \"深圳\", \"isp_id\": \"100017\", \"region\": \"广东\", \"city_id\": \"440300\", \"country\": \"中国\", \"region_id\": \"440000\", \"country_id\": \"CN\"}}', 6, 0, '', '2025-03-27 04:23:08.393', '2025-10-31 14:03:50.763', 'k.2439646234', 0, NULL, 0, '2025-09-20 21:35:31.415', 99978, 0, 1);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for im_user_apply
|
||||
@@ -629,7 +631,7 @@ CREATE TABLE `im_user_apply` (
|
||||
INDEX `idx_target_id`(`target_id` ASC) USING BTREE,
|
||||
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
|
||||
INDEX `idx_update_time`(`update_time` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 89403246617601 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户申请表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90516389736449 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户申请表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of im_user_apply
|
||||
@@ -656,7 +658,7 @@ CREATE TABLE `im_user_backpack` (
|
||||
INDEX `idx_uid`(`uid` ASC) USING BTREE,
|
||||
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
|
||||
INDEX `idx_update_time`(`update_time` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 89400339964939 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户背包表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90501697089540 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户背包表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of im_user_backpack
|
||||
@@ -699,7 +701,7 @@ CREATE TABLE `im_user_emoji` (
|
||||
`update_by` bigint NULL DEFAULT NULL COMMENT '更新者',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `IDX_USER_EMOJIS_UID`(`uid` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 86588445005313 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表情包' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90111324826625 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表情包' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of im_user_emoji
|
||||
@@ -732,7 +734,7 @@ CREATE TABLE `im_user_friend` (
|
||||
INDEX `idx_uid_friend_uid`(`uid` ASC, `friend_uid` ASC) USING BTREE,
|
||||
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
|
||||
INDEX `idx_update_time`(`update_time` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 89403284366338 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户联系人表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90505799118852 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户联系人表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of im_user_friend
|
||||
@@ -910,7 +912,7 @@ CREATE TABLE `secure_invoke_record` (
|
||||
`is_del` tinyint NOT NULL DEFAULT 0 COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_next_retry_time`(`next_retry_time` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 89403284366340 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '本地消息表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90516414902275 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '本地消息表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of secure_invoke_record
|
||||
@@ -929,7 +931,7 @@ CREATE TABLE `worker_node` (
|
||||
`modified` timestamp NULL DEFAULT NULL COMMENT '修改时间',
|
||||
`created` timestamp NULL DEFAULT NULL COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 211 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'DB;WorkerID Assigner for UID Generator' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 217 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'DB;WorkerID Assigner for UID Generator' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of worker_node
|
||||
|
||||
@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import com.luohuo.flex.ai.common.pojo.PageResult;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.conversation.AiChatConversationCreateMyReqVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.conversation.AiDelReqVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.conversation.AiChatConversationPageReqVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.conversation.AiChatConversationRespVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.conversation.AiChatConversationUpdateMyReqVO;
|
||||
@@ -40,7 +41,7 @@ public class AiChatConversationController {
|
||||
|
||||
@PostMapping("/create-my")
|
||||
@Operation(summary = "创建【我的】聊天对话")
|
||||
public R<Long> createChatConversationMy(@RequestBody @Valid AiChatConversationCreateMyReqVO createReqVO) {
|
||||
public R<AiChatConversationDO> createChatConversationMy(@RequestBody @Valid AiChatConversationCreateMyReqVO createReqVO) {
|
||||
return success(chatConversationService.createChatConversationMy(createReqVO, ContextUtil.getUid()));
|
||||
}
|
||||
|
||||
@@ -71,9 +72,8 @@ public class AiChatConversationController {
|
||||
|
||||
@DeleteMapping("/delete-my")
|
||||
@Operation(summary = "删除聊天对话")
|
||||
@Parameter(name = "id", required = true, description = "对话编号", example = "1024")
|
||||
public R<Boolean> deleteChatConversationMy(@RequestParam("id") Long id) {
|
||||
chatConversationService.deleteChatConversationMy(id, ContextUtil.getUid());
|
||||
public R<Boolean> deleteChatConversationMy(@RequestBody AiDelReqVO reqVO) {
|
||||
chatConversationService.deleteChatConversationMy(reqVO, ContextUtil.getUid());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import com.luohuo.basic.context.ContextUtil;
|
||||
import com.luohuo.flex.ai.common.pojo.PageResult;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.conversation.AiDelReqVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.message.AiChatMessagePageReqVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.message.AiChatMessageRespVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.message.AiChatMessageSendReqVO;
|
||||
@@ -78,8 +79,7 @@ public class AiChatMessageController {
|
||||
@Operation(summary = "获得指定对话的消息列表")
|
||||
@GetMapping("/list-by-conversation-id")
|
||||
@Parameter(name = "conversationId", required = true, description = "对话编号", example = "1024")
|
||||
public R<List<AiChatMessageRespVO>> getChatMessageListByConversationId(
|
||||
@RequestParam("conversationId") Long conversationId) {
|
||||
public R<List<AiChatMessageRespVO>> getChatMessageListByConversationId(@RequestParam("conversationId") Long conversationId) {
|
||||
AiChatConversationDO conversation = chatConversationService.getChatConversation(conversationId);
|
||||
if (conversation == null || ObjUtil.notEqual(conversation.getUserId(), ContextUtil.getUid())) {
|
||||
return success(Collections.emptyList());
|
||||
@@ -129,8 +129,8 @@ public class AiChatMessageController {
|
||||
@Operation(summary = "删除指定对话的消息")
|
||||
@DeleteMapping("/delete-by-conversation-id")
|
||||
@Parameter(name = "conversationId", required = true, description = "对话编号", example = "1024")
|
||||
public R<Boolean> deleteChatMessageByConversationId(@RequestParam("conversationId") Long conversationId) {
|
||||
chatMessageService.deleteChatMessageByConversationId(conversationId, ContextUtil.getUid());
|
||||
public R<Boolean> deleteChatMessageByConversationId(@RequestBody AiDelReqVO reqVOS) {
|
||||
chatMessageService.deleteChatMessageByConversationId(reqVOS, ContextUtil.getUid());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.luohuo.flex.ai.controller.chat.vo.conversation;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "会话id")
|
||||
@Data
|
||||
public class AiDelReqVO {
|
||||
|
||||
@Schema(description = "会话id", example = "1")
|
||||
private List<Long> conversationIdList;
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import com.luohuo.flex.ai.dal.model.AiApiKeyDO;
|
||||
import com.luohuo.flex.ai.service.model.AiApiKeyService;
|
||||
import com.luohuo.flex.ai.utils.BeanUtils;
|
||||
import com.luohuo.basic.base.R;
|
||||
import com.luohuo.basic.context.ContextUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@@ -35,13 +36,13 @@ public class AiApiKeyController {
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建 API 密钥")
|
||||
public R<Long> createApiKey(@Valid @RequestBody AiApiKeySaveReqVO createReqVO) {
|
||||
return success(apiKeyService.createApiKey(createReqVO));
|
||||
return success(apiKeyService.createApiKey(createReqVO, ContextUtil.getUid()));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新 API 密钥")
|
||||
public R<Boolean> updateApiKey(@Valid @RequestBody AiApiKeySaveReqVO updateReqVO) {
|
||||
apiKeyService.updateApiKey(updateReqVO);
|
||||
apiKeyService.updateApiKey(updateReqVO, ContextUtil.getUid());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@@ -49,7 +50,7 @@ public class AiApiKeyController {
|
||||
@Operation(summary = "删除 API 密钥")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
public R<Boolean> deleteApiKey(@RequestParam("id") Long id) {
|
||||
apiKeyService.deleteApiKey(id);
|
||||
apiKeyService.deleteApiKey(id, ContextUtil.getUid());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@@ -62,9 +63,9 @@ public class AiApiKeyController {
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得 API 密钥分页")
|
||||
@Operation(summary = "获得 API 密钥分页(包含系统公开密钥和用户私有密钥)")
|
||||
public R<PageResult<AiApiKeyRespVO>> getApiKeyPage(@Valid AiApiKeyPageReqVO pageReqVO) {
|
||||
PageResult<AiApiKeyDO> pageResult = apiKeyService.getApiKeyPage(pageReqVO);
|
||||
PageResult<AiApiKeyDO> pageResult = apiKeyService.getApiKeyPage(pageReqVO, ContextUtil.getUid());
|
||||
return success(BeanUtils.toBean(pageResult, AiApiKeyRespVO.class));
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.luohuo.basic.base.R.success;
|
||||
|
||||
@@ -33,63 +34,36 @@ public class AiChatRoleController {
|
||||
@Resource
|
||||
private AiChatRoleService chatRoleService;
|
||||
|
||||
@GetMapping("/my-page")
|
||||
@Operation(summary = "获得【我的】聊天角色分页")
|
||||
public R<PageResult<AiChatRoleRespVO>> getChatRoleMyPage(@Valid AiChatRolePageReqVO pageReqVO) {
|
||||
PageResult<AiChatRoleDO> pageResult = chatRoleService.getChatRoleMyPage(pageReqVO, ContextUtil.getUid());
|
||||
return success(BeanUtils.toBean(pageResult, AiChatRoleRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get-my")
|
||||
@Operation(summary = "获得【我的】聊天角色")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
public R<AiChatRoleRespVO> getChatRoleMy(@RequestParam("id") Long id) {
|
||||
AiChatRoleDO chatRole = chatRoleService.getChatRole(id);
|
||||
if (ObjUtil.notEqual(chatRole.getUserId(), ContextUtil.getUid())) {
|
||||
return success(null);
|
||||
}
|
||||
return success(BeanUtils.toBean(chatRole, AiChatRoleRespVO.class));
|
||||
}
|
||||
|
||||
@PostMapping("/create-my")
|
||||
@Operation(summary = "创建【我的】聊天角色")
|
||||
public R<Long> createChatRoleMy(@Valid @RequestBody AiChatRoleSaveMyReqVO createReqVO) {
|
||||
return success(chatRoleService.createChatRoleMy(createReqVO, ContextUtil.getUid()));
|
||||
}
|
||||
|
||||
@PutMapping("/update-my")
|
||||
@Operation(summary = "更新【我的】聊天角色")
|
||||
public R<Boolean> updateChatRoleMy(@Valid @RequestBody AiChatRoleSaveMyReqVO updateReqVO) {
|
||||
chatRoleService.updateChatRoleMy(updateReqVO, ContextUtil.getUid());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-my")
|
||||
@Operation(summary = "删除【我的】聊天角色")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
public R<Boolean> deleteChatRoleMy(@RequestParam("id") Long id) {
|
||||
chatRoleService.deleteChatRoleMy(id, ContextUtil.getUid());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/category-list")
|
||||
@Operation(summary = "获得聊天角色的分类列表")
|
||||
public R<List<String>> getChatRoleCategoryList() {
|
||||
return success(chatRoleService.getChatRoleCategoryList());
|
||||
}
|
||||
|
||||
// ========== 角色管理 ==========
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建聊天角色")
|
||||
public R<Long> createChatRole(@Valid @RequestBody AiChatRoleSaveReqVO createReqVO) {
|
||||
if (createReqVO.getPublicStatus() == null || Boolean.FALSE.equals(createReqVO.getPublicStatus())) {
|
||||
AiChatRoleSaveMyReqVO myReqVO = BeanUtils.toBean(createReqVO, AiChatRoleSaveMyReqVO.class);
|
||||
return success(chatRoleService.createChatRoleMy(myReqVO, ContextUtil.getUid()));
|
||||
}
|
||||
// 管理员创建公开角色
|
||||
return success(chatRoleService.createChatRole(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新聊天角色")
|
||||
public R<Boolean> updateChatRole(@Valid @RequestBody AiChatRoleSaveReqVO updateReqVO) {
|
||||
chatRoleService.updateChatRole(updateReqVO);
|
||||
AiChatRoleDO chatRole = chatRoleService.getChatRole(updateReqVO.getId());
|
||||
if (chatRole == null) {
|
||||
return success(false);
|
||||
}
|
||||
|
||||
Long uid = ContextUtil.getUid();
|
||||
if (Boolean.FALSE.equals(chatRole.getPublicStatus())) {
|
||||
if (ObjUtil.notEqual(chatRole.getUserId(), uid)) {
|
||||
return success(false); // 无权限
|
||||
}
|
||||
chatRoleService.updateChatRoleMy(updateReqVO, uid);
|
||||
} else {
|
||||
if (uid < 10937855681025L) {
|
||||
chatRoleService.updateChatRole(updateReqVO);
|
||||
}
|
||||
}
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@@ -97,7 +71,22 @@ public class AiChatRoleController {
|
||||
@Operation(summary = "删除聊天角色")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
public R<Boolean> deleteChatRole(@RequestParam("id") Long id) {
|
||||
chatRoleService.deleteChatRole(id);
|
||||
AiChatRoleDO chatRole = chatRoleService.getChatRole(id);
|
||||
if (chatRole == null) {
|
||||
return success(false);
|
||||
}
|
||||
|
||||
Long uid = ContextUtil.getUid();
|
||||
if (Boolean.FALSE.equals(chatRole.getPublicStatus())) {
|
||||
if (ObjUtil.notEqual(chatRole.getUserId(), uid)) {
|
||||
return success(false); // 无权限
|
||||
}
|
||||
chatRoleService.deleteChatRoleMy(id, uid);
|
||||
} else {
|
||||
if (uid < 10937855681025L) {
|
||||
chatRoleService.deleteChatRole(id);
|
||||
}
|
||||
}
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@@ -110,10 +99,16 @@ public class AiChatRoleController {
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得聊天角色分页")
|
||||
@Operation(summary = "获得聊天角色分页(包含系统公开角色和用户私有角色)")
|
||||
public R<PageResult<AiChatRoleRespVO>> getChatRolePage(@Valid AiChatRolePageReqVO pageReqVO) {
|
||||
PageResult<AiChatRoleDO> pageResult = chatRoleService.getChatRolePage(pageReqVO);
|
||||
PageResult<AiChatRoleDO> pageResult = chatRoleService.getChatRoleMyPage(pageReqVO, ContextUtil.getUid());
|
||||
return success(BeanUtils.toBean(pageResult, AiChatRoleRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/category-list")
|
||||
@Operation(summary = "获得聊天角色的分类列表")
|
||||
public R<List<Map<String, String>>> getChatRoleCategoryList() {
|
||||
return success(chatRoleService.getChatRoleCategoryList());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
package com.luohuo.flex.ai.controller.model;
|
||||
|
||||
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import com.luohuo.flex.ai.common.pojo.PageResult;
|
||||
import com.luohuo.flex.ai.controller.model.vo.model.AiModelPageReqVO;
|
||||
import com.luohuo.flex.ai.controller.model.vo.model.AiModelRespVO;
|
||||
import com.luohuo.flex.ai.controller.model.vo.model.AiModelSaveMyReqVO;
|
||||
import com.luohuo.flex.ai.controller.model.vo.model.AiModelSaveReqVO;
|
||||
import com.luohuo.flex.ai.dal.model.AiModelDO;
|
||||
import com.luohuo.flex.ai.enums.CommonStatusEnum;
|
||||
import com.luohuo.flex.ai.service.model.AiModelService;
|
||||
import com.luohuo.flex.ai.utils.BeanUtils;
|
||||
import com.luohuo.basic.base.R;
|
||||
import com.luohuo.basic.context.ContextUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@@ -23,63 +25,94 @@ import java.util.List;
|
||||
import static com.luohuo.basic.base.R.success;
|
||||
import static com.luohuo.basic.utils.collection.CollectionUtils.convertList;
|
||||
|
||||
|
||||
@Tag(name = "管理后台 - AI 模型")
|
||||
@RestController
|
||||
@RequestMapping("/model")
|
||||
@Validated
|
||||
public class AiModelController {
|
||||
|
||||
@Resource
|
||||
private AiModelService modelService;
|
||||
@Resource
|
||||
private AiModelService modelService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建模型")
|
||||
public R<Long> createModel(@Valid @RequestBody AiModelSaveReqVO createReqVO) {
|
||||
return success(modelService.createModel(createReqVO));
|
||||
}
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建模型")
|
||||
public R<Long> createModel(@Valid @RequestBody AiModelSaveReqVO createReqVO) {
|
||||
if (createReqVO.getPublicStatus() == null || !createReqVO.getPublicStatus()) {
|
||||
AiModelSaveMyReqVO myReqVO = BeanUtils.toBean(createReqVO, AiModelSaveMyReqVO.class);
|
||||
return success(modelService.createModelMy(myReqVO, ContextUtil.getUid()));
|
||||
}
|
||||
return success(modelService.createModel(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新模型")
|
||||
public R<Boolean> updateModel(@Valid @RequestBody AiModelSaveReqVO updateReqVO) {
|
||||
modelService.updateModel(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新模型")
|
||||
public R<Boolean> updateModel(@Valid @RequestBody AiModelSaveReqVO updateReqVO) {
|
||||
AiModelDO model = modelService.getModel(updateReqVO.getId());
|
||||
if (model == null) {
|
||||
return success(false);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除模型")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
public R<Boolean> deleteModel(@RequestParam("id") Long id) {
|
||||
modelService.deleteModel(id);
|
||||
return success(true);
|
||||
}
|
||||
Long uid = ContextUtil.getUid();
|
||||
if (Boolean.FALSE.equals(model.getPublicStatus())) {
|
||||
if (ObjUtil.notEqual(model.getUserId(), uid)) {
|
||||
return success(false); // 无权限
|
||||
}
|
||||
AiModelSaveMyReqVO myReqVO = BeanUtils.toBean(updateReqVO, AiModelSaveMyReqVO.class);
|
||||
modelService.updateModelMy(myReqVO, ContextUtil.getUid());
|
||||
} else {
|
||||
if (uid < 10937855681025L){
|
||||
modelService.updateModel(updateReqVO);
|
||||
}
|
||||
}
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得模型")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
public R<AiModelRespVO> getModel(@RequestParam("id") Long id) {
|
||||
AiModelDO model = modelService.getModel(id);
|
||||
return success(BeanUtils.toBean(model, AiModelRespVO.class));
|
||||
}
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除模型")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
public R<Boolean> deleteModel(@RequestParam("id") Long id) {
|
||||
AiModelDO model = modelService.getModel(id);
|
||||
if (model == null) {
|
||||
return success(false);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得模型分页")
|
||||
public R<PageResult<AiModelRespVO>> getModelPage(@Valid AiModelPageReqVO pageReqVO) {
|
||||
PageResult<AiModelDO> pageResult = modelService.getModelPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiModelRespVO.class));
|
||||
}
|
||||
Long uid = ContextUtil.getUid();
|
||||
if (Boolean.FALSE.equals(model.getPublicStatus())) {
|
||||
if (ObjUtil.notEqual(model.getUserId(), uid)) {
|
||||
return success(false); // 无权限
|
||||
}
|
||||
modelService.deleteModelMy(id, ContextUtil.getUid());
|
||||
} else {
|
||||
if (uid < 10937855681025L){
|
||||
modelService.deleteModel(id);
|
||||
}
|
||||
}
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/simple-list")
|
||||
@Operation(summary = "获得模型列表")
|
||||
@Parameter(name = "type", description = "类型", required = true, example = "1")
|
||||
@Parameter(name = "platform", description = "平台", example = "midjourney")
|
||||
public R<List<AiModelRespVO>> getModelSimpleList(
|
||||
@RequestParam("type") Integer type,
|
||||
@RequestParam(value = "platform", required = false) String platform) {
|
||||
List<AiModelDO> list = modelService.getModelListByStatusAndType(
|
||||
CommonStatusEnum.ENABLE.getStatus(), type, platform);
|
||||
return success(convertList(list, model -> new AiModelRespVO().setId(model.getId())
|
||||
.setName(model.getName()).setModel(model.getModel()).setPlatform(model.getPlatform())));
|
||||
}
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得模型")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
public R<AiModelRespVO> getModel(@RequestParam("id") Long id) {
|
||||
AiModelDO model = modelService.getModel(id);
|
||||
return success(BeanUtils.toBean(model, AiModelRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得模型分页(包含系统公开模型和用户私有模型)")
|
||||
public R<PageResult<AiModelRespVO>> getModelPage(@Valid AiModelPageReqVO pageReqVO) {
|
||||
PageResult<AiModelDO> pageResult = modelService.getModelMyPage(pageReqVO, ContextUtil.getUid());
|
||||
return success(BeanUtils.toBean(pageResult, AiModelRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/simple-list")
|
||||
@Operation(summary = "获得模型列表(包含系统公开模型和用户私有模型)")
|
||||
@Parameter(name = "type", description = "类型", required = true, example = "1")
|
||||
@Parameter(name = "platform", description = "平台", example = "midjourney")
|
||||
public R<List<AiModelRespVO>> getModelSimpleList(@RequestParam("type") Integer type, @RequestParam(value = "platform", required = false) String platform) {
|
||||
List<AiModelDO> list = modelService.getModelListByStatusAndTypeAndUserId(CommonStatusEnum.ENABLE.getStatus(), type, platform, ContextUtil.getUid());
|
||||
return success(convertList(list, model -> new AiModelRespVO().setId(model.getId())
|
||||
.setName(model.getName()).setModel(model.getModel()).setPlatform(model.getPlatform())));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,4 +17,7 @@ public class AiApiKeyPageReqVO extends PageParam {
|
||||
@Schema(description = "状态", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "是否公开", example = "true")
|
||||
private Boolean publicStatus;
|
||||
|
||||
}
|
||||
@@ -25,4 +25,5 @@ public class AiApiKeyRespVO {
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
private Boolean publicStatus;
|
||||
}
|
||||
@@ -31,4 +31,7 @@ public class AiApiKeySaveReqVO {
|
||||
@NotNull(message = "状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "是否公开", example = "false")
|
||||
private Boolean publicStatus;
|
||||
|
||||
}
|
||||
@@ -18,6 +18,8 @@ public class AiChatRoleSaveMyReqVO {
|
||||
@NotEmpty(message = "角色名称不能为空")
|
||||
private String name;
|
||||
|
||||
private String category;
|
||||
|
||||
@Schema(description = "角色头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
|
||||
@NotEmpty(message = "角色头像不能为空")
|
||||
@URL(message = "角色头像必须是 URL 格式")
|
||||
@@ -37,4 +39,6 @@ public class AiChatRoleSaveMyReqVO {
|
||||
@Schema(description = "引用的工具编号列表", example = "1,2,3")
|
||||
private List<Long> toolIds;
|
||||
|
||||
@Schema(description = "模型id", example = "1")
|
||||
private Long modelId;
|
||||
}
|
||||
@@ -17,4 +17,7 @@ public class AiModelPageReqVO extends PageParam {
|
||||
@Schema(description = "模型平台", example = "OpenAI")
|
||||
private String platform;
|
||||
|
||||
@Schema(description = "是否公开", example = "true")
|
||||
private Boolean publicStatus;
|
||||
|
||||
}
|
||||
@@ -47,4 +47,7 @@ public class AiModelRespVO {
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "是否公开", example = "false")
|
||||
private Boolean publicStatus;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.luohuo.flex.ai.controller.model.vo.model;
|
||||
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - API 模型新增/修改【我的】 Request VO")
|
||||
@Data
|
||||
public class AiModelSaveMyReqVO {
|
||||
|
||||
@Schema(description = "编号", example = "2630")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "API 秘钥编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22042")
|
||||
@NotNull(message = "API 秘钥编号不能为空")
|
||||
private Long keyId;
|
||||
|
||||
@Schema(description = "模型名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
|
||||
@NotEmpty(message = "模型名字不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "模型标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "gpt-3.5-turbo-0125")
|
||||
@NotEmpty(message = "模型标识不能为空")
|
||||
private String model;
|
||||
|
||||
@Schema(description = "模型平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "OpenAI")
|
||||
@NotEmpty(message = "模型平台不能为空")
|
||||
private String platform;
|
||||
|
||||
@Schema(description = "模型类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "模型类型不能为空")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "排序", example = "1")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "温度参数", example = "1")
|
||||
private Double temperature;
|
||||
|
||||
@Schema(description = "单条回复的最大 Token 数量", example = "4096")
|
||||
private Integer maxTokens;
|
||||
|
||||
@Schema(description = "上下文的最大 Message 数量", example = "8192")
|
||||
private Integer maxContexts;
|
||||
|
||||
}
|
||||
@@ -50,4 +50,7 @@ public class AiModelSaveReqVO {
|
||||
@Schema(description = "上下文的最大 Message 数量", example = "8192")
|
||||
private Integer maxContexts;
|
||||
|
||||
@Schema(description = "是否公开", example = "false")
|
||||
private Boolean publicStatus;
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package com.luohuo.flex.ai.controller;
|
||||
@@ -8,6 +8,7 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* AI API 秘钥 DO
|
||||
@@ -19,6 +20,7 @@ import lombok.NoArgsConstructor;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class AiApiKeyDO extends BaseDO {
|
||||
|
||||
/**
|
||||
@@ -26,6 +28,13 @@ public class AiApiKeyDO extends BaseDO {
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*
|
||||
* 关联 AdminUserDO 的 userId 字段
|
||||
*/
|
||||
private Long userId;
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
@@ -51,4 +60,12 @@ public class AiApiKeyDO extends BaseDO {
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 是否公开
|
||||
*
|
||||
* 1. true - 公开;由管理员在【API 秘钥管理】所创建
|
||||
* 2. false - 私有;由个人在【我的 API 秘钥】所创建
|
||||
*/
|
||||
private Boolean publicStatus;
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* AI 模型 DO
|
||||
@@ -23,6 +24,7 @@ import lombok.NoArgsConstructor;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class AiModelDO extends BaseDO {
|
||||
|
||||
/**
|
||||
@@ -30,6 +32,14 @@ public class AiModelDO extends BaseDO {
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*
|
||||
* 关联 AdminUserDO 的 userId 字段
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* API 秘钥编号
|
||||
*
|
||||
@@ -68,6 +78,14 @@ public class AiModelDO extends BaseDO {
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 是否公开
|
||||
*
|
||||
* 1. true - 公开;系统级别模型,所有用户可见
|
||||
* 2. false - 私有;用户专属模型,仅创建者可见
|
||||
*/
|
||||
private Boolean publicStatus;
|
||||
|
||||
// ========== 对话配置 ==========
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,20 +16,48 @@ import org.springframework.stereotype.Repository;
|
||||
@Repository
|
||||
public interface AiApiKeyMapper extends BaseMapperX<AiApiKeyDO> {
|
||||
|
||||
default PageResult<AiApiKeyDO> selectPage(AiApiKeyPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<AiApiKeyDO>()
|
||||
.likeIfPresent(AiApiKeyDO::getName, reqVO.getName())
|
||||
.eqIfPresent(AiApiKeyDO::getPlatform, reqVO.getPlatform())
|
||||
.eqIfPresent(AiApiKeyDO::getStatus, reqVO.getStatus())
|
||||
.orderByDesc(AiApiKeyDO::getId));
|
||||
}
|
||||
default PageResult<AiApiKeyDO> selectPage(AiApiKeyPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<AiApiKeyDO>()
|
||||
.likeIfPresent(AiApiKeyDO::getName, reqVO.getName())
|
||||
.eqIfPresent(AiApiKeyDO::getPlatform, reqVO.getPlatform())
|
||||
.eqIfPresent(AiApiKeyDO::getStatus, reqVO.getStatus())
|
||||
.eqIfPresent(AiApiKeyDO::getPublicStatus, reqVO.getPublicStatus())
|
||||
.orderByDesc(AiApiKeyDO::getId));
|
||||
}
|
||||
|
||||
default AiApiKeyDO selectFirstByPlatformAndStatus(String platform, Integer status) {
|
||||
return selectOne(new QueryWrapperX<AiApiKeyDO>()
|
||||
.eq("platform", platform)
|
||||
.eq("status", status)
|
||||
.limitN(1)
|
||||
.orderByAsc("id"));
|
||||
}
|
||||
default PageResult<AiApiKeyDO> selectPageByMy(AiApiKeyPageReqVO reqVO, Long userId) {
|
||||
LambdaQueryWrapperX<AiApiKeyDO> wrapper = new LambdaQueryWrapperX<AiApiKeyDO>()
|
||||
.likeIfPresent(AiApiKeyDO::getName, reqVO.getName())
|
||||
.eqIfPresent(AiApiKeyDO::getPlatform, reqVO.getPlatform())
|
||||
.eqIfPresent(AiApiKeyDO::getStatus, reqVO.getStatus());
|
||||
|
||||
// 根据 publicStatus 参数决定查询范围
|
||||
if (reqVO.getPublicStatus() == null) {
|
||||
// 未指定:返回所有公开密钥 + 用户私有密钥
|
||||
wrapper.and(w -> w
|
||||
.eq(AiApiKeyDO::getPublicStatus, true)
|
||||
.or()
|
||||
.eq(AiApiKeyDO::getUserId, userId)
|
||||
);
|
||||
} else if (Boolean.TRUE.equals(reqVO.getPublicStatus())) {
|
||||
// 只查询公开密钥
|
||||
wrapper.eq(AiApiKeyDO::getPublicStatus, true);
|
||||
} else {
|
||||
// 只查询用户私有密钥
|
||||
wrapper.eq(AiApiKeyDO::getUserId, userId)
|
||||
.eq(AiApiKeyDO::getPublicStatus, false);
|
||||
}
|
||||
|
||||
wrapper.orderByDesc(AiApiKeyDO::getId);
|
||||
return selectPage(reqVO, wrapper);
|
||||
}
|
||||
|
||||
default AiApiKeyDO selectFirstByPlatformAndStatus(String platform, Integer status) {
|
||||
return selectOne(new QueryWrapperX<AiApiKeyDO>()
|
||||
.eq("platform", platform)
|
||||
.eq("status", status)
|
||||
.limitN(1)
|
||||
.orderByAsc("id"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,29 +17,74 @@ import java.util.List;
|
||||
@Repository
|
||||
public interface AiChatMapper extends BaseMapperX<AiModelDO> {
|
||||
|
||||
default AiModelDO selectFirstByStatus(Integer type, Integer status) {
|
||||
return selectOne(new QueryWrapperX<AiModelDO>()
|
||||
.eq("type", type)
|
||||
.eq("status", status)
|
||||
.limitN(1)
|
||||
.orderByAsc("sort"));
|
||||
}
|
||||
default AiModelDO selectFirstByStatus(Integer type, Integer status) {
|
||||
return selectOne(new QueryWrapperX<AiModelDO>()
|
||||
.eq("type", type)
|
||||
.eq("status", status)
|
||||
.limitN(1)
|
||||
.orderByAsc("sort"));
|
||||
}
|
||||
|
||||
default PageResult<AiModelDO> selectPage(AiModelPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<AiModelDO>()
|
||||
.likeIfPresent(AiModelDO::getName, reqVO.getName())
|
||||
.eqIfPresent(AiModelDO::getModel, reqVO.getModel())
|
||||
.eqIfPresent(AiModelDO::getPlatform, reqVO.getPlatform())
|
||||
.orderByAsc(AiModelDO::getSort));
|
||||
}
|
||||
default PageResult<AiModelDO> selectPage(AiModelPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<AiModelDO>()
|
||||
.likeIfPresent(AiModelDO::getName, reqVO.getName())
|
||||
.eqIfPresent(AiModelDO::getModel, reqVO.getModel())
|
||||
.eqIfPresent(AiModelDO::getPlatform, reqVO.getPlatform())
|
||||
.eqIfPresent(AiModelDO::getPublicStatus, reqVO.getPublicStatus())
|
||||
.orderByAsc(AiModelDO::getSort));
|
||||
}
|
||||
|
||||
default List<AiModelDO> selectListByStatusAndType(Integer status, Integer type,
|
||||
@Nullable String platform) {
|
||||
return selectList(new LambdaQueryWrapperX<AiModelDO>()
|
||||
.eq(AiModelDO::getStatus, status)
|
||||
.eq(AiModelDO::getType, type)
|
||||
.eqIfPresent(AiModelDO::getPlatform, platform)
|
||||
.orderByAsc(AiModelDO::getSort));
|
||||
}
|
||||
default PageResult<AiModelDO> selectPageByMy(AiModelPageReqVO reqVO, Long userId) {
|
||||
LambdaQueryWrapperX<AiModelDO> wrapper = new LambdaQueryWrapperX<AiModelDO>()
|
||||
.likeIfPresent(AiModelDO::getName, reqVO.getName())
|
||||
.eqIfPresent(AiModelDO::getModel, reqVO.getModel())
|
||||
.eqIfPresent(AiModelDO::getPlatform, reqVO.getPlatform());
|
||||
|
||||
// 根据 publicStatus 参数决定查询范围
|
||||
if (reqVO.getPublicStatus() == null) {
|
||||
// 未指定:返回所有公开模型 + 用户私有模型
|
||||
wrapper.and(w -> w
|
||||
.eq(AiModelDO::getPublicStatus, true)
|
||||
.or()
|
||||
.eq(AiModelDO::getUserId, userId)
|
||||
);
|
||||
} else if (Boolean.TRUE.equals(reqVO.getPublicStatus())) {
|
||||
// 只查询公开模型
|
||||
wrapper.eq(AiModelDO::getPublicStatus, true);
|
||||
} else {
|
||||
// 只查询用户私有模型
|
||||
wrapper.eq(AiModelDO::getUserId, userId)
|
||||
.eq(AiModelDO::getPublicStatus, false);
|
||||
}
|
||||
|
||||
wrapper.orderByAsc(AiModelDO::getSort);
|
||||
return selectPage(reqVO, wrapper);
|
||||
}
|
||||
|
||||
default List<AiModelDO> selectListByStatusAndType(Integer status, Integer type,
|
||||
@Nullable String platform) {
|
||||
return selectList(new LambdaQueryWrapperX<AiModelDO>()
|
||||
.eq(AiModelDO::getStatus, status)
|
||||
.eq(AiModelDO::getType, type)
|
||||
.eqIfPresent(AiModelDO::getPlatform, platform)
|
||||
.orderByAsc(AiModelDO::getSort));
|
||||
}
|
||||
|
||||
default List<AiModelDO> selectListByStatusAndTypeAndUserId(Integer status, Integer type,
|
||||
@Nullable String platform, Long userId) {
|
||||
return selectList(new LambdaQueryWrapperX<AiModelDO>()
|
||||
.eq(AiModelDO::getStatus, status)
|
||||
.eq(AiModelDO::getType, type)
|
||||
.eqIfPresent(AiModelDO::getPlatform, platform)
|
||||
.and(wrapper -> wrapper
|
||||
// 公开模型
|
||||
.eq(AiModelDO::getPublicStatus, true)
|
||||
// 或用户自己的私有模型
|
||||
.or()
|
||||
.eq(AiModelDO::getUserId, userId)
|
||||
.eq(AiModelDO::getPublicStatus, false)
|
||||
)
|
||||
.orderByAsc(AiModelDO::getSort));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,37 +17,51 @@ import java.util.List;
|
||||
@Repository
|
||||
public interface AiChatRoleMapper extends BaseMapperX<AiChatRoleDO> {
|
||||
|
||||
default PageResult<AiChatRoleDO> selectPage(AiChatRolePageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<AiChatRoleDO>()
|
||||
.likeIfPresent(AiChatRoleDO::getName, reqVO.getName())
|
||||
.eqIfPresent(AiChatRoleDO::getCategory, reqVO.getCategory())
|
||||
.eqIfPresent(AiChatRoleDO::getPublicStatus, reqVO.getPublicStatus())
|
||||
.orderByAsc(AiChatRoleDO::getSort));
|
||||
}
|
||||
default PageResult<AiChatRoleDO> selectPage(AiChatRolePageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<AiChatRoleDO>()
|
||||
.likeIfPresent(AiChatRoleDO::getName, reqVO.getName())
|
||||
.eqIfPresent(AiChatRoleDO::getCategory, reqVO.getCategory())
|
||||
.eqIfPresent(AiChatRoleDO::getPublicStatus, reqVO.getPublicStatus())
|
||||
.orderByAsc(AiChatRoleDO::getSort));
|
||||
}
|
||||
|
||||
default PageResult<AiChatRoleDO> selectPageByMy(AiChatRolePageReqVO reqVO, Long userId) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<AiChatRoleDO>()
|
||||
.likeIfPresent(AiChatRoleDO::getName, reqVO.getName())
|
||||
.eqIfPresent(AiChatRoleDO::getCategory, reqVO.getCategory())
|
||||
// 情况一:公开
|
||||
.eq(Boolean.TRUE.equals(reqVO.getPublicStatus()), AiChatRoleDO::getPublicStatus, reqVO.getPublicStatus())
|
||||
// 情况二:私有
|
||||
.eq(Boolean.FALSE.equals(reqVO.getPublicStatus()), AiChatRoleDO::getUserId, userId)
|
||||
.eq(Boolean.FALSE.equals(reqVO.getPublicStatus()), AiChatRoleDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
|
||||
.orderByAsc(AiChatRoleDO::getSort));
|
||||
}
|
||||
default PageResult<AiChatRoleDO> selectPageByMy(AiChatRolePageReqVO reqVO, Long userId) {
|
||||
LambdaQueryWrapperX<AiChatRoleDO> wrapper = new LambdaQueryWrapperX<AiChatRoleDO>()
|
||||
.likeIfPresent(AiChatRoleDO::getName, reqVO.getName())
|
||||
.eqIfPresent(AiChatRoleDO::getCategory, reqVO.getCategory());
|
||||
|
||||
default List<AiChatRoleDO> selectListGroupByCategory(Integer status) {
|
||||
return selectList(new LambdaQueryWrapperX<AiChatRoleDO>()
|
||||
.select(AiChatRoleDO::getCategory)
|
||||
.eq(AiChatRoleDO::getStatus, status)
|
||||
.groupBy(AiChatRoleDO::getCategory));
|
||||
}
|
||||
// 根据 publicStatus 参数决定查询范围
|
||||
if (reqVO.getPublicStatus() == null) {
|
||||
// 未指定:返回所有公开角色 + 用户私有角色
|
||||
wrapper.and(w -> w
|
||||
.eq(AiChatRoleDO::getPublicStatus, true)
|
||||
.or()
|
||||
.eq(AiChatRoleDO::getUserId, userId)
|
||||
);
|
||||
} else if (Boolean.TRUE.equals(reqVO.getPublicStatus())) {
|
||||
// 只查询公开角色
|
||||
wrapper.eq(AiChatRoleDO::getPublicStatus, true);
|
||||
} else {
|
||||
// 只查询用户私有角色
|
||||
wrapper.eq(AiChatRoleDO::getUserId, userId)
|
||||
.eq(AiChatRoleDO::getPublicStatus, false);
|
||||
}
|
||||
|
||||
default List<AiChatRoleDO> selectListByName(String name) {
|
||||
return selectList(new LambdaQueryWrapperX<AiChatRoleDO>()
|
||||
.likeIfPresent(AiChatRoleDO::getName, name)
|
||||
.orderByAsc(AiChatRoleDO::getSort));
|
||||
}
|
||||
wrapper.orderByAsc(AiChatRoleDO::getSort);
|
||||
return selectPage(reqVO, wrapper);
|
||||
}
|
||||
|
||||
}
|
||||
default List<AiChatRoleDO> selectListGroupByCategory(Integer status) {
|
||||
return selectList(new LambdaQueryWrapperX<AiChatRoleDO>()
|
||||
.select(AiChatRoleDO::getCategory)
|
||||
.eq(AiChatRoleDO::getStatus, status)
|
||||
.groupBy(AiChatRoleDO::getCategory));
|
||||
}
|
||||
|
||||
default List<AiChatRoleDO> selectListByName(String name) {
|
||||
return selectList(new LambdaQueryWrapperX<AiChatRoleDO>()
|
||||
.likeIfPresent(AiChatRoleDO::getName, name)
|
||||
.orderByAsc(AiChatRoleDO::getSort));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.luohuo.flex.ai.service.chat;
|
||||
|
||||
import com.luohuo.flex.ai.common.pojo.PageResult;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.conversation.AiChatConversationCreateMyReqVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.conversation.AiDelReqVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.conversation.AiChatConversationPageReqVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.conversation.AiChatConversationUpdateMyReqVO;
|
||||
import com.luohuo.flex.ai.dal.chat.AiChatConversationDO;
|
||||
@@ -21,7 +22,7 @@ public interface AiChatConversationService {
|
||||
* @param userId 用户编号
|
||||
* @return 编号
|
||||
*/
|
||||
Long createChatConversationMy(AiChatConversationCreateMyReqVO createReqVO, Long userId);
|
||||
AiChatConversationDO createChatConversationMy(AiChatConversationCreateMyReqVO createReqVO, Long userId);
|
||||
|
||||
/**
|
||||
* 更新【我的】聊天对话
|
||||
@@ -50,10 +51,10 @@ public interface AiChatConversationService {
|
||||
/**
|
||||
* 删除【我的】聊天对话
|
||||
*
|
||||
* @param id 编号
|
||||
* @param reqVO 编号
|
||||
* @param userId 用户编号
|
||||
*/
|
||||
void deleteChatConversationMy(Long id, Long userId);
|
||||
void deleteChatConversationMy(AiDelReqVO reqVO, Long userId);
|
||||
|
||||
/**
|
||||
* 【管理员】删除聊天对话
|
||||
|
||||
@@ -6,6 +6,7 @@ import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.luohuo.flex.ai.common.pojo.PageResult;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.conversation.AiChatConversationCreateMyReqVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.conversation.AiDelReqVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.conversation.AiChatConversationPageReqVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.conversation.AiChatConversationUpdateMyReqVO;
|
||||
import com.luohuo.flex.ai.dal.chat.AiChatConversationDO;
|
||||
@@ -53,7 +54,7 @@ public class AiChatConversationServiceImpl implements AiChatConversationService
|
||||
private AiKnowledgeService knowledgeService;
|
||||
|
||||
@Override
|
||||
public Long createChatConversationMy(AiChatConversationCreateMyReqVO createReqVO, Long userId) {
|
||||
public AiChatConversationDO createChatConversationMy(AiChatConversationCreateMyReqVO createReqVO, Long userId) {
|
||||
// 1.1 获得 AiChatRoleDO 聊天角色
|
||||
AiChatRoleDO role = createReqVO.getRoleId() != null ? chatRoleService.validateChatRole(createReqVO.getRoleId()) : null;
|
||||
// 1.2 获得 AiModelDO 聊天模型
|
||||
@@ -77,7 +78,7 @@ public class AiChatConversationServiceImpl implements AiChatConversationService
|
||||
conversation.setTitle(AiChatConversationDO.TITLE_DEFAULT);
|
||||
}
|
||||
chatConversationMapper.insert(conversation);
|
||||
return conversation.getId();
|
||||
return conversation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -120,14 +121,17 @@ public class AiChatConversationServiceImpl implements AiChatConversationService
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteChatConversationMy(Long id, Long userId) {
|
||||
public void deleteChatConversationMy(AiDelReqVO reqVO, Long userId) {
|
||||
// 1. 校验对话是否存在
|
||||
AiChatConversationDO conversation = validateChatConversationExists(id);
|
||||
if (conversation == null || ObjUtil.notEqual(conversation.getUserId(), userId)) {
|
||||
throw exception(CHAT_CONVERSATION_NOT_EXISTS);
|
||||
}
|
||||
reqVO.getConversationIdList().forEach(id -> {
|
||||
AiChatConversationDO conversation = validateChatConversationExists(id);
|
||||
if (conversation == null || ObjUtil.notEqual(conversation.getUserId(), userId)) {
|
||||
throw exception(CHAT_CONVERSATION_NOT_EXISTS);
|
||||
}
|
||||
});
|
||||
|
||||
// 2. 执行删除
|
||||
chatConversationMapper.deleteById(id);
|
||||
chatConversationMapper.deleteByIds(reqVO.getConversationIdList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.luohuo.flex.ai.service.chat;
|
||||
|
||||
|
||||
import com.luohuo.flex.ai.common.pojo.PageResult;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.conversation.AiDelReqVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.message.AiChatMessagePageReqVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.message.AiChatMessageSendReqVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.message.AiChatMessageSendRespVO;
|
||||
@@ -57,10 +58,10 @@ public interface AiChatMessageService {
|
||||
/**
|
||||
* 删除指定对话的消息
|
||||
*
|
||||
* @param conversationId 对话编号
|
||||
* @param reqVOS 对话编号
|
||||
* @param userId 用户编号
|
||||
*/
|
||||
void deleteChatMessageByConversationId(Long conversationId, Long userId);
|
||||
void deleteChatMessageByConversationId(AiDelReqVO reqVOS, Long userId);
|
||||
|
||||
/**
|
||||
* 【管理员】删除消息
|
||||
|
||||
@@ -6,6 +6,7 @@ import cn.hutool.core.util.StrUtil;
|
||||
import com.luohuo.basic.context.ContextUtil;
|
||||
import com.luohuo.basic.tenant.core.aop.TenantIgnore;
|
||||
import com.luohuo.flex.ai.common.pojo.PageResult;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.conversation.AiDelReqVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.message.AiChatMessagePageReqVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.message.AiChatMessageRespVO;
|
||||
import com.luohuo.flex.ai.controller.chat.vo.message.AiChatMessageSendReqVO;
|
||||
@@ -341,14 +342,16 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteChatMessageByConversationId(Long conversationId, Long userId) {
|
||||
// 1. 校验消息存在
|
||||
List<AiChatMessageDO> messages = chatMessageMapper.selectListByConversationId(conversationId);
|
||||
if (CollUtil.isEmpty(messages) || ObjUtil.notEqual(messages.get(0).getUserId(), userId)) {
|
||||
throw exception(CHAT_MESSAGE_NOT_EXIST);
|
||||
}
|
||||
// 2. 执行删除
|
||||
chatMessageMapper.deleteBatchIds(convertList(messages, AiChatMessageDO::getId));
|
||||
public void deleteChatMessageByConversationId(AiDelReqVO reqVOS, Long userId) {
|
||||
reqVOS.getConversationIdList().forEach(conversationId -> {
|
||||
// 1. 校验消息存在
|
||||
List<AiChatMessageDO> messages = chatMessageMapper.selectListByConversationId(conversationId);
|
||||
if (CollUtil.isEmpty(messages) || ObjUtil.notEqual(messages.get(0).getUserId(), userId)) {
|
||||
throw exception(CHAT_MESSAGE_NOT_EXIST);
|
||||
}
|
||||
// 2. 执行删除
|
||||
chatMessageMapper.deleteBatchIds(convertList(messages, AiChatMessageDO::getId));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,23 +18,26 @@ public interface AiApiKeyService {
|
||||
* 创建 API 密钥
|
||||
*
|
||||
* @param createReqVO 创建信息
|
||||
* @param userId 用户编号
|
||||
* @return 编号
|
||||
*/
|
||||
Long createApiKey(@Valid AiApiKeySaveReqVO createReqVO);
|
||||
Long createApiKey(@Valid AiApiKeySaveReqVO createReqVO, Long userId);
|
||||
|
||||
/**
|
||||
* 更新 API 密钥
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
* @param userId 用户编号
|
||||
*/
|
||||
void updateApiKey(@Valid AiApiKeySaveReqVO updateReqVO);
|
||||
void updateApiKey(@Valid AiApiKeySaveReqVO updateReqVO, Long userId);
|
||||
|
||||
/**
|
||||
* 删除 API 密钥
|
||||
*
|
||||
* @param id 编号
|
||||
* @param id 编号
|
||||
* @param userId 用户编号
|
||||
*/
|
||||
void deleteApiKey(Long id);
|
||||
void deleteApiKey(Long id, Long userId);
|
||||
|
||||
/**
|
||||
* 获得 API 密钥
|
||||
@@ -56,9 +59,10 @@ public interface AiApiKeyService {
|
||||
* 获得 API 密钥分页
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @param userId 用户编号
|
||||
* @return API 密钥分页
|
||||
*/
|
||||
PageResult<AiApiKeyDO> getApiKeyPage(AiApiKeyPageReqVO pageReqVO);
|
||||
PageResult<AiApiKeyDO> getApiKeyPage(AiApiKeyPageReqVO pageReqVO, Long userId);
|
||||
|
||||
/**
|
||||
* 获得 API 密钥列表
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.luohuo.flex.ai.service.model;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.luohuo.flex.ai.common.pojo.PageResult;
|
||||
import com.luohuo.flex.ai.controller.model.vo.apikey.AiApiKeyPageReqVO;
|
||||
import com.luohuo.flex.ai.controller.model.vo.apikey.AiApiKeySaveReqVO;
|
||||
@@ -17,7 +18,6 @@ import static com.luohuo.flex.ai.enums.ErrorCodeConstants.API_KEY_DISABLE;
|
||||
import static com.luohuo.flex.ai.enums.ErrorCodeConstants.API_KEY_NOT_EXISTS;
|
||||
import static com.luohuo.flex.ai.utils.ServiceExceptionUtil.exception;
|
||||
|
||||
|
||||
/**
|
||||
* AI API 密钥 Service 实现类
|
||||
*
|
||||
@@ -27,74 +27,112 @@ import static com.luohuo.flex.ai.utils.ServiceExceptionUtil.exception;
|
||||
@Validated
|
||||
public class AiApiKeyServiceImpl implements AiApiKeyService {
|
||||
|
||||
@Resource
|
||||
private AiApiKeyMapper apiKeyMapper;
|
||||
@Resource
|
||||
private AiApiKeyMapper apiKeyMapper;
|
||||
|
||||
@Override
|
||||
public Long createApiKey(AiApiKeySaveReqVO createReqVO) {
|
||||
// 插入
|
||||
AiApiKeyDO apiKey = BeanUtils.toBean(createReqVO, AiApiKeyDO.class);
|
||||
apiKeyMapper.insert(apiKey);
|
||||
// 返回
|
||||
return apiKey.getId();
|
||||
}
|
||||
@Override
|
||||
public Long createApiKey(AiApiKeySaveReqVO createReqVO, Long userId) {
|
||||
// 插入
|
||||
AiApiKeyDO apiKey = BeanUtils.toBean(createReqVO, AiApiKeyDO.class);
|
||||
|
||||
@Override
|
||||
public void updateApiKey(AiApiKeySaveReqVO updateReqVO) {
|
||||
// 校验存在
|
||||
validateApiKeyExists(updateReqVO.getId());
|
||||
// 更新
|
||||
AiApiKeyDO updateObj = BeanUtils.toBean(updateReqVO, AiApiKeyDO.class);
|
||||
apiKeyMapper.updateById(updateObj);
|
||||
}
|
||||
// 如果是私有密钥,设置 userId
|
||||
if (createReqVO.getPublicStatus() == null || Boolean.FALSE.equals(createReqVO.getPublicStatus())) {
|
||||
apiKey.setUserId(userId)
|
||||
.setPublicStatus(false);
|
||||
// 私有密钥默认启用
|
||||
if (createReqVO.getStatus() == null) {
|
||||
apiKey.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteApiKey(Long id) {
|
||||
// 校验存在
|
||||
validateApiKeyExists(id);
|
||||
// 删除
|
||||
apiKeyMapper.deleteById(id);
|
||||
}
|
||||
apiKeyMapper.insert(apiKey);
|
||||
return apiKey.getId();
|
||||
}
|
||||
|
||||
private AiApiKeyDO validateApiKeyExists(Long id) {
|
||||
AiApiKeyDO apiKey = apiKeyMapper.selectById(id);
|
||||
if (apiKey == null) {
|
||||
throw exception(API_KEY_NOT_EXISTS);
|
||||
}
|
||||
return apiKey;
|
||||
}
|
||||
@Override
|
||||
public void updateApiKey(AiApiKeySaveReqVO updateReqVO, Long userId) {
|
||||
// 校验存在
|
||||
AiApiKeyDO apiKey = validateApiKeyExists(updateReqVO.getId());
|
||||
|
||||
@Override
|
||||
public AiApiKeyDO getApiKey(Long id) {
|
||||
return apiKeyMapper.selectById(id);
|
||||
}
|
||||
// 权限校验
|
||||
if (Boolean.FALSE.equals(apiKey.getPublicStatus())) {
|
||||
// 私有密钥,只有创建者可以编辑
|
||||
if (ObjectUtil.notEqual(apiKey.getUserId(), userId)) {
|
||||
throw exception(API_KEY_NOT_EXISTS);
|
||||
}
|
||||
} else {
|
||||
// 公开密钥,需要管理员权限
|
||||
if (userId >= 10937855681025L) {
|
||||
throw exception(API_KEY_NOT_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiApiKeyDO validateApiKey(Long id) {
|
||||
AiApiKeyDO apiKey = validateApiKeyExists(id);
|
||||
if (CommonStatusEnum.isDisable(apiKey.getStatus())) {
|
||||
throw exception(API_KEY_DISABLE);
|
||||
}
|
||||
return apiKey;
|
||||
}
|
||||
// 更新
|
||||
AiApiKeyDO updateObj = BeanUtils.toBean(updateReqVO, AiApiKeyDO.class);
|
||||
apiKeyMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<AiApiKeyDO> getApiKeyPage(AiApiKeyPageReqVO pageReqVO) {
|
||||
return apiKeyMapper.selectPage(pageReqVO);
|
||||
}
|
||||
@Override
|
||||
public void deleteApiKey(Long id, Long userId) {
|
||||
// 校验存在
|
||||
AiApiKeyDO apiKey = validateApiKeyExists(id);
|
||||
|
||||
@Override
|
||||
public List<AiApiKeyDO> getApiKeyList() {
|
||||
return apiKeyMapper.selectList();
|
||||
}
|
||||
// 权限校验
|
||||
if (Boolean.FALSE.equals(apiKey.getPublicStatus())) {
|
||||
// 私有密钥,只有创建者可以删除
|
||||
if (ObjectUtil.notEqual(apiKey.getUserId(), userId)) {
|
||||
throw exception(API_KEY_NOT_EXISTS);
|
||||
}
|
||||
} else {
|
||||
// 公开密钥,需要管理员权限
|
||||
if (userId >= 10937855681025L) {
|
||||
throw exception(API_KEY_NOT_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiApiKeyDO getRequiredDefaultApiKey(String platform, Integer status) {
|
||||
AiApiKeyDO apiKey = apiKeyMapper.selectFirstByPlatformAndStatus(platform, status);
|
||||
if (apiKey == null) {
|
||||
throw exception(API_KEY_NOT_EXISTS);
|
||||
}
|
||||
return apiKey;
|
||||
}
|
||||
// 删除
|
||||
apiKeyMapper.deleteById(id);
|
||||
}
|
||||
|
||||
private AiApiKeyDO validateApiKeyExists(Long id) {
|
||||
AiApiKeyDO apiKey = apiKeyMapper.selectById(id);
|
||||
if (apiKey == null) {
|
||||
throw exception(API_KEY_NOT_EXISTS);
|
||||
}
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiApiKeyDO getApiKey(Long id) {
|
||||
return apiKeyMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiApiKeyDO validateApiKey(Long id) {
|
||||
AiApiKeyDO apiKey = validateApiKeyExists(id);
|
||||
if (CommonStatusEnum.isDisable(apiKey.getStatus())) {
|
||||
throw exception(API_KEY_DISABLE);
|
||||
}
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<AiApiKeyDO> getApiKeyPage(AiApiKeyPageReqVO pageReqVO, Long userId) {
|
||||
return apiKeyMapper.selectPageByMy(pageReqVO, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiApiKeyDO> getApiKeyList() {
|
||||
return apiKeyMapper.selectList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiApiKeyDO getRequiredDefaultApiKey(String platform, Integer status) {
|
||||
AiApiKeyDO apiKey = apiKeyMapper.selectFirstByPlatformAndStatus(platform, status);
|
||||
if (apiKey == null) {
|
||||
throw exception(API_KEY_NOT_EXISTS);
|
||||
}
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public interface AiChatRoleService {
|
||||
* @param updateReqVO 更新信息
|
||||
* @param userId 用户编号
|
||||
*/
|
||||
void updateChatRoleMy(AiChatRoleSaveMyReqVO updateReqVO, Long userId);
|
||||
void updateChatRoleMy(AiChatRoleSaveReqVO updateReqVO, Long userId);
|
||||
|
||||
/**
|
||||
* 删除聊天角色
|
||||
@@ -117,7 +117,7 @@ public interface AiChatRoleService {
|
||||
*
|
||||
* @return 分类列表
|
||||
*/
|
||||
List<String> getChatRoleCategoryList();
|
||||
List<Map<String, String>> getChatRoleCategoryList();
|
||||
|
||||
/**
|
||||
* 根据名字获得聊天角色
|
||||
|
||||
@@ -16,14 +16,16 @@ import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.luohuo.flex.ai.enums.ErrorCodeConstants.CHAT_ROLE_DISABLE;
|
||||
import static com.luohuo.flex.ai.enums.ErrorCodeConstants.CHAT_ROLE_NOT_EXISTS;
|
||||
import static com.luohuo.flex.ai.utils.ServiceExceptionUtil.exception;
|
||||
import static com.luohuo.basic.utils.collection.CollectionUtils.convertList;
|
||||
|
||||
|
||||
/**
|
||||
@@ -63,8 +65,7 @@ public class AiChatRoleServiceImpl implements AiChatRoleService {
|
||||
validateTools(createReqVO.getToolIds());
|
||||
|
||||
// 保存角色
|
||||
AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class).setUserId(userId)
|
||||
.setStatus(CommonStatusEnum.ENABLE.getStatus()).setPublicStatus(false);
|
||||
AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class).setUserId(userId).setStatus(CommonStatusEnum.ENABLE.getStatus()).setPublicStatus(false);
|
||||
chatRoleMapper.insert(chatRole);
|
||||
return chatRole.getId();
|
||||
}
|
||||
@@ -84,7 +85,7 @@ public class AiChatRoleServiceImpl implements AiChatRoleService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChatRoleMy(AiChatRoleSaveMyReqVO updateReqVO, Long userId) {
|
||||
public void updateChatRoleMy(AiChatRoleSaveReqVO updateReqVO, Long userId) {
|
||||
// 校验存在
|
||||
AiChatRoleDO chatRole = validateChatRoleExists(updateReqVO.getId());
|
||||
if (ObjectUtil.notEqual(chatRole.getUserId(), userId)) {
|
||||
@@ -185,12 +186,30 @@ public class AiChatRoleServiceImpl implements AiChatRoleService {
|
||||
return chatRoleMapper.selectPageByMy(pageReqVO, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getChatRoleCategoryList() {
|
||||
List<AiChatRoleDO> list = chatRoleMapper.selectListGroupByCategory(CommonStatusEnum.ENABLE.getStatus());
|
||||
return convertList(list, AiChatRoleDO::getCategory,
|
||||
role -> role != null && StrUtil.isNotBlank(role.getCategory()));
|
||||
}
|
||||
@Override
|
||||
public List<Map<String, String>> getChatRoleCategoryList() {
|
||||
return CATEGORY_OPTIONS;
|
||||
}
|
||||
|
||||
public static final List<Map<String, String>> CATEGORY_OPTIONS = Arrays.asList(
|
||||
createOption("AI助手", "AI助手"),
|
||||
createOption("写作", "写作"),
|
||||
createOption("编程开发", "编程开发"),
|
||||
createOption("学习教育", "学习教育"),
|
||||
createOption("生活娱乐", "生活娱乐"),
|
||||
createOption("商务办公", "商务办公"),
|
||||
createOption("创意设计", "创意设计"),
|
||||
createOption("数据分析", "数据分析"),
|
||||
createOption("翻译", "翻译"),
|
||||
createOption("其他", "其他")
|
||||
);
|
||||
|
||||
private static Map<String, String> createOption(String label, String value) {
|
||||
Map<String, String> option = new HashMap<>();
|
||||
option.put("label", label);
|
||||
option.put("value", value);
|
||||
return option;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiChatRoleDO> getChatRoleListByName(String name) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.luohuo.flex.ai.service.model;
|
||||
|
||||
import com.luohuo.flex.ai.common.pojo.PageResult;
|
||||
import com.luohuo.flex.ai.controller.model.vo.model.AiModelPageReqVO;
|
||||
import com.luohuo.flex.ai.controller.model.vo.model.AiModelSaveMyReqVO;
|
||||
import com.luohuo.flex.ai.controller.model.vo.model.AiModelSaveReqVO;
|
||||
import com.luohuo.flex.ai.core.model.MidjourneyApi;
|
||||
import com.luohuo.flex.ai.core.model.SunoApi;
|
||||
@@ -34,6 +35,15 @@ public interface AiModelService {
|
||||
*/
|
||||
Long createModel(@Valid AiModelSaveReqVO createReqVO);
|
||||
|
||||
/**
|
||||
* 创建【我的】模型
|
||||
*
|
||||
* @param createReqVO 创建信息
|
||||
* @param userId 用户编号
|
||||
* @return 编号
|
||||
*/
|
||||
Long createModelMy(@Valid AiModelSaveMyReqVO createReqVO, Long userId);
|
||||
|
||||
/**
|
||||
* 更新模型
|
||||
*
|
||||
@@ -41,6 +51,14 @@ public interface AiModelService {
|
||||
*/
|
||||
void updateModel(@Valid AiModelSaveReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 更新【我的】模型
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
* @param userId 用户编号
|
||||
*/
|
||||
void updateModelMy(@Valid AiModelSaveMyReqVO updateReqVO, Long userId);
|
||||
|
||||
/**
|
||||
* 删除模型
|
||||
*
|
||||
@@ -48,6 +66,14 @@ public interface AiModelService {
|
||||
*/
|
||||
void deleteModel(Long id);
|
||||
|
||||
/**
|
||||
* 删除【我的】模型
|
||||
*
|
||||
* @param id 编号
|
||||
* @param userId 用户编号
|
||||
*/
|
||||
void deleteModelMy(Long id, Long userId);
|
||||
|
||||
/**
|
||||
* 获得模型
|
||||
*
|
||||
@@ -73,6 +99,15 @@ public interface AiModelService {
|
||||
*/
|
||||
PageResult<AiModelDO> getModelPage(AiModelPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 获得【我的】模型分页
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @param userId 用户编号
|
||||
* @return 模型分页
|
||||
*/
|
||||
PageResult<AiModelDO> getModelMyPage(AiModelPageReqVO pageReqVO, Long userId);
|
||||
|
||||
/**
|
||||
* 校验模型是否可使用
|
||||
*
|
||||
@@ -92,6 +127,20 @@ public interface AiModelService {
|
||||
List<AiModelDO> getModelListByStatusAndType(Integer status, Integer type,
|
||||
@Nullable String platform);
|
||||
|
||||
/**
|
||||
* 获得模型列表(用户可见)
|
||||
*
|
||||
* 包含:系统级别的公开模型 + 用户自己的私有模型
|
||||
*
|
||||
* @param status 状态
|
||||
* @param type 类型
|
||||
* @param platform 平台,允许空
|
||||
* @param userId 用户编号
|
||||
* @return 模型列表
|
||||
*/
|
||||
List<AiModelDO> getModelListByStatusAndTypeAndUserId(Integer status, Integer type,
|
||||
@Nullable String platform, Long userId);
|
||||
|
||||
// ========== 与 Spring AI 集成 ==========
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package com.luohuo.flex.ai.service.model;
|
||||
|
||||
|
||||
import com.agentsflex.llm.ollama.OllamaLlm;
|
||||
import com.agentsflex.llm.ollama.OllamaLlmConfig;
|
||||
import com.agentsflex.llm.qwen.QwenLlm;
|
||||
import com.agentsflex.llm.qwen.QwenLlmConfig;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.luohuo.flex.ai.common.pojo.PageResult;
|
||||
import com.luohuo.flex.ai.controller.model.vo.model.AiModelPageReqVO;
|
||||
import com.luohuo.flex.ai.controller.model.vo.model.AiModelSaveMyReqVO;
|
||||
import com.luohuo.flex.ai.controller.model.vo.model.AiModelSaveReqVO;
|
||||
import com.luohuo.flex.ai.core.AiModelFactory;
|
||||
import com.luohuo.flex.ai.core.model.MidjourneyApi;
|
||||
@@ -43,161 +44,233 @@ import static com.luohuo.flex.ai.utils.ServiceExceptionUtil.exception;
|
||||
@Validated
|
||||
public class AiModelServiceImpl implements AiModelService {
|
||||
|
||||
@Resource
|
||||
private AiApiKeyService apiKeyService;
|
||||
@Resource
|
||||
private AiApiKeyService apiKeyService;
|
||||
|
||||
@Resource
|
||||
private AiChatMapper modelMapper;
|
||||
@Resource
|
||||
private AiChatMapper modelMapper;
|
||||
|
||||
@Resource
|
||||
private AiModelFactory modelFactory;
|
||||
@Resource
|
||||
private AiModelFactory modelFactory;
|
||||
|
||||
@Override
|
||||
public Long createModel(AiModelSaveReqVO createReqVO) {
|
||||
// 1. 校验
|
||||
AiPlatformEnum.validatePlatform(createReqVO.getPlatform());
|
||||
apiKeyService.validateApiKey(createReqVO.getKeyId());
|
||||
@Override
|
||||
public Long createModel(AiModelSaveReqVO createReqVO) {
|
||||
// 1. 校验
|
||||
AiPlatformEnum.validatePlatform(createReqVO.getPlatform());
|
||||
apiKeyService.validateApiKey(createReqVO.getKeyId());
|
||||
|
||||
// 2. 插入
|
||||
AiModelDO model = BeanUtils.toBean(createReqVO, AiModelDO.class);
|
||||
modelMapper.insert(model);
|
||||
return model.getId();
|
||||
}
|
||||
// 2. 插入
|
||||
AiModelDO model = BeanUtils.toBean(createReqVO, AiModelDO.class);
|
||||
// 如果是私有模型且没有设置 userId,则抛出异常
|
||||
if (Boolean.FALSE.equals(createReqVO.getPublicStatus()) && model.getUserId() == null) {
|
||||
throw exception(MODEL_NOT_EXISTS); // 使用适当的错误码
|
||||
}
|
||||
modelMapper.insert(model);
|
||||
return model.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateModel(AiModelSaveReqVO updateReqVO) {
|
||||
// 1. 校验
|
||||
validateModelExists(updateReqVO.getId());
|
||||
AiPlatformEnum.validatePlatform(updateReqVO.getPlatform());
|
||||
apiKeyService.validateApiKey(updateReqVO.getKeyId());
|
||||
@Override
|
||||
public Long createModelMy(AiModelSaveMyReqVO createReqVO, Long userId) {
|
||||
// 1. 校验
|
||||
AiPlatformEnum.validatePlatform(createReqVO.getPlatform());
|
||||
apiKeyService.validateApiKey(createReqVO.getKeyId());
|
||||
|
||||
// 2. 更新
|
||||
AiModelDO updateObj = BeanUtils.toBean(updateReqVO, AiModelDO.class);
|
||||
modelMapper.updateById(updateObj);
|
||||
}
|
||||
// 2. 插入
|
||||
AiModelDO model = BeanUtils.toBean(createReqVO, AiModelDO.class)
|
||||
.setUserId(userId)
|
||||
.setStatus(CommonStatusEnum.ENABLE.getStatus())
|
||||
.setPublicStatus(false);
|
||||
modelMapper.insert(model);
|
||||
return model.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteModel(Long id) {
|
||||
// 校验存在
|
||||
validateModelExists(id);
|
||||
// 删除
|
||||
modelMapper.deleteById(id);
|
||||
}
|
||||
@Override
|
||||
public void updateModel(AiModelSaveReqVO updateReqVO) {
|
||||
// 1. 校验存在
|
||||
AiModelDO model = validateModelExists(updateReqVO.getId());
|
||||
|
||||
private AiModelDO validateModelExists(Long id) {
|
||||
AiModelDO model = modelMapper.selectById(id);
|
||||
if (modelMapper.selectById(id) == null) {
|
||||
throw exception(MODEL_NOT_EXISTS);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
// 2. 权限校验:公开模型不允许普通用户编辑(管理员可以通过其他方式编辑)
|
||||
// 如果 updateReqVO 中指定了 userId,说明是普通用户操作
|
||||
if (updateReqVO.getId() != null) {
|
||||
// 如果是私有模型,校验是否是创建者
|
||||
if (Boolean.FALSE.equals(model.getPublicStatus())) {
|
||||
// 私有模型需要校验 userId
|
||||
if (updateReqVO instanceof AiModelSaveReqVO && model.getUserId() != null) {
|
||||
// 这里需要从上下文获取当前用户ID进行校验
|
||||
// 暂时保持原有逻辑,具体权限在 Controller 层控制
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiModelDO getModel(Long id) {
|
||||
return modelMapper.selectById(id);
|
||||
}
|
||||
// 3. 校验平台和密钥
|
||||
AiPlatformEnum.validatePlatform(updateReqVO.getPlatform());
|
||||
apiKeyService.validateApiKey(updateReqVO.getKeyId());
|
||||
|
||||
@Override
|
||||
public AiModelDO getRequiredDefaultModel(Integer type) {
|
||||
AiModelDO model = modelMapper.selectFirstByStatus(type, CommonStatusEnum.ENABLE.getStatus());
|
||||
if (model == null) {
|
||||
throw exception(MODEL_DEFAULT_NOT_EXISTS);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
// 4. 更新
|
||||
AiModelDO updateObj = BeanUtils.toBean(updateReqVO, AiModelDO.class);
|
||||
modelMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<AiModelDO> getModelPage(AiModelPageReqVO pageReqVO) {
|
||||
return modelMapper.selectPage(pageReqVO);
|
||||
}
|
||||
@Override
|
||||
public void updateModelMy(AiModelSaveMyReqVO updateReqVO, Long userId) {
|
||||
// 1. 校验存在
|
||||
AiModelDO model = validateModelExists(updateReqVO.getId());
|
||||
if (ObjectUtil.notEqual(model.getUserId(), userId)) {
|
||||
throw exception(MODEL_NOT_EXISTS);
|
||||
}
|
||||
// 2. 校验平台和密钥
|
||||
AiPlatformEnum.validatePlatform(updateReqVO.getPlatform());
|
||||
apiKeyService.validateApiKey(updateReqVO.getKeyId());
|
||||
|
||||
@Override
|
||||
public AiModelDO validateModel(Long id) {
|
||||
AiModelDO model = validateModelExists(id);
|
||||
if (CommonStatusEnum.isDisable(model.getStatus())) {
|
||||
throw exception(MODEL_DISABLE);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
// 3. 更新
|
||||
AiModelDO updateObj = BeanUtils.toBean(updateReqVO, AiModelDO.class);
|
||||
updateObj.setUserId(userId);
|
||||
modelMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiModelDO> getModelListByStatusAndType(Integer status, Integer type, String platform) {
|
||||
return modelMapper.selectListByStatusAndType(status, type, platform);
|
||||
}
|
||||
@Override
|
||||
public void deleteModel(Long id) {
|
||||
// 校验存在
|
||||
validateModelExists(id);
|
||||
// 删除
|
||||
modelMapper.deleteById(id);
|
||||
}
|
||||
|
||||
// ========== 与 Spring AI 集成 ==========
|
||||
@Override
|
||||
public void deleteModelMy(Long id, Long userId) {
|
||||
// 校验存在
|
||||
AiModelDO model = validateModelExists(id);
|
||||
if (ObjectUtil.notEqual(model.getUserId(), userId)) {
|
||||
throw exception(MODEL_NOT_EXISTS);
|
||||
}
|
||||
// 删除
|
||||
modelMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatModel getChatModel(Long id) {
|
||||
AiModelDO model = validateModel(id);
|
||||
AiApiKeyDO apiKey = apiKeyService.validateApiKey(model.getKeyId());
|
||||
AiPlatformEnum platform = AiPlatformEnum.validatePlatform(apiKey.getPlatform());
|
||||
return modelFactory.getOrCreateChatModel(platform, apiKey.getApiKey(), apiKey.getUrl());
|
||||
}
|
||||
private AiModelDO validateModelExists(Long id) {
|
||||
AiModelDO model = modelMapper.selectById(id);
|
||||
if (modelMapper.selectById(id) == null) {
|
||||
throw exception(MODEL_NOT_EXISTS);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageModel getImageModel(Long id) {
|
||||
AiModelDO model = validateModel(id);
|
||||
AiApiKeyDO apiKey = apiKeyService.validateApiKey(model.getKeyId());
|
||||
AiPlatformEnum platform = AiPlatformEnum.validatePlatform(apiKey.getPlatform());
|
||||
return modelFactory.getOrCreateImageModel(platform, apiKey.getApiKey(), apiKey.getUrl());
|
||||
}
|
||||
@Override
|
||||
public AiModelDO getModel(Long id) {
|
||||
return modelMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MidjourneyApi getMidjourneyApi(Long id) {
|
||||
AiModelDO model = validateModel(id);
|
||||
AiApiKeyDO apiKey = apiKeyService.validateApiKey(model.getKeyId());
|
||||
return modelFactory.getOrCreateMidjourneyApi(apiKey.getApiKey(), apiKey.getUrl());
|
||||
}
|
||||
@Override
|
||||
public AiModelDO getRequiredDefaultModel(Integer type) {
|
||||
AiModelDO model = modelMapper.selectFirstByStatus(type, CommonStatusEnum.ENABLE.getStatus());
|
||||
if (model == null) {
|
||||
throw exception(MODEL_DEFAULT_NOT_EXISTS);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SunoApi getSunoApi() {
|
||||
AiApiKeyDO apiKey = apiKeyService.getRequiredDefaultApiKey(
|
||||
AiPlatformEnum.SUNO.getPlatform(), CommonStatusEnum.ENABLE.getStatus());
|
||||
return modelFactory.getOrCreateSunoApi(apiKey.getApiKey(), apiKey.getUrl());
|
||||
}
|
||||
@Override
|
||||
public PageResult<AiModelDO> getModelPage(AiModelPageReqVO pageReqVO) {
|
||||
return modelMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VectorStore getOrCreateVectorStore(Long id, Map<String, Class<?>> metadataFields) {
|
||||
// 获取模型 + 密钥
|
||||
AiModelDO model = validateModel(id);
|
||||
AiApiKeyDO apiKey = apiKeyService.validateApiKey(model.getKeyId());
|
||||
AiPlatformEnum platform = AiPlatformEnum.validatePlatform(apiKey.getPlatform());
|
||||
@Override
|
||||
public PageResult<AiModelDO> getModelMyPage(AiModelPageReqVO pageReqVO, Long userId) {
|
||||
return modelMapper.selectPageByMy(pageReqVO, userId);
|
||||
}
|
||||
|
||||
// 创建或获取 EmbeddingModel 对象
|
||||
EmbeddingModel embeddingModel = modelFactory.getOrCreateEmbeddingModel(
|
||||
platform, apiKey.getApiKey(), apiKey.getUrl(), model.getModel());
|
||||
@Override
|
||||
public AiModelDO validateModel(Long id) {
|
||||
AiModelDO model = validateModelExists(id);
|
||||
if (CommonStatusEnum.isDisable(model.getStatus())) {
|
||||
throw exception(MODEL_DISABLE);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
// 创建或获取 VectorStore 对象
|
||||
return modelFactory.getOrCreateVectorStore(SimpleVectorStore.class, embeddingModel, metadataFields);
|
||||
@Override
|
||||
public List<AiModelDO> getModelListByStatusAndType(Integer status, Integer type, String platform) {
|
||||
return modelMapper.selectListByStatusAndType(status, type, platform);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiModelDO> getModelListByStatusAndTypeAndUserId(Integer status, Integer type, String platform, Long userId) {
|
||||
return modelMapper.selectListByStatusAndTypeAndUserId(status, type, platform, userId);
|
||||
}
|
||||
|
||||
// ========== 与 Spring AI 集成 ==========
|
||||
|
||||
@Override
|
||||
public ChatModel getChatModel(Long id) {
|
||||
AiModelDO model = validateModel(id);
|
||||
AiApiKeyDO apiKey = apiKeyService.validateApiKey(model.getKeyId());
|
||||
AiPlatformEnum platform = AiPlatformEnum.validatePlatform(apiKey.getPlatform());
|
||||
return modelFactory.getOrCreateChatModel(platform, apiKey.getApiKey(), apiKey.getUrl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageModel getImageModel(Long id) {
|
||||
AiModelDO model = validateModel(id);
|
||||
AiApiKeyDO apiKey = apiKeyService.validateApiKey(model.getKeyId());
|
||||
AiPlatformEnum platform = AiPlatformEnum.validatePlatform(apiKey.getPlatform());
|
||||
return modelFactory.getOrCreateImageModel(platform, apiKey.getApiKey(), apiKey.getUrl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MidjourneyApi getMidjourneyApi(Long id) {
|
||||
AiModelDO model = validateModel(id);
|
||||
AiApiKeyDO apiKey = apiKeyService.validateApiKey(model.getKeyId());
|
||||
return modelFactory.getOrCreateMidjourneyApi(apiKey.getApiKey(), apiKey.getUrl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SunoApi getSunoApi() {
|
||||
AiApiKeyDO apiKey = apiKeyService.getRequiredDefaultApiKey(
|
||||
AiPlatformEnum.SUNO.getPlatform(), CommonStatusEnum.ENABLE.getStatus());
|
||||
return modelFactory.getOrCreateSunoApi(apiKey.getApiKey(), apiKey.getUrl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public VectorStore getOrCreateVectorStore(Long id, Map<String, Class<?>> metadataFields) {
|
||||
// 获取模型 + 密钥
|
||||
AiModelDO model = validateModel(id);
|
||||
AiApiKeyDO apiKey = apiKeyService.validateApiKey(model.getKeyId());
|
||||
AiPlatformEnum platform = AiPlatformEnum.validatePlatform(apiKey.getPlatform());
|
||||
|
||||
// 创建或获取 EmbeddingModel 对象
|
||||
EmbeddingModel embeddingModel = modelFactory.getOrCreateEmbeddingModel(
|
||||
platform, apiKey.getApiKey(), apiKey.getUrl(), model.getModel());
|
||||
|
||||
// 创建或获取 VectorStore 对象
|
||||
return modelFactory.getOrCreateVectorStore(SimpleVectorStore.class, embeddingModel, metadataFields);
|
||||
// return modelFactory.getOrCreateVectorStore(QdrantVectorStore.class, embeddingModel, metadataFields);
|
||||
// return modelFactory.getOrCreateVectorStore(RedisVectorStore.class, embeddingModel, metadataFields);
|
||||
// return modelFactory.getOrCreateVectorStore(MilvusVectorStore.class, embeddingModel, metadataFields);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO @lesan:是不是返回 Llm 对象会好点哈?
|
||||
@Override
|
||||
public void getLLmProvider4Tinyflow(Tinyflow tinyflow, Long modelId) {
|
||||
AiModelDO model = validateModel(modelId);
|
||||
AiApiKeyDO apiKey = apiKeyService.validateApiKey(model.getKeyId());
|
||||
AiPlatformEnum platform = AiPlatformEnum.validatePlatform(apiKey.getPlatform());
|
||||
switch (platform) {
|
||||
// TODO @lesan 考虑到未来不需要使用agents-flex 现在仅测试通义千问
|
||||
// TODO @lesan:【重要】是不是可以实现一个 SpringAiLlm,这样的话,内部全部用它就好了。只实现 chat 部分;这样,就把 flex 作为一个 agent 框架,内部调用,还是 spring ai 相关的。成本可能低一点?!
|
||||
case TONG_YI:
|
||||
QwenLlmConfig qwenLlmConfig = new QwenLlmConfig();
|
||||
qwenLlmConfig.setApiKey(apiKey.getApiKey());
|
||||
qwenLlmConfig.setModel(model.getModel());
|
||||
// TODO @lesan:这个有点奇怪。。。如果一个链式里,有多个模型,咋整呀。。。
|
||||
tinyflow.setLlmProvider(id -> new QwenLlm(qwenLlmConfig));
|
||||
break;
|
||||
case OLLAMA:
|
||||
OllamaLlmConfig ollamaLlmConfig = new OllamaLlmConfig();
|
||||
ollamaLlmConfig.setEndpoint(apiKey.getUrl());
|
||||
ollamaLlmConfig.setModel(model.getModel());
|
||||
tinyflow.setLlmProvider(id -> new OllamaLlm(ollamaLlmConfig));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO @lesan:是不是返回 Llm 对象会好点哈?
|
||||
@Override
|
||||
public void getLLmProvider4Tinyflow(Tinyflow tinyflow, Long modelId) {
|
||||
AiModelDO model = validateModel(modelId);
|
||||
AiApiKeyDO apiKey = apiKeyService.validateApiKey(model.getKeyId());
|
||||
AiPlatformEnum platform = AiPlatformEnum.validatePlatform(apiKey.getPlatform());
|
||||
switch (platform) {
|
||||
// TODO @lesan 考虑到未来不需要使用agents-flex 现在仅测试通义千问
|
||||
// TODO @lesan:【重要】是不是可以实现一个 SpringAiLlm,这样的话,内部全部用它就好了。只实现 chat 部分;这样,就把 flex 作为一个 agent 框架,内部调用,还是 spring ai 相关的。成本可能低一点?!
|
||||
case TONG_YI:
|
||||
QwenLlmConfig qwenLlmConfig = new QwenLlmConfig();
|
||||
qwenLlmConfig.setApiKey(apiKey.getApiKey());
|
||||
qwenLlmConfig.setModel(model.getModel());
|
||||
// TODO @lesan:这个有点奇怪。。。如果一个链式里,有多个模型,咋整呀。。。
|
||||
tinyflow.setLlmProvider(id -> new QwenLlm(qwenLlmConfig));
|
||||
break;
|
||||
case OLLAMA:
|
||||
OllamaLlmConfig ollamaLlmConfig = new OllamaLlmConfig();
|
||||
ollamaLlmConfig.setEndpoint(apiKey.getUrl());
|
||||
ollamaLlmConfig.setModel(model.getModel());
|
||||
tinyflow.setLlmProvider(id -> new OllamaLlm(ollamaLlmConfig));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,15 +31,14 @@ public class BlackInterceptor implements HandlerInterceptor {
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
Map<Integer, Set<String>> blackMap = userSummaryCache.getBlackMap();
|
||||
Long uid = ContextUtil.getUid();
|
||||
if (isBlackList(uid, blackMap.get(BlackTypeEnum.UID.getType()))) {
|
||||
if (isBlackList(ContextUtil.getUid(), blackMap.get(BlackTypeEnum.UID.getType()))) {
|
||||
response.setStatus(HttpStatus.OK.value());
|
||||
R<Object> responseData = R.fail("对不起,不在白名单内");
|
||||
response.setContentType(ContentType.JSON.toString(Charset.forName("UTF-8")));
|
||||
response.getWriter().write(JSONUtil.toJsonStr(responseData));
|
||||
return false;
|
||||
}
|
||||
if (isBlackList(uid, blackMap.get(BlackTypeEnum.IP.getType()))) {
|
||||
if (isBlackList(ContextUtil.getIP(), blackMap.get(BlackTypeEnum.IP.getType()))) {
|
||||
response.setStatus(HttpStatus.OK.value());
|
||||
R<Object> responseData = R.fail("对不起,不在白名单内");
|
||||
response.setContentType(ContentType.JSON.toString(Charset.forName("UTF-8")));
|
||||
|
||||
@@ -509,10 +509,6 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
public Boolean updateMyRoomInfo(Long uid, RoomMyInfoReq request) {
|
||||
// 1.校验修改权限
|
||||
Triple<RoomGroup, GroupMember, Boolean> permissionCheck = checkGroupPermission(uid, request.getId());
|
||||
if (!permissionCheck.getRight()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RoomGroup roomGroup = permissionCheck.getLeft();
|
||||
GroupMember member = permissionCheck.getMiddle();
|
||||
|
||||
|
||||
@@ -9,14 +9,22 @@ import com.luohuo.flex.im.domain.vo.req.feed.FeedVo;
|
||||
import com.luohuo.flex.im.core.user.mapper.FeedMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 朋友圈基础信息
|
||||
*/
|
||||
@Service
|
||||
public class FeedDao extends ServiceImpl<FeedMapper, Feed> {
|
||||
|
||||
public CursorPageBaseResp<Feed> getFeedPage(Long uid, CursorPageBaseReq request) {
|
||||
return CursorUtils.getCursorPageByMysql(this, request, wrapper -> wrapper.eq(Feed::getUid, uid), Feed::getCreateTime);
|
||||
/**
|
||||
* 查询朋友圈列表(包括指定用户列表的朋友圈)
|
||||
* @param uidList 用户ID列表(包括当前用户和好友)
|
||||
* @param request 分页请求
|
||||
* @return 朋友圈分页结果
|
||||
*/
|
||||
public CursorPageBaseResp<Feed> getFeedPage(List<Long> uidList, CursorPageBaseReq request) {
|
||||
return CursorUtils.getCursorPageByMysql(this, request, wrapper -> wrapper.in(Feed::getUid, uidList), Feed::getCreateTime);
|
||||
}
|
||||
|
||||
public FeedVo getDetail(Long id) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.luohuo.flex.im.core.user.service.cache;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.luohuo.basic.tenant.core.aop.TenantIgnore;
|
||||
import com.luohuo.flex.im.common.constant.RedisKey;
|
||||
import com.luohuo.flex.im.common.service.cache.AbstractRedisStringCache;
|
||||
import com.luohuo.flex.im.core.user.dao.BlackDao;
|
||||
@@ -112,6 +113,7 @@ public class UserSummaryCache extends AbstractRedisStringCache<Long, SummeryInfo
|
||||
return null;
|
||||
}
|
||||
|
||||
@TenantIgnore
|
||||
@Cacheable(cacheNames = "luohuo:user", key = "'blackList'")
|
||||
public Map<Integer, Set<String>> getBlackMap() {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
@@ -84,11 +84,46 @@ public class FeedServiceImpl implements FeedService {
|
||||
*/
|
||||
@Override
|
||||
public CursorPageBaseResp<FeedVo> getFeedPage(CursorPageBaseReq request, Long uid) {
|
||||
// 1. 查询朋友圈列表
|
||||
CursorPageBaseResp<Feed> page = feedDao.getFeedPage(uid, request);
|
||||
// 1. 查询当前用户的所有好友ID
|
||||
List<Long> friendIds = userFriendDao.getAllFriendIdsByUid(uid);
|
||||
friendIds.add(uid); // 添加自己
|
||||
|
||||
// 2. 合并朋友圈内容
|
||||
List<FeedVo> result = buildFeedResp(page.getList());
|
||||
// 2. 查询这些用户的朋友圈列表
|
||||
CursorPageBaseResp<Feed> page = feedDao.getFeedPage(friendIds, request);
|
||||
|
||||
// 3. 根据权限过滤朋友圈
|
||||
List<Feed> filteredFeeds = page.getList().stream().filter(feed -> {
|
||||
// 如果是自己的朋友圈,全部可见
|
||||
if (feed.getUid().equals(uid)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 根据权限类型过滤
|
||||
FeedPermissionEnum permission = FeedPermissionEnum.get(feed.getPermission());
|
||||
switch (permission) {
|
||||
case privacy:
|
||||
// 私密:只有发布者自己可见
|
||||
return false;
|
||||
case open:
|
||||
// 公开:所有好友可见
|
||||
return true;
|
||||
case partVisible:
|
||||
// 部分可见:查询是否在可见列表中
|
||||
List<FeedTarget> targets = feedTargetDao.selectFeedTargets(feed.getId());
|
||||
// type=2 表示用户,targetId 就是用户ID
|
||||
return targets.stream().anyMatch(t -> t.getType() == 2 && t.getTargetId().equals(uid));
|
||||
case notAnyone:
|
||||
// 不给谁看:查询是否在不可见列表中
|
||||
List<FeedTarget> excludes = feedTargetDao.selectFeedTargets(feed.getId());
|
||||
// type=2 表示用户,targetId 就是用户ID
|
||||
return excludes.stream().noneMatch(t -> t.getType() == 2 && t.getTargetId().equals(uid));
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
// 4. 合并朋友圈内容
|
||||
List<FeedVo> result = buildFeedResp(filteredFeeds);
|
||||
return CursorPageBaseResp.init(page, result, page.getTotal());
|
||||
}
|
||||
|
||||
@@ -117,6 +152,17 @@ public class FeedServiceImpl implements FeedService {
|
||||
* @param feed 朋友圈
|
||||
*/
|
||||
public void saveFeed(FeedParam param, Long uid, Feed feed) {
|
||||
saveFeed(param, uid, feed, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存朋友圈权限+素材
|
||||
* @param param 参数
|
||||
* @param uid 操作人
|
||||
* @param feed 朋友圈
|
||||
* @param needClearCache 是否需要清除缓存(编辑时为true,新建时为false)
|
||||
*/
|
||||
private void saveFeed(FeedParam param, Long uid, Feed feed, boolean needClearCache) {
|
||||
List<Long> pushList = new ArrayList<>();
|
||||
List<FeedTarget> feedTargets = new ArrayList<>();
|
||||
switch (FeedPermissionEnum.get(param.getPermission())){
|
||||
@@ -173,9 +219,13 @@ public class FeedServiceImpl implements FeedService {
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 缓存权限+素材 告知 pushList 我发布了朋友圈
|
||||
// cachePlusOps.hDel(FeedMediaRelCacheKeyBuilder.build(feed.getId()));
|
||||
// cachePlusOps.hDel(FeedTargetRelCacheKeyBuilder.build(feed.getId()));
|
||||
// 3. 清除缓存
|
||||
if (needClearCache) {
|
||||
cachePlusOps.del(FeedMediaRelCacheKeyBuilder.build(feed.getId()));
|
||||
cachePlusOps.del(FeedTargetRelCacheKeyBuilder.build(feed.getId()));
|
||||
}
|
||||
|
||||
// 4. 告知 pushList 我发布了朋友圈
|
||||
pushService.sendPushMsg(MemberAdapter.buildFeedPushWS(uid), pushList, uid);
|
||||
}
|
||||
|
||||
@@ -230,8 +280,8 @@ public class FeedServiceImpl implements FeedService {
|
||||
feedDao.removeById(feedId);
|
||||
|
||||
// 2. 清空缓存
|
||||
cachePlusOps.hDel(FeedTargetRelCacheKeyBuilder.build(feedId));
|
||||
cachePlusOps.hDel(FeedMediaRelCacheKeyBuilder.build(feedId));
|
||||
cachePlusOps.del(FeedTargetRelCacheKeyBuilder.build(feedId));
|
||||
cachePlusOps.del(FeedMediaRelCacheKeyBuilder.build(feedId));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -247,12 +297,12 @@ public class FeedServiceImpl implements FeedService {
|
||||
public FeedVo feedDetail(Long feedId) {
|
||||
FeedVo feed = getDetail(feedId);
|
||||
|
||||
if(feed.getMediaType().equals(FeedEnum.WORD.getType())){
|
||||
CacheResult<Object> cacheResult = cachePlusOps.hGet(FeedMediaRelCacheKeyBuilder.build(feedId));
|
||||
List<FeedMedia> feedMediaList = cacheResult.asList();
|
||||
if(CollUtil.isEmpty(feedMediaList)){
|
||||
feedMediaList = feedMediaDao.getMediaByFeedId(feedId);
|
||||
}
|
||||
if(!feed.getMediaType().equals(FeedEnum.WORD.getType())){
|
||||
// 使用带回调的方式,自动处理缓存读写
|
||||
CacheHashKey hashKey = FeedMediaRelCacheKeyBuilder.build(feedId);
|
||||
CacheResult<List<FeedMedia>> result = cachePlusOps.get(hashKey, t -> feedMediaDao.getMediaByFeedId(feedId));
|
||||
List<FeedMedia> feedMediaList = result.getValue();
|
||||
|
||||
if (CollUtil.isNotEmpty(feedMediaList)){
|
||||
feed.setUrls(feedMediaList.stream().sorted(Comparator.comparingInt(FeedMedia::getSort)).map(FeedMedia::getUrl).collect(Collectors.toList()));
|
||||
}
|
||||
@@ -313,8 +363,8 @@ public class FeedServiceImpl implements FeedService {
|
||||
feedTargetDao.delByFeedId(feed.getId());
|
||||
feedMediaDao.delMediaByFeedId(feed.getId());
|
||||
|
||||
// 3. 更新朋友圈的权限+素材
|
||||
saveFeed(param, uid, feed);
|
||||
// 3. 更新朋友圈的权限+素材(编辑场景,需要清除缓存)
|
||||
saveFeed(param, uid, feed, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,18 +18,28 @@ package com.luohuo.flex.oauth.granter;
|
||||
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.session.SaTerminalInfo;
|
||||
import cn.dev33.satoken.stp.SaLoginModel;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.temp.SaTempUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.luohuo.basic.context.ContextUtil;
|
||||
import com.luohuo.basic.exception.TokenExceedException;
|
||||
import com.luohuo.basic.utils.SpringUtils;
|
||||
import com.luohuo.flex.common.utils.ToolsUtil;
|
||||
import com.luohuo.flex.model.entity.ws.OffLineResp;
|
||||
import com.luohuo.flex.oauth.event.TokenExpireEvent;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.luohuo.flex.oauth.vo.result.LoginResultVO;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.luohuo.basic.context.ContextConstants.*;
|
||||
|
||||
/**
|
||||
@@ -66,8 +76,11 @@ public class RefreshTokenGranter {
|
||||
String systemType = obj.getStr(JWT_KEY_SYSTEM_TYPE);
|
||||
String device = obj.getStr(JWT_KEY_DEVICE);
|
||||
|
||||
// 2、为其生成新的短 token
|
||||
StpUtil.login(userId, new SaLoginModel().setDevice(ToolsUtil.combineStrings(systemType, device)));
|
||||
// 2、处理挤下线逻辑
|
||||
String combinedDeviceType = kickout(uid, userId, systemType, device);
|
||||
|
||||
// 3、为其生成新的短 token
|
||||
StpUtil.login(userId, new SaLoginModel().setDevice(combinedDeviceType));
|
||||
SaSession tokenSession = StpUtil.getTokenSession();
|
||||
tokenSession.setLoginId(userId);
|
||||
tokenSession.set(JWT_KEY_SYSTEM_TYPE, systemType);
|
||||
@@ -108,4 +121,50 @@ public class RefreshTokenGranter {
|
||||
return resultVO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理挤下线的逻辑(刷新 token 时)
|
||||
* @param uid 登录id
|
||||
* @param userId 用户基础信息ID
|
||||
* @param systemType 系统类型
|
||||
* @param deviceType 登录设备
|
||||
* @return 组合后的设备类型
|
||||
*/
|
||||
private String kickout(Long uid, Long userId, String systemType, String deviceType) {
|
||||
// 1. 组合完整的设备类型标识
|
||||
String combinedDeviceType = ToolsUtil.combineStrings(systemType, deviceType);
|
||||
|
||||
// 2. 检查是否已有相同组合设备的登录
|
||||
List<String> sameDeviceTokens = new ArrayList<>();
|
||||
SaSession saSession = StpUtil.getSessionByLoginId(userId.toString(), false);
|
||||
|
||||
if (ObjectUtil.isNotNull(saSession)) {
|
||||
for (SaTerminalInfo terminal : saSession.getTerminalList()) {
|
||||
String terminalDeviceType = terminal.getDeviceType();
|
||||
String tokenValue = terminal.getTokenValue();
|
||||
|
||||
// 3. 匹配设备类型
|
||||
if (combinedDeviceType.equals(terminalDeviceType)) {
|
||||
sameDeviceTokens.add(tokenValue);
|
||||
log.info("刷新token时发现同设备登录: token={}, 设备类型={}", tokenValue, terminalDeviceType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 处理已有登录
|
||||
if (CollUtil.isNotEmpty(sameDeviceTokens)) {
|
||||
for (String token : sameDeviceTokens) {
|
||||
try {
|
||||
String clientId = StpUtil.getTokenSessionByToken(token).getString(CLIENT_ID);
|
||||
StpUtil.kickout(token);
|
||||
log.info("刷新token时已踢出旧会话: token={}", token);
|
||||
|
||||
SpringUtils.publishEvent(new TokenExpireEvent(this, new OffLineResp(uid, deviceType, clientId, ContextUtil.getIP(), token)));
|
||||
} catch (Exception e) {
|
||||
log.error("刷新token时踢出旧会话失败: token={}", token, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return combinedDeviceType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user