Commit 90fa7be66001068f558835ca86fd82a1aeb39a62
Committed by
Gitee
!1006 AI 大模型的草稿提交(code review 代码)
Merge pull request !1006 from 芋道源码/master-jdk21-ai
Showing
172 changed files
with
13626 additions
and
333 deletions
Too many changes.
To preserve performance only 100 of 172 files are displayed.
.DS_Store
0 → 100644
No preview for this file type
pom.xml
| ... | ... | @@ -23,6 +23,7 @@ |
| 23 | 23 | <!-- <module>yudao-module-mall</module>--> |
| 24 | 24 | <!-- <module>yudao-module-crm</module>--> |
| 25 | 25 | <!-- <module>yudao-module-erp</module>--> |
| 26 | + <module>yudao-module-ai</module> | |
| 26 | 27 | </modules> |
| 27 | 28 | |
| 28 | 29 | <name>${project.artifactId}</name> |
| ... | ... | @@ -147,6 +148,23 @@ |
| 147 | 148 | <name>aliyun</name> |
| 148 | 149 | <url>https://maven.aliyun.com/repository/public</url> |
| 149 | 150 | </repository> |
| 151 | + | |
| 152 | + <repository> | |
| 153 | + <id>spring-milestones</id> | |
| 154 | + <name>Spring Milestones</name> | |
| 155 | + <url>https://repo.spring.io/milestone</url> | |
| 156 | + <snapshots> | |
| 157 | + <enabled>false</enabled> | |
| 158 | + </snapshots> | |
| 159 | + </repository> | |
| 160 | + <repository> | |
| 161 | + <id>spring-snapshots</id> | |
| 162 | + <name>Spring Snapshots</name> | |
| 163 | + <url>https://repo.spring.io/snapshot</url> | |
| 164 | + <releases> | |
| 165 | + <enabled>false</enabled> | |
| 166 | + </releases> | |
| 167 | + </repository> | |
| 150 | 168 | </repositories> |
| 151 | 169 | |
| 152 | 170 | </project> | ... | ... |
sql/mysql/ruoyi-vue-pro.sql
| ... | ... | @@ -11,308 +11,13 @@ |
| 11 | 11 | Target Server Version : 80200 (8.2.0) |
| 12 | 12 | File Encoding : 65001 |
| 13 | 13 | |
| 14 | - Date: 30/04/2024 09:54:18 | |
| 14 | + Date: 07/07/2024 18:29:17 | |
| 15 | 15 | */ |
| 16 | 16 | |
| 17 | 17 | SET NAMES utf8mb4; |
| 18 | 18 | SET FOREIGN_KEY_CHECKS = 0; |
| 19 | 19 | |
| 20 | 20 | -- ---------------------------- |
| 21 | --- Table structure for QRTZ_BLOB_TRIGGERS | |
| 22 | --- ---------------------------- | |
| 23 | -DROP TABLE IF EXISTS `QRTZ_BLOB_TRIGGERS`; | |
| 24 | -CREATE TABLE `QRTZ_BLOB_TRIGGERS` ( | |
| 25 | - `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 26 | - `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 27 | - `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 28 | - `BLOB_DATA` blob NULL, | |
| 29 | - PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, | |
| 30 | - INDEX `SCHED_NAME`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE, | |
| 31 | - CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT | |
| 32 | -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; | |
| 33 | - | |
| 34 | --- ---------------------------- | |
| 35 | --- Records of QRTZ_BLOB_TRIGGERS | |
| 36 | --- ---------------------------- | |
| 37 | -BEGIN; | |
| 38 | -COMMIT; | |
| 39 | - | |
| 40 | --- ---------------------------- | |
| 41 | --- Table structure for QRTZ_CALENDARS | |
| 42 | --- ---------------------------- | |
| 43 | -DROP TABLE IF EXISTS `QRTZ_CALENDARS`; | |
| 44 | -CREATE TABLE `QRTZ_CALENDARS` ( | |
| 45 | - `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 46 | - `CALENDAR_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 47 | - `CALENDAR` blob NOT NULL, | |
| 48 | - PRIMARY KEY (`SCHED_NAME`, `CALENDAR_NAME`) USING BTREE | |
| 49 | -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; | |
| 50 | - | |
| 51 | --- ---------------------------- | |
| 52 | --- Records of QRTZ_CALENDARS | |
| 53 | --- ---------------------------- | |
| 54 | -BEGIN; | |
| 55 | -COMMIT; | |
| 56 | - | |
| 57 | --- ---------------------------- | |
| 58 | --- Table structure for QRTZ_CRON_TRIGGERS | |
| 59 | --- ---------------------------- | |
| 60 | -DROP TABLE IF EXISTS `QRTZ_CRON_TRIGGERS`; | |
| 61 | -CREATE TABLE `QRTZ_CRON_TRIGGERS` ( | |
| 62 | - `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 63 | - `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 64 | - `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 65 | - `CRON_EXPRESSION` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 66 | - `TIME_ZONE_ID` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, | |
| 67 | - PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, | |
| 68 | - CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT | |
| 69 | -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; | |
| 70 | - | |
| 71 | --- ---------------------------- | |
| 72 | --- Records of QRTZ_CRON_TRIGGERS | |
| 73 | --- ---------------------------- | |
| 74 | -BEGIN; | |
| 75 | -INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'accessLogCleanJob', 'DEFAULT', '0 0 0 * * ?', 'Asia/Shanghai'); | |
| 76 | -INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'brokerageRecordUnfreezeJob', 'DEFAULT', '0 * * * * ?', 'Asia/Shanghai'); | |
| 77 | -INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'errorLogCleanJob', 'DEFAULT', '0 0 0 * * ?', 'Asia/Shanghai'); | |
| 78 | -INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'jobLogCleanJob', 'DEFAULT', '0 0 0 * * ?', 'Asia/Shanghai'); | |
| 79 | -INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', '* * * * * ?', 'Asia/Shanghai'); | |
| 80 | -INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'payOrderExpireJob', 'DEFAULT', '0 0/1 * * * ?', 'Asia/Shanghai'); | |
| 81 | -INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'payOrderSyncJob', 'DEFAULT', '0 0/1 * * * ?', 'Asia/Shanghai'); | |
| 82 | -INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'payRefundSyncJob', 'DEFAULT', '0 0/1 * * * ?', 'Asia/Shanghai'); | |
| 83 | -INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'tradeOrderAutoCancelJob', 'DEFAULT', '0 * * * * ?', 'Asia/Shanghai'); | |
| 84 | -INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'tradeOrderAutoCommentJob', 'DEFAULT', '0 * * * * ?', 'Asia/Shanghai'); | |
| 85 | -INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'tradeOrderAutoReceiveJob', 'DEFAULT', '0 * * * * ?', 'Asia/Shanghai'); | |
| 86 | -COMMIT; | |
| 87 | - | |
| 88 | --- ---------------------------- | |
| 89 | --- Table structure for QRTZ_FIRED_TRIGGERS | |
| 90 | --- ---------------------------- | |
| 91 | -DROP TABLE IF EXISTS `QRTZ_FIRED_TRIGGERS`; | |
| 92 | -CREATE TABLE `QRTZ_FIRED_TRIGGERS` ( | |
| 93 | - `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 94 | - `ENTRY_ID` varchar(95) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 95 | - `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 96 | - `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 97 | - `INSTANCE_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 98 | - `FIRED_TIME` bigint NOT NULL, | |
| 99 | - `SCHED_TIME` bigint NOT NULL, | |
| 100 | - `PRIORITY` int NOT NULL, | |
| 101 | - `STATE` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 102 | - `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, | |
| 103 | - `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, | |
| 104 | - `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, | |
| 105 | - `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, | |
| 106 | - PRIMARY KEY (`SCHED_NAME`, `ENTRY_ID`) USING BTREE, | |
| 107 | - INDEX `IDX_QRTZ_FT_TRIG_INST_NAME`(`SCHED_NAME` ASC, `INSTANCE_NAME` ASC) USING BTREE, | |
| 108 | - INDEX `IDX_QRTZ_FT_INST_JOB_REQ_RCVRY`(`SCHED_NAME` ASC, `INSTANCE_NAME` ASC, `REQUESTS_RECOVERY` ASC) USING BTREE, | |
| 109 | - INDEX `IDX_QRTZ_FT_J_G`(`SCHED_NAME` ASC, `JOB_NAME` ASC, `JOB_GROUP` ASC) USING BTREE, | |
| 110 | - INDEX `IDX_QRTZ_FT_JG`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE, | |
| 111 | - INDEX `IDX_QRTZ_FT_T_G`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE, | |
| 112 | - INDEX `IDX_QRTZ_FT_TG`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE | |
| 113 | -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; | |
| 114 | - | |
| 115 | --- ---------------------------- | |
| 116 | --- Records of QRTZ_FIRED_TRIGGERS | |
| 117 | --- ---------------------------- | |
| 118 | -BEGIN; | |
| 119 | -COMMIT; | |
| 120 | - | |
| 121 | --- ---------------------------- | |
| 122 | --- Table structure for QRTZ_JOB_DETAILS | |
| 123 | --- ---------------------------- | |
| 124 | -DROP TABLE IF EXISTS `QRTZ_JOB_DETAILS`; | |
| 125 | -CREATE TABLE `QRTZ_JOB_DETAILS` ( | |
| 126 | - `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 127 | - `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 128 | - `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 129 | - `DESCRIPTION` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, | |
| 130 | - `JOB_CLASS_NAME` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 131 | - `IS_DURABLE` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 132 | - `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 133 | - `IS_UPDATE_DATA` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 134 | - `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 135 | - `JOB_DATA` blob NULL, | |
| 136 | - PRIMARY KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) USING BTREE, | |
| 137 | - INDEX `IDX_QRTZ_J_REQ_RECOVERY`(`SCHED_NAME` ASC, `REQUESTS_RECOVERY` ASC) USING BTREE, | |
| 138 | - INDEX `IDX_QRTZ_J_GRP`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE | |
| 139 | -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; | |
| 140 | - | |
| 141 | --- ---------------------------- | |
| 142 | --- Records of QRTZ_JOB_DETAILS | |
| 143 | --- ---------------------------- | |
| 144 | -BEGIN; | |
| 145 | -INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'accessLogCleanJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000197400104A4F425F48414E444C45525F4E414D457400116163636573734C6F67436C65616E4A6F627800); | |
| 146 | -INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'brokerageRecordUnfreezeJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000187400104A4F425F48414E444C45525F4E414D4574001A62726F6B65726167655265636F7264556E667265657A654A6F627800); | |
| 147 | -INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'errorLogCleanJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000000000001A7400104A4F425F48414E444C45525F4E414D457400106572726F724C6F67436C65616E4A6F627800); | |
| 148 | -INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'jobLogCleanJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000000000001B7400104A4F425F48414E444C45525F4E414D4574000E6A6F624C6F67436C65616E4A6F627800); | |
| 149 | -INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000057400104A4F425F48414E444C45525F4E414D4574000C7061794E6F746966794A6F627800); | |
| 150 | -INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'payOrderExpireJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000127400104A4F425F48414E444C45525F4E414D457400117061794F726465724578706972654A6F627800); | |
| 151 | -INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'payOrderSyncJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000117400104A4F425F48414E444C45525F4E414D4574000F7061794F7264657253796E634A6F627800); | |
| 152 | -INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'payRefundSyncJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000137400104A4F425F48414E444C45525F4E414D45740010706179526566756E6453796E634A6F627800); | |
| 153 | -INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'tradeOrderAutoCancelJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000157400104A4F425F48414E444C45525F4E414D4574001774726164654F726465724175746F43616E63656C4A6F627800); | |
| 154 | -INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'tradeOrderAutoCommentJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000177400104A4F425F48414E444C45525F4E414D4574001874726164654F726465724175746F436F6D6D656E744A6F627800); | |
| 155 | -INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'tradeOrderAutoReceiveJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000167400104A4F425F48414E444C45525F4E414D4574001874726164654F726465724175746F526563656976654A6F627800); | |
| 156 | -COMMIT; | |
| 157 | - | |
| 158 | --- ---------------------------- | |
| 159 | --- Table structure for QRTZ_LOCKS | |
| 160 | --- ---------------------------- | |
| 161 | -DROP TABLE IF EXISTS `QRTZ_LOCKS`; | |
| 162 | -CREATE TABLE `QRTZ_LOCKS` ( | |
| 163 | - `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 164 | - `LOCK_NAME` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 165 | - PRIMARY KEY (`SCHED_NAME`, `LOCK_NAME`) USING BTREE | |
| 166 | -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; | |
| 167 | - | |
| 168 | --- ---------------------------- | |
| 169 | --- Records of QRTZ_LOCKS | |
| 170 | --- ---------------------------- | |
| 171 | -BEGIN; | |
| 172 | -INSERT INTO `QRTZ_LOCKS` (`SCHED_NAME`, `LOCK_NAME`) VALUES ('schedulerName', 'STATE_ACCESS'); | |
| 173 | -INSERT INTO `QRTZ_LOCKS` (`SCHED_NAME`, `LOCK_NAME`) VALUES ('schedulerName', 'TRIGGER_ACCESS'); | |
| 174 | -COMMIT; | |
| 175 | - | |
| 176 | --- ---------------------------- | |
| 177 | --- Table structure for QRTZ_PAUSED_TRIGGER_GRPS | |
| 178 | --- ---------------------------- | |
| 179 | -DROP TABLE IF EXISTS `QRTZ_PAUSED_TRIGGER_GRPS`; | |
| 180 | -CREATE TABLE `QRTZ_PAUSED_TRIGGER_GRPS` ( | |
| 181 | - `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 182 | - `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 183 | - PRIMARY KEY (`SCHED_NAME`, `TRIGGER_GROUP`) USING BTREE | |
| 184 | -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; | |
| 185 | - | |
| 186 | --- ---------------------------- | |
| 187 | --- Records of QRTZ_PAUSED_TRIGGER_GRPS | |
| 188 | --- ---------------------------- | |
| 189 | -BEGIN; | |
| 190 | -COMMIT; | |
| 191 | - | |
| 192 | --- ---------------------------- | |
| 193 | --- Table structure for QRTZ_SCHEDULER_STATE | |
| 194 | --- ---------------------------- | |
| 195 | -DROP TABLE IF EXISTS `QRTZ_SCHEDULER_STATE`; | |
| 196 | -CREATE TABLE `QRTZ_SCHEDULER_STATE` ( | |
| 197 | - `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 198 | - `INSTANCE_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 199 | - `LAST_CHECKIN_TIME` bigint NOT NULL, | |
| 200 | - `CHECKIN_INTERVAL` bigint NOT NULL, | |
| 201 | - PRIMARY KEY (`SCHED_NAME`, `INSTANCE_NAME`) USING BTREE | |
| 202 | -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; | |
| 203 | - | |
| 204 | --- ---------------------------- | |
| 205 | --- Records of QRTZ_SCHEDULER_STATE | |
| 206 | --- ---------------------------- | |
| 207 | -BEGIN; | |
| 208 | -INSERT INTO `QRTZ_SCHEDULER_STATE` (`SCHED_NAME`, `INSTANCE_NAME`, `LAST_CHECKIN_TIME`, `CHECKIN_INTERVAL`) VALUES ('schedulerName', 'MacBook-Pro.local1713489703551', 1713742509534, 15000); | |
| 209 | -COMMIT; | |
| 210 | - | |
| 211 | --- ---------------------------- | |
| 212 | --- Table structure for QRTZ_SIMPLE_TRIGGERS | |
| 213 | --- ---------------------------- | |
| 214 | -DROP TABLE IF EXISTS `QRTZ_SIMPLE_TRIGGERS`; | |
| 215 | -CREATE TABLE `QRTZ_SIMPLE_TRIGGERS` ( | |
| 216 | - `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 217 | - `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 218 | - `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 219 | - `REPEAT_COUNT` bigint NOT NULL, | |
| 220 | - `REPEAT_INTERVAL` bigint NOT NULL, | |
| 221 | - `TIMES_TRIGGERED` bigint NOT NULL, | |
| 222 | - PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, | |
| 223 | - CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT | |
| 224 | -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; | |
| 225 | - | |
| 226 | --- ---------------------------- | |
| 227 | --- Records of QRTZ_SIMPLE_TRIGGERS | |
| 228 | --- ---------------------------- | |
| 229 | -BEGIN; | |
| 230 | -COMMIT; | |
| 231 | - | |
| 232 | --- ---------------------------- | |
| 233 | --- Table structure for QRTZ_SIMPROP_TRIGGERS | |
| 234 | --- ---------------------------- | |
| 235 | -DROP TABLE IF EXISTS `QRTZ_SIMPROP_TRIGGERS`; | |
| 236 | -CREATE TABLE `QRTZ_SIMPROP_TRIGGERS` ( | |
| 237 | - `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 238 | - `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 239 | - `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 240 | - `STR_PROP_1` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, | |
| 241 | - `STR_PROP_2` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, | |
| 242 | - `STR_PROP_3` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, | |
| 243 | - `INT_PROP_1` int NULL DEFAULT NULL, | |
| 244 | - `INT_PROP_2` int NULL DEFAULT NULL, | |
| 245 | - `LONG_PROP_1` bigint NULL DEFAULT NULL, | |
| 246 | - `LONG_PROP_2` bigint NULL DEFAULT NULL, | |
| 247 | - `DEC_PROP_1` decimal(13, 4) NULL DEFAULT NULL, | |
| 248 | - `DEC_PROP_2` decimal(13, 4) NULL DEFAULT NULL, | |
| 249 | - `BOOL_PROP_1` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, | |
| 250 | - `BOOL_PROP_2` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, | |
| 251 | - PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, | |
| 252 | - CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT | |
| 253 | -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; | |
| 254 | - | |
| 255 | --- ---------------------------- | |
| 256 | --- Records of QRTZ_SIMPROP_TRIGGERS | |
| 257 | --- ---------------------------- | |
| 258 | -BEGIN; | |
| 259 | -COMMIT; | |
| 260 | - | |
| 261 | --- ---------------------------- | |
| 262 | --- Table structure for QRTZ_TRIGGERS | |
| 263 | --- ---------------------------- | |
| 264 | -DROP TABLE IF EXISTS `QRTZ_TRIGGERS`; | |
| 265 | -CREATE TABLE `QRTZ_TRIGGERS` ( | |
| 266 | - `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 267 | - `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 268 | - `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 269 | - `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 270 | - `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 271 | - `DESCRIPTION` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, | |
| 272 | - `NEXT_FIRE_TIME` bigint NULL DEFAULT NULL, | |
| 273 | - `PREV_FIRE_TIME` bigint NULL DEFAULT NULL, | |
| 274 | - `PRIORITY` int NULL DEFAULT NULL, | |
| 275 | - `TRIGGER_STATE` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 276 | - `TRIGGER_TYPE` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, | |
| 277 | - `START_TIME` bigint NOT NULL, | |
| 278 | - `END_TIME` bigint NULL DEFAULT NULL, | |
| 279 | - `CALENDAR_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, | |
| 280 | - `MISFIRE_INSTR` smallint NULL DEFAULT NULL, | |
| 281 | - `JOB_DATA` blob NULL, | |
| 282 | - PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, | |
| 283 | - INDEX `IDX_QRTZ_T_J`(`SCHED_NAME` ASC, `JOB_NAME` ASC, `JOB_GROUP` ASC) USING BTREE, | |
| 284 | - INDEX `IDX_QRTZ_T_JG`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE, | |
| 285 | - INDEX `IDX_QRTZ_T_C`(`SCHED_NAME` ASC, `CALENDAR_NAME` ASC) USING BTREE, | |
| 286 | - INDEX `IDX_QRTZ_T_G`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE, | |
| 287 | - INDEX `IDX_QRTZ_T_STATE`(`SCHED_NAME` ASC, `TRIGGER_STATE` ASC) USING BTREE, | |
| 288 | - INDEX `IDX_QRTZ_T_N_STATE`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE, | |
| 289 | - INDEX `IDX_QRTZ_T_N_G_STATE`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE, | |
| 290 | - INDEX `IDX_QRTZ_T_NEXT_FIRE_TIME`(`SCHED_NAME` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE, | |
| 291 | - INDEX `IDX_QRTZ_T_NFT_ST`(`SCHED_NAME` ASC, `TRIGGER_STATE` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE, | |
| 292 | - INDEX `IDX_QRTZ_T_NFT_MISFIRE`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE, | |
| 293 | - INDEX `IDX_QRTZ_T_NFT_ST_MISFIRE`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC, `TRIGGER_STATE` ASC) USING BTREE, | |
| 294 | - INDEX `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE, | |
| 295 | - CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT | |
| 296 | -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; | |
| 297 | - | |
| 298 | --- ---------------------------- | |
| 299 | --- Records of QRTZ_TRIGGERS | |
| 300 | --- ---------------------------- | |
| 301 | -BEGIN; | |
| 302 | -INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'accessLogCleanJob', 'DEFAULT', 'accessLogCleanJob', 'DEFAULT', NULL, 1696348800000, -1, 5, 'PAUSED', 'CRON', 1696301981000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); | |
| 303 | -INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'brokerageRecordUnfreezeJob', 'DEFAULT', 'brokerageRecordUnfreezeJob', 'DEFAULT', NULL, 1695909720000, -1, 5, 'PAUSED', 'CRON', 1695909706000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); | |
| 304 | -INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'errorLogCleanJob', 'DEFAULT', 'errorLogCleanJob', 'DEFAULT', NULL, 1696348800000, -1, 5, 'PAUSED', 'CRON', 1696302043000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); | |
| 305 | -INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'jobLogCleanJob', 'DEFAULT', 'jobLogCleanJob', 'DEFAULT', NULL, 1696348800000, -1, 5, 'PAUSED', 'CRON', 1696302092000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); | |
| 306 | -INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', 'payNotifyJob', 'DEFAULT', NULL, 1688907102000, 1688907101000, 5, 'PAUSED', 'CRON', 1635294882000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800); | |
| 307 | -INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'payOrderExpireJob', 'DEFAULT', 'payOrderExpireJob', 'DEFAULT', NULL, 1690011600000, -1, 5, 'PAUSED', 'CRON', 1690011553000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800); | |
| 308 | -INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'payOrderSyncJob', 'DEFAULT', 'payOrderSyncJob', 'DEFAULT', NULL, 1690011600000, 1690011540000, 5, 'PAUSED', 'CRON', 1690007785000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800); | |
| 309 | -INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'payRefundSyncJob', 'DEFAULT', 'payRefundSyncJob', 'DEFAULT', NULL, 1690117560000, 1690117500000, 5, 'PAUSED', 'CRON', 1690117424000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800); | |
| 310 | -INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'tradeOrderAutoCancelJob', 'DEFAULT', 'tradeOrderAutoCancelJob', 'DEFAULT', NULL, 1695727440000, 1695727380000, 5, 'PAUSED', 'CRON', 1695656605000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); | |
| 311 | -INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'tradeOrderAutoCommentJob', 'DEFAULT', 'tradeOrderAutoCommentJob', 'DEFAULT', NULL, 1695783840000, 1695783780000, 5, 'PAUSED', 'CRON', 1695742709000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); | |
| 312 | -INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'tradeOrderAutoReceiveJob', 'DEFAULT', 'tradeOrderAutoReceiveJob', 'DEFAULT', NULL, 1695742740000, 1695742680000, 5, 'PAUSED', 'CRON', 1695727433000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); | |
| 313 | -COMMIT; | |
| 314 | - | |
| 315 | --- ---------------------------- | |
| 316 | 21 | -- Table structure for infra_api_access_log |
| 317 | 22 | -- ---------------------------- |
| 318 | 23 | DROP TABLE IF EXISTS `infra_api_access_log`; |
| ... | ... | @@ -344,7 +49,7 @@ CREATE TABLE `infra_api_access_log` ( |
| 344 | 49 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 345 | 50 | PRIMARY KEY (`id`) USING BTREE, |
| 346 | 51 | INDEX `idx_create_time`(`create_time` ASC) USING BTREE |
| 347 | -) ENGINE = InnoDB AUTO_INCREMENT = 35934 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'API 访问日志表'; | |
| 52 | +) ENGINE = InnoDB AUTO_INCREMENT = 35940 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'API 访问日志表'; | |
| 348 | 53 | |
| 349 | 54 | -- ---------------------------- |
| 350 | 55 | -- Records of infra_api_access_log |
| ... | ... | @@ -358,24 +63,24 @@ COMMIT; |
| 358 | 63 | DROP TABLE IF EXISTS `infra_api_error_log`; |
| 359 | 64 | CREATE TABLE `infra_api_error_log` ( |
| 360 | 65 | `id` int NOT NULL AUTO_INCREMENT COMMENT '编号', |
| 361 | - `trace_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '链路追踪编号\n *\n * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。', | |
| 66 | + `trace_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '链路追踪编号', | |
| 362 | 67 | `user_id` int NOT NULL DEFAULT 0 COMMENT '用户编号', |
| 363 | 68 | `user_type` tinyint NOT NULL DEFAULT 0 COMMENT '用户类型', |
| 364 | - `application_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '应用名\n *\n * 目前读取 spring.application.name', | |
| 69 | + `application_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '应用名', | |
| 365 | 70 | `request_method` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '请求方法名', |
| 366 | 71 | `request_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '请求地址', |
| 367 | 72 | `request_params` varchar(8000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '请求参数', |
| 368 | 73 | `user_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户 IP', |
| 369 | 74 | `user_agent` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '浏览器 UA', |
| 370 | 75 | `exception_time` datetime NOT NULL COMMENT '异常发生时间', |
| 371 | - `exception_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '异常名\n *\n * {@link Throwable#getClass()} 的类全名', | |
| 372 | - `exception_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常导致的消息\n *\n * {@link cn.iocoder.common.framework.util.ExceptionUtil#getMessage(Throwable)}', | |
| 373 | - `exception_root_cause_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常导致的根消息\n *\n * {@link cn.iocoder.common.framework.util.ExceptionUtil#getRootCauseMessage(Throwable)}', | |
| 374 | - `exception_stack_trace` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常的栈轨迹\n *\n * {@link cn.iocoder.common.framework.util.ExceptionUtil#getServiceException(Exception)}', | |
| 375 | - `exception_class_name` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常发生的类全名\n *\n * {@link StackTraceElement#getClassName()}', | |
| 376 | - `exception_file_name` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常发生的类文件\n *\n * {@link StackTraceElement#getFileName()}', | |
| 377 | - `exception_method_name` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常发生的方法名\n *\n * {@link StackTraceElement#getMethodName()}', | |
| 378 | - `exception_line_number` int NOT NULL COMMENT '异常发生的方法所在行\n *\n * {@link StackTraceElement#getLineNumber()}', | |
| 76 | + `exception_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '异常名', | |
| 77 | + `exception_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常导致的消息', | |
| 78 | + `exception_root_cause_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常导致的根消息', | |
| 79 | + `exception_stack_trace` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常的栈轨迹', | |
| 80 | + `exception_class_name` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常发生的类全名', | |
| 81 | + `exception_file_name` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常发生的类文件', | |
| 82 | + `exception_method_name` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常发生的方法名', | |
| 83 | + `exception_line_number` int NOT NULL COMMENT '异常发生的方法所在行', | |
| 379 | 84 | `process_status` tinyint NOT NULL COMMENT '处理状态', |
| 380 | 85 | `process_time` datetime NULL DEFAULT NULL COMMENT '处理时间', |
| 381 | 86 | `process_user_id` int NULL DEFAULT 0 COMMENT '处理用户编号', |
| ... | ... | @@ -386,7 +91,7 @@ CREATE TABLE `infra_api_error_log` ( |
| 386 | 91 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 387 | 92 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 388 | 93 | PRIMARY KEY (`id`) USING BTREE |
| 389 | -) ENGINE = InnoDB AUTO_INCREMENT = 16530 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志'; | |
| 94 | +) ENGINE = InnoDB AUTO_INCREMENT = 17761 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志'; | |
| 390 | 95 | |
| 391 | 96 | -- ---------------------------- |
| 392 | 97 | -- Records of infra_api_error_log |
| ... | ... | @@ -423,7 +128,7 @@ CREATE TABLE `infra_codegen_column` ( |
| 423 | 128 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 424 | 129 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 425 | 130 | PRIMARY KEY (`id`) USING BTREE |
| 426 | -) ENGINE = InnoDB AUTO_INCREMENT = 2305 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义'; | |
| 131 | +) ENGINE = InnoDB AUTO_INCREMENT = 2440 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义'; | |
| 427 | 132 | |
| 428 | 133 | -- ---------------------------- |
| 429 | 134 | -- Records of infra_codegen_column |
| ... | ... | @@ -461,7 +166,7 @@ CREATE TABLE `infra_codegen_table` ( |
| 461 | 166 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 462 | 167 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 463 | 168 | PRIMARY KEY (`id`) USING BTREE |
| 464 | -) ENGINE = InnoDB AUTO_INCREMENT = 176 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表定义'; | |
| 169 | +) ENGINE = InnoDB AUTO_INCREMENT = 184 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表定义'; | |
| 465 | 170 | |
| 466 | 171 | -- ---------------------------- |
| 467 | 172 | -- Records of infra_codegen_table |
| ... | ... | @@ -545,7 +250,7 @@ CREATE TABLE `infra_file` ( |
| 545 | 250 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 546 | 251 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 547 | 252 | PRIMARY KEY (`id`) USING BTREE |
| 548 | -) ENGINE = InnoDB AUTO_INCREMENT = 1307 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; | |
| 253 | +) ENGINE = InnoDB AUTO_INCREMENT = 1397 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; | |
| 549 | 254 | |
| 550 | 255 | -- ---------------------------- |
| 551 | 256 | -- Records of infra_file |
| ... | ... | @@ -691,7 +396,7 @@ CREATE TABLE `system_dept` ( |
| 691 | 396 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 692 | 397 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 693 | 398 | PRIMARY KEY (`id`) USING BTREE |
| 694 | -) ENGINE = InnoDB AUTO_INCREMENT = 114 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '部门表'; | |
| 399 | +) ENGINE = InnoDB AUTO_INCREMENT = 115 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '部门表'; | |
| 695 | 400 | |
| 696 | 401 | -- ---------------------------- |
| 697 | 402 | -- Records of system_dept |
| ... | ... | @@ -733,7 +438,7 @@ CREATE TABLE `system_dict_data` ( |
| 733 | 438 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 734 | 439 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 735 | 440 | PRIMARY KEY (`id`) USING BTREE |
| 736 | -) ENGINE = InnoDB AUTO_INCREMENT = 1537 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表'; | |
| 441 | +) ENGINE = InnoDB AUTO_INCREMENT = 1555 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表'; | |
| 737 | 442 | |
| 738 | 443 | -- ---------------------------- |
| 739 | 444 | -- Records of system_dict_data |
| ... | ... | @@ -1104,6 +809,24 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st |
| 1104 | 809 | INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1534, 1, '赢单', '1', 'crm_business_end_status_type', 0, 'success', '', '', '1', '2024-04-13 23:26:57', '1', '2024-04-13 23:26:57', b'0'); |
| 1105 | 810 | INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1535, 2, '输单', '2', 'crm_business_end_status_type', 0, 'primary', '', '', '1', '2024-04-13 23:27:31', '1', '2024-04-13 23:27:31', b'0'); |
| 1106 | 811 | INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1536, 3, '无效', '3', 'crm_business_end_status_type', 0, 'info', '', '', '1', '2024-04-13 23:27:59', '1', '2024-04-13 23:27:59', b'0'); |
| 812 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1537, 1, 'OpenAI', 'OpenAI', 'ai_platform', 0, '', '', '', '1', '2024-05-09 22:33:47', '1', '2024-05-09 22:58:46', b'0'); | |
| 813 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1538, 2, 'Ollama', 'Ollama', 'ai_platform', 0, '', '', '', '1', '2024-05-17 23:02:55', '1', '2024-05-17 23:02:55', b'0'); | |
| 814 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1539, 3, '文心一言', 'YiYan', 'ai_platform', 0, '', '', '', '1', '2024-05-18 09:24:20', '1', '2024-05-18 09:29:01', b'0'); | |
| 815 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1540, 4, '讯飞星火', 'XingHuo', 'ai_platform', 0, '', '', '', '1', '2024-05-18 10:08:56', '1', '2024-05-18 10:08:56', b'0'); | |
| 816 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1541, 5, '通义千问', 'TongYi', 'ai_platform', 0, '', '', '', '1', '2024-05-18 10:32:29', '1', '2024-07-06 15:42:29', b'0'); | |
| 817 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1542, 6, 'StableDiffusion', 'StableDiffusion', 'ai_platform', 0, '', '', '', '1', '2024-06-01 15:09:31', '1', '2024-06-01 15:10:25', b'0'); | |
| 818 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1543, 10, '进行中', '10', 'ai_image_status', 0, 'primary', '', '', '1', '2024-06-26 20:51:41', '1', '2024-06-26 20:52:48', b'0'); | |
| 819 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1544, 20, '已完成', '20', 'ai_image_status', 0, 'success', '', '', '1', '2024-06-26 20:52:07', '1', '2024-06-26 20:52:41', b'0'); | |
| 820 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1545, 30, '已失败', '30', 'ai_image_status', 0, 'warning', '', '', '1', '2024-06-26 20:52:25', '1', '2024-06-26 20:52:35', b'0'); | |
| 821 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1546, 7, 'Midjourney', 'Midjourney', 'ai_platform', 0, '', '', '', '1', '2024-06-26 22:14:46', '1', '2024-06-26 22:14:46', b'0'); | |
| 822 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1547, 10, '进行中', '10', 'ai_music_status', 0, 'primary', '', '', '1', '2024-06-27 22:45:22', '1', '2024-06-28 00:56:17', b'0'); | |
| 823 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1548, 20, '已完成', '20', 'ai_music_status', 0, 'success', '', '', '1', '2024-06-27 22:45:33', '1', '2024-06-28 00:56:18', b'0'); | |
| 824 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1549, 30, '已失败', '30', 'ai_music_status', 0, 'danger', '', '', '1', '2024-06-27 22:45:44', '1', '2024-06-28 00:56:19', b'0'); | |
| 825 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1550, 1, '歌词模式', '1', 'ai_generate_mode', 0, '', '', '', '1', '2024-06-27 22:46:31', '1', '2024-06-28 01:22:25', b'0'); | |
| 826 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1551, 2, '描述模式', '2', 'ai_generate_mode', 0, '', '', '', '1', '2024-06-27 22:46:37', '1', '2024-06-28 01:22:24', b'0'); | |
| 827 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1552, 8, 'Suno', 'Suno', 'ai_platform', 0, '', '', '', '1', '2024-06-29 09:13:36', '1', '2024-06-29 09:13:41', b'0'); | |
| 828 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1553, 9, 'DeepSeek', 'DeepSeek', 'ai_platform', 0, '', '', '', '1', '2024-07-06 12:04:30', '1', '2024-07-06 12:05:20', b'0'); | |
| 829 | +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1554, 10, '智谱', 'ZhiPu', 'ai_platform', 0, '', '', '', '1', '2024-07-06 18:00:35', '1', '2024-07-06 18:00:35', b'0'); | |
| 1107 | 830 | COMMIT; |
| 1108 | 831 | |
| 1109 | 832 | -- ---------------------------- |
| ... | ... | @@ -1122,9 +845,8 @@ CREATE TABLE `system_dict_type` ( |
| 1122 | 845 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 1123 | 846 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 1124 | 847 | `deleted_time` datetime NULL DEFAULT NULL COMMENT '删除时间', |
| 1125 | - PRIMARY KEY (`id`) USING BTREE, | |
| 1126 | - UNIQUE INDEX `dict_type`(`type` ASC) USING BTREE | |
| 1127 | -) ENGINE = InnoDB AUTO_INCREMENT = 620 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表'; | |
| 848 | + PRIMARY KEY (`id`) USING BTREE | |
| 849 | +) ENGINE = InnoDB AUTO_INCREMENT = 624 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表'; | |
| 1128 | 850 | |
| 1129 | 851 | -- ---------------------------- |
| 1130 | 852 | -- Records of system_dict_type |
| ... | ... | @@ -1213,6 +935,10 @@ INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creat |
| 1213 | 935 | INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (615, 'BPM 监听器值类型', 'bpm_process_listener_value_type', 0, '', '1', '2024-03-23 13:00:31', '1', '2024-03-23 13:00:31', b'0', '1970-01-01 00:00:00'); |
| 1214 | 936 | INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (616, '时间间隔', 'date_interval', 0, '', '1', '2024-03-29 22:50:09', '1', '2024-03-29 22:50:09', b'0', '1970-01-01 00:00:00'); |
| 1215 | 937 | INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (619, 'CRM 商机结束状态类型', 'crm_business_end_status_type', 0, '', '1', '2024-04-13 23:23:00', '1', '2024-04-13 23:23:00', b'0', '1970-01-01 00:00:00'); |
| 938 | +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (620, 'AI 模型平台', 'ai_platform', 0, '', '1', '2024-05-09 22:27:38', '1', '2024-05-09 22:27:38', b'0', '1970-01-01 00:00:00'); | |
| 939 | +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (621, 'AI 绘画状态', 'ai_image_status', 0, '', '1', '2024-06-26 20:51:23', '1', '2024-06-26 20:51:23', b'0', '1970-01-01 00:00:00'); | |
| 940 | +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (622, 'AI 音乐状态', 'ai_music_status', 0, '', '1', '2024-06-27 22:45:07', '1', '2024-06-28 00:56:27', b'0', '1970-01-01 00:00:00'); | |
| 941 | +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (623, 'AI 音乐生成模式', 'ai_generate_mode', 0, '', '1', '2024-06-27 22:46:21', '1', '2024-06-28 01:22:29', b'0', '1970-01-01 00:00:00'); | |
| 1216 | 942 | COMMIT; |
| 1217 | 943 | |
| 1218 | 944 | -- ---------------------------- |
| ... | ... | @@ -1236,7 +962,7 @@ CREATE TABLE `system_login_log` ( |
| 1236 | 962 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 1237 | 963 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 1238 | 964 | PRIMARY KEY (`id`) USING BTREE |
| 1239 | -) ENGINE = InnoDB AUTO_INCREMENT = 3104 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录'; | |
| 965 | +) ENGINE = InnoDB AUTO_INCREMENT = 3177 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录'; | |
| 1240 | 966 | |
| 1241 | 967 | -- ---------------------------- |
| 1242 | 968 | -- Records of system_login_log |
| ... | ... | @@ -1367,17 +1093,17 @@ CREATE TABLE `system_menu` ( |
| 1367 | 1093 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 1368 | 1094 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 1369 | 1095 | PRIMARY KEY (`id`) USING BTREE |
| 1370 | -) ENGINE = InnoDB AUTO_INCREMENT = 2758 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表'; | |
| 1096 | +) ENGINE = InnoDB AUTO_INCREMENT = 2792 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表'; | |
| 1371 | 1097 | |
| 1372 | 1098 | -- ---------------------------- |
| 1373 | 1099 | -- Records of system_menu |
| 1374 | 1100 | -- ---------------------------- |
| 1375 | 1101 | BEGIN; |
| 1376 | -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '系统管理', '', 1, 10, 0, '/system', 'ep:tools', NULL, NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:04:23', b'0'); | |
| 1102 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '系统管理', '', 1, 10, 0, '/system', 'ep:tools', NULL, NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-06-18 01:19:41', b'0'); | |
| 1377 | 1103 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, '基础设施', '', 1, 20, 0, '/infra', 'ep:monitor', NULL, NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-03-01 08:28:40', b'0'); |
| 1378 | 1104 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5, 'OA 示例', '', 1, 40, 1185, 'oa', 'fa:road', NULL, NULL, 0, b'1', b'1', b'1', 'admin', '2021-09-20 16:26:19', '1', '2024-02-29 12:38:13', b'0'); |
| 1379 | 1105 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (100, '用户管理', 'system:user:list', 2, 1, 1, 'user', 'ep:avatar', 'system/user/index', 'SystemUser', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:02:04', b'0'); |
| 1380 | -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (101, '角色管理', '', 2, 2, 1, 'role', 'ep:user', 'system/role/index', 'SystemRole', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:03:28', b'0'); | |
| 1106 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (101, '角色管理', '', 2, 2, 1, 'role', 'ep:user', 'system/role/index', 'SystemRole', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-05-01 18:35:29', b'0'); | |
| 1381 | 1107 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (102, '菜单管理', '', 2, 3, 1, 'menu', 'ep:menu', 'system/menu/index', 'SystemMenu', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:03:50', b'0'); |
| 1382 | 1108 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (103, '部门管理', '', 2, 4, 1, 'dept', 'fa:address-card', 'system/dept/index', 'SystemDept', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:06:28', b'0'); |
| 1383 | 1109 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (104, '岗位管理', '', 2, 5, 1, 'post', 'fa:address-book-o', 'system/post/index', 'SystemPost', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:06:39', b'0'); |
| ... | ... | @@ -1902,7 +1628,7 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i |
| 1902 | 1628 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2445, '装修页面更新', 'promotion:diy-page:update', 3, 3, 2442, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', b'0'); |
| 1903 | 1629 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2446, '装修页面删除', 'promotion:diy-page:delete', 3, 4, 2442, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', b'0'); |
| 1904 | 1630 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2447, '三方登录', '', 1, 10, 1, 'social', 'fa:rocket', '', '', 0, b'1', b'1', b'1', '1', '2023-11-04 12:12:01', '1', '2024-02-29 01:14:05', b'0'); |
| 1905 | -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2448, '三方应用', '', 2, 1, 2447, 'client', 'ep:set-up', 'views/system/social/client/index.vue', 'SocialClient', 0, b'1', b'1', b'1', '1', '2023-11-04 12:17:19', '1', '2023-11-04 12:17:19', b'0'); | |
| 1631 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2448, '三方应用', '', 2, 1, 2447, 'client', 'ep:set-up', 'system/social/client/index.vue', 'SocialClient', 0, b'1', b'1', b'1', '1', '2023-11-04 12:17:19', '1', '2024-05-04 19:09:54', b'0'); | |
| 1906 | 1632 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2449, '三方应用查询', 'system:social-client:query', 3, 1, 2448, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-11-04 12:43:12', '1', '2023-11-04 12:43:33', b'0'); |
| 1907 | 1633 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2450, '三方应用创建', 'system:social-client:create', 3, 2, 2448, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-11-04 12:43:58', '1', '2023-11-04 12:43:58', b'0'); |
| 1908 | 1634 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2451, '三方应用更新', 'system:social-client:update', 3, 3, 2448, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-11-04 12:44:27', '1', '2023-11-04 12:44:27', b'0'); |
| ... | ... | @@ -2118,7 +1844,7 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i |
| 2118 | 1844 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2709, '客户公海配置查询', 'crm:customer-pool-config:query', 3, 2, 2516, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-24 16:45:19', '1', '2024-02-24 16:45:28', b'0'); |
| 2119 | 1845 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2710, '合同配置更新', 'crm:contract-config:update', 3, 1, 2708, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-24 16:45:56', '1', '2024-02-24 16:45:56', b'0'); |
| 2120 | 1846 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2711, '合同配置查询', 'crm:contract-config:query', 3, 2, 2708, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-24 16:46:16', '1', '2024-02-24 16:46:16', b'0'); |
| 2121 | -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2712, '客户分析', 'crm:statistics-customer:query', 2, 0, 2560, 'customer', 'ep:avatar', 'views/crm/statistics/customer/index.vue', 'CrmStatisticsCustomer', 0, b'1', b'1', b'1', '1', '2024-03-09 16:43:56', '1', '2024-04-24 19:42:52', b'0'); | |
| 1847 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2712, '客户分析', 'crm:statistics-customer:query', 2, 0, 2560, 'customer', 'ep:avatar', 'crm/statistics/customer/index.vue', 'CrmStatisticsCustomer', 0, b'1', b'1', b'1', '1', '2024-03-09 16:43:56', '1', '2024-05-04 20:38:50', b'0'); | |
| 2122 | 1848 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2713, '抄送我的', 'bpm:process-instance-cc:query', 2, 30, 1200, 'copy', 'ep:copy-document', 'bpm/task/copy/index', 'BpmProcessInstanceCopy', 0, b'1', b'1', b'1', '1', '2024-03-17 21:50:23', '1', '2024-04-24 19:55:12', b'0'); |
| 2123 | 1849 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2714, '流程分类', '', 2, 3, 1186, 'category', 'fa:object-ungroup', 'bpm/category/index', 'BpmCategory', 0, b'1', b'1', b'1', '', '2024-03-08 02:00:51', '1', '2024-03-21 23:51:18', b'0'); |
| 2124 | 1850 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2715, '分类查询', 'bpm:category:query', 3, 1, 2714, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:25', b'0'); |
| ... | ... | @@ -2163,6 +1889,38 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i |
| 2163 | 1889 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2755, '删除项目', 'report:go-view-project:delete', 3, 2, 2153, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 20:01:37', '1', '2024-04-24 20:01:37', b'0'); |
| 2164 | 1890 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2756, '会员等级记录查询', 'member:level-record:query', 3, 10, 2325, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 20:02:32', '1', '2024-04-24 20:02:32', b'0'); |
| 2165 | 1891 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2757, '会员经验记录查询', 'member:experience-record:query', 3, 11, 2325, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 20:02:51', '1', '2024-04-24 20:02:51', b'0'); |
| 1892 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2758, 'AI 大模型', '', 1, 400, 0, '/ai', 'fa:apple', '', '', 0, b'1', b'1', b'1', '1', '2024-05-07 15:07:56', '1', '2024-05-25 12:36:12', b'0'); | |
| 1893 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2759, 'AI 对话', '', 2, 1, 2758, 'chat', 'ep:message', 'ai/chat/index/index.vue', 'AiChat', 0, b'1', b'1', b'1', '1', '2024-05-07 15:09:14', '1', '2024-07-07 17:15:36', b'0'); | |
| 1894 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2760, '控制台', '', 1, 100, 2758, 'console', 'ep:setting', '', '', 0, b'1', b'1', b'1', '1', '2024-05-09 22:39:09', '1', '2024-05-24 23:34:21', b'0'); | |
| 1895 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2761, 'API 密钥', '', 2, 0, 2760, 'api-key', 'ep:key', 'ai/model/apiKey/index.vue', 'AiApiKey', 0, b'1', b'1', b'1', '', '2024-05-09 14:52:56', '1', '2024-05-10 22:44:08', b'0'); | |
| 1896 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2762, 'API 密钥查询', 'ai:api-key:query', 3, 1, 2761, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-05-09 14:52:56', '1', '2024-05-13 20:36:32', b'0'); | |
| 1897 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2763, 'API 密钥创建', 'ai:api-key:create', 3, 2, 2761, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-05-09 14:52:56', '1', '2024-05-13 20:36:26', b'0'); | |
| 1898 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2764, 'API 密钥更新', 'ai:api-key:update', 3, 3, 2761, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-05-09 14:52:56', '1', '2024-05-13 20:36:42', b'0'); | |
| 1899 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2765, 'API 密钥删除', 'ai:api-key:delete', 3, 4, 2761, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-05-09 14:52:56', '1', '2024-05-13 20:36:48', b'0'); | |
| 1900 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2767, '聊天模型', '', 2, 0, 2760, 'chat-model', 'fa-solid:abacus', 'ai/model/chatModel/index.vue', 'AiChatModel', 0, b'1', b'1', b'1', '', '2024-05-10 14:42:48', '1', '2024-05-10 22:44:16', b'0'); | |
| 1901 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2768, '聊天模型查询', 'ai:chat-model:query', 3, 1, 2767, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-05-10 14:42:48', '1', '2024-05-13 20:37:02', b'0'); | |
| 1902 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2769, '聊天模型创建', 'ai:chat-model:create', 3, 2, 2767, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-05-10 14:42:48', '1', '2024-05-13 20:37:12', b'0'); | |
| 1903 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2770, '聊天模型更新', 'ai:chat-model:update', 3, 3, 2767, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-05-10 14:42:48', '1', '2024-05-13 20:37:18', b'0'); | |
| 1904 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2771, '聊天模型删除', 'ai:chat-model:delete', 3, 4, 2767, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-05-10 14:42:48', '1', '2024-05-13 20:37:23', b'0'); | |
| 1905 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2773, '聊天角色', '', 2, 0, 2760, 'chat-role', 'fa:user-secret', 'ai/model/chatRole/index.vue', 'AiChatRole', 0, b'1', b'1', b'1', '', '2024-05-13 12:39:28', '1', '2024-05-13 20:41:45', b'0'); | |
| 1906 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2774, '聊天角色查询', 'ai:chat-role:query', 3, 1, 2773, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-05-13 12:39:28', '', '2024-05-13 12:39:28', b'0'); | |
| 1907 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2775, '聊天角色创建', 'ai:chat-role:create', 3, 2, 2773, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-05-13 12:39:28', '', '2024-05-13 12:39:28', b'0'); | |
| 1908 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2776, '聊天角色更新', 'ai:chat-role:update', 3, 3, 2773, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-05-13 12:39:28', '', '2024-05-13 12:39:28', b'0'); | |
| 1909 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2777, '聊天角色删除', 'ai:chat-role:delete', 3, 4, 2773, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-05-13 21:43:38', '1', '2024-05-13 21:43:38', b'0'); | |
| 1910 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2778, '聊天管理', '', 2, 10, 2760, 'chat-conversation', 'ep:chat-square', 'ai/chat/manager/index.vue', 'AiChatManager', 0, b'1', b'1', b'1', '', '2024-05-24 15:39:18', '1', '2024-06-26 21:36:56', b'0'); | |
| 1911 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2779, '会话查询', 'ai:chat-conversation:query', 3, 1, 2778, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-05-24 15:39:18', '1', '2024-05-25 08:38:30', b'0'); | |
| 1912 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2780, '会话删除', 'ai:chat-conversation:delete', 3, 2, 2778, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-05-24 15:39:18', '1', '2024-05-25 08:38:40', b'0'); | |
| 1913 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2781, '消息查询', 'ai:chat-message:query', 3, 11, 2778, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-05-25 08:38:56', '1', '2024-05-25 08:38:56', b'0'); | |
| 1914 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2782, '消息删除', 'ai:chat-message:delete', 3, 12, 2778, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-05-25 08:39:10', '1', '2024-05-25 08:39:10', b'0'); | |
| 1915 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2783, 'AI 绘画', '', 2, 2, 2758, 'image', 'ep:picture-rounded', 'ai/image/index/index.vue', 'AiImage', 0, b'1', b'1', b'1', '1', '2024-05-26 11:45:17', '1', '2024-07-07 17:18:59', b'0'); | |
| 1916 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2784, '绘画管理', '', 2, 11, 2760, 'image', 'fa:file-image-o', 'ai/image/manager/index.vue', 'AiImageManager', 0, b'1', b'1', b'1', '', '2024-06-26 13:32:31', '1', '2024-06-26 21:37:13', b'0'); | |
| 1917 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2785, '绘画查询', 'ai:image:query', 3, 1, 2784, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-06-26 13:32:31', '1', '2024-06-26 22:21:57', b'0'); | |
| 1918 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2786, '绘画删除', 'ai:image:delete', 3, 4, 2784, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-06-26 13:32:31', '1', '2024-06-26 22:22:08', b'0'); | |
| 1919 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2787, '会话更新公开状态', 'ai:image:update-public-status', 3, 2, 2784, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-06-26 22:47:56', '1', '2024-06-26 22:47:56', b'0'); | |
| 1920 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2788, '音乐管理', '', 2, 12, 2760, 'music', 'fa:music', 'ai/music/manager/index.vue', 'AiMusicManager', 0, b'1', b'1', b'1', '', '2024-06-27 15:03:33', '1', '2024-06-27 23:04:19', b'0'); | |
| 1921 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2789, '音乐查询', 'ai:music:query', 3, 1, 2788, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-06-27 15:03:33', '', '2024-06-27 15:03:33', b'0'); | |
| 1922 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2790, '音乐更新', 'ai:music:update', 3, 3, 2788, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-06-27 15:03:33', '', '2024-06-27 15:03:33', b'0'); | |
| 1923 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2791, '音乐删除', 'ai:music:delete', 3, 4, 2788, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-06-27 15:03:33', '', '2024-06-27 15:03:33', b'0'); | |
| 2166 | 1924 | COMMIT; |
| 2167 | 1925 | |
| 2168 | 1926 | -- ---------------------------- |
| ... | ... | @@ -2284,7 +2042,7 @@ CREATE TABLE `system_oauth2_access_token` ( |
| 2284 | 2042 | PRIMARY KEY (`id`) USING BTREE, |
| 2285 | 2043 | INDEX `idx_access_token`(`access_token` ASC) USING BTREE, |
| 2286 | 2044 | INDEX `idx_refresh_token`(`refresh_token` ASC) USING BTREE |
| 2287 | -) ENGINE = InnoDB AUTO_INCREMENT = 6620 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌'; | |
| 2045 | +) ENGINE = InnoDB AUTO_INCREMENT = 7699 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌'; | |
| 2288 | 2046 | |
| 2289 | 2047 | -- ---------------------------- |
| 2290 | 2048 | -- Records of system_oauth2_access_token |
| ... | ... | @@ -2406,7 +2164,7 @@ CREATE TABLE `system_oauth2_refresh_token` ( |
| 2406 | 2164 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 2407 | 2165 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 2408 | 2166 | PRIMARY KEY (`id`) USING BTREE |
| 2409 | -) ENGINE = InnoDB AUTO_INCREMENT = 1483 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌'; | |
| 2167 | +) ENGINE = InnoDB AUTO_INCREMENT = 1539 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌'; | |
| 2410 | 2168 | |
| 2411 | 2169 | -- ---------------------------- |
| 2412 | 2170 | -- Records of system_oauth2_refresh_token |
| ... | ... | @@ -3410,7 +3168,7 @@ CREATE TABLE `system_sms_code` ( |
| 3410 | 3168 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 3411 | 3169 | PRIMARY KEY (`id`) USING BTREE, |
| 3412 | 3170 | INDEX `idx_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号' |
| 3413 | -) ENGINE = InnoDB AUTO_INCREMENT = 614 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码'; | |
| 3171 | +) ENGINE = InnoDB AUTO_INCREMENT = 615 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码'; | |
| 3414 | 3172 | |
| 3415 | 3173 | -- ---------------------------- |
| 3416 | 3174 | -- Records of system_sms_code |
| ... | ... | @@ -3451,7 +3209,7 @@ CREATE TABLE `system_sms_log` ( |
| 3451 | 3209 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 3452 | 3210 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 3453 | 3211 | PRIMARY KEY (`id`) USING BTREE |
| 3454 | -) ENGINE = InnoDB AUTO_INCREMENT = 962 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志'; | |
| 3212 | +) ENGINE = InnoDB AUTO_INCREMENT = 972 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志'; | |
| 3455 | 3213 | |
| 3456 | 3214 | -- ---------------------------- |
| 3457 | 3215 | -- Records of system_sms_log |
| ... | ... | @@ -3616,8 +3374,8 @@ CREATE TABLE `system_tenant` ( |
| 3616 | 3374 | -- ---------------------------- |
| 3617 | 3375 | BEGIN; |
| 3618 | 3376 | INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2023-11-06 11:41:41', b'0'); |
| 3619 | -INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2024-03-11 00:00:00', 20, '1', '2022-02-22 00:56:14', '1', '2023-11-06 11:41:47', b'0'); | |
| 3620 | -INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-30 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2023-11-06 11:41:53', b'0'); | |
| 3377 | +INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2024-03-11 00:00:00', 20, '1', '2022-02-22 00:56:14', '1', '2024-05-04 22:37:03', b'0'); | |
| 3378 | +INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-29 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2024-05-04 22:36:09', b'0'); | |
| 3621 | 3379 | COMMIT; |
| 3622 | 3380 | |
| 3623 | 3381 | -- ---------------------------- |
| ... | ... | @@ -3739,18 +3497,17 @@ CREATE TABLE `system_users` ( |
| 3739 | 3497 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 3740 | 3498 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 3741 | 3499 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 3742 | - PRIMARY KEY (`id`) USING BTREE, | |
| 3743 | - UNIQUE INDEX `idx_username`(`username` ASC, `update_time` ASC, `tenant_id` ASC) USING BTREE | |
| 3500 | + PRIMARY KEY (`id`) USING BTREE | |
| 3744 | 3501 | ) ENGINE = InnoDB AUTO_INCREMENT = 139 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户信息表'; |
| 3745 | 3502 | |
| 3746 | 3503 | -- ---------------------------- |
| 3747 | 3504 | -- Records of system_users |
| 3748 | 3505 | -- ---------------------------- |
| 3749 | 3506 | BEGIN; |
| 3750 | -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/96c787a2ce88bf6d0ce3cd8b6cf5314e80e7703cd41bf4af8cd2e2909dbd6b6d.png', 0, '0:0:0:0:0:0:0:1', '2024-04-29 21:50:32', 'admin', '2021-01-05 17:03:47', NULL, '2024-04-29 21:50:32', b'0', 1); | |
| 3507 | +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/96c787a2ce88bf6d0ce3cd8b6cf5314e80e7703cd41bf4af8cd2e2909dbd6b6d.png', 0, '0:0:0:0:0:0:0:1', '2024-07-07 17:15:51', 'admin', '2021-01-05 17:03:47', NULL, '2024-07-07 17:15:51', b'0', 1); | |
| 3751 | 3508 | INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '127.0.0.1', '2022-07-09 23:03:33', '', '2021-01-07 09:07:17', NULL, '2022-07-09 23:03:33', b'0', 1); |
| 3752 | 3509 | INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, 'yuanma', '$2a$10$YMpimV4T6BtDhIaA8jSW.u8UTGBeGhc/qwXP4oxoMr4mOw9.qttt6', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '0:0:0:0:0:0:0:1', '2024-03-18 21:09:04', '', '2021-01-13 23:50:35', NULL, '2024-03-18 21:09:04', b'0', 1); |
| 3753 | -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$04$KhExCYl7lx6eWWZYKsibKOZ8IBJRyuNuCcEOLQ11RYhJKgHmlSwK.', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-26 07:11:35', '', '2021-01-21 02:13:53', NULL, '2024-03-26 07:11:35', b'0', 1); | |
| 3510 | +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$04$KhExCYl7lx6eWWZYKsibKOZ8IBJRyuNuCcEOLQ11RYhJKgHmlSwK.', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-06-17 14:23:23', '', '2021-01-21 02:13:53', NULL, '2024-06-17 14:23:23', b'0', 1); | |
| 3754 | 3511 | INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (107, 'admin107', '$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 22:59:33', '1', '2022-02-27 08:26:51', b'0', 118); |
| 3755 | 3512 | INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (108, 'admin108', '$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:00:50', '1', '2022-02-27 08:26:53', b'0', 119); |
| 3756 | 3513 | INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (109, 'admin109', '$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:11:50', '1', '2022-02-27 08:26:56', b'0', 120); | ... | ... |
yudao-dependencies/pom.xml
| ... | ... | @@ -77,6 +77,7 @@ |
| 77 | 77 | <jimureport.version>1.6.6-beta2</jimureport.version> |
| 78 | 78 | <xercesImpl.version>2.12.2</xercesImpl.version> |
| 79 | 79 | <weixin-java.version>4.6.0</weixin-java.version> |
| 80 | + <spring-ai-bom.version>0.8.0</spring-ai-bom.version> | |
| 80 | 81 | </properties> |
| 81 | 82 | |
| 82 | 83 | <dependencyManagement> | ... | ... |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/enums/ServiceErrorCodeRange.java
yudao-module-ai/pom.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | |
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| 4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
| 5 | + <parent> | |
| 6 | + <groupId>cn.iocoder.boot</groupId> | |
| 7 | + <artifactId>yudao</artifactId> | |
| 8 | + <version>${revision}</version> | |
| 9 | + </parent> | |
| 10 | + <modelVersion>4.0.0</modelVersion> | |
| 11 | + <modules> | |
| 12 | + <module>yudao-module-ai-api</module> | |
| 13 | + <module>yudao-module-ai-biz</module> | |
| 14 | + <module>yudao-spring-boot-starter-ai</module> | |
| 15 | + </modules> | |
| 16 | + <packaging>pom</packaging> | |
| 17 | + <artifactId>yudao-module-ai</artifactId> | |
| 18 | + | |
| 19 | + <name>${project.artifactId}</name> | |
| 20 | + <description> | |
| 21 | + ai 模块下,接入 LLM 大模型,支持聊天、绘图、音乐、写作、思维脑图等功能。 | |
| 22 | + 目前已接入各种模型,不限于: | |
| 23 | + 国内:通义千问、文心一言、讯飞星火、智谱 GLM、DeepSeek | |
| 24 | + 国外:OpenAI、Ollama、Midjourney、StableDiffusion、Suno | |
| 25 | + </description> | |
| 26 | + | |
| 27 | +</project> | |
| 0 | 28 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-api/pom.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | |
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| 4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
| 5 | + <parent> | |
| 6 | + <groupId>cn.iocoder.boot</groupId> | |
| 7 | + <artifactId>yudao-module-ai</artifactId> | |
| 8 | + <version>${revision}</version> | |
| 9 | + </parent> | |
| 10 | + <modelVersion>4.0.0</modelVersion> | |
| 11 | + <artifactId>yudao-module-ai-api</artifactId> | |
| 12 | + <packaging>jar</packaging> | |
| 13 | + | |
| 14 | + <name>${project.artifactId}</name> | |
| 15 | + <description> | |
| 16 | + ai 模块 API,暴露给其它模块调用 | |
| 17 | + </description> | |
| 18 | + | |
| 19 | + <dependencies> | |
| 20 | + <dependency> | |
| 21 | + <groupId>cn.iocoder.boot</groupId> | |
| 22 | + <artifactId>yudao-common</artifactId> | |
| 23 | + </dependency> | |
| 24 | + | |
| 25 | + <!-- 参数校验 --> | |
| 26 | + <dependency> | |
| 27 | + <groupId>org.springframework.boot</groupId> | |
| 28 | + <artifactId>spring-boot-starter-validation</artifactId> | |
| 29 | + <optional>true</optional> | |
| 30 | + </dependency> | |
| 31 | + </dependencies> | |
| 32 | +</project> | |
| 0 | 33 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/api/package-info.java
0 → 100644
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiChatRoleEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.enums; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | |
| 4 | +import lombok.AllArgsConstructor; | |
| 5 | +import lombok.Getter; | |
| 6 | + | |
| 7 | +import java.util.Arrays; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * AI 内置聊天角色的枚举 | |
| 11 | + * | |
| 12 | + * @author xiaoxin | |
| 13 | + */ | |
| 14 | +@AllArgsConstructor | |
| 15 | +@Getter | |
| 16 | +public enum AiChatRoleEnum implements IntArrayValuable { | |
| 17 | + | |
| 18 | + AI_WRITE_ROLE(1, "写作助手", """ | |
| 19 | + 你是一位出色的写作助手,能够帮助用户生成创意和灵感,并在用户提供场景和提示词时生成对应的回复。你的任务包括: | |
| 20 | + 1. 撰写建议:根据用户提供的主题或问题,提供详细的写作建议、情节发展方向、角色设定以及背景描写,确保内容结构清晰、有逻辑。 | |
| 21 | + 2. 回复生成:根据用户提供的场景和提示词,生成合适的对话或文字回复,确保语气和风格符合场景需求。 | |
| 22 | + 除此之外不需要除了正文内容外的其他回复,如标题、开头、任何解释性语句或道歉。 | |
| 23 | + """), | |
| 24 | + | |
| 25 | + AI_MIND_MAP_ROLE(2, "脑图助手", """ | |
| 26 | + 你是一位非常优秀的思维导图助手,你会把用户的所有提问都总结成思维导图,然后以 Markdown 格式输出。markdown 只需要输出一级标题,二级标题,三级标题,四级标题,最多输出四级,除此之外不要输出任何其他 markdown 标记。下面是一个合格的例子: | |
| 27 | + # Geek-AI 助手 | |
| 28 | + ## 完整的开源系统 | |
| 29 | + ### 前端开源 | |
| 30 | + ### 后端开源 | |
| 31 | + ## 支持各种大模型 | |
| 32 | + ### OpenAI | |
| 33 | + ### Azure | |
| 34 | + ### 文心一言 | |
| 35 | + ### 通义千问 | |
| 36 | + ## 集成多种收费方式 | |
| 37 | + ### 支付宝 | |
| 38 | + ### 微信 | |
| 39 | + 除此之外不要任何解释性语句。 | |
| 40 | + """); | |
| 41 | + | |
| 42 | + // TODO @xin:这个 role 是不是删除掉好点哈。= = 目前主要是没做角色枚举。这里多了 role 反倒容易误解哈 | |
| 43 | + /** | |
| 44 | + * 角色 | |
| 45 | + */ | |
| 46 | + private final Integer role; | |
| 47 | + /** | |
| 48 | + * 角色名 | |
| 49 | + */ | |
| 50 | + private final String name; | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * 角色设定 | |
| 54 | + */ | |
| 55 | + private final String systemMessage; | |
| 56 | + | |
| 57 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AiChatRoleEnum::getRole).toArray(); | |
| 58 | + | |
| 59 | + @Override | |
| 60 | + public int[] array() { | |
| 61 | + return ARRAYS; | |
| 62 | + } | |
| 63 | + | |
| 64 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/DictTypeConstants.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.enums; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * AI 字典类型的枚举类 | |
| 5 | + * | |
| 6 | + * @author xiaoxin | |
| 7 | + */ | |
| 8 | +public interface DictTypeConstants { | |
| 9 | + | |
| 10 | + // ========== AI Write ========== | |
| 11 | + String AI_WRITE_FORMAT = "ai_write_format"; // 写作格式 | |
| 12 | + String AI_WRITE_LENGTH = "ai_write_length"; // 写作长度 | |
| 13 | + String AI_WRITE_LANGUAGE = "ai_write_language"; // 写作语言 | |
| 14 | + String AI_WRITE_TONE = "ai_write_tone"; // 写作语气 | |
| 15 | + | |
| 16 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/ErrorCodeConstants.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.enums; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.exception.ErrorCode; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * AI 错误码枚举类 | |
| 7 | + * | |
| 8 | + * ai 系统,使用 1-040-000-000 段 | |
| 9 | + */ | |
| 10 | +public interface ErrorCodeConstants { | |
| 11 | + | |
| 12 | + // ========== API 密钥 1-040-000-000 ========== | |
| 13 | + ErrorCode API_KEY_NOT_EXISTS = new ErrorCode(1_040_000_000, "API 密钥不存在"); | |
| 14 | + ErrorCode API_KEY_DISABLE = new ErrorCode(1_040_000_001, "API 密钥已禁用!"); | |
| 15 | + ErrorCode API_KEY_MIDJOURNEY_NOT_FOUND = new ErrorCode(1_040_000_900, "Midjourney 模型不存在"); | |
| 16 | + ErrorCode API_KEY_SUNO_NOT_FOUND = new ErrorCode(1_040_000_901, "Suno 模型不存在"); | |
| 17 | + ErrorCode API_KEY_IMAGE_NODE_FOUND = new ErrorCode(1_040_000_902, "平台({}) 图片模型未配置"); | |
| 18 | + | |
| 19 | + // ========== API 聊天模型 1-040-001-000 ========== | |
| 20 | + ErrorCode CHAT_MODEL_NOT_EXISTS = new ErrorCode(1_040_001_000, "模型不存在!"); | |
| 21 | + ErrorCode CHAT_MODEL_DISABLE = new ErrorCode(1_040_001_001, "模型({})已禁用!"); | |
| 22 | + ErrorCode CHAT_MODEL_DEFAULT_NOT_EXISTS = new ErrorCode(1_040_001_002, "操作失败,找不到默认聊天模型"); | |
| 23 | + | |
| 24 | + // ========== API 聊天模型 1-040-002-000 ========== | |
| 25 | + ErrorCode CHAT_ROLE_NOT_EXISTS = new ErrorCode(1_040_002_000, "聊天角色不存在"); | |
| 26 | + ErrorCode CHAT_ROLE_DISABLE = new ErrorCode(1_040_001_001, "聊天角色({})已禁用!"); | |
| 27 | + | |
| 28 | + // ========== API 聊天会话 1-040-003-000 ========== | |
| 29 | + | |
| 30 | + ErrorCode CHAT_CONVERSATION_NOT_EXISTS = new ErrorCode(1_040_003_000, "对话不存在!"); | |
| 31 | + ErrorCode CHAT_CONVERSATION_MODEL_ERROR = new ErrorCode(1_040_003_001, "操作失败,该聊天模型的配置不完整"); | |
| 32 | + | |
| 33 | + // ========== API 聊天消息 1-040-004-000 ========== | |
| 34 | + | |
| 35 | + ErrorCode CHAT_MESSAGE_NOT_EXIST = new ErrorCode(1_040_004_000, "消息不存在!"); | |
| 36 | + ErrorCode CHAT_STREAM_ERROR = new ErrorCode(1_040_004_001, "对话生成异常!"); | |
| 37 | + | |
| 38 | + // ========== API 绘画 1-040-005-000 ========== | |
| 39 | + | |
| 40 | + ErrorCode IMAGE_NOT_EXISTS = new ErrorCode(1_022_005_000, "图片不存在!"); | |
| 41 | + ErrorCode IMAGE_MIDJOURNEY_SUBMIT_FAIL = new ErrorCode(1_022_005_001, "Midjourney 提交失败!原因:{}"); | |
| 42 | + ErrorCode IMAGE_CUSTOM_ID_NOT_EXISTS = new ErrorCode(1_022_005_002, "Midjourney 按钮 customId 不存在! {}"); | |
| 43 | + ErrorCode IMAGE_FAIL = new ErrorCode(1_022_005_002, "图片绘画失败! {}"); | |
| 44 | + | |
| 45 | + // ========== API 音乐 1-040-006-000 ========== | |
| 46 | + ErrorCode MUSIC_NOT_EXISTS = new ErrorCode(1_022_006_000, "音乐不存在!"); | |
| 47 | + | |
| 48 | + | |
| 49 | + // ========== API 写作 1-022-007-000 ========== | |
| 50 | + ErrorCode WRITE_NOT_EXISTS = new ErrorCode(1_022_007_000, "作文不存在!"); | |
| 51 | + ErrorCode WRITE_STREAM_ERROR = new ErrorCode(1_022_07_001, "写作生成异常!"); | |
| 52 | + | |
| 53 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/image/AiImageStatusEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.enums.image; | |
| 2 | + | |
| 3 | +import lombok.AllArgsConstructor; | |
| 4 | +import lombok.Getter; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * AI 绘画状态的枚举 | |
| 8 | + * | |
| 9 | + * @author fansili | |
| 10 | + */ | |
| 11 | +@AllArgsConstructor | |
| 12 | +@Getter | |
| 13 | +public enum AiImageStatusEnum { | |
| 14 | + | |
| 15 | + IN_PROGRESS(10, "进行中"), | |
| 16 | + SUCCESS(20, "已完成"), | |
| 17 | + FAIL(30, "已失败"); | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 状态 | |
| 21 | + */ | |
| 22 | + private final Integer status; | |
| 23 | + /** | |
| 24 | + * 状态名 | |
| 25 | + */ | |
| 26 | + private final String name; | |
| 27 | + | |
| 28 | + public static AiImageStatusEnum valueOfStatus(Integer status) { | |
| 29 | + for (AiImageStatusEnum statusEnum : AiImageStatusEnum.values()) { | |
| 30 | + if (statusEnum.getStatus().equals(status)) { | |
| 31 | + return statusEnum; | |
| 32 | + } | |
| 33 | + } | |
| 34 | + throw new IllegalArgumentException("未知会话状态: " + status); | |
| 35 | + } | |
| 36 | + | |
| 37 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/music/AiMusicGenerateModeEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.enums.music; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | |
| 4 | +import lombok.AllArgsConstructor; | |
| 5 | +import lombok.Getter; | |
| 6 | + | |
| 7 | +import java.util.Arrays; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * AI 音乐生成模式的枚举 | |
| 11 | + * | |
| 12 | + * @author xiaoxin | |
| 13 | + */ | |
| 14 | +@AllArgsConstructor | |
| 15 | +@Getter | |
| 16 | +public enum AiMusicGenerateModeEnum implements IntArrayValuable { | |
| 17 | + | |
| 18 | + DESCRIPTION(1, "描述模式"), | |
| 19 | + LYRIC(2, "歌词模式"); | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * 模式 | |
| 23 | + */ | |
| 24 | + private final Integer mode; | |
| 25 | + /** | |
| 26 | + * 模式名 | |
| 27 | + */ | |
| 28 | + private final String name; | |
| 29 | + | |
| 30 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AiMusicGenerateModeEnum::getMode).toArray(); | |
| 31 | + | |
| 32 | + @Override | |
| 33 | + public int[] array() { | |
| 34 | + return ARRAYS; | |
| 35 | + } | |
| 36 | + | |
| 37 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/music/AiMusicStatusEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.enums.music; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | |
| 4 | +import lombok.AllArgsConstructor; | |
| 5 | +import lombok.Getter; | |
| 6 | + | |
| 7 | +import java.util.Arrays; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * AI 音乐状态的枚举 | |
| 11 | + * | |
| 12 | + * @author xiaoxin | |
| 13 | + */ | |
| 14 | +@AllArgsConstructor | |
| 15 | +@Getter | |
| 16 | +public enum AiMusicStatusEnum implements IntArrayValuable { | |
| 17 | + | |
| 18 | + IN_PROGRESS(10, "进行中"), | |
| 19 | + SUCCESS(20, "已完成"), | |
| 20 | + FAIL(30, "已失败"); | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * 状态 | |
| 24 | + */ | |
| 25 | + private final Integer status; | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * 状态名 | |
| 29 | + */ | |
| 30 | + private final String name; | |
| 31 | + | |
| 32 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AiMusicStatusEnum::getStatus).toArray(); | |
| 33 | + | |
| 34 | + @Override | |
| 35 | + public int[] array() { | |
| 36 | + return ARRAYS; | |
| 37 | + } | |
| 38 | + | |
| 39 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/write/AiWriteTypeEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.enums.write; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | |
| 4 | +import lombok.AllArgsConstructor; | |
| 5 | +import lombok.Getter; | |
| 6 | + | |
| 7 | +import java.util.Arrays; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * AI 写作类型的枚举 | |
| 11 | + * | |
| 12 | + * @author xiaoxin | |
| 13 | + */ | |
| 14 | +@AllArgsConstructor | |
| 15 | +@Getter | |
| 16 | +public enum AiWriteTypeEnum implements IntArrayValuable { | |
| 17 | + | |
| 18 | + WRITING(1, "撰写", "请撰写一篇关于 [{}] 的文章。文章的内容格式:{},语气:{},语言:{},长度:{}。请确保涵盖主要内容,不需要除了正文内容外的其他回复,如标题、额外的解释或道歉。"), | |
| 19 | + REPLY(2, "回复", "请针对如下内容:[{}] 做个回复。回复内容参考:[{}], 回复格式:{},语气:{},语言:{},长度:{}。不需要除了正文内容外的其他回复,如标题、开头、额外的解释或道歉。"); | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * 类型 | |
| 23 | + */ | |
| 24 | + private final Integer type; | |
| 25 | + /** | |
| 26 | + * 类型名 | |
| 27 | + */ | |
| 28 | + private final String name; | |
| 29 | + | |
| 30 | + /** | |
| 31 | + * 模版 | |
| 32 | + */ | |
| 33 | + private final String prompt; | |
| 34 | + | |
| 35 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AiWriteTypeEnum::getType).toArray(); | |
| 36 | + | |
| 37 | + @Override | |
| 38 | + public int[] array() { | |
| 39 | + return ARRAYS; | |
| 40 | + } | |
| 41 | + | |
| 42 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/pom.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | |
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| 4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
| 5 | + <parent> | |
| 6 | + <groupId>cn.iocoder.boot</groupId> | |
| 7 | + <artifactId>yudao-module-ai</artifactId> | |
| 8 | + <version>${revision}</version> | |
| 9 | + </parent> | |
| 10 | + <modelVersion>4.0.0</modelVersion> | |
| 11 | + <artifactId>yudao-module-ai-biz</artifactId> | |
| 12 | + | |
| 13 | + <name>${project.artifactId}</name> | |
| 14 | + <description> | |
| 15 | + ai 模块下,接入 LLM 大模型,支持聊天、绘图、音乐、写作、思维脑图等功能。 | |
| 16 | + 目前已接入各种模型,不限于: | |
| 17 | + 国内:通义千问、文心一言、讯飞星火、智谱 GLM、DeepSeek | |
| 18 | + 国外:OpenAI、Ollama、Midjourney、StableDiffusion、Suno | |
| 19 | + </description> | |
| 20 | + | |
| 21 | + <dependencies> | |
| 22 | + <dependency> | |
| 23 | + <groupId>cn.iocoder.boot</groupId> | |
| 24 | + <artifactId>yudao-module-ai-api</artifactId> | |
| 25 | + <version>${revision}</version> | |
| 26 | + </dependency> | |
| 27 | + | |
| 28 | + <!-- 业务组件 --> | |
| 29 | + <dependency> | |
| 30 | + <groupId>cn.iocoder.boot</groupId> | |
| 31 | + <artifactId>yudao-spring-boot-starter-ai</artifactId> | |
| 32 | + <version>${revision}</version> | |
| 33 | + </dependency> | |
| 34 | + | |
| 35 | + <dependency> | |
| 36 | + <groupId>cn.iocoder.boot</groupId> | |
| 37 | + <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId> | |
| 38 | + </dependency> | |
| 39 | + | |
| 40 | + <!-- Web 相关 --> | |
| 41 | + <dependency> | |
| 42 | + <groupId>cn.iocoder.boot</groupId> | |
| 43 | + <artifactId>yudao-spring-boot-starter-security</artifactId> | |
| 44 | + </dependency> | |
| 45 | + | |
| 46 | + <!-- DB 相关 --> | |
| 47 | + <dependency> | |
| 48 | + <groupId>cn.iocoder.boot</groupId> | |
| 49 | + <artifactId>yudao-spring-boot-starter-mybatis</artifactId> | |
| 50 | + </dependency> | |
| 51 | + | |
| 52 | + <!-- Job 相关 --> | |
| 53 | + <dependency> | |
| 54 | + <groupId>cn.iocoder.boot</groupId> | |
| 55 | + <artifactId>yudao-spring-boot-starter-job</artifactId> | |
| 56 | + </dependency> | |
| 57 | + | |
| 58 | + <!-- Test 测试相关 --> | |
| 59 | + <dependency> | |
| 60 | + <groupId>cn.iocoder.boot</groupId> | |
| 61 | + <artifactId>yudao-spring-boot-starter-test</artifactId> | |
| 62 | + </dependency> | |
| 63 | + </dependencies> | |
| 64 | +</project> | |
| 0 | 65 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatConversationController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.chat; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.util.ObjUtil; | |
| 5 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 6 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 7 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 8 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO; | |
| 9 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationPageReqVO; | |
| 10 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO; | |
| 11 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO; | |
| 12 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; | |
| 13 | +import cn.iocoder.yudao.module.ai.service.chat.AiChatConversationService; | |
| 14 | +import cn.iocoder.yudao.module.ai.service.chat.AiChatMessageService; | |
| 15 | +import io.swagger.v3.oas.annotations.Operation; | |
| 16 | +import io.swagger.v3.oas.annotations.Parameter; | |
| 17 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 18 | +import jakarta.annotation.Resource; | |
| 19 | +import jakarta.validation.Valid; | |
| 20 | +import org.springframework.security.access.prepost.PreAuthorize; | |
| 21 | +import org.springframework.validation.annotation.Validated; | |
| 22 | +import org.springframework.web.bind.annotation.*; | |
| 23 | + | |
| 24 | +import java.util.List; | |
| 25 | +import java.util.Map; | |
| 26 | + | |
| 27 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 28 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 29 | +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | |
| 30 | + | |
| 31 | +@Tag(name = "管理后台 - AI 聊天对话") | |
| 32 | +@RestController | |
| 33 | +@RequestMapping("/ai/chat/conversation") | |
| 34 | +@Validated | |
| 35 | +public class AiChatConversationController { | |
| 36 | + | |
| 37 | + @Resource | |
| 38 | + private AiChatConversationService chatConversationService; | |
| 39 | + @Resource | |
| 40 | + private AiChatMessageService chatMessageService; | |
| 41 | + | |
| 42 | + @PostMapping("/create-my") | |
| 43 | + @Operation(summary = "创建【我的】聊天对话") | |
| 44 | + public CommonResult<Long> createChatConversationMy(@RequestBody @Valid AiChatConversationCreateMyReqVO createReqVO) { | |
| 45 | + return success(chatConversationService.createChatConversationMy(createReqVO, getLoginUserId())); | |
| 46 | + } | |
| 47 | + | |
| 48 | + @PutMapping("/update-my") | |
| 49 | + @Operation(summary = "更新【我的】聊天对话") | |
| 50 | + public CommonResult<Boolean> updateChatConversationMy(@RequestBody @Valid AiChatConversationUpdateMyReqVO updateReqVO) { | |
| 51 | + chatConversationService.updateChatConversationMy(updateReqVO, getLoginUserId()); | |
| 52 | + return success(true); | |
| 53 | + } | |
| 54 | + | |
| 55 | + @GetMapping("/my-list") | |
| 56 | + @Operation(summary = "获得【我的】聊天对话列表") | |
| 57 | + public CommonResult<List<AiChatConversationRespVO>> getChatConversationMyList() { | |
| 58 | + List<AiChatConversationDO> list = chatConversationService.getChatConversationListByUserId(getLoginUserId()); | |
| 59 | + return success(BeanUtils.toBean(list, AiChatConversationRespVO.class)); | |
| 60 | + } | |
| 61 | + | |
| 62 | + @GetMapping("/get-my") | |
| 63 | + @Operation(summary = "获得【我的】聊天对话") | |
| 64 | + @Parameter(name = "id", required = true, description = "对话编号", example = "1024") | |
| 65 | + public CommonResult<AiChatConversationRespVO> getChatConversationMy(@RequestParam("id") Long id) { | |
| 66 | + AiChatConversationDO conversation = chatConversationService.getChatConversation(id); | |
| 67 | + if (conversation != null && ObjUtil.notEqual(conversation.getUserId(), getLoginUserId())) { | |
| 68 | + conversation = null; | |
| 69 | + } | |
| 70 | + return success(BeanUtils.toBean(conversation, AiChatConversationRespVO.class)); | |
| 71 | + } | |
| 72 | + | |
| 73 | + @DeleteMapping("/delete-my") | |
| 74 | + @Operation(summary = "删除聊天对话") | |
| 75 | + @Parameter(name = "id", required = true, description = "对话编号", example = "1024") | |
| 76 | + public CommonResult<Boolean> deleteChatConversationMy(@RequestParam("id") Long id) { | |
| 77 | + chatConversationService.deleteChatConversationMy(id, getLoginUserId()); | |
| 78 | + return success(true); | |
| 79 | + } | |
| 80 | + | |
| 81 | + @DeleteMapping("/delete-by-unpinned") | |
| 82 | + @Operation(summary = "删除未置顶的聊天对话") | |
| 83 | + public CommonResult<Boolean> deleteChatConversationMyByUnpinned() { | |
| 84 | + chatConversationService.deleteChatConversationMyByUnpinned(getLoginUserId()); | |
| 85 | + return success(true); | |
| 86 | + } | |
| 87 | + | |
| 88 | + // ========== 对话管理 ========== | |
| 89 | + | |
| 90 | + @GetMapping("/page") | |
| 91 | + @Operation(summary = "获得对话分页", description = "用于【对话管理】菜单") | |
| 92 | + @PreAuthorize("@ss.hasPermission('ai:chat-conversation:query')") | |
| 93 | + public CommonResult<PageResult<AiChatConversationRespVO>> getChatConversationPage(AiChatConversationPageReqVO pageReqVO) { | |
| 94 | + PageResult<AiChatConversationDO> pageResult = chatConversationService.getChatConversationPage(pageReqVO); | |
| 95 | + if (CollUtil.isEmpty(pageResult.getList())) { | |
| 96 | + return success(PageResult.empty()); | |
| 97 | + } | |
| 98 | + // 拼接关联数据 | |
| 99 | + Map<Long, Integer> messageCountMap = chatMessageService.getChatMessageCountMap( | |
| 100 | + convertList(pageResult.getList(), AiChatConversationDO::getId)); | |
| 101 | + return success(BeanUtils.toBean(pageResult, AiChatConversationRespVO.class, | |
| 102 | + conversation -> conversation.setMessageCount(messageCountMap.getOrDefault(conversation.getId(), 0)))); | |
| 103 | + } | |
| 104 | + | |
| 105 | + @Operation(summary = "管理员删除对话") | |
| 106 | + @DeleteMapping("/delete-by-admin") | |
| 107 | + @Parameter(name = "id", required = true, description = "对话编号", example = "1024") | |
| 108 | + @PreAuthorize("@ss.hasPermission('ai:chat-conversation:delete')") | |
| 109 | + public CommonResult<Boolean> deleteChatConversationByAdmin(@RequestParam("id") Long id) { | |
| 110 | + chatConversationService.deleteChatConversationByAdmin(id); | |
| 111 | + return success(true); | |
| 112 | + } | |
| 113 | + | |
| 114 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatMessageController.http
0 → 100644
| 1 | +### 发送消息(段式) | |
| 2 | +POST {{baseUrl}}/ai/chat/message/send | |
| 3 | +Content-Type: application/json | |
| 4 | +Authorization: {{token}} | |
| 5 | +tenant-id: {{adminTenentId}} | |
| 6 | + | |
| 7 | +{ | |
| 8 | + "conversationId": "1781604279872581724", | |
| 9 | + "content": "你是 OpenAI 么?" | |
| 10 | +} | |
| 11 | + | |
| 12 | +### 发送消息(流式) | |
| 13 | +POST {{baseUrl}}/ai/chat/message/send-stream | |
| 14 | +Content-Type: application/json | |
| 15 | +Authorization: {{token}} | |
| 16 | +tenant-id: {{adminTenentId}} | |
| 17 | + | |
| 18 | +{ | |
| 19 | + "conversationId": "1781604279872581724", | |
| 20 | + "content": "1+1=?" | |
| 21 | +} | |
| 22 | + | |
| 23 | +### 获得指定对话的消息列表 | |
| 24 | +GET {{baseUrl}}/ai/chat/message/list-by-conversation-id?conversationId=1781604279872581649 | |
| 25 | +Authorization: {{token}} | |
| 26 | + | |
| 27 | +### 删除消息 | |
| 28 | +DELETE {{baseUrl}}/ai/chat/message/delete?id=50 | |
| 29 | +Authorization: {{token}} | |
| 0 | 30 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatMessageController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.chat; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.util.ObjUtil; | |
| 5 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 6 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 7 | +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | |
| 8 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 9 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO; | |
| 10 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO; | |
| 11 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO; | |
| 12 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendRespVO; | |
| 13 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; | |
| 14 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; | |
| 15 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | |
| 16 | +import cn.iocoder.yudao.module.ai.service.chat.AiChatConversationService; | |
| 17 | +import cn.iocoder.yudao.module.ai.service.chat.AiChatMessageService; | |
| 18 | +import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService; | |
| 19 | +import io.swagger.v3.oas.annotations.Operation; | |
| 20 | +import io.swagger.v3.oas.annotations.Parameter; | |
| 21 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 22 | +import jakarta.annotation.Resource; | |
| 23 | +import jakarta.annotation.security.PermitAll; | |
| 24 | +import jakarta.validation.Valid; | |
| 25 | +import lombok.extern.slf4j.Slf4j; | |
| 26 | +import org.springframework.http.MediaType; | |
| 27 | +import org.springframework.security.access.prepost.PreAuthorize; | |
| 28 | +import org.springframework.web.bind.annotation.*; | |
| 29 | +import reactor.core.publisher.Flux; | |
| 30 | + | |
| 31 | +import java.util.Collections; | |
| 32 | +import java.util.List; | |
| 33 | +import java.util.Map; | |
| 34 | + | |
| 35 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 36 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | |
| 37 | +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | |
| 38 | + | |
| 39 | +@Tag(name = "管理后台 - 聊天消息") | |
| 40 | +@RestController | |
| 41 | +@RequestMapping("/ai/chat/message") | |
| 42 | +@Slf4j | |
| 43 | +public class AiChatMessageController { | |
| 44 | + | |
| 45 | + @Resource | |
| 46 | + private AiChatMessageService chatMessageService; | |
| 47 | + @Resource | |
| 48 | + private AiChatConversationService chatConversationService; | |
| 49 | + @Resource | |
| 50 | + private AiChatRoleService chatRoleService; | |
| 51 | + | |
| 52 | + @Operation(summary = "发送消息(段式)", description = "一次性返回,响应较慢") | |
| 53 | + @PostMapping("/send") | |
| 54 | + public CommonResult<AiChatMessageSendRespVO> sendMessage(@Valid @RequestBody AiChatMessageSendReqVO sendReqVO) { | |
| 55 | + return success(chatMessageService.sendMessage(sendReqVO, getLoginUserId())); | |
| 56 | + } | |
| 57 | + | |
| 58 | + @Operation(summary = "发送消息(流式)", description = "流式返回,响应较快") | |
| 59 | + @PostMapping(value = "/send-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) | |
| 60 | + @PermitAll // 解决 SSE 最终响应的时候,会被 Access Denied 拦截的问题 | |
| 61 | + public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(@Valid @RequestBody AiChatMessageSendReqVO sendReqVO) { | |
| 62 | + return chatMessageService.sendChatMessageStream(sendReqVO, getLoginUserId()); | |
| 63 | + } | |
| 64 | + | |
| 65 | + @Operation(summary = "获得指定对话的消息列表") | |
| 66 | + @GetMapping("/list-by-conversation-id") | |
| 67 | + @Parameter(name = "conversationId", required = true, description = "对话编号", example = "1024") | |
| 68 | + public CommonResult<List<AiChatMessageRespVO>> getChatMessageListByConversationId( | |
| 69 | + @RequestParam("conversationId") Long conversationId) { | |
| 70 | + AiChatConversationDO conversation = chatConversationService.getChatConversation(conversationId); | |
| 71 | + if (conversation == null || ObjUtil.notEqual(conversation.getUserId(), getLoginUserId())) { | |
| 72 | + return success(Collections.emptyList()); | |
| 73 | + } | |
| 74 | + List<AiChatMessageDO> messageList = chatMessageService.getChatMessageListByConversationId(conversationId); | |
| 75 | + return success(BeanUtils.toBean(messageList, AiChatMessageRespVO.class)); | |
| 76 | + } | |
| 77 | + | |
| 78 | + @Operation(summary = "删除消息") | |
| 79 | + @DeleteMapping("/delete") | |
| 80 | + @Parameter(name = "id", required = true, description = "消息编号", example = "1024") | |
| 81 | + public CommonResult<Boolean> deleteChatMessage(@RequestParam("id") Long id) { | |
| 82 | + chatMessageService.deleteChatMessage(id, getLoginUserId()); | |
| 83 | + return success(true); | |
| 84 | + } | |
| 85 | + | |
| 86 | + @Operation(summary = "删除指定对话的消息") | |
| 87 | + @DeleteMapping("/delete-by-conversation-id") | |
| 88 | + @Parameter(name = "conversationId", required = true, description = "对话编号", example = "1024") | |
| 89 | + public CommonResult<Boolean> deleteChatMessageByConversationId(@RequestParam("conversationId") Long conversationId) { | |
| 90 | + chatMessageService.deleteChatMessageByConversationId(conversationId, getLoginUserId()); | |
| 91 | + return success(true); | |
| 92 | + } | |
| 93 | + | |
| 94 | + // ========== 对话管理 ========== | |
| 95 | + | |
| 96 | + @GetMapping("/page") | |
| 97 | + @Operation(summary = "获得消息分页", description = "用于【对话管理】菜单") | |
| 98 | + @PreAuthorize("@ss.hasPermission('ai:chat-conversation:query')") | |
| 99 | + public CommonResult<PageResult<AiChatMessageRespVO>> getChatMessagePage(AiChatMessagePageReqVO pageReqVO) { | |
| 100 | + PageResult<AiChatMessageDO> pageResult = chatMessageService.getChatMessagePage(pageReqVO); | |
| 101 | + if (CollUtil.isEmpty(pageResult.getList())) { | |
| 102 | + return success(PageResult.empty()); | |
| 103 | + } | |
| 104 | + // 拼接数据 | |
| 105 | + Map<Long, AiChatRoleDO> roleMap = chatRoleService.getChatRoleMap( | |
| 106 | + convertSet(pageResult.getList(), AiChatMessageDO::getRoleId)); | |
| 107 | + return success(BeanUtils.toBean(pageResult, AiChatMessageRespVO.class, | |
| 108 | + respVO -> MapUtils.findAndThen(roleMap, respVO.getRoleId(), role -> respVO.setRoleName(role.getName())))); | |
| 109 | + } | |
| 110 | + | |
| 111 | + @Operation(summary = "管理员删除消息") | |
| 112 | + @DeleteMapping("/delete-by-admin") | |
| 113 | + @Parameter(name = "id", required = true, description = "消息编号", example = "1024") | |
| 114 | + @PreAuthorize("@ss.hasPermission('ai:chat-message:delete')") | |
| 115 | + public CommonResult<Boolean> deleteChatMessageByAdmin(@RequestParam("id") Long id) { | |
| 116 | + chatMessageService.deleteChatMessageByAdmin(id); | |
| 117 | + return success(true); | |
| 118 | + } | |
| 119 | + | |
| 120 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationCreateMyReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +@Schema(description = "管理后台 - AI 聊天对话创建【我的】 Request VO") | |
| 7 | +@Data | |
| 8 | +public class AiChatConversationCreateMyReqVO { | |
| 9 | + | |
| 10 | + @Schema(description = "聊天角色编号", example = "666") | |
| 11 | + private Long roleId; | |
| 12 | + | |
| 13 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import lombok.Data; | |
| 6 | +import org.springframework.format.annotation.DateTimeFormat; | |
| 7 | + | |
| 8 | +import java.time.LocalDateTime; | |
| 9 | + | |
| 10 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | |
| 11 | + | |
| 12 | +@Schema(description = "管理后台 - AI 聊天对话的分页 Request VO") | |
| 13 | +@Data | |
| 14 | +public class AiChatConversationPageReqVO extends PageParam { | |
| 15 | + | |
| 16 | + @Schema(description = "用户编号", example = "1024") | |
| 17 | + private Long userId; | |
| 18 | + | |
| 19 | + @Schema(description = "对话标题", example = "你好") | |
| 20 | + private String title; | |
| 21 | + | |
| 22 | + @Schema(description = "创建时间") | |
| 23 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 24 | + private LocalDateTime[] createTime; | |
| 25 | + | |
| 26 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | |
| 4 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | |
| 5 | +import com.fhs.core.trans.anno.Trans; | |
| 6 | +import com.fhs.core.trans.constant.TransType; | |
| 7 | +import com.fhs.core.trans.vo.VO; | |
| 8 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 9 | +import lombok.Data; | |
| 10 | + | |
| 11 | +import java.time.LocalDateTime; | |
| 12 | + | |
| 13 | +@Schema(description = "管理后台 - AI 聊天对话 Response VO") | |
| 14 | +@Data | |
| 15 | +public class AiChatConversationRespVO implements VO { | |
| 16 | + | |
| 17 | + @Schema(description = "对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 18 | + private Long id; | |
| 19 | + | |
| 20 | + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") | |
| 21 | + private Long userId; | |
| 22 | + | |
| 23 | + @Schema(description = "对话标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是一个标题") | |
| 24 | + private String title; | |
| 25 | + | |
| 26 | + @Schema(description = "是否置顶", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") | |
| 27 | + private Boolean pinned; | |
| 28 | + | |
| 29 | + @Schema(description = "角色编号", example = "1") | |
| 30 | + @Trans(type = TransType.SIMPLE, target = AiChatRoleDO.class, fields = {"name", "avatar"}, refs = {"roleName", "roleAvatar"}) | |
| 31 | + private Long roleId; | |
| 32 | + | |
| 33 | + @Schema(description = "模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 34 | + @Trans(type = TransType.SIMPLE, target = AiChatModelDO.class, fields = "name", ref = "modelName") | |
| 35 | + private Long modelId; | |
| 36 | + | |
| 37 | + @Schema(description = "模型标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "ERNIE-Bot-turbo-0922") | |
| 38 | + private String model; | |
| 39 | + | |
| 40 | + @Schema(description = "模型名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") | |
| 41 | + private String modelName; | |
| 42 | + | |
| 43 | + @Schema(description = "角色设定", example = "一个快乐的程序员") | |
| 44 | + private String systemMessage; | |
| 45 | + | |
| 46 | + @Schema(description = "温度参数", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.8") | |
| 47 | + private Double temperature; | |
| 48 | + | |
| 49 | + @Schema(description = "单条回复的最大 Token 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096") | |
| 50 | + private Integer maxTokens; | |
| 51 | + | |
| 52 | + @Schema(description = "上下文的最大 Message 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | |
| 53 | + private Integer maxContexts; | |
| 54 | + | |
| 55 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 56 | + private LocalDateTime createTime; | |
| 57 | + | |
| 58 | + // ========== 关联 role 信息 ========== | |
| 59 | + | |
| 60 | + @Schema(description = "角色头像", example = "https://www.iocoder.cn/1.png") | |
| 61 | + private String roleAvatar; | |
| 62 | + | |
| 63 | + @Schema(description = "角色名字", example = "小黄") | |
| 64 | + private String roleName; | |
| 65 | + | |
| 66 | + // ========== 仅在【对话管理】时加载 ========== | |
| 67 | + | |
| 68 | + @Schema(description = "消息数量", example = "20") | |
| 69 | + private Integer messageCount; | |
| 70 | + | |
| 71 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationUpdateMyReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import jakarta.validation.constraints.NotNull; | |
| 5 | +import lombok.Data; | |
| 6 | + | |
| 7 | +@Schema(description = "管理后台 - AI 聊天对话更新【我的】 Request VO") | |
| 8 | +@Data | |
| 9 | +public class AiChatConversationUpdateMyReqVO { | |
| 10 | + | |
| 11 | + @Schema(description = "对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 12 | + @NotNull(message = "对话编号不能为空") | |
| 13 | + private Long id; | |
| 14 | + | |
| 15 | + @Schema(description = "对话标题", example = "我是一个标题") | |
| 16 | + private String title; | |
| 17 | + | |
| 18 | + @Schema(description = "是否置顶", example = "true") | |
| 19 | + private Boolean pinned; | |
| 20 | + | |
| 21 | + @Schema(description = "模型编号", example = "1") | |
| 22 | + private Long modelId; | |
| 23 | + | |
| 24 | + @Schema(description = "角色设定", example = "一个快乐的程序员") | |
| 25 | + private String systemMessage; | |
| 26 | + | |
| 27 | + @Schema(description = "温度参数", example = "0.8") | |
| 28 | + private Double temperature; | |
| 29 | + | |
| 30 | + @Schema(description = "单条回复的最大 Token 数量", example = "4096") | |
| 31 | + private Integer maxTokens; | |
| 32 | + | |
| 33 | + @Schema(description = "上下文的最大 Message 数量", example = "10") | |
| 34 | + private Integer maxContexts; | |
| 35 | + | |
| 36 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/message/AiChatMessagePageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import lombok.Data; | |
| 6 | +import org.springframework.format.annotation.DateTimeFormat; | |
| 7 | + | |
| 8 | +import java.time.LocalDateTime; | |
| 9 | + | |
| 10 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | |
| 11 | + | |
| 12 | +@Schema(description = "管理后台 - AI 聊天消息的分页 Request VO") | |
| 13 | +@Data | |
| 14 | +public class AiChatMessagePageReqVO extends PageParam { | |
| 15 | + | |
| 16 | + @Schema(description = "对话编号", example = "2048") | |
| 17 | + private Long conversationId; | |
| 18 | + | |
| 19 | + @Schema(description = "用户编号", example = "1024") | |
| 20 | + private Long userId; | |
| 21 | + | |
| 22 | + @Schema(description = "消息内容", example = "你好") | |
| 23 | + private String content; | |
| 24 | + | |
| 25 | + @Schema(description = "创建时间") | |
| 26 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 27 | + private LocalDateTime[] createTime; | |
| 28 | + | |
| 29 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/message/AiChatMessageRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +import java.time.LocalDateTime; | |
| 7 | + | |
| 8 | +@Schema(description = "管理后台 - AI 聊天消息 Response VO") | |
| 9 | +@Data | |
| 10 | +public class AiChatMessageRespVO { | |
| 11 | + | |
| 12 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 13 | + private Long id; | |
| 14 | + | |
| 15 | + @Schema(description = "对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") | |
| 16 | + private Long conversationId; | |
| 17 | + | |
| 18 | + @Schema(description = "回复消息编号", example = "1024") | |
| 19 | + private Long replyId; | |
| 20 | + | |
| 21 | + @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "role") | |
| 22 | + private String type; // 参见 MessageType 枚举类 | |
| 23 | + | |
| 24 | + @Schema(description = "用户编号", example = "4096") | |
| 25 | + private Long userId; | |
| 26 | + | |
| 27 | + @Schema(description = "角色编号", example = "888") | |
| 28 | + private Long roleId; | |
| 29 | + | |
| 30 | + @Schema(description = "模型标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "gpt-3.5-turbo") | |
| 31 | + private String model; | |
| 32 | + | |
| 33 | + @Schema(description = "模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123") | |
| 34 | + private Long modelId; | |
| 35 | + | |
| 36 | + @Schema(description = "聊天内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,你好啊") | |
| 37 | + private String content; | |
| 38 | + | |
| 39 | + @Schema(description = "是否携带上下文", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") | |
| 40 | + private Boolean useContext; | |
| 41 | + | |
| 42 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-05-12 12:51") | |
| 43 | + private LocalDateTime createTime; | |
| 44 | + | |
| 45 | + // ========== 仅在【对话管理】时加载 ========== | |
| 46 | + | |
| 47 | + @Schema(description = "角色名字", example = "小黄") | |
| 48 | + private String roleName; | |
| 49 | + | |
| 50 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/message/AiChatMessageSendReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import jakarta.validation.constraints.NotEmpty; | |
| 5 | +import jakarta.validation.constraints.NotNull; | |
| 6 | +import jakarta.validation.constraints.Size; | |
| 7 | +import lombok.Data; | |
| 8 | +import lombok.experimental.Accessors; | |
| 9 | + | |
| 10 | +@Schema(description = "管理后台 - AI 聊天消息发送 Request VO") | |
| 11 | +@Data | |
| 12 | +public class AiChatMessageSendReqVO { | |
| 13 | + | |
| 14 | + @Schema(description = "聊天对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 15 | + @NotNull(message = "聊天对话编号不能为空") | |
| 16 | + private Long conversationId; | |
| 17 | + | |
| 18 | + @Schema(description = "聊天内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "帮我写个 Java 算法") | |
| 19 | + @NotEmpty(message = "聊天内容不能为空") | |
| 20 | + private String content; | |
| 21 | + | |
| 22 | + @Schema(description = "是否携带上下文", example = "true") | |
| 23 | + private Boolean useContext; | |
| 24 | + | |
| 25 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/message/AiChatMessageSendRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +import java.time.LocalDateTime; | |
| 7 | + | |
| 8 | +@Schema(description = "管理后台 - AI 聊天消息发送 Response VO") | |
| 9 | +@Data | |
| 10 | +public class AiChatMessageSendRespVO { | |
| 11 | + | |
| 12 | + @Schema(description = "发送消息", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 13 | + private Message send; | |
| 14 | + | |
| 15 | + @Schema(description = "接收消息", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 16 | + private Message receive; | |
| 17 | + | |
| 18 | + @Schema(description = "消息") | |
| 19 | + @Data | |
| 20 | + public static class Message { | |
| 21 | + | |
| 22 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 23 | + private Long id; | |
| 24 | + | |
| 25 | + @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "role") | |
| 26 | + private String type; // 参见 MessageType 枚举类 | |
| 27 | + | |
| 28 | + @Schema(description = "聊天内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,你好啊") | |
| 29 | + private String content; | |
| 30 | + | |
| 31 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 32 | + private LocalDateTime createTime; | |
| 33 | + | |
| 34 | + } | |
| 35 | + | |
| 36 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.http
0 → 100644
| 1 | +### 生成图片:OpenAI(DALL) | |
| 2 | +POST {{baseUrl}}/ai/image/draw | |
| 3 | +Content-Type: application/json | |
| 4 | +Authorization: {{token}} | |
| 5 | + | |
| 6 | +{ | |
| 7 | + "platform": "OpenAI", | |
| 8 | + "prompt": "可爱的小喵星人", | |
| 9 | + "model": "dall-e-3", | |
| 10 | + "height": "1024", | |
| 11 | + "width": "1024", | |
| 12 | + "options": { | |
| 13 | + "style": "vivid" | |
| 14 | + } | |
| 15 | +} | |
| 16 | + | |
| 17 | +### 生成图片:StableDiffusion | |
| 18 | +POST {{baseUrl}}/ai/image/draw | |
| 19 | +Content-Type: application/json | |
| 20 | +Authorization: {{token}} | |
| 21 | + | |
| 22 | +{ | |
| 23 | + "platform": "StableDiffusion", | |
| 24 | + "prompt": "中国长城", | |
| 25 | + "model": "stable-diffusion-v1-6", | |
| 26 | + "height": "1024", | |
| 27 | + "width": "1024", | |
| 28 | + "style": "vivid" | |
| 29 | +} | |
| 30 | + | |
| 31 | +### 生成图片:生成图片(Midjourney) | |
| 32 | +POST {{baseUrl}}/ai/image/midjourney/imagine | |
| 33 | +Content-Type: application/json | |
| 34 | +Authorization: {{token}} | |
| 35 | + | |
| 36 | +{ | |
| 37 | + "prompt": "中国旗袍", | |
| 38 | + "model": "midjourney", | |
| 39 | + "width": "1", | |
| 40 | + "height": "1", | |
| 41 | + "version": "6.0" | |
| 42 | +} | |
| 0 | 43 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.image; | |
| 2 | + | |
| 3 | +import cn.hutool.core.util.ObjUtil; | |
| 4 | +import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; | |
| 5 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 6 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 7 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 8 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 9 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDrawReqVO; | |
| 10 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImagePageReqVO; | |
| 11 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageRespVO; | |
| 12 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageUpdateReqVO; | |
| 13 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.midjourney.AiMidjourneyActionReqVO; | |
| 14 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.midjourney.AiMidjourneyImagineReqVO; | |
| 15 | +import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO; | |
| 16 | +import cn.iocoder.yudao.module.ai.service.image.AiImageService; | |
| 17 | +import io.swagger.v3.oas.annotations.Operation; | |
| 18 | +import io.swagger.v3.oas.annotations.Parameter; | |
| 19 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 20 | +import jakarta.annotation.Resource; | |
| 21 | +import jakarta.annotation.security.PermitAll; | |
| 22 | +import jakarta.validation.Valid; | |
| 23 | +import lombok.extern.slf4j.Slf4j; | |
| 24 | +import org.springframework.security.access.prepost.PreAuthorize; | |
| 25 | +import org.springframework.validation.annotation.Validated; | |
| 26 | +import org.springframework.web.bind.annotation.*; | |
| 27 | + | |
| 28 | +import java.util.List; | |
| 29 | + | |
| 30 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 31 | +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | |
| 32 | + | |
| 33 | +@Tag(name = "管理后台 - AI 绘画") | |
| 34 | +@RestController | |
| 35 | +@RequestMapping("/ai/image") | |
| 36 | +@Slf4j | |
| 37 | +public class AiImageController { | |
| 38 | + | |
| 39 | + @Resource | |
| 40 | + private AiImageService imageService; | |
| 41 | + | |
| 42 | + @GetMapping("/my-page") | |
| 43 | + @Operation(summary = "获取【我的】绘图分页") | |
| 44 | + public CommonResult<PageResult<AiImageRespVO>> getImagePageMy(@Validated PageParam pageReqVO) { | |
| 45 | + PageResult<AiImageDO> pageResult = imageService.getImagePageMy(getLoginUserId(), pageReqVO); | |
| 46 | + return success(BeanUtils.toBean(pageResult, AiImageRespVO.class)); | |
| 47 | + } | |
| 48 | + | |
| 49 | + @GetMapping("/get-my") | |
| 50 | + @Operation(summary = "获取【我的】绘图记录") | |
| 51 | + @Parameter(name = "id", required = true, description = "绘画编号", example = "1024") | |
| 52 | + public CommonResult<AiImageRespVO> getImageMy(@RequestParam("id") Long id) { | |
| 53 | + AiImageDO image = imageService.getImage(id); | |
| 54 | + if (image == null || ObjUtil.notEqual(getLoginUserId(), image.getUserId())) { | |
| 55 | + return success(null); | |
| 56 | + } | |
| 57 | + return success(BeanUtils.toBean(image, AiImageRespVO.class)); | |
| 58 | + } | |
| 59 | + | |
| 60 | + @GetMapping("/my-list-by-ids") | |
| 61 | + @Operation(summary = "获取【我的】绘图记录列表") | |
| 62 | + @Parameter(name = "ids", required = true, description = "绘画编号数组", example = "1024,2048") | |
| 63 | + public CommonResult<List<AiImageRespVO>> getImageListMyByIds(@RequestParam("ids") List<Long> ids) { | |
| 64 | + List<AiImageDO> imageList = imageService.getImageList(ids); | |
| 65 | + imageList.removeIf(item -> !ObjUtil.equal(getLoginUserId(), item.getUserId())); | |
| 66 | + return success(BeanUtils.toBean(imageList, AiImageRespVO.class)); | |
| 67 | + } | |
| 68 | + | |
| 69 | + @Operation(summary = "生成图片") | |
| 70 | + @PostMapping("/draw") | |
| 71 | + public CommonResult<Long> drawImage(@Valid @RequestBody AiImageDrawReqVO drawReqVO) { | |
| 72 | + return success(imageService.drawImage(getLoginUserId(), drawReqVO)); | |
| 73 | + } | |
| 74 | + | |
| 75 | + @Operation(summary = "删除【我的】绘画记录") | |
| 76 | + @DeleteMapping("/delete-my") | |
| 77 | + @Parameter(name = "id", required = true, description = "绘画编号", example = "1024") | |
| 78 | + public CommonResult<Boolean> deleteImageMy(@RequestParam("id") Long id) { | |
| 79 | + imageService.deleteImageMy(id, getLoginUserId()); | |
| 80 | + return success(true); | |
| 81 | + } | |
| 82 | + | |
| 83 | + // ================ midjourney 专属 ================ | |
| 84 | + | |
| 85 | + @Operation(summary = "【Midjourney】生成图片") | |
| 86 | + @PostMapping("/midjourney/imagine") | |
| 87 | + public CommonResult<Long> midjourneyImagine(@Valid @RequestBody AiMidjourneyImagineReqVO reqVO) { | |
| 88 | + Long imageId = imageService.midjourneyImagine(getLoginUserId(), reqVO); | |
| 89 | + return success(imageId); | |
| 90 | + } | |
| 91 | + | |
| 92 | + @Operation(summary = "【Midjourney】通知图片进展", description = "由 Midjourney Proxy 回调") | |
| 93 | + @PostMapping("/midjourney/notify") // 必须是 POST 方法,否则会报错 | |
| 94 | + @PermitAll | |
| 95 | + public CommonResult<Boolean> midjourneyNotify(@Valid @RequestBody MidjourneyApi.Notify notify) { | |
| 96 | + imageService.midjourneyNotify(notify); | |
| 97 | + return success(true); | |
| 98 | + } | |
| 99 | + | |
| 100 | + @Operation(summary = "【Midjourney】Action 操作(二次生成图片)", description = "例如说:放大、缩小、U1、U2 等") | |
| 101 | + @PostMapping("/midjourney/action") | |
| 102 | + public CommonResult<Long> midjourneyAction(@Valid @RequestBody AiMidjourneyActionReqVO reqVO) { | |
| 103 | + Long imageId = imageService.midjourneyAction(getLoginUserId(), reqVO); | |
| 104 | + return success(imageId); | |
| 105 | + } | |
| 106 | + | |
| 107 | + // ================ 绘图管理 ================ | |
| 108 | + | |
| 109 | + @GetMapping("/page") | |
| 110 | + @Operation(summary = "获得绘画分页") | |
| 111 | + @PreAuthorize("@ss.hasPermission('ai:image:query')") | |
| 112 | + public CommonResult<PageResult<AiImageRespVO>> getImagePage(@Valid AiImagePageReqVO pageReqVO) { | |
| 113 | + PageResult<AiImageDO> pageResult = imageService.getImagePage(pageReqVO); | |
| 114 | + return success(BeanUtils.toBean(pageResult, AiImageRespVO.class)); | |
| 115 | + } | |
| 116 | + | |
| 117 | + @PutMapping("/update") | |
| 118 | + @Operation(summary = "更新绘画") | |
| 119 | + @PreAuthorize("@ss.hasPermission('ai:image:update')") | |
| 120 | + public CommonResult<Boolean> updateImage(@Valid @RequestBody AiImageUpdateReqVO updateReqVO) { | |
| 121 | + imageService.updateImage(updateReqVO); | |
| 122 | + return success(true); | |
| 123 | + } | |
| 124 | + | |
| 125 | + @DeleteMapping("/delete") | |
| 126 | + @Operation(summary = "删除绘画") | |
| 127 | + @Parameter(name = "id", description = "编号", required = true) | |
| 128 | + @PreAuthorize("@ss.hasPermission('ai:image:delete')") | |
| 129 | + public CommonResult<Boolean> deleteImage(@RequestParam("id") Long id) { | |
| 130 | + imageService.deleteImage(id); | |
| 131 | + return success(true); | |
| 132 | + } | |
| 133 | + | |
| 134 | +} | |
| 0 | 135 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageDrawReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.image.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import jakarta.validation.constraints.NotEmpty; | |
| 5 | +import jakarta.validation.constraints.NotNull; | |
| 6 | +import jakarta.validation.constraints.Size; | |
| 7 | +import lombok.Data; | |
| 8 | +import org.springframework.ai.openai.OpenAiImageOptions; | |
| 9 | +import org.springframework.ai.stabilityai.api.StabilityAiImageOptions; | |
| 10 | + | |
| 11 | +import java.util.Map; | |
| 12 | + | |
| 13 | +@Schema(description = "管理后台 - AI 绘画 Request VO") | |
| 14 | +@Data | |
| 15 | +public class AiImageDrawReqVO { | |
| 16 | + | |
| 17 | + @Schema(description = "模型平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "OpenAI") | |
| 18 | + private String platform; // 参见 AiPlatformEnum 枚举 | |
| 19 | + | |
| 20 | + @Schema(description = "提示词", requiredMode = Schema.RequiredMode.REQUIRED, example = "画一个长城") | |
| 21 | + @NotEmpty(message = "提示词不能为空") | |
| 22 | + @Size(max = 1200, message = "提示词最大 1200") | |
| 23 | + private String prompt; | |
| 24 | + | |
| 25 | + @Schema(description = "模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "stable-diffusion-v1-6") | |
| 26 | + @NotEmpty(message = "模型不能为空") | |
| 27 | + private String model; | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * 1. dall-e-2 模型:256x256、512x512、1024x1024 | |
| 31 | + * 2. dall-e-3 模型:1024x1024, 1792x1024, 或 1024x1792 | |
| 32 | + */ | |
| 33 | + @Schema(description = "图片高度") | |
| 34 | + @NotNull(message = "图片高度不能为空") | |
| 35 | + private Integer height; | |
| 36 | + | |
| 37 | + @Schema(description = "图片宽度") | |
| 38 | + @NotNull(message = "图片宽度不能为空") | |
| 39 | + private Integer width; | |
| 40 | + | |
| 41 | + // ========== 各平台绘画的拓展参数 ========== | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * 绘制参数,不同 platform 的不同参数 | |
| 45 | + * | |
| 46 | + * 1. {@link OpenAiImageOptions} | |
| 47 | + * 2. {@link StabilityAiImageOptions} | |
| 48 | + */ | |
| 49 | + @Schema(description = "绘制参数") | |
| 50 | + private Map<String, String> options; | |
| 51 | + | |
| 52 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImagePageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.image.vo; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import lombok.Data; | |
| 6 | +import lombok.EqualsAndHashCode; | |
| 7 | +import lombok.ToString; | |
| 8 | +import org.springframework.format.annotation.DateTimeFormat; | |
| 9 | + | |
| 10 | +import java.time.LocalDateTime; | |
| 11 | + | |
| 12 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | |
| 13 | + | |
| 14 | +@Schema(description = "管理后台 - AI 绘画分页 Request VO") | |
| 15 | +@Data | |
| 16 | +public class AiImagePageReqVO extends PageParam { | |
| 17 | + | |
| 18 | + @Schema(description = "用户编号", example = "28987") | |
| 19 | + private Long userId; | |
| 20 | + | |
| 21 | + @Schema(description = "平台", example = "OpenAI") | |
| 22 | + private String platform; | |
| 23 | + | |
| 24 | + @Schema(description = "绘画状态", example = "1") | |
| 25 | + private Integer status; | |
| 26 | + | |
| 27 | + @Schema(description = "是否发布", example = "1") | |
| 28 | + private Boolean publicStatus; | |
| 29 | + | |
| 30 | + @Schema(description = "创建时间") | |
| 31 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 32 | + private LocalDateTime[] createTime; | |
| 33 | + | |
| 34 | +} | |
| 0 | 35 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.image.vo; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import lombok.Data; | |
| 6 | + | |
| 7 | +import java.time.LocalDateTime; | |
| 8 | +import java.util.List; | |
| 9 | +import java.util.Map; | |
| 10 | + | |
| 11 | +@Schema(description = "管理后台 - AI 绘画 Response VO") | |
| 12 | +@Data | |
| 13 | +public class AiImageRespVO { | |
| 14 | + | |
| 15 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 16 | + private Long id; | |
| 17 | + | |
| 18 | + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 19 | + private Long userId; | |
| 20 | + | |
| 21 | + @Schema(description = "平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "OpenAI") | |
| 22 | + private String platform; // 参见 AiPlatformEnum 枚举 | |
| 23 | + | |
| 24 | + @Schema(description = "模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "stable-diffusion-v1-6") | |
| 25 | + private String model; | |
| 26 | + | |
| 27 | + @Schema(description = "提示词", requiredMode = Schema.RequiredMode.REQUIRED, example = "南极的小企鹅") | |
| 28 | + private String prompt; | |
| 29 | + | |
| 30 | + @Schema(description = "图片宽度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 31 | + private Integer width; | |
| 32 | + | |
| 33 | + @Schema(description = "图片高度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 34 | + private Integer height; | |
| 35 | + | |
| 36 | + @Schema(description = "绘画状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | |
| 37 | + private Integer status; | |
| 38 | + | |
| 39 | + @Schema(description = "是否发布", requiredMode = Schema.RequiredMode.REQUIRED, example = "public") | |
| 40 | + private Boolean publicStatus; | |
| 41 | + | |
| 42 | + @Schema(description = "图片地址", example = "https://www.iocoder.cn/1.png") | |
| 43 | + private String picUrl; | |
| 44 | + | |
| 45 | + @Schema(description = "绘画错误信息", example = "图片错误信息") | |
| 46 | + private String errorMessage; | |
| 47 | + | |
| 48 | + @Schema(description = "绘制参数") | |
| 49 | + private Map<String, String> options; | |
| 50 | + | |
| 51 | + @Schema(description = "mj buttons 按钮") | |
| 52 | + private List<MidjourneyApi.Button> buttons; | |
| 53 | + | |
| 54 | + @Schema(description = "完成时间") | |
| 55 | + private LocalDateTime finishTime; | |
| 56 | + | |
| 57 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 58 | + private LocalDateTime createTime; | |
| 59 | + | |
| 60 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageUpdateReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.image.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import jakarta.validation.constraints.NotNull; | |
| 5 | +import lombok.Data; | |
| 6 | + | |
| 7 | +@Schema(description = "管理后台 - AI 绘画修改 Request VO") | |
| 8 | +@Data | |
| 9 | +public class AiImageUpdateReqVO { | |
| 10 | + | |
| 11 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15583") | |
| 12 | + @NotNull(message = "编号不能为空") | |
| 13 | + private Long id; | |
| 14 | + | |
| 15 | + @Schema(description = "是否发布", example = "true") | |
| 16 | + private Boolean publicStatus; | |
| 17 | + | |
| 18 | +} | |
| 0 | 19 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/midjourney/AiMidjourneyActionReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.image.vo.midjourney; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import jakarta.validation.constraints.NotEmpty; | |
| 5 | +import jakarta.validation.constraints.NotNull; | |
| 6 | +import lombok.Data; | |
| 7 | + | |
| 8 | +@Schema(description = "管理后台 - AI 绘图操作(Midjourney) Request VO") | |
| 9 | +@Data | |
| 10 | +public class AiMidjourneyActionReqVO { | |
| 11 | + | |
| 12 | + @Schema(description = "图片编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 13 | + @NotNull(message = "图片编号不能为空") | |
| 14 | + private Long id; | |
| 15 | + | |
| 16 | + @Schema(description = "操作按钮编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "MJ::JOB::variation::4::06aa3e66-0e97-49cc-8201-e0295d883de4") | |
| 17 | + @NotEmpty(message = "操作按钮编号不能为空") | |
| 18 | + private String customId; | |
| 19 | + | |
| 20 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/midjourney/AiMidjourneyImagineReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.image.vo.midjourney; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import jakarta.validation.constraints.NotEmpty; | |
| 5 | +import jakarta.validation.constraints.NotNull; | |
| 6 | +import lombok.Data; | |
| 7 | + | |
| 8 | +@Schema(description = "管理后台 - AI 绘画生成(Midjourney) Request VO") | |
| 9 | +@Data | |
| 10 | +public class AiMidjourneyImagineReqVO { | |
| 11 | + | |
| 12 | + @Schema(description = "提示词", requiredMode = Schema.RequiredMode.REQUIRED, example = "中国神龙") | |
| 13 | + @NotEmpty(message = "提示词不能为空!") | |
| 14 | + private String prompt; | |
| 15 | + | |
| 16 | + @Schema(description = "模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "midjourney") | |
| 17 | + @NotEmpty(message = "模型不能为空") | |
| 18 | + private String model; // 参考 MidjourneyApi.ModelEnum | |
| 19 | + | |
| 20 | + @Schema(description = "图片宽度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 21 | + @NotNull(message = "图片宽度不能为空") | |
| 22 | + private Integer width; | |
| 23 | + | |
| 24 | + @Schema(description = "图片高度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 25 | + @NotNull(message = "图片高度不能为空") | |
| 26 | + private Integer height; | |
| 27 | + | |
| 28 | + @Schema(description = "版本号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6.0") | |
| 29 | + @NotEmpty(message = "版本号不能为空") | |
| 30 | + private String version; | |
| 31 | + | |
| 32 | + @Schema(description = "参考图", example = "https://www.iocoder.cn/x.png") | |
| 33 | + private String referImageUrl; | |
| 34 | + | |
| 35 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/mindmap/AiMindMapController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.mindmap; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 4 | +import cn.iocoder.yudao.module.ai.controller.admin.mindmap.vo.AiMindMapGenerateReqVO; | |
| 5 | +import cn.iocoder.yudao.module.ai.service.mindmap.AiMindMapService; | |
| 6 | +import io.swagger.v3.oas.annotations.Operation; | |
| 7 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 8 | +import jakarta.annotation.Resource; | |
| 9 | +import jakarta.annotation.security.PermitAll; | |
| 10 | +import jakarta.validation.Valid; | |
| 11 | +import org.springframework.http.MediaType; | |
| 12 | +import org.springframework.web.bind.annotation.PostMapping; | |
| 13 | +import org.springframework.web.bind.annotation.RequestBody; | |
| 14 | +import org.springframework.web.bind.annotation.RequestMapping; | |
| 15 | +import org.springframework.web.bind.annotation.RestController; | |
| 16 | +import reactor.core.publisher.Flux; | |
| 17 | + | |
| 18 | +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | |
| 19 | + | |
| 20 | +@Tag(name = "管理后台 - AI 思维导图") | |
| 21 | +@RestController | |
| 22 | +@RequestMapping("/ai/mind-map") | |
| 23 | +public class AiMindMapController { | |
| 24 | + | |
| 25 | + @Resource | |
| 26 | + private AiMindMapService mindMapService; | |
| 27 | + | |
| 28 | + @PostMapping(value = "/generate-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) | |
| 29 | + @Operation(summary = "脑图生成(流式)", description = "流式返回,响应较快") | |
| 30 | + @PermitAll // 解决 SSE 最终响应的时候,会被 Access Denied 拦截的问题 | |
| 31 | + public Flux<CommonResult<String>> generateMindMap(@RequestBody @Valid AiMindMapGenerateReqVO generateReqVO) { | |
| 32 | + return mindMapService.generateMindMap(generateReqVO, getLoginUserId()); | |
| 33 | + } | |
| 34 | + | |
| 35 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/mindmap/vo/AiMindMapGenerateReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.mindmap.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import jakarta.validation.constraints.NotBlank; | |
| 5 | +import lombok.Data; | |
| 6 | + | |
| 7 | +@Schema(description = "管理后台 - AI 思维导图生成 Request VO") | |
| 8 | +@Data | |
| 9 | +public class AiMindMapGenerateReqVO { | |
| 10 | + | |
| 11 | + @Schema(description = "思维导图内容提示", example = "Java 学习路线") | |
| 12 | + @NotBlank(message = "思维导图内容提示不能为空") | |
| 13 | + private String prompt; | |
| 14 | + | |
| 15 | +} | |
| 0 | 16 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/AiApiKeyController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.model; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 5 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 6 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeyPageReqVO; | |
| 7 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeyRespVO; | |
| 8 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeySaveReqVO; | |
| 9 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatModel.AiChatModelRespVO; | |
| 10 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO; | |
| 11 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | |
| 12 | +import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService; | |
| 13 | +import io.swagger.v3.oas.annotations.Operation; | |
| 14 | +import io.swagger.v3.oas.annotations.Parameter; | |
| 15 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 16 | +import jakarta.annotation.Resource; | |
| 17 | +import jakarta.validation.Valid; | |
| 18 | +import org.springframework.security.access.prepost.PreAuthorize; | |
| 19 | +import org.springframework.validation.annotation.Validated; | |
| 20 | +import org.springframework.web.bind.annotation.*; | |
| 21 | + | |
| 22 | +import java.util.List; | |
| 23 | + | |
| 24 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 25 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 26 | + | |
| 27 | +@Tag(name = "管理后台 - AI API 密钥") | |
| 28 | +@RestController | |
| 29 | +@RequestMapping("/ai/api-key") | |
| 30 | +@Validated | |
| 31 | +public class AiApiKeyController { | |
| 32 | + | |
| 33 | + @Resource | |
| 34 | + private AiApiKeyService apiKeyService; | |
| 35 | + | |
| 36 | + @PostMapping("/create") | |
| 37 | + @Operation(summary = "创建 API 密钥") | |
| 38 | + @PreAuthorize("@ss.hasPermission('ai:api-key:create')") | |
| 39 | + public CommonResult<Long> createApiKey(@Valid @RequestBody AiApiKeySaveReqVO createReqVO) { | |
| 40 | + return success(apiKeyService.createApiKey(createReqVO)); | |
| 41 | + } | |
| 42 | + | |
| 43 | + @PutMapping("/update") | |
| 44 | + @Operation(summary = "更新 API 密钥") | |
| 45 | + @PreAuthorize("@ss.hasPermission('ai:api-key:update')") | |
| 46 | + public CommonResult<Boolean> updateApiKey(@Valid @RequestBody AiApiKeySaveReqVO updateReqVO) { | |
| 47 | + apiKeyService.updateApiKey(updateReqVO); | |
| 48 | + return success(true); | |
| 49 | + } | |
| 50 | + | |
| 51 | + @DeleteMapping("/delete") | |
| 52 | + @Operation(summary = "删除 API 密钥") | |
| 53 | + @Parameter(name = "id", description = "编号", required = true) | |
| 54 | + @PreAuthorize("@ss.hasPermission('ai:api-key:delete')") | |
| 55 | + public CommonResult<Boolean> deleteApiKey(@RequestParam("id") Long id) { | |
| 56 | + apiKeyService.deleteApiKey(id); | |
| 57 | + return success(true); | |
| 58 | + } | |
| 59 | + | |
| 60 | + @GetMapping("/get") | |
| 61 | + @Operation(summary = "获得 API 密钥") | |
| 62 | + @Parameter(name = "id", description = "编号", required = true, example = "1024") | |
| 63 | + @PreAuthorize("@ss.hasPermission('ai:api-key:query')") | |
| 64 | + public CommonResult<AiApiKeyRespVO> getApiKey(@RequestParam("id") Long id) { | |
| 65 | + AiApiKeyDO apiKey = apiKeyService.getApiKey(id); | |
| 66 | + return success(BeanUtils.toBean(apiKey, AiApiKeyRespVO.class)); | |
| 67 | + } | |
| 68 | + | |
| 69 | + @GetMapping("/page") | |
| 70 | + @Operation(summary = "获得 API 密钥分页") | |
| 71 | + @PreAuthorize("@ss.hasPermission('ai:api-key:query')") | |
| 72 | + public CommonResult<PageResult<AiApiKeyRespVO>> getApiKeyPage(@Valid AiApiKeyPageReqVO pageReqVO) { | |
| 73 | + PageResult<AiApiKeyDO> pageResult = apiKeyService.getApiKeyPage(pageReqVO); | |
| 74 | + return success(BeanUtils.toBean(pageResult, AiApiKeyRespVO.class)); | |
| 75 | + } | |
| 76 | + | |
| 77 | + @GetMapping("/simple-list") | |
| 78 | + @Operation(summary = "获得 API 密钥分页列表") | |
| 79 | + public CommonResult<List<AiChatModelRespVO>> getApiKeySimpleList() { | |
| 80 | + List<AiApiKeyDO> list = apiKeyService.getApiKeyList(); | |
| 81 | + return success(convertList(list, key -> new AiChatModelRespVO().setId(key.getId()).setName(key.getName()))); | |
| 82 | + } | |
| 83 | + | |
| 84 | +} | |
| 0 | 85 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/AiChatModelController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.model; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 5 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 6 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatModel.AiChatModelPageReqVO; | |
| 7 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatModel.AiChatModelRespVO; | |
| 8 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatModel.AiChatModelSaveReqVO; | |
| 9 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | |
| 10 | +import cn.iocoder.yudao.module.ai.service.model.AiChatModelService; | |
| 11 | +import io.swagger.v3.oas.annotations.Operation; | |
| 12 | +import io.swagger.v3.oas.annotations.Parameter; | |
| 13 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 14 | +import jakarta.annotation.Resource; | |
| 15 | +import jakarta.validation.Valid; | |
| 16 | +import org.springframework.security.access.prepost.PreAuthorize; | |
| 17 | +import org.springframework.validation.annotation.Validated; | |
| 18 | +import org.springframework.web.bind.annotation.*; | |
| 19 | + | |
| 20 | +import java.util.List; | |
| 21 | + | |
| 22 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 23 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 24 | + | |
| 25 | +@Tag(name = "管理后台 - AI 聊天模型") | |
| 26 | +@RestController | |
| 27 | +@RequestMapping("/ai/chat-model") | |
| 28 | +@Validated | |
| 29 | +public class AiChatModelController { | |
| 30 | + | |
| 31 | + @Resource | |
| 32 | + private AiChatModelService chatModelService; | |
| 33 | + | |
| 34 | + @PostMapping("/create") | |
| 35 | + @Operation(summary = "创建聊天模型") | |
| 36 | + @PreAuthorize("@ss.hasPermission('ai:chat-model:create')") | |
| 37 | + public CommonResult<Long> createChatModel(@Valid @RequestBody AiChatModelSaveReqVO createReqVO) { | |
| 38 | + return success(chatModelService.createChatModel(createReqVO)); | |
| 39 | + } | |
| 40 | + | |
| 41 | + @PutMapping("/update") | |
| 42 | + @Operation(summary = "更新聊天模型") | |
| 43 | + @PreAuthorize("@ss.hasPermission('ai:chat-model:update')") | |
| 44 | + public CommonResult<Boolean> updateChatModel(@Valid @RequestBody AiChatModelSaveReqVO updateReqVO) { | |
| 45 | + chatModelService.updateChatModel(updateReqVO); | |
| 46 | + return success(true); | |
| 47 | + } | |
| 48 | + | |
| 49 | + @DeleteMapping("/delete") | |
| 50 | + @Operation(summary = "删除聊天模型") | |
| 51 | + @Parameter(name = "id", description = "编号", required = true) | |
| 52 | + @PreAuthorize("@ss.hasPermission('ai:chat-model:delete')") | |
| 53 | + public CommonResult<Boolean> deleteChatModel(@RequestParam("id") Long id) { | |
| 54 | + chatModelService.deleteChatModel(id); | |
| 55 | + return success(true); | |
| 56 | + } | |
| 57 | + | |
| 58 | + @GetMapping("/get") | |
| 59 | + @Operation(summary = "获得聊天模型") | |
| 60 | + @Parameter(name = "id", description = "编号", required = true, example = "1024") | |
| 61 | + @PreAuthorize("@ss.hasPermission('ai:chat-model:query')") | |
| 62 | + public CommonResult<AiChatModelRespVO> getChatModel(@RequestParam("id") Long id) { | |
| 63 | + AiChatModelDO chatModel = chatModelService.getChatModel(id); | |
| 64 | + return success(BeanUtils.toBean(chatModel, AiChatModelRespVO.class)); | |
| 65 | + } | |
| 66 | + | |
| 67 | + @GetMapping("/page") | |
| 68 | + @Operation(summary = "获得聊天模型分页") | |
| 69 | + @PreAuthorize("@ss.hasPermission('ai:chat-model:query')") | |
| 70 | + public CommonResult<PageResult<AiChatModelRespVO>> getChatModelPage(@Valid AiChatModelPageReqVO pageReqVO) { | |
| 71 | + PageResult<AiChatModelDO> pageResult = chatModelService.getChatModelPage(pageReqVO); | |
| 72 | + return success(BeanUtils.toBean(pageResult, AiChatModelRespVO.class)); | |
| 73 | + } | |
| 74 | + | |
| 75 | + @GetMapping("/simple-list") | |
| 76 | + @Operation(summary = "获得聊天模型列表") | |
| 77 | + @Parameter(name = "status", description = "状态", required = true, example = "1") | |
| 78 | + public CommonResult<List<AiChatModelRespVO>> getChatModelSimpleList(@RequestParam("status") Integer status) { | |
| 79 | + List<AiChatModelDO> list = chatModelService.getChatModelListByStatus(status); | |
| 80 | + return success(convertList(list, model -> new AiChatModelRespVO().setId(model.getId()) | |
| 81 | + .setName(model.getName()).setModel(model.getModel()))); | |
| 82 | + } | |
| 83 | + | |
| 84 | +} | |
| 0 | 85 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/AiChatRoleController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.model; | |
| 2 | + | |
| 3 | +import cn.hutool.core.util.ObjUtil; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 5 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 6 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 7 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRolePageReqVO; | |
| 8 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleRespVO; | |
| 9 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveMyReqVO; | |
| 10 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveReqVO; | |
| 11 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | |
| 12 | +import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService; | |
| 13 | +import io.swagger.v3.oas.annotations.Operation; | |
| 14 | +import io.swagger.v3.oas.annotations.Parameter; | |
| 15 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 16 | +import jakarta.annotation.Resource; | |
| 17 | +import jakarta.validation.Valid; | |
| 18 | +import org.springframework.security.access.prepost.PreAuthorize; | |
| 19 | +import org.springframework.validation.annotation.Validated; | |
| 20 | +import org.springframework.web.bind.annotation.*; | |
| 21 | + | |
| 22 | +import java.util.List; | |
| 23 | + | |
| 24 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 25 | +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | |
| 26 | + | |
| 27 | +@Tag(name = "管理后台 - AI 聊天角色") | |
| 28 | +@RestController | |
| 29 | +@RequestMapping("/ai/chat-role") | |
| 30 | +@Validated | |
| 31 | +public class AiChatRoleController { | |
| 32 | + | |
| 33 | + @Resource | |
| 34 | + private AiChatRoleService chatRoleService; | |
| 35 | + | |
| 36 | + @GetMapping("/my-page") | |
| 37 | + @Operation(summary = "获得【我的】聊天角色分页") | |
| 38 | + public CommonResult<PageResult<AiChatRoleRespVO>> getChatRoleMyPage(@Valid AiChatRolePageReqVO pageReqVO) { | |
| 39 | + PageResult<AiChatRoleDO> pageResult = chatRoleService.getChatRoleMyPage(pageReqVO, getLoginUserId()); | |
| 40 | + return success(BeanUtils.toBean(pageResult, AiChatRoleRespVO.class)); | |
| 41 | + } | |
| 42 | + | |
| 43 | + @GetMapping("/get-my") | |
| 44 | + @Operation(summary = "获得【我的】聊天角色") | |
| 45 | + @Parameter(name = "id", description = "编号", required = true, example = "1024") | |
| 46 | + public CommonResult<AiChatRoleRespVO> getChatRoleMy(@RequestParam("id") Long id) { | |
| 47 | + AiChatRoleDO chatRole = chatRoleService.getChatRole(id); | |
| 48 | + if (ObjUtil.notEqual(chatRole.getUserId(), getLoginUserId())) { | |
| 49 | + return success(null); | |
| 50 | + } | |
| 51 | + return success(BeanUtils.toBean(chatRole, AiChatRoleRespVO.class)); | |
| 52 | + } | |
| 53 | + | |
| 54 | + @PostMapping("/create-my") | |
| 55 | + @Operation(summary = "创建【我的】聊天角色") | |
| 56 | + public CommonResult<Long> createChatRoleMy(@Valid @RequestBody AiChatRoleSaveMyReqVO createReqVO) { | |
| 57 | + return success(chatRoleService.createChatRoleMy(createReqVO, getLoginUserId())); | |
| 58 | + } | |
| 59 | + | |
| 60 | + @PutMapping("/update-my") | |
| 61 | + @Operation(summary = "更新【我的】聊天角色") | |
| 62 | + public CommonResult<Boolean> updateChatRoleMy(@Valid @RequestBody AiChatRoleSaveMyReqVO updateReqVO) { | |
| 63 | + chatRoleService.updateChatRoleMy(updateReqVO, getLoginUserId()); | |
| 64 | + return success(true); | |
| 65 | + } | |
| 66 | + | |
| 67 | + @DeleteMapping("/delete-my") | |
| 68 | + @Operation(summary = "删除【我的】聊天角色") | |
| 69 | + @Parameter(name = "id", description = "编号", required = true) | |
| 70 | + public CommonResult<Boolean> deleteChatRoleMy(@RequestParam("id") Long id) { | |
| 71 | + chatRoleService.deleteChatRoleMy(id, getLoginUserId()); | |
| 72 | + return success(true); | |
| 73 | + } | |
| 74 | + | |
| 75 | + @GetMapping("/category-list") | |
| 76 | + @Operation(summary = "获得聊天角色的分类列表") | |
| 77 | + public CommonResult<List<String>> getChatRoleCategoryList() { | |
| 78 | + return success(chatRoleService.getChatRoleCategoryList()); | |
| 79 | + } | |
| 80 | + | |
| 81 | + // ========== 角色管理 ========== | |
| 82 | + | |
| 83 | + @PostMapping("/create") | |
| 84 | + @Operation(summary = "创建聊天角色") | |
| 85 | + @PreAuthorize("@ss.hasPermission('ai:chat-role:create')") | |
| 86 | + public CommonResult<Long> createChatRole(@Valid @RequestBody AiChatRoleSaveReqVO createReqVO) { | |
| 87 | + return success(chatRoleService.createChatRole(createReqVO)); | |
| 88 | + } | |
| 89 | + | |
| 90 | + @PutMapping("/update") | |
| 91 | + @Operation(summary = "更新聊天角色") | |
| 92 | + @PreAuthorize("@ss.hasPermission('ai:chat-role:update')") | |
| 93 | + public CommonResult<Boolean> updateChatRole(@Valid @RequestBody AiChatRoleSaveReqVO updateReqVO) { | |
| 94 | + chatRoleService.updateChatRole(updateReqVO); | |
| 95 | + return success(true); | |
| 96 | + } | |
| 97 | + | |
| 98 | + @DeleteMapping("/delete") | |
| 99 | + @Operation(summary = "删除聊天角色") | |
| 100 | + @Parameter(name = "id", description = "编号", required = true) | |
| 101 | + @PreAuthorize("@ss.hasPermission('ai:chat-role:delete')") | |
| 102 | + public CommonResult<Boolean> deleteChatRole(@RequestParam("id") Long id) { | |
| 103 | + chatRoleService.deleteChatRole(id); | |
| 104 | + return success(true); | |
| 105 | + } | |
| 106 | + | |
| 107 | + @GetMapping("/get") | |
| 108 | + @Operation(summary = "获得聊天角色") | |
| 109 | + @Parameter(name = "id", description = "编号", required = true, example = "1024") | |
| 110 | + @PreAuthorize("@ss.hasPermission('ai:chat-role:query')") | |
| 111 | + public CommonResult<AiChatRoleRespVO> getChatRole(@RequestParam("id") Long id) { | |
| 112 | + AiChatRoleDO chatRole = chatRoleService.getChatRole(id); | |
| 113 | + return success(BeanUtils.toBean(chatRole, AiChatRoleRespVO.class)); | |
| 114 | + } | |
| 115 | + | |
| 116 | + @GetMapping("/page") | |
| 117 | + @Operation(summary = "获得聊天角色分页") | |
| 118 | + @PreAuthorize("@ss.hasPermission('ai:chat-role:query')") | |
| 119 | + public CommonResult<PageResult<AiChatRoleRespVO>> getChatRolePage(@Valid AiChatRolePageReqVO pageReqVO) { | |
| 120 | + PageResult<AiChatRoleDO> pageResult = chatRoleService.getChatRolePage(pageReqVO); | |
| 121 | + return success(BeanUtils.toBean(pageResult, AiChatRoleRespVO.class)); | |
| 122 | + } | |
| 123 | + | |
| 124 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/apikey/AiApiKeyPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey; | |
| 2 | + | |
| 3 | +import lombok.*; | |
| 4 | +import java.util.*; | |
| 5 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 6 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 7 | +import org.springframework.format.annotation.DateTimeFormat; | |
| 8 | +import java.time.LocalDateTime; | |
| 9 | + | |
| 10 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | |
| 11 | + | |
| 12 | +@Schema(description = "管理后台 - AI API 密钥分页 Request VO") | |
| 13 | +@Data | |
| 14 | +public class AiApiKeyPageReqVO extends PageParam { | |
| 15 | + | |
| 16 | + @Schema(description = "名称", example = "文心一言") | |
| 17 | + private String name; | |
| 18 | + | |
| 19 | + @Schema(description = "平台", example = "OpenAI") | |
| 20 | + private String platform; | |
| 21 | + | |
| 22 | + @Schema(description = "状态", example = "1") | |
| 23 | + private Integer status; | |
| 24 | + | |
| 25 | +} | |
| 0 | 26 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/apikey/AiApiKeyRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.*; | |
| 5 | + | |
| 6 | +@Schema(description = "管理后台 - AI API 密钥 Response VO") | |
| 7 | +@Data | |
| 8 | +public class AiApiKeyRespVO { | |
| 9 | + | |
| 10 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23538") | |
| 11 | + private Long id; | |
| 12 | + | |
| 13 | + @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "文心一言") | |
| 14 | + private String name; | |
| 15 | + | |
| 16 | + @Schema(description = "密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "ABC") | |
| 17 | + private String apiKey; | |
| 18 | + | |
| 19 | + @Schema(description = "平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "OpenAI") | |
| 20 | + private String platform; | |
| 21 | + | |
| 22 | + @Schema(description = "自定义 API 地址", example = "https://aip.baidubce.com") | |
| 23 | + private String url; | |
| 24 | + | |
| 25 | + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 26 | + private Integer status; | |
| 27 | + | |
| 28 | +} | |
| 0 | 29 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/apikey/AiApiKeySaveReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.*; | |
| 5 | +import java.util.*; | |
| 6 | +import jakarta.validation.constraints.*; | |
| 7 | + | |
| 8 | +@Schema(description = "管理后台 - AI API 密钥新增/修改 Request VO") | |
| 9 | +@Data | |
| 10 | +public class AiApiKeySaveReqVO { | |
| 11 | + | |
| 12 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23538") | |
| 13 | + private Long id; | |
| 14 | + | |
| 15 | + @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "文心一言") | |
| 16 | + @NotEmpty(message = "名称不能为空") | |
| 17 | + private String name; | |
| 18 | + | |
| 19 | + @Schema(description = "密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "ABC") | |
| 20 | + @NotEmpty(message = "密钥不能为空") | |
| 21 | + private String apiKey; | |
| 22 | + | |
| 23 | + @Schema(description = "平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "OpenAI") | |
| 24 | + @NotEmpty(message = "平台不能为空") | |
| 25 | + private String platform; | |
| 26 | + | |
| 27 | + @Schema(description = "自定义 API 地址", example = "https://aip.baidubce.com") | |
| 28 | + private String url; | |
| 29 | + | |
| 30 | + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 31 | + @NotNull(message = "状态不能为空") | |
| 32 | + private Integer status; | |
| 33 | + | |
| 34 | +} | |
| 0 | 35 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatModel/AiChatModelPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatModel; | |
| 2 | + | |
| 3 | +import lombok.*; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 6 | + | |
| 7 | +@Schema(description = "管理后台 - API 聊天模型分页 Request VO") | |
| 8 | +@Data | |
| 9 | +public class AiChatModelPageReqVO extends PageParam { | |
| 10 | + | |
| 11 | + @Schema(description = "模型名字", example = "张三") | |
| 12 | + private String name; | |
| 13 | + | |
| 14 | + @Schema(description = "模型标识", example = "gpt-3.5-turbo-0125") | |
| 15 | + private String model; | |
| 16 | + | |
| 17 | + @Schema(description = "模型平台", example = "OpenAI") | |
| 18 | + private String platform; | |
| 19 | + | |
| 20 | +} | |
| 0 | 21 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatModel/AiChatModelRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatModel; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +import java.time.LocalDateTime; | |
| 7 | + | |
| 8 | +@Schema(description = "管理后台 - AI 聊天模型 Response VO") | |
| 9 | +@Data | |
| 10 | +public class AiChatModelRespVO { | |
| 11 | + | |
| 12 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2630") | |
| 13 | + private Long id; | |
| 14 | + | |
| 15 | + @Schema(description = "API 秘钥编号", example = "22042") | |
| 16 | + private Long keyId; | |
| 17 | + | |
| 18 | + @Schema(description = "模型名字", example = "张三") | |
| 19 | + private String name; | |
| 20 | + | |
| 21 | + @Schema(description = "模型标识", example = "gpt-3.5-turbo-0125") | |
| 22 | + private String model; | |
| 23 | + | |
| 24 | + @Schema(description = "模型平台", example = "OpenAI") | |
| 25 | + private String platform; | |
| 26 | + | |
| 27 | + @Schema(description = "排序", example = "1") | |
| 28 | + private Integer sort; | |
| 29 | + | |
| 30 | + @Schema(description = "状态", example = "2") | |
| 31 | + private Integer status; | |
| 32 | + | |
| 33 | + @Schema(description = "温度参数", example = "1") | |
| 34 | + private Double temperature; | |
| 35 | + | |
| 36 | + @Schema(description = "单条回复的最大 Token 数量", example = "4096") | |
| 37 | + private Integer maxTokens; | |
| 38 | + | |
| 39 | + @Schema(description = "上下文的最大 Message 数量", example = "8192") | |
| 40 | + private Integer maxContexts; | |
| 41 | + | |
| 42 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 43 | + private LocalDateTime createTime; | |
| 44 | + | |
| 45 | +} | |
| 0 | 46 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatModel/AiChatModelSaveReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatModel; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 4 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | |
| 5 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 6 | +import lombok.*; | |
| 7 | +import jakarta.validation.constraints.*; | |
| 8 | + | |
| 9 | +@Schema(description = "管理后台 - API 聊天模型新增/修改 Request VO") | |
| 10 | +@Data | |
| 11 | +public class AiChatModelSaveReqVO { | |
| 12 | + | |
| 13 | + @Schema(description = "编号", example = "2630") | |
| 14 | + private Long id; | |
| 15 | + | |
| 16 | + @Schema(description = "API 秘钥编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22042") | |
| 17 | + @NotNull(message = "API 秘钥编号不能为空") | |
| 18 | + private Long keyId; | |
| 19 | + | |
| 20 | + @Schema(description = "模型名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") | |
| 21 | + @NotEmpty(message = "模型名字不能为空") | |
| 22 | + private String name; | |
| 23 | + | |
| 24 | + @Schema(description = "模型标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "gpt-3.5-turbo-0125") | |
| 25 | + @NotEmpty(message = "模型标识不能为空") | |
| 26 | + private String model; | |
| 27 | + | |
| 28 | + @Schema(description = "模型平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "OpenAI") | |
| 29 | + @NotEmpty(message = "模型平台不能为空") | |
| 30 | + private String platform; | |
| 31 | + | |
| 32 | + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 33 | + @NotNull(message = "排序不能为空") | |
| 34 | + private Integer sort; | |
| 35 | + | |
| 36 | + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 37 | + @InEnum(CommonStatusEnum.class) | |
| 38 | + @NotNull(message = "状态不能为空") | |
| 39 | + private Integer status; | |
| 40 | + | |
| 41 | + @Schema(description = "温度参数", example = "1") | |
| 42 | + private Double temperature; | |
| 43 | + | |
| 44 | + @Schema(description = "单条回复的最大 Token 数量", example = "4096") | |
| 45 | + private Integer maxTokens; | |
| 46 | + | |
| 47 | + @Schema(description = "上下文的最大 Message 数量", example = "8192") | |
| 48 | + private Integer maxContexts; | |
| 49 | + | |
| 50 | +} | |
| 0 | 51 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatRole/AiChatRolePageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole; | |
| 2 | + | |
| 3 | +import lombok.*; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 6 | + | |
| 7 | +@Schema(description = "管理后台 - AI 聊天角色分页 Request VO") | |
| 8 | +@Data | |
| 9 | +public class AiChatRolePageReqVO extends PageParam { | |
| 10 | + | |
| 11 | + @Schema(description = "角色名称", example = "李四") | |
| 12 | + private String name; | |
| 13 | + | |
| 14 | + @Schema(description = "角色类别", example = "创作") | |
| 15 | + private String category; | |
| 16 | + | |
| 17 | + @Schema(description = "是否公开", example = "1") | |
| 18 | + private Boolean publicStatus; | |
| 19 | + | |
| 20 | +} | |
| 0 | 21 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatRole/AiChatRoleRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | |
| 4 | +import com.fhs.core.trans.anno.Trans; | |
| 5 | +import com.fhs.core.trans.constant.TransType; | |
| 6 | +import com.fhs.core.trans.vo.VO; | |
| 7 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 8 | +import lombok.Data; | |
| 9 | + | |
| 10 | +import java.time.LocalDateTime; | |
| 11 | + | |
| 12 | +@Schema(description = "管理后台 - AI 聊天角色 Response VO") | |
| 13 | +@Data | |
| 14 | +public class AiChatRoleRespVO implements VO { | |
| 15 | + | |
| 16 | + @Schema(description = "角色编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32746") | |
| 17 | + private Long id; | |
| 18 | + | |
| 19 | + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "9442") | |
| 20 | + private Long userId; | |
| 21 | + | |
| 22 | + @Schema(description = "模型编号", example = "17640") | |
| 23 | + @Trans(type = TransType.SIMPLE, target = AiChatModelDO.class, fields = {"name", "model"}, refs = {"modelName", "model"}) | |
| 24 | + private Long modelId; | |
| 25 | + @Schema(description = "模型名字", example = "张三") | |
| 26 | + private String modelName; | |
| 27 | + @Schema(description = "模型标识", example = "gpt-3.5-turbo-0125") | |
| 28 | + private String model; | |
| 29 | + | |
| 30 | + @Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") | |
| 31 | + private String name; | |
| 32 | + | |
| 33 | + @Schema(description = "角色头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") | |
| 34 | + private String avatar; | |
| 35 | + | |
| 36 | + @Schema(description = "角色类别", requiredMode = Schema.RequiredMode.REQUIRED, example = "创作") | |
| 37 | + private String category; | |
| 38 | + | |
| 39 | + @Schema(description = "角色排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 40 | + private Integer sort; | |
| 41 | + | |
| 42 | + @Schema(description = "角色描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对") | |
| 43 | + private String description; | |
| 44 | + | |
| 45 | + @Schema(description = "角色设定", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 46 | + private String systemMessage; | |
| 47 | + | |
| 48 | + @Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 49 | + private Boolean publicStatus; | |
| 50 | + | |
| 51 | + @Schema(description = "状态", example = "1") | |
| 52 | + private Integer status; | |
| 53 | + | |
| 54 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 55 | + private LocalDateTime createTime; | |
| 56 | + | |
| 57 | +} | |
| 0 | 58 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatRole/AiChatRoleSaveMyReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import jakarta.validation.constraints.NotEmpty; | |
| 5 | +import lombok.Data; | |
| 6 | +import org.hibernate.validator.constraints.URL; | |
| 7 | + | |
| 8 | +@Schema(description = "管理后台 - AI 聊天角色新增/修改【我的】 Request VO") | |
| 9 | +@Data | |
| 10 | +public class AiChatRoleSaveMyReqVO { | |
| 11 | + | |
| 12 | + @Schema(description = "角色编号", example = "32746") | |
| 13 | + private Long id; | |
| 14 | + | |
| 15 | + @Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") | |
| 16 | + @NotEmpty(message = "角色名称不能为空") | |
| 17 | + private String name; | |
| 18 | + | |
| 19 | + @Schema(description = "角色头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") | |
| 20 | + @NotEmpty(message = "角色头像不能为空") | |
| 21 | + @URL(message = "角色头像必须是 URL 格式") | |
| 22 | + private String avatar; | |
| 23 | + | |
| 24 | + @Schema(description = "角色描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对") | |
| 25 | + @NotEmpty(message = "角色描述不能为空") | |
| 26 | + private String description; | |
| 27 | + | |
| 28 | + @Schema(description = "角色设定", requiredMode = Schema.RequiredMode.REQUIRED, example = "现在开始你扮演一位程序员,你是一名优秀的程序员,具有很强的逻辑思维能力,总能高效的解决问题") | |
| 29 | + @NotEmpty(message = "角色设定不能为空") | |
| 30 | + private String systemMessage; | |
| 31 | + | |
| 32 | +} | |
| 0 | 33 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatRole/AiChatRoleSaveReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 4 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | |
| 5 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 6 | +import lombok.*; | |
| 7 | +import jakarta.validation.constraints.*; | |
| 8 | +import org.hibernate.validator.constraints.URL; | |
| 9 | + | |
| 10 | +@Schema(description = "管理后台 - AI 聊天角色新增/修改 Request VO") | |
| 11 | +@Data | |
| 12 | +public class AiChatRoleSaveReqVO { | |
| 13 | + | |
| 14 | + @Schema(description = "角色编号", example = "32746") | |
| 15 | + private Long id; | |
| 16 | + | |
| 17 | + @Schema(description = "模型编号", example = "17640") | |
| 18 | + private Long modelId; | |
| 19 | + | |
| 20 | + @Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") | |
| 21 | + @NotEmpty(message = "角色名称不能为空") | |
| 22 | + private String name; | |
| 23 | + | |
| 24 | + @Schema(description = "角色头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") | |
| 25 | + @NotEmpty(message = "角色头像不能为空") | |
| 26 | + @URL(message = "角色头像必须是 URL 格式") | |
| 27 | + private String avatar; | |
| 28 | + | |
| 29 | + @Schema(description = "角色类别", requiredMode = Schema.RequiredMode.REQUIRED, example = "创作") | |
| 30 | + @NotEmpty(message = "角色类别不能为空") | |
| 31 | + private String category; | |
| 32 | + | |
| 33 | + @Schema(description = "角色排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 34 | + @NotNull(message = "角色排序不能为空") | |
| 35 | + private Integer sort; | |
| 36 | + | |
| 37 | + @Schema(description = "角色描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对") | |
| 38 | + @NotEmpty(message = "角色描述不能为空") | |
| 39 | + private String description; | |
| 40 | + | |
| 41 | + @Schema(description = "角色设定", requiredMode = Schema.RequiredMode.REQUIRED, example = "现在开始你扮演一位程序员,你是一名优秀的程序员,具有很强的逻辑思维能力,总能高效的解决问题") | |
| 42 | + @NotEmpty(message = "角色设定不能为空") | |
| 43 | + private String systemMessage; | |
| 44 | + | |
| 45 | + @Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 46 | + @NotNull(message = "是否公开不能为空") | |
| 47 | + private Boolean publicStatus; | |
| 48 | + | |
| 49 | + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 50 | + @NotNull(message = "状态不能为空") | |
| 51 | + @InEnum(CommonStatusEnum.class) | |
| 52 | + private Integer status; | |
| 53 | + | |
| 54 | +} | |
| 0 | 55 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/AiMusicController.http
0 → 100644
| 1 | +### 生成音乐:Suno + 歌词模式 | |
| 2 | +POST {{baseUrl}}/ai/music/generate | |
| 3 | +Content-Type: application/json | |
| 4 | +Authorization: {{token}} | |
| 5 | + | |
| 6 | +{ | |
| 7 | + "platform": "Suno", | |
| 8 | + "generateMode": 2, | |
| 9 | + "prompt": "创作一首带有轻松吉他旋律的流行歌曲,[verse] 描述夏日海滩的宁静,[chorus] 节奏加快,表达对自由的向往。", | |
| 10 | + "model": "chirp-v3.5", | |
| 11 | + "tags": ["Happy"], | |
| 12 | + "title": "Happy Song" | |
| 13 | +} | |
| 14 | + | |
| 15 | +### 生成音乐:Suno + 描述模式 | |
| 16 | +POST {{baseUrl}}/ai/music/generate | |
| 17 | +Content-Type: application/json | |
| 18 | +Authorization: {{token}} | |
| 19 | + | |
| 20 | +{ | |
| 21 | + "platform": "Suno", | |
| 22 | + "generateMode": 1, | |
| 23 | + "model": "chirp-v3.5", | |
| 24 | + "prompt": "happy music", | |
| 25 | + "makeInstrumental": false | |
| 26 | +} | |
| 0 | 27 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/AiMusicController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.music; | |
| 2 | + | |
| 3 | +import cn.hutool.core.util.ObjUtil; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 5 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 6 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 7 | +import cn.iocoder.yudao.module.ai.controller.admin.music.vo.*; | |
| 8 | +import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO; | |
| 9 | +import cn.iocoder.yudao.module.ai.service.music.AiMusicService; | |
| 10 | +import io.swagger.v3.oas.annotations.Operation; | |
| 11 | +import io.swagger.v3.oas.annotations.Parameter; | |
| 12 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 13 | +import jakarta.annotation.Resource; | |
| 14 | +import jakarta.validation.Valid; | |
| 15 | +import org.springframework.security.access.prepost.PreAuthorize; | |
| 16 | +import org.springframework.web.bind.annotation.*; | |
| 17 | + | |
| 18 | +import java.util.List; | |
| 19 | + | |
| 20 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 21 | +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | |
| 22 | + | |
| 23 | +@Tag(name = "管理后台 - AI 音乐") | |
| 24 | +@RestController | |
| 25 | +@RequestMapping("/ai/music") | |
| 26 | +public class AiMusicController { | |
| 27 | + | |
| 28 | + @Resource | |
| 29 | + private AiMusicService musicService; | |
| 30 | + | |
| 31 | + @GetMapping("/my-page") | |
| 32 | + @Operation(summary = "获得【我的】音乐分页") | |
| 33 | + public CommonResult<PageResult<AiMusicRespVO>> getMusicMyPage(@Valid AiMusicPageReqVO pageReqVO) { | |
| 34 | + PageResult<AiMusicDO> pageResult = musicService.getMusicMyPage(pageReqVO, getLoginUserId()); | |
| 35 | + return success(BeanUtils.toBean(pageResult, AiMusicRespVO.class)); | |
| 36 | + } | |
| 37 | + | |
| 38 | + @PostMapping("/generate") | |
| 39 | + @Operation(summary = "音乐生成") | |
| 40 | + public CommonResult<List<Long>> generateMusic(@RequestBody @Valid AiSunoGenerateReqVO reqVO) { | |
| 41 | + return success(musicService.generateMusic(getLoginUserId(), reqVO)); | |
| 42 | + } | |
| 43 | + | |
| 44 | + @Operation(summary = "删除【我的】音乐记录") | |
| 45 | + @DeleteMapping("/delete-my") | |
| 46 | + @Parameter(name = "id", required = true, description = "音乐编号", example = "1024") | |
| 47 | + public CommonResult<Boolean> deleteMusicMy(@RequestParam("id") Long id) { | |
| 48 | + musicService.deleteMusicMy(id, getLoginUserId()); | |
| 49 | + return success(true); | |
| 50 | + } | |
| 51 | + | |
| 52 | + @GetMapping("/get-my") | |
| 53 | + @Operation(summary = "获取【我的】音乐") | |
| 54 | + @Parameter(name = "id", required = true, description = "音乐编号", example = "1024") | |
| 55 | + public CommonResult<AiMusicRespVO> getMusicMy(@RequestParam("id") Long id) { | |
| 56 | + AiMusicDO music = musicService.getMusic(id); | |
| 57 | + if (music == null || ObjUtil.notEqual(getLoginUserId(), music.getUserId())) { | |
| 58 | + return success(null); | |
| 59 | + } | |
| 60 | + return success(BeanUtils.toBean(music, AiMusicRespVO.class)); | |
| 61 | + } | |
| 62 | + | |
| 63 | + @PostMapping("/update-my") | |
| 64 | + @Operation(summary = "修改【我的】音乐 目前只支持修改标题") | |
| 65 | + @Parameter(name = "title", required = true, description = "音乐名称", example = "夜空中最亮的星") | |
| 66 | + public CommonResult<Boolean> updateMy(AiMusicUpdateMyReqVO updateReqVO) { | |
| 67 | + musicService.updateMyMusic(updateReqVO, getLoginUserId()); | |
| 68 | + return success(true); | |
| 69 | + } | |
| 70 | + | |
| 71 | + // ================ 音乐管理 ================ | |
| 72 | + | |
| 73 | + @GetMapping("/page") | |
| 74 | + @Operation(summary = "获得音乐分页") | |
| 75 | + @PreAuthorize("@ss.hasPermission('ai:music:query')") | |
| 76 | + public CommonResult<PageResult<AiMusicRespVO>> getMusicPage(@Valid AiMusicPageReqVO pageReqVO) { | |
| 77 | + PageResult<AiMusicDO> pageResult = musicService.getMusicPage(pageReqVO); | |
| 78 | + return success(BeanUtils.toBean(pageResult, AiMusicRespVO.class)); | |
| 79 | + } | |
| 80 | + | |
| 81 | + @DeleteMapping("/delete") | |
| 82 | + @Operation(summary = "删除音乐") | |
| 83 | + @Parameter(name = "id", description = "编号", required = true) | |
| 84 | + @PreAuthorize("@ss.hasPermission('ai:music:delete')") | |
| 85 | + public CommonResult<Boolean> deleteMusic(@RequestParam("id") Long id) { | |
| 86 | + musicService.deleteMusic(id); | |
| 87 | + return success(true); | |
| 88 | + } | |
| 89 | + | |
| 90 | + @PutMapping("/update") | |
| 91 | + @Operation(summary = "更新音乐") | |
| 92 | + @PreAuthorize("@ss.hasPermission('ai:music:update')") | |
| 93 | + public CommonResult<Boolean> updateMusic(@Valid @RequestBody AiMusicUpdateReqVO updateReqVO) { | |
| 94 | + musicService.updateMusic(updateReqVO); | |
| 95 | + return success(true); | |
| 96 | + } | |
| 97 | + | |
| 98 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiMusicPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.music.vo; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 4 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | |
| 5 | +import cn.iocoder.yudao.module.ai.enums.music.AiMusicGenerateModeEnum; | |
| 6 | +import cn.iocoder.yudao.module.ai.enums.music.AiMusicStatusEnum; | |
| 7 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 8 | +import lombok.Data; | |
| 9 | +import lombok.EqualsAndHashCode; | |
| 10 | +import lombok.ToString; | |
| 11 | +import org.springframework.format.annotation.DateTimeFormat; | |
| 12 | + | |
| 13 | +import java.time.LocalDateTime; | |
| 14 | + | |
| 15 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | |
| 16 | + | |
| 17 | +@Schema(description = "管理后台 - AI 音乐分页 Request VO") | |
| 18 | +@Data | |
| 19 | +public class AiMusicPageReqVO extends PageParam { | |
| 20 | + | |
| 21 | + @Schema(description = "用户编号", example = "12212") | |
| 22 | + private Long userId; | |
| 23 | + | |
| 24 | + @Schema(description = "音乐名称", example = "夜空中最亮的星") | |
| 25 | + private String title; | |
| 26 | + | |
| 27 | + @Schema(description = "音乐状态", example = "20") | |
| 28 | + @InEnum(AiMusicStatusEnum.class) | |
| 29 | + private Integer status; | |
| 30 | + | |
| 31 | + @Schema(description = "生成模式", example = "1") | |
| 32 | + @InEnum(AiMusicGenerateModeEnum.class) | |
| 33 | + private Integer generateMode; | |
| 34 | + | |
| 35 | + @Schema(description = "是否发布", example = "true") | |
| 36 | + private Boolean publicStatus; | |
| 37 | + | |
| 38 | + @Schema(description = "创建时间") | |
| 39 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 40 | + private LocalDateTime[] createTime; | |
| 41 | + | |
| 42 | +} | |
| 0 | 43 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiMusicRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.music.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +import java.time.LocalDateTime; | |
| 7 | +import java.util.List; | |
| 8 | + | |
| 9 | +@Schema(description = "管理后台 - AI 音乐 Response VO") | |
| 10 | +@Data | |
| 11 | +public class AiMusicRespVO { | |
| 12 | + | |
| 13 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790") | |
| 14 | + private Long id; | |
| 15 | + | |
| 16 | + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12212") | |
| 17 | + private Long userId; | |
| 18 | + | |
| 19 | + @Schema(description = "音乐名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "夜空中最亮的星") | |
| 20 | + private String title; | |
| 21 | + | |
| 22 | + @Schema(description = "歌词", example = "oh~卖糕的") | |
| 23 | + private String lyric; | |
| 24 | + | |
| 25 | + @Schema(description = "图片地址", example = "https://www.iocoder.cn") | |
| 26 | + private String imageUrl; | |
| 27 | + | |
| 28 | + @Schema(description = "音频地址", example = "https://www.iocoder.cn") | |
| 29 | + private String audioUrl; | |
| 30 | + | |
| 31 | + @Schema(description = "视频地址", example = "https://www.iocoder.cn") | |
| 32 | + private String videoUrl; | |
| 33 | + | |
| 34 | + @Schema(description = "音乐状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") | |
| 35 | + private Integer status; | |
| 36 | + | |
| 37 | + @Schema(description = "描述词", example = "一首轻快的歌曲") | |
| 38 | + private String gptDescriptionPrompt; | |
| 39 | + | |
| 40 | + @Schema(description = "提示词", example = "创作一首带有轻松吉他旋律的流行歌曲,[verse] 描述夏日海滩的宁静,[chorus] 节奏加快,表达对自由的向往。") | |
| 41 | + private String prompt; | |
| 42 | + | |
| 43 | + @Schema(description = "模型平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "Suno") | |
| 44 | + private String platform; | |
| 45 | + | |
| 46 | + @Schema(description = "模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "chirp-v3.5") | |
| 47 | + private String model; | |
| 48 | + | |
| 49 | + @Schema(description = "生成模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 50 | + private Integer generateMode; | |
| 51 | + | |
| 52 | + @Schema(description = "音乐风格标签") | |
| 53 | + private List<String> tags; | |
| 54 | + | |
| 55 | + @Schema(description = "音乐时长", example = "[\"pop\",\"jazz\",\"punk\"]") | |
| 56 | + private Double duration; | |
| 57 | + | |
| 58 | + @Schema(description = "是否发布", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") | |
| 59 | + private Boolean publicStatus; | |
| 60 | + | |
| 61 | + @Schema(description = "任务编号", example = "11369") | |
| 62 | + private String taskId; | |
| 63 | + | |
| 64 | + @Schema(description = "错误信息") | |
| 65 | + private String errorMessage; | |
| 66 | + | |
| 67 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 68 | + private LocalDateTime createTime; | |
| 69 | + | |
| 70 | +} | |
| 0 | 71 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiMusicUpdateMyReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.music.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import jakarta.validation.constraints.NotNull; | |
| 5 | +import lombok.Data; | |
| 6 | + | |
| 7 | +@Schema(description = "管理后台 - AI 修改我的音乐 Request VO") | |
| 8 | +@Data | |
| 9 | +public class AiMusicUpdateMyReqVO { | |
| 10 | + | |
| 11 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15583") | |
| 12 | + @NotNull(message = "编号不能为空") | |
| 13 | + private Long id; | |
| 14 | + | |
| 15 | + @Schema(description = "音乐名称", example = "夜空中最亮的星") | |
| 16 | + private String title; | |
| 17 | + | |
| 18 | +} | |
| 0 | 19 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiMusicUpdateReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.music.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import jakarta.validation.constraints.NotNull; | |
| 5 | +import lombok.Data; | |
| 6 | + | |
| 7 | +@Schema(description = "管理后台 - AI 音乐修改 Request VO") | |
| 8 | +@Data | |
| 9 | +public class AiMusicUpdateReqVO { | |
| 10 | + | |
| 11 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15583") | |
| 12 | + @NotNull(message = "编号不能为空") | |
| 13 | + private Long id; | |
| 14 | + | |
| 15 | + @Schema(description = "是否发布", example = "true") | |
| 16 | + private Boolean publicStatus; | |
| 17 | + | |
| 18 | +} | |
| 0 | 19 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiSunoGenerateReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.music.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import jakarta.validation.constraints.NotBlank; | |
| 5 | +import jakarta.validation.constraints.NotEmpty; | |
| 6 | +import jakarta.validation.constraints.NotNull; | |
| 7 | +import lombok.Data; | |
| 8 | + | |
| 9 | +import java.util.List; | |
| 10 | + | |
| 11 | +@Schema(description = "管理后台 - AI 音乐生成 Request VO") | |
| 12 | +@Data | |
| 13 | +public class AiSunoGenerateReqVO { | |
| 14 | + | |
| 15 | + @Schema(description = "平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "Suno") | |
| 16 | + @NotBlank(message = "平台不能为空") | |
| 17 | + private String platform; // 参见 AiPlatformEnum 枚举 | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 1. 描述模式:描述词 + 是否纯音乐 + 模型 | |
| 21 | + * 2. 歌词模式:歌词 + 音乐风格 + 标题 + 模型 | |
| 22 | + */ | |
| 23 | + @Schema(description = "生成模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | |
| 24 | + @NotNull(message = "生成模式不能为空") | |
| 25 | + private Integer generateMode; // 参见 AiMusicGenerateModeEnum 枚举 | |
| 26 | + | |
| 27 | + @Schema(description = "用于生成音乐音频的歌词提示", | |
| 28 | + example = """ | |
| 29 | + 1.描述模式:创作一首带有轻松吉他旋律的流行歌曲,[verse] 描述夏日海滩的宁静,[chorus] 节奏加快,表达对自由的向往。 | |
| 30 | + 2.歌词模式: | |
| 31 | + [Verse] | |
| 32 | + 阳光下奔跑 多么欢快 | |
| 33 | + 假期就要来 心都飞起来 | |
| 34 | + 朋友在一旁 笑声又灿烂 | |
| 35 | + 无忧无虑的 每一天甜蜜 | |
| 36 | + [Chorus] | |
| 37 | + 马上放假了 快来庆祝 | |
| 38 | + 一起去旅行 快去冒险 | |
| 39 | + 日子太短暂 别再等待 | |
| 40 | + 马上放假了 梦想起飞 | |
| 41 | + """) | |
| 42 | + private String prompt; | |
| 43 | + | |
| 44 | + @Schema(description = "是否纯音乐", example = "true") | |
| 45 | + private Boolean makeInstrumental; | |
| 46 | + | |
| 47 | + @Schema(description = "模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "chirp-v3.5") | |
| 48 | + @NotEmpty(message = "模型不能为空") | |
| 49 | + private String model; | |
| 50 | + | |
| 51 | + @Schema(description = "音乐风格", example = "[\"pop\",\"jazz\",\"punk\"]") | |
| 52 | + private List<String> tags; | |
| 53 | + | |
| 54 | + @Schema(description = "音乐/歌曲名称", example = "夜空中最亮的星") | |
| 55 | + private String title; | |
| 56 | + | |
| 57 | +} | |
| 0 | 58 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/write/AiWriteController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.write; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 5 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 6 | +import cn.iocoder.yudao.module.ai.controller.admin.write.vo.AiWriteGenerateReqVO; | |
| 7 | +import cn.iocoder.yudao.module.ai.controller.admin.write.vo.AiWritePageReqVO; | |
| 8 | +import cn.iocoder.yudao.module.ai.controller.admin.write.vo.AiWriteRespVO; | |
| 9 | +import cn.iocoder.yudao.module.ai.dal.dataobject.write.AiWriteDO; | |
| 10 | +import cn.iocoder.yudao.module.ai.service.write.AiWriteService; | |
| 11 | +import io.swagger.v3.oas.annotations.Operation; | |
| 12 | +import io.swagger.v3.oas.annotations.Parameter; | |
| 13 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 14 | +import jakarta.annotation.Resource; | |
| 15 | +import jakarta.annotation.security.PermitAll; | |
| 16 | +import jakarta.validation.Valid; | |
| 17 | +import org.springframework.http.MediaType; | |
| 18 | +import org.springframework.security.access.prepost.PreAuthorize; | |
| 19 | +import org.springframework.web.bind.annotation.*; | |
| 20 | +import reactor.core.publisher.Flux; | |
| 21 | + | |
| 22 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 23 | +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | |
| 24 | + | |
| 25 | +@Tag(name = "管理后台 - AI 写作") | |
| 26 | +@RestController | |
| 27 | +@RequestMapping("/ai/write") | |
| 28 | +public class AiWriteController { | |
| 29 | + | |
| 30 | + @Resource | |
| 31 | + private AiWriteService writeService; | |
| 32 | + | |
| 33 | + @PostMapping(value = "/generate-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) | |
| 34 | + @Operation(summary = "写作生成(流式)", description = "流式返回,响应较快") | |
| 35 | + @PermitAll // 解决 SSE 最终响应的时候,会被 Access Denied 拦截的问题 | |
| 36 | + public Flux<CommonResult<String>> generateWriteContent(@RequestBody @Valid AiWriteGenerateReqVO generateReqVO) { | |
| 37 | + return writeService.generateWriteContent(generateReqVO, getLoginUserId()); | |
| 38 | + } | |
| 39 | + | |
| 40 | + // ================ 写作管理 ================ | |
| 41 | + | |
| 42 | + @DeleteMapping("/delete") | |
| 43 | + @Operation(summary = "删除写作") | |
| 44 | + @Parameter(name = "id", description = "编号", required = true) | |
| 45 | + @PreAuthorize("@ss.hasPermission('ai:write:delete')") | |
| 46 | + public CommonResult<Boolean> deleteWrite(@RequestParam("id") Long id) { | |
| 47 | + writeService.deleteWrite(id); | |
| 48 | + return success(true); | |
| 49 | + } | |
| 50 | + | |
| 51 | + @GetMapping("/page") | |
| 52 | + @Operation(summary = "获得写作分页") | |
| 53 | + @PreAuthorize("@ss.hasPermission('ai:write:query')") | |
| 54 | + public CommonResult<PageResult<AiWriteRespVO>> getWritePage(@Valid AiWritePageReqVO pageReqVO) { | |
| 55 | + PageResult<AiWriteDO> pageResult = writeService.getWritePage(pageReqVO); | |
| 56 | + return success(BeanUtils.toBean(pageResult, AiWriteRespVO.class)); | |
| 57 | + } | |
| 58 | + | |
| 59 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/write/vo/AiWriteGenerateReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.write.vo; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | |
| 4 | +import cn.iocoder.yudao.module.ai.enums.write.AiWriteTypeEnum; | |
| 5 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 6 | +import jakarta.validation.constraints.NotNull; | |
| 7 | +import lombok.Data; | |
| 8 | + | |
| 9 | +@Schema(description = "管理后台 - AI 写作生成 Request VO") | |
| 10 | +@Data | |
| 11 | +public class AiWriteGenerateReqVO { | |
| 12 | + | |
| 13 | + @Schema(description = "写作类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 14 | + @InEnum(value = AiWriteTypeEnum.class, message = "写作类型必须是 {value}") | |
| 15 | + private Integer type; | |
| 16 | + | |
| 17 | + @Schema(description = "写作内容提示", example = "1.撰写:田忌赛马;2.回复:不批") | |
| 18 | + private String prompt; | |
| 19 | + | |
| 20 | + @Schema(description = "原文", example = "领导我要辞职") | |
| 21 | + private String originalContent; | |
| 22 | + | |
| 23 | + @Schema(description = "长度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 24 | + @NotNull(message = "长度不能为空") | |
| 25 | + private Integer length; | |
| 26 | + | |
| 27 | + @Schema(description = "格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 28 | + @NotNull(message = "格式不能为空") | |
| 29 | + private Integer format; | |
| 30 | + | |
| 31 | + @Schema(description = "语气", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 32 | + @NotNull(message = "语气不能为空") | |
| 33 | + private Integer tone; | |
| 34 | + | |
| 35 | + @Schema(description = "语言", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 36 | + @NotNull(message = "语言不能为空") | |
| 37 | + private Integer language; | |
| 38 | + | |
| 39 | +} | |
| 0 | 40 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/write/vo/AiWritePageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.write.vo; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import lombok.Data; | |
| 6 | +import lombok.EqualsAndHashCode; | |
| 7 | +import lombok.ToString; | |
| 8 | +import org.springframework.format.annotation.DateTimeFormat; | |
| 9 | + | |
| 10 | +import java.time.LocalDateTime; | |
| 11 | + | |
| 12 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | |
| 13 | + | |
| 14 | +@Schema(description = "管理后台 - AI 写作分页 Request VO") | |
| 15 | +@Data | |
| 16 | +@EqualsAndHashCode(callSuper = true) | |
| 17 | +@ToString(callSuper = true) | |
| 18 | +public class AiWritePageReqVO extends PageParam { | |
| 19 | + | |
| 20 | + @Schema(description = "用户编号", example = "28404") | |
| 21 | + private Long userId; | |
| 22 | + | |
| 23 | + @Schema(description = "写作类型", example = "1") | |
| 24 | + private Integer type; | |
| 25 | + | |
| 26 | + @Schema(description = "平台", example = "TongYi") | |
| 27 | + private String platform; | |
| 28 | + | |
| 29 | + @Schema(description = "创建时间") | |
| 30 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 31 | + private LocalDateTime[] createTime; | |
| 32 | + | |
| 33 | +} | |
| 0 | 34 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/write/vo/AiWriteRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.write.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +import java.time.LocalDateTime; | |
| 7 | + | |
| 8 | +@Schema(description = "管理后台 - AI 写作 Response VO") | |
| 9 | +@Data | |
| 10 | +public class AiWriteRespVO { | |
| 11 | + | |
| 12 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5311") | |
| 13 | + private Long id; | |
| 14 | + | |
| 15 | + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28404") | |
| 16 | + private Long userId; | |
| 17 | + | |
| 18 | + @Schema(description = "写作类型", example = "1") | |
| 19 | + private Integer type; | |
| 20 | + | |
| 21 | + @Schema(description = "平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "TongYi") | |
| 22 | + private String platform; | |
| 23 | + | |
| 24 | + @Schema(description = "模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "qwen") | |
| 25 | + private String model; | |
| 26 | + | |
| 27 | + @Schema(description = "生成内容提示", requiredMode = Schema.RequiredMode.REQUIRED, example = "撰写:田忌赛马") | |
| 28 | + private String prompt; | |
| 29 | + | |
| 30 | + @Schema(description = "生成的内容", example = "你非常不错") | |
| 31 | + private String generatedContent; | |
| 32 | + | |
| 33 | + @Schema(description = "原文", example = "真的么?") | |
| 34 | + private String originalContent; | |
| 35 | + | |
| 36 | + @Schema(description = "长度提示词", example = "1") | |
| 37 | + private Integer length; | |
| 38 | + | |
| 39 | + @Schema(description = "格式提示词", example = "2") | |
| 40 | + private Integer format; | |
| 41 | + | |
| 42 | + @Schema(description = "语气提示词", example = "3") | |
| 43 | + private Integer tone; | |
| 44 | + | |
| 45 | + @Schema(description = "语言提示词", example = "4") | |
| 46 | + private Integer language; | |
| 47 | + | |
| 48 | + @Schema(description = "错误信息") | |
| 49 | + private String errorMessage; | |
| 50 | + | |
| 51 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 52 | + private LocalDateTime createTime; | |
| 53 | + | |
| 54 | +} | |
| 0 | 55 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/app/package-info.java
0 → 100644
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/package-info.java
0 → 100644
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatConversationDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.dataobject.chat; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |
| 4 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | |
| 5 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | |
| 6 | +import com.baomidou.mybatisplus.annotation.KeySequence; | |
| 7 | +import com.baomidou.mybatisplus.annotation.TableId; | |
| 8 | +import com.baomidou.mybatisplus.annotation.TableName; | |
| 9 | +import lombok.*; | |
| 10 | + | |
| 11 | +import java.time.LocalDateTime; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * AI Chat 对话 DO | |
| 15 | + * | |
| 16 | + * 用户每次发起 Chat 聊天时,会创建一个 {@link AiChatConversationDO} 对象,将它的消息关联在一起 | |
| 17 | + * | |
| 18 | + * @author fansili | |
| 19 | + * @since 2024/4/14 17:35 | |
| 20 | + */ | |
| 21 | +@TableName("ai_chat_conversation") | |
| 22 | +@KeySequence("ai_chat_conversation_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | |
| 23 | +@Data | |
| 24 | +@EqualsAndHashCode(callSuper = true) | |
| 25 | +@Builder | |
| 26 | +@NoArgsConstructor | |
| 27 | +@AllArgsConstructor | |
| 28 | +public class AiChatConversationDO extends BaseDO { | |
| 29 | + | |
| 30 | + public static final String TITLE_DEFAULT = "新对话"; | |
| 31 | + | |
| 32 | + /** | |
| 33 | + * ID 编号,自增 | |
| 34 | + */ | |
| 35 | + @TableId | |
| 36 | + private Long id; | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * 用户编号 | |
| 40 | + * | |
| 41 | + * 关联 AdminUserDO 的 userId 字段 | |
| 42 | + */ | |
| 43 | + private Long userId; | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * 对话标题 | |
| 47 | + * | |
| 48 | + * 默认由系统自动生成,可用户手动修改 | |
| 49 | + */ | |
| 50 | + private String title; | |
| 51 | + /** | |
| 52 | + * 是否置顶 | |
| 53 | + */ | |
| 54 | + private Boolean pinned; | |
| 55 | + /** | |
| 56 | + * 置顶时间 | |
| 57 | + */ | |
| 58 | + private LocalDateTime pinnedTime; | |
| 59 | + | |
| 60 | + /** | |
| 61 | + * 角色编号 | |
| 62 | + * | |
| 63 | + * 关联 {@link AiChatRoleDO#getId()} | |
| 64 | + */ | |
| 65 | + private Long roleId; | |
| 66 | + | |
| 67 | + /** | |
| 68 | + * 模型编号 | |
| 69 | + * | |
| 70 | + * 关联 {@link AiChatModelDO#getId()} 字段 | |
| 71 | + */ | |
| 72 | + private Long modelId; | |
| 73 | + /** | |
| 74 | + * 模型标志 | |
| 75 | + */ | |
| 76 | + private String model; | |
| 77 | + | |
| 78 | + // ========== 对话配置 ========== | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * 角色设定 | |
| 82 | + */ | |
| 83 | + private String systemMessage; | |
| 84 | + /** | |
| 85 | + * 温度参数 | |
| 86 | + * | |
| 87 | + * 用于调整生成回复的随机性和多样性程度:较低的温度值会使输出更收敛于高频词汇,较高的则增加多样性 | |
| 88 | + */ | |
| 89 | + private Double temperature; | |
| 90 | + /** | |
| 91 | + * 单条回复的最大 Token 数量 | |
| 92 | + */ | |
| 93 | + private Integer maxTokens; | |
| 94 | + /** | |
| 95 | + * 上下文的最大 Message 数量 | |
| 96 | + */ | |
| 97 | + private Integer maxContexts; | |
| 98 | + | |
| 99 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatMessageDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.dataobject.chat; | |
| 2 | + | |
| 3 | +import com.baomidou.mybatisplus.annotation.TableId; | |
| 4 | +import org.springframework.ai.chat.messages.MessageType; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |
| 6 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | |
| 7 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | |
| 8 | +import com.baomidou.mybatisplus.annotation.KeySequence; | |
| 9 | +import com.baomidou.mybatisplus.annotation.TableName; | |
| 10 | +import lombok.*; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * AI Chat 消息 DO | |
| 14 | + * | |
| 15 | + * @since 2024/4/14 17:35 | |
| 16 | + * @since 2024/4/14 17:35 | |
| 17 | + */ | |
| 18 | +@TableName("ai_chat_message") | |
| 19 | +@KeySequence("ai_chat_conversation_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | |
| 20 | +@Data | |
| 21 | +@EqualsAndHashCode(callSuper = true) | |
| 22 | +@Builder | |
| 23 | +@NoArgsConstructor | |
| 24 | +@AllArgsConstructor | |
| 25 | +public class AiChatMessageDO extends BaseDO { | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * 编号,作为每条聊天记录的唯一标识符 | |
| 29 | + */ | |
| 30 | + @TableId | |
| 31 | + private Long id; | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 对话编号 | |
| 35 | + * | |
| 36 | + * 关联 {@link AiChatConversationDO#getId()} 字段 | |
| 37 | + */ | |
| 38 | + private Long conversationId; | |
| 39 | + /** | |
| 40 | + * 回复消息编号 | |
| 41 | + * | |
| 42 | + * 关联 {@link #id} 字段 | |
| 43 | + * | |
| 44 | + * 大模型回复的消息编号,用于“问答”的关联 | |
| 45 | + */ | |
| 46 | + private Long replyId; | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * 消息类型 | |
| 50 | + * | |
| 51 | + * 也等价于 OpenAPI 的 role 字段 | |
| 52 | + * | |
| 53 | + * 枚举 {@link MessageType} | |
| 54 | + */ | |
| 55 | + private String type; | |
| 56 | + /** | |
| 57 | + * 用户编号 | |
| 58 | + * | |
| 59 | + * 关联 AdminUserDO 的 userId 字段 | |
| 60 | + */ | |
| 61 | + private Long userId; | |
| 62 | + /** | |
| 63 | + * 角色编号 | |
| 64 | + * | |
| 65 | + * 关联 {@link AiChatRoleDO#getId()} 字段 | |
| 66 | + */ | |
| 67 | + private Long roleId; | |
| 68 | + | |
| 69 | + /** | |
| 70 | + * 模型标志 | |
| 71 | + */ | |
| 72 | + private String model; | |
| 73 | + /** | |
| 74 | + * 模型编号 | |
| 75 | + * | |
| 76 | + * 关联 {@link AiChatModelDO#getId()} 字段 | |
| 77 | + */ | |
| 78 | + private Long modelId; | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * 聊天内容 | |
| 82 | + */ | |
| 83 | + private String content; | |
| 84 | + | |
| 85 | + /** | |
| 86 | + * 是否携带上下文 | |
| 87 | + */ | |
| 88 | + private Boolean useContext; | |
| 89 | + | |
| 90 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.dataobject.image; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; | |
| 4 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |
| 6 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | |
| 7 | +import cn.iocoder.yudao.module.ai.enums.image.AiImageStatusEnum; | |
| 8 | +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | |
| 9 | +import com.baomidou.mybatisplus.annotation.IdType; | |
| 10 | +import com.baomidou.mybatisplus.annotation.TableField; | |
| 11 | +import com.baomidou.mybatisplus.annotation.TableId; | |
| 12 | +import com.baomidou.mybatisplus.annotation.TableName; | |
| 13 | +import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler; | |
| 14 | +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; | |
| 15 | +import lombok.Data; | |
| 16 | +import org.springframework.ai.openai.OpenAiImageOptions; | |
| 17 | +import org.springframework.ai.stabilityai.api.StabilityAiImageOptions; | |
| 18 | + | |
| 19 | +import java.time.LocalDateTime; | |
| 20 | +import java.util.List; | |
| 21 | +import java.util.Map; | |
| 22 | + | |
| 23 | +/** | |
| 24 | + * AI 绘画 DO | |
| 25 | + * | |
| 26 | + * @author fansili | |
| 27 | + */ | |
| 28 | +@TableName(value = "ai_image", autoResultMap = true) | |
| 29 | +@Data | |
| 30 | +public class AiImageDO extends BaseDO { | |
| 31 | + | |
| 32 | + /** | |
| 33 | + * 编号 | |
| 34 | + */ | |
| 35 | + @TableId(type = IdType.AUTO) | |
| 36 | + private Long id; | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * 用户编号 | |
| 40 | + * | |
| 41 | + * 关联 {@link AdminUserRespDTO#getId()} | |
| 42 | + */ | |
| 43 | + private Long userId; | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * 提示词 | |
| 47 | + */ | |
| 48 | + private String prompt; | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * 平台 | |
| 52 | + * | |
| 53 | + * 枚举 {@link cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum} | |
| 54 | + */ | |
| 55 | + private String platform; | |
| 56 | + /** | |
| 57 | + * 模型 | |
| 58 | + * | |
| 59 | + * 冗余 {@link AiChatModelDO#getModel()} | |
| 60 | + */ | |
| 61 | + private String model; | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * 图片宽度 | |
| 65 | + */ | |
| 66 | + private Integer width; | |
| 67 | + /** | |
| 68 | + * 图片高度 | |
| 69 | + */ | |
| 70 | + private Integer height; | |
| 71 | + | |
| 72 | + /** | |
| 73 | + * 生成状态 | |
| 74 | + * | |
| 75 | + * 枚举 {@link AiImageStatusEnum} | |
| 76 | + */ | |
| 77 | + private Integer status; | |
| 78 | + | |
| 79 | + /** | |
| 80 | + * 完成时间 | |
| 81 | + */ | |
| 82 | + private LocalDateTime finishTime; | |
| 83 | + | |
| 84 | + /** | |
| 85 | + * 绘画错误信息 | |
| 86 | + */ | |
| 87 | + private String errorMessage; | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * 图片地址 | |
| 91 | + */ | |
| 92 | + private String picUrl; | |
| 93 | + /** | |
| 94 | + * 是否公开 | |
| 95 | + */ | |
| 96 | + private Boolean publicStatus; | |
| 97 | + | |
| 98 | + /** | |
| 99 | + * 绘制参数,不同 platform 的不同参数 | |
| 100 | + * | |
| 101 | + * 1. {@link OpenAiImageOptions} | |
| 102 | + * 2. {@link StabilityAiImageOptions} | |
| 103 | + */ | |
| 104 | + @TableField(typeHandler = JacksonTypeHandler.class) | |
| 105 | + private Map<String, Object> options; | |
| 106 | + | |
| 107 | + /** | |
| 108 | + * mj buttons 按钮 | |
| 109 | + */ | |
| 110 | + @TableField(typeHandler = ButtonTypeHandler.class) | |
| 111 | + private List<MidjourneyApi.Button> buttons; | |
| 112 | + | |
| 113 | + /** | |
| 114 | + * 任务编号 | |
| 115 | + * | |
| 116 | + * 1. midjourney proxy:关联的 task id | |
| 117 | + */ | |
| 118 | + private String taskId; | |
| 119 | + | |
| 120 | + public static class ButtonTypeHandler extends AbstractJsonTypeHandler<Object> { | |
| 121 | + | |
| 122 | + @Override | |
| 123 | + protected Object parse(String json) { | |
| 124 | + return JsonUtils.parseArray(json, MidjourneyApi.Button.class); | |
| 125 | + } | |
| 126 | + | |
| 127 | + @Override | |
| 128 | + protected String toJson(Object obj) { | |
| 129 | + return JsonUtils.toJsonString(obj); | |
| 130 | + } | |
| 131 | + | |
| 132 | + } | |
| 133 | + | |
| 134 | +} | |
| 135 | + | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/mindmap/AiMindMapDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.dataobject.mindmap; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; | |
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |
| 5 | +import com.baomidou.mybatisplus.annotation.IdType; | |
| 6 | +import com.baomidou.mybatisplus.annotation.TableId; | |
| 7 | +import com.baomidou.mybatisplus.annotation.TableName; | |
| 8 | +import lombok.Data; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * AI 思维导图 DO | |
| 12 | + * | |
| 13 | + * @author xiaoxin | |
| 14 | + */ | |
| 15 | +@TableName(value = "ai_mind_map") | |
| 16 | +@Data | |
| 17 | +public class AiMindMapDO extends BaseDO { | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 编号 | |
| 21 | + */ | |
| 22 | + @TableId(type = IdType.AUTO) | |
| 23 | + private Long id; | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 用户编号 | |
| 27 | + * <p> | |
| 28 | + * 关联 AdminUserDO 的 userId 字段 | |
| 29 | + */ | |
| 30 | + private Long userId; | |
| 31 | + | |
| 32 | + /** | |
| 33 | + * 平台 | |
| 34 | + * <p> | |
| 35 | + * 枚举 {@link AiPlatformEnum} | |
| 36 | + */ | |
| 37 | + private String platform; | |
| 38 | + /** | |
| 39 | + * 模型 | |
| 40 | + */ | |
| 41 | + private String model; | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * 生成内容提示 | |
| 45 | + */ | |
| 46 | + private String prompt; | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * 生成的内容 | |
| 50 | + */ | |
| 51 | + private String generatedContent; | |
| 52 | + | |
| 53 | + /** | |
| 54 | + * 错误信息 | |
| 55 | + */ | |
| 56 | + private String errorMessage; | |
| 57 | + | |
| 58 | +} | |
| 0 | 59 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiApiKeyDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.dataobject.model; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; | |
| 4 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |
| 6 | +import com.baomidou.mybatisplus.annotation.KeySequence; | |
| 7 | +import com.baomidou.mybatisplus.annotation.TableId; | |
| 8 | +import com.baomidou.mybatisplus.annotation.TableName; | |
| 9 | +import lombok.*; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * AI API 秘钥 DO | |
| 13 | + * | |
| 14 | + * @author 芋道源码 | |
| 15 | + */ | |
| 16 | +@TableName("ai_api_key") | |
| 17 | +@KeySequence("ai_chat_conversation_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | |
| 18 | +@Data | |
| 19 | +@EqualsAndHashCode(callSuper = true) | |
| 20 | +@Builder | |
| 21 | +@NoArgsConstructor | |
| 22 | +@AllArgsConstructor | |
| 23 | +public class AiApiKeyDO extends BaseDO { | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 编号 | |
| 27 | + */ | |
| 28 | + @TableId | |
| 29 | + private Long id; | |
| 30 | + /** | |
| 31 | + * 名称 | |
| 32 | + */ | |
| 33 | + private String name; | |
| 34 | + /** | |
| 35 | + * 密钥 | |
| 36 | + */ | |
| 37 | + private String apiKey; | |
| 38 | + /** | |
| 39 | + * 平台 | |
| 40 | + * | |
| 41 | + * 枚举 {@link AiPlatformEnum} | |
| 42 | + */ | |
| 43 | + private String platform; | |
| 44 | + /** | |
| 45 | + * API 地址 | |
| 46 | + */ | |
| 47 | + private String url; | |
| 48 | + /** | |
| 49 | + * 状态 | |
| 50 | + * | |
| 51 | + * 枚举 {@link CommonStatusEnum} | |
| 52 | + */ | |
| 53 | + private Integer status; | |
| 54 | + | |
| 55 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatModelDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.dataobject.model; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; | |
| 4 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |
| 6 | +import com.baomidou.mybatisplus.annotation.KeySequence; | |
| 7 | +import com.baomidou.mybatisplus.annotation.TableId; | |
| 8 | +import com.baomidou.mybatisplus.annotation.TableName; | |
| 9 | +import lombok.*; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * AI 聊天模型 DO | |
| 13 | + * | |
| 14 | + * 默认聊天模型:{@link #status} 为开启,并且 {@link #sort} 排序第一 | |
| 15 | + * | |
| 16 | + * @author fansili | |
| 17 | + * @since 2024/4/24 19:39 | |
| 18 | + */ | |
| 19 | +@TableName("ai_chat_model") | |
| 20 | +@KeySequence("ai_chat_model_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | |
| 21 | +@Data | |
| 22 | +@EqualsAndHashCode(callSuper = true) | |
| 23 | +@Builder | |
| 24 | +@NoArgsConstructor | |
| 25 | +@AllArgsConstructor | |
| 26 | +public class AiChatModelDO extends BaseDO { | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * 编号 | |
| 30 | + */ | |
| 31 | + @TableId | |
| 32 | + private Long id; | |
| 33 | + /** | |
| 34 | + * API 秘钥编号 | |
| 35 | + * | |
| 36 | + * 关联 {@link AiApiKeyDO#getId()} | |
| 37 | + */ | |
| 38 | + private Long keyId; | |
| 39 | + /** | |
| 40 | + * 模型名称 | |
| 41 | + */ | |
| 42 | + private String name; | |
| 43 | + /** | |
| 44 | + * 模型标志 | |
| 45 | + */ | |
| 46 | + private String model; | |
| 47 | + /** | |
| 48 | + * 平台 | |
| 49 | + * | |
| 50 | + * 枚举 {@link AiPlatformEnum} | |
| 51 | + */ | |
| 52 | + private String platform; | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * 排序值 | |
| 56 | + */ | |
| 57 | + private Integer sort; | |
| 58 | + /** | |
| 59 | + * 状态 | |
| 60 | + * | |
| 61 | + * 枚举 {@link CommonStatusEnum} | |
| 62 | + */ | |
| 63 | + private Integer status; | |
| 64 | + | |
| 65 | + // ========== 对话配置 ========== | |
| 66 | + | |
| 67 | + /** | |
| 68 | + * 温度参数 | |
| 69 | + * | |
| 70 | + * 用于调整生成回复的随机性和多样性程度:较低的温度值会使输出更收敛于高频词汇,较高的则增加多样性 | |
| 71 | + */ | |
| 72 | + private Double temperature; | |
| 73 | + /** | |
| 74 | + * 单条回复的最大 Token 数量 | |
| 75 | + */ | |
| 76 | + private Integer maxTokens; | |
| 77 | + /** | |
| 78 | + * 上下文的最大 Message 数量 | |
| 79 | + */ | |
| 80 | + private Integer maxContexts; | |
| 81 | + | |
| 82 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatRoleDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.dataobject.model; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |
| 5 | +import com.baomidou.mybatisplus.annotation.*; | |
| 6 | +import lombok.*; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * AI 聊天角色 DO | |
| 10 | + * | |
| 11 | + * @author fansili | |
| 12 | + * @since 2024/4/24 19:39 | |
| 13 | + */ | |
| 14 | +@TableName(value = "ai_chat_role", autoResultMap = true) | |
| 15 | +@KeySequence("ai_chat_role_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | |
| 16 | +@Data | |
| 17 | +@EqualsAndHashCode(callSuper = true) | |
| 18 | +@Builder | |
| 19 | +@NoArgsConstructor | |
| 20 | +@AllArgsConstructor | |
| 21 | +public class AiChatRoleDO extends BaseDO { | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * 编号 | |
| 25 | + */ | |
| 26 | + @TableId | |
| 27 | + private Long id; | |
| 28 | + /** | |
| 29 | + * 角色名称 | |
| 30 | + */ | |
| 31 | + private String name; | |
| 32 | + /** | |
| 33 | + * 角色头像 | |
| 34 | + */ | |
| 35 | + private String avatar; | |
| 36 | + /** | |
| 37 | + * 角色分类 | |
| 38 | + */ | |
| 39 | + private String category; | |
| 40 | + /** | |
| 41 | + * 角色描述 | |
| 42 | + */ | |
| 43 | + private String description; | |
| 44 | + /** | |
| 45 | + * 角色设定 | |
| 46 | + */ | |
| 47 | + private String systemMessage; | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * 用户编号 | |
| 51 | + * | |
| 52 | + * 关联 AdminUserDO 的 userId 字段 | |
| 53 | + */ | |
| 54 | + private Long userId; | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * 模型编号 | |
| 58 | + * | |
| 59 | + * 关联 {@link AiChatModelDO#getId()} 字段 | |
| 60 | + */ | |
| 61 | + private Long modelId; | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * 是否公开 | |
| 65 | + * | |
| 66 | + * 1. true - 公开;由管理员在【角色管理】所创建 | |
| 67 | + * 2. false - 私有;由个人在【我的角色】所创建 | |
| 68 | + */ | |
| 69 | + private Boolean publicStatus; | |
| 70 | + | |
| 71 | + /** | |
| 72 | + * 排序值 | |
| 73 | + */ | |
| 74 | + private Integer sort; | |
| 75 | + /** | |
| 76 | + * 状态 | |
| 77 | + * | |
| 78 | + * 枚举 {@link CommonStatusEnum} | |
| 79 | + */ | |
| 80 | + private Integer status; | |
| 81 | + | |
| 82 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.dataobject.music; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; | |
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |
| 5 | +import cn.iocoder.yudao.module.ai.enums.music.AiMusicGenerateModeEnum; | |
| 6 | +import cn.iocoder.yudao.module.ai.enums.music.AiMusicStatusEnum; | |
| 7 | +import com.baomidou.mybatisplus.annotation.IdType; | |
| 8 | +import com.baomidou.mybatisplus.annotation.TableField; | |
| 9 | +import com.baomidou.mybatisplus.annotation.TableId; | |
| 10 | +import com.baomidou.mybatisplus.annotation.TableName; | |
| 11 | +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; | |
| 12 | +import lombok.Data; | |
| 13 | + | |
| 14 | +import java.util.List; | |
| 15 | + | |
| 16 | +/** | |
| 17 | + * AI 音乐 DO | |
| 18 | + * | |
| 19 | + * @author xiaoxin | |
| 20 | + */ | |
| 21 | +@TableName(value = "ai_music", autoResultMap = true) | |
| 22 | +@Data | |
| 23 | +public class AiMusicDO extends BaseDO { | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 编号 | |
| 27 | + */ | |
| 28 | + @TableId(type = IdType.AUTO) | |
| 29 | + private Long id; | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * 用户编号 | |
| 33 | + * <p> | |
| 34 | + * 关联 AdminUserDO 的 userId 字段 | |
| 35 | + */ | |
| 36 | + private Long userId; | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * 音乐名称 | |
| 40 | + */ | |
| 41 | + private String title; | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * 歌词 | |
| 45 | + */ | |
| 46 | + private String lyric; | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * 图片地址 | |
| 50 | + */ | |
| 51 | + private String imageUrl; | |
| 52 | + /** | |
| 53 | + * 音频地址 | |
| 54 | + */ | |
| 55 | + private String audioUrl; | |
| 56 | + /** | |
| 57 | + * 视频地址 | |
| 58 | + */ | |
| 59 | + private String videoUrl; | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * 音乐状态 | |
| 63 | + * <p> | |
| 64 | + * 枚举 {@link AiMusicStatusEnum} | |
| 65 | + */ | |
| 66 | + private Integer status; | |
| 67 | + | |
| 68 | + /** | |
| 69 | + * 生成模式 | |
| 70 | + * <p> | |
| 71 | + * 枚举 {@link AiMusicGenerateModeEnum} | |
| 72 | + */ | |
| 73 | + private Integer generateMode; | |
| 74 | + | |
| 75 | + /** | |
| 76 | + * 描述词 | |
| 77 | + */ | |
| 78 | + private String description; | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * 平台 | |
| 82 | + * <p> | |
| 83 | + * 枚举 {@link AiPlatformEnum} | |
| 84 | + */ | |
| 85 | + private String platform; | |
| 86 | + /** | |
| 87 | + * 模型 | |
| 88 | + */ | |
| 89 | + private String model; | |
| 90 | + | |
| 91 | + /** | |
| 92 | + * 音乐风格标签 | |
| 93 | + */ | |
| 94 | + @TableField(typeHandler = JacksonTypeHandler.class) | |
| 95 | + private List<String> tags; | |
| 96 | + | |
| 97 | + /** | |
| 98 | + * 音乐时长 | |
| 99 | + */ | |
| 100 | + private Double duration; | |
| 101 | + | |
| 102 | + /** | |
| 103 | + * 是否公开 | |
| 104 | + */ | |
| 105 | + private Boolean publicStatus; | |
| 106 | + | |
| 107 | + /** | |
| 108 | + * 任务编号 | |
| 109 | + */ | |
| 110 | + private String taskId; | |
| 111 | + | |
| 112 | + /** | |
| 113 | + * 错误信息 | |
| 114 | + */ | |
| 115 | + private String errorMessage; | |
| 116 | + | |
| 117 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/write/AiWriteDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.dataobject.write; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; | |
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |
| 5 | +import cn.iocoder.yudao.module.ai.enums.write.AiWriteTypeEnum; | |
| 6 | +import com.baomidou.mybatisplus.annotation.IdType; | |
| 7 | +import com.baomidou.mybatisplus.annotation.TableId; | |
| 8 | +import com.baomidou.mybatisplus.annotation.TableName; | |
| 9 | +import lombok.Data; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * AI 写作 DO | |
| 13 | + * | |
| 14 | + * @author xiaoxin | |
| 15 | + */ | |
| 16 | +@TableName("ai_write") | |
| 17 | +@Data | |
| 18 | +public class AiWriteDO extends BaseDO { | |
| 19 | + | |
| 20 | + /** | |
| 21 | + * 编号 | |
| 22 | + */ | |
| 23 | + @TableId(type = IdType.AUTO) | |
| 24 | + private Long id; | |
| 25 | + | |
| 26 | + /** | |
| 27 | + * 用户编号 | |
| 28 | + * | |
| 29 | + * 关联 AdminUserDO 的 userId 字段 | |
| 30 | + */ | |
| 31 | + private Long userId; | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 写作类型 | |
| 35 | + * <p> | |
| 36 | + * 枚举 {@link AiWriteTypeEnum} | |
| 37 | + */ | |
| 38 | + private Integer type; | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * 平台 | |
| 42 | + * | |
| 43 | + * 枚举 {@link AiPlatformEnum} | |
| 44 | + */ | |
| 45 | + private String platform; | |
| 46 | + /** | |
| 47 | + * 模型 | |
| 48 | + */ | |
| 49 | + private String model; | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * 生成内容提示 | |
| 53 | + */ | |
| 54 | + private String prompt; | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * 生成的内容 | |
| 58 | + */ | |
| 59 | + private String generatedContent; | |
| 60 | + /** | |
| 61 | + * 原文 | |
| 62 | + */ | |
| 63 | + private String originalContent; | |
| 64 | + | |
| 65 | + /** | |
| 66 | + * 长度提示词 | |
| 67 | + * | |
| 68 | + * 字典:{@link cn.iocoder.yudao.module.ai.enums.DictTypeConstants#AI_WRITE_LENGTH} | |
| 69 | + */ | |
| 70 | + private Integer length; | |
| 71 | + /** | |
| 72 | + * 格式提示词 | |
| 73 | + * | |
| 74 | + * 字典:{@link cn.iocoder.yudao.module.ai.enums.DictTypeConstants#AI_WRITE_FORMAT} | |
| 75 | + */ | |
| 76 | + private Integer format; | |
| 77 | + /** | |
| 78 | + * 语气提示词 | |
| 79 | + * | |
| 80 | + * 字典:{@link cn.iocoder.yudao.module.ai.enums.DictTypeConstants#AI_WRITE_TONE} | |
| 81 | + */ | |
| 82 | + private Integer tone; | |
| 83 | + /** | |
| 84 | + * 语言提示词 | |
| 85 | + * | |
| 86 | + * 字典:{@link cn.iocoder.yudao.module.ai.enums.DictTypeConstants#AI_WRITE_LANGUAGE} | |
| 87 | + */ | |
| 88 | + private Integer language; | |
| 89 | + | |
| 90 | + /** | |
| 91 | + * 错误信息 | |
| 92 | + */ | |
| 93 | + private String errorMessage; | |
| 94 | + | |
| 95 | +} | |
| 0 | 96 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/chat/AiChatConversationMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.mysql.chat; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | |
| 6 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationPageReqVO; | |
| 7 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; | |
| 8 | +import org.apache.ibatis.annotations.Mapper; | |
| 9 | + | |
| 10 | +import java.util.List; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * AI 聊天对话 Mapper | |
| 14 | + * | |
| 15 | + * @author 芋道源码 | |
| 16 | + */ | |
| 17 | +@Mapper | |
| 18 | +public interface AiChatConversationMapper extends BaseMapperX<AiChatConversationDO> { | |
| 19 | + | |
| 20 | + default List<AiChatConversationDO> selectListByUserId(Long userId) { | |
| 21 | + return selectList(AiChatConversationDO::getUserId, userId); | |
| 22 | + } | |
| 23 | + | |
| 24 | + default List<AiChatConversationDO> selectListByUserIdAndPinned(Long userId, boolean pinned) { | |
| 25 | + return selectList(new LambdaQueryWrapperX<AiChatConversationDO>() | |
| 26 | + .eq(AiChatConversationDO::getUserId, userId) | |
| 27 | + .eq(AiChatConversationDO::getPinned, pinned)); | |
| 28 | + } | |
| 29 | + | |
| 30 | + default PageResult<AiChatConversationDO> selectChatConversationPage(AiChatConversationPageReqVO pageReqVO) { | |
| 31 | + return selectPage(pageReqVO, new LambdaQueryWrapperX<AiChatConversationDO>() | |
| 32 | + .eqIfPresent(AiChatConversationDO::getUserId, pageReqVO.getUserId()) | |
| 33 | + .likeIfPresent(AiChatConversationDO::getTitle, pageReqVO.getTitle()) | |
| 34 | + .betweenIfPresent(AiChatConversationDO::getCreateTime, pageReqVO.getCreateTime()) | |
| 35 | + .orderByDesc(AiChatConversationDO::getId)); | |
| 36 | + } | |
| 37 | + | |
| 38 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/chat/AiChatMessageMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.mysql.chat; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.map.MapUtil; | |
| 5 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 6 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 7 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | |
| 8 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | |
| 9 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationPageReqVO; | |
| 10 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO; | |
| 11 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; | |
| 12 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; | |
| 13 | +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | |
| 14 | +import org.apache.ibatis.annotations.Mapper; | |
| 15 | + | |
| 16 | +import java.util.Collection; | |
| 17 | +import java.util.Collections; | |
| 18 | +import java.util.List; | |
| 19 | +import java.util.Map; | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * AI 聊天对话 Mapper | |
| 23 | + * | |
| 24 | + * @author fansili | |
| 25 | + */ | |
| 26 | +@Mapper | |
| 27 | +public interface AiChatMessageMapper extends BaseMapperX<AiChatMessageDO> { | |
| 28 | + | |
| 29 | + default List<AiChatMessageDO> selectListByConversationId(Long conversationId) { | |
| 30 | + return selectList(new LambdaQueryWrapperX<AiChatMessageDO>() | |
| 31 | + .eq(AiChatMessageDO::getConversationId, conversationId) | |
| 32 | + .orderByAsc(AiChatMessageDO::getId)); | |
| 33 | + } | |
| 34 | + | |
| 35 | + default Map<Long, Integer> selectCountMapByConversationId(Collection<Long> conversationIds) { | |
| 36 | + // SQL count 查询 | |
| 37 | + List<Map<String, Object>> result = selectMaps(new QueryWrapper<AiChatMessageDO>() | |
| 38 | + .select("COUNT(id) AS count, conversation_id AS conversationId") | |
| 39 | + .in("conversation_id", conversationIds) | |
| 40 | + .groupBy("conversation_id")); | |
| 41 | + if (CollUtil.isEmpty(result)) { | |
| 42 | + return Collections.emptyMap(); | |
| 43 | + } | |
| 44 | + // 转换数据 | |
| 45 | + return CollectionUtils.convertMap(result, | |
| 46 | + record -> MapUtil.getLong(record, "conversationId"), | |
| 47 | + record -> MapUtil.getInt(record, "count" )); | |
| 48 | + } | |
| 49 | + | |
| 50 | + default PageResult<AiChatMessageDO> selectPage(AiChatMessagePageReqVO pageReqVO) { | |
| 51 | + return selectPage(pageReqVO, new LambdaQueryWrapperX<AiChatMessageDO>() | |
| 52 | + .eqIfPresent(AiChatMessageDO::getConversationId, pageReqVO.getConversationId()) | |
| 53 | + .eqIfPresent(AiChatMessageDO::getUserId, pageReqVO.getUserId()) | |
| 54 | + .likeIfPresent(AiChatMessageDO::getContent, pageReqVO.getContent()) | |
| 55 | + .betweenIfPresent(AiChatMessageDO::getCreateTime, pageReqVO.getCreateTime()) | |
| 56 | + .orderByDesc(AiChatMessageDO::getId)); | |
| 57 | + } | |
| 58 | + | |
| 59 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/image/AiImageMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.mysql.image; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | |
| 6 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | |
| 7 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImagePageReqVO; | |
| 8 | +import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO; | |
| 9 | +import org.apache.ibatis.annotations.Mapper; | |
| 10 | + | |
| 11 | +import java.util.List; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * AI 绘图 Mapper | |
| 15 | + * | |
| 16 | + * @author fansili | |
| 17 | + */ | |
| 18 | +@Mapper | |
| 19 | +public interface AiImageMapper extends BaseMapperX<AiImageDO> { | |
| 20 | + | |
| 21 | + default AiImageDO selectByTaskId(String taskId) { | |
| 22 | + return this.selectOne(AiImageDO::getTaskId, taskId); | |
| 23 | + } | |
| 24 | + | |
| 25 | + default PageResult<AiImageDO> selectPage(AiImagePageReqVO reqVO) { | |
| 26 | + return selectPage(reqVO, new LambdaQueryWrapperX<AiImageDO>() | |
| 27 | + .eqIfPresent(AiImageDO::getUserId, reqVO.getUserId()) | |
| 28 | + .eqIfPresent(AiImageDO::getPlatform, reqVO.getPlatform()) | |
| 29 | + .eqIfPresent(AiImageDO::getStatus, reqVO.getStatus()) | |
| 30 | + .eqIfPresent(AiImageDO::getPublicStatus, reqVO.getPublicStatus()) | |
| 31 | + .betweenIfPresent(AiImageDO::getCreateTime, reqVO.getCreateTime()) | |
| 32 | + .orderByDesc(AiImageDO::getId)); | |
| 33 | + } | |
| 34 | + | |
| 35 | + default PageResult<AiImageDO> selectPage(Long userId, PageParam pageReqVO) { | |
| 36 | + return selectPage(pageReqVO, new LambdaQueryWrapperX<AiImageDO>() | |
| 37 | + .eq(AiImageDO::getUserId, userId) | |
| 38 | + .orderByDesc(AiImageDO::getId)); | |
| 39 | + } | |
| 40 | + | |
| 41 | + default List<AiImageDO> selectListByStatusAndPlatform(Integer status, String platform) { | |
| 42 | + return selectList(AiImageDO::getStatus, status, | |
| 43 | + AiImageDO::getPlatform, platform); | |
| 44 | + } | |
| 45 | + | |
| 46 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/mindmap/AiMindMapMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.mysql.mindmap; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | |
| 4 | +import cn.iocoder.yudao.module.ai.dal.dataobject.mindmap.AiMindMapDO; | |
| 5 | +import org.apache.ibatis.annotations.Mapper; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * AI 思维导图 Mapper | |
| 9 | + * | |
| 10 | + * @author xiaoxin | |
| 11 | + */ | |
| 12 | +@Mapper | |
| 13 | +public interface AiMindMapMapper extends BaseMapperX<AiMindMapDO> { | |
| 14 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/model/AiApiKeyMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.mysql.model; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | |
| 6 | +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; | |
| 7 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeyPageReqVO; | |
| 8 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO; | |
| 9 | +import org.apache.ibatis.annotations.Mapper; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * AI API 密钥 Mapper | |
| 13 | + * | |
| 14 | + * @author 芋道源码 | |
| 15 | + */ | |
| 16 | +@Mapper | |
| 17 | +public interface AiApiKeyMapper extends BaseMapperX<AiApiKeyDO> { | |
| 18 | + | |
| 19 | + default PageResult<AiApiKeyDO> selectPage(AiApiKeyPageReqVO reqVO) { | |
| 20 | + return selectPage(reqVO, new LambdaQueryWrapperX<AiApiKeyDO>() | |
| 21 | + .likeIfPresent(AiApiKeyDO::getName, reqVO.getName()) | |
| 22 | + .eqIfPresent(AiApiKeyDO::getPlatform, reqVO.getPlatform()) | |
| 23 | + .eqIfPresent(AiApiKeyDO::getStatus, reqVO.getStatus()) | |
| 24 | + .orderByDesc(AiApiKeyDO::getId)); | |
| 25 | + } | |
| 26 | + | |
| 27 | + default AiApiKeyDO selectFirstByPlatformAndStatus(String platform, Integer status) { | |
| 28 | + return selectOne(new QueryWrapperX<AiApiKeyDO>() | |
| 29 | + .eq("platform", platform) | |
| 30 | + .eq("status", status) | |
| 31 | + .limitN(1) | |
| 32 | + .orderByAsc("id")); | |
| 33 | + } | |
| 34 | + | |
| 35 | +} | |
| 0 | 36 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/model/AiChatModelMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.mysql.model; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | |
| 6 | +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; | |
| 7 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatModel.AiChatModelPageReqVO; | |
| 8 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | |
| 9 | +import org.apache.ibatis.annotations.Mapper; | |
| 10 | + | |
| 11 | +import java.util.Collection; | |
| 12 | +import java.util.List; | |
| 13 | + | |
| 14 | +/** | |
| 15 | + * API 聊天模型 Mapper | |
| 16 | + * | |
| 17 | + * @author fansili | |
| 18 | + */ | |
| 19 | +@Mapper | |
| 20 | +public interface AiChatModelMapper extends BaseMapperX<AiChatModelDO> { | |
| 21 | + | |
| 22 | + default AiChatModelDO selectFirstByStatus(Integer status) { | |
| 23 | + return selectOne(new QueryWrapperX<AiChatModelDO>() | |
| 24 | + .eq("status", status) | |
| 25 | + .limitN(1) | |
| 26 | + .orderByAsc("sort")); | |
| 27 | + } | |
| 28 | + | |
| 29 | + default PageResult<AiChatModelDO> selectPage(AiChatModelPageReqVO reqVO) { | |
| 30 | + return selectPage(reqVO, new LambdaQueryWrapperX<AiChatModelDO>() | |
| 31 | + .likeIfPresent(AiChatModelDO::getName, reqVO.getName()) | |
| 32 | + .eqIfPresent(AiChatModelDO::getModel, reqVO.getModel()) | |
| 33 | + .eqIfPresent(AiChatModelDO::getPlatform, reqVO.getPlatform()) | |
| 34 | + .orderByAsc(AiChatModelDO::getSort)); | |
| 35 | + } | |
| 36 | + | |
| 37 | + default List<AiChatModelDO> selectList(Integer status) { | |
| 38 | + return selectList(new LambdaQueryWrapperX<AiChatModelDO>() | |
| 39 | + .eq(AiChatModelDO::getStatus, status) | |
| 40 | + .orderByAsc(AiChatModelDO::getSort)); | |
| 41 | + } | |
| 42 | + | |
| 43 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/model/AiChatRoleMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.mysql.model; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | |
| 6 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | |
| 7 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRolePageReqVO; | |
| 8 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | |
| 9 | +import org.apache.ibatis.annotations.Mapper; | |
| 10 | + | |
| 11 | +import java.util.List; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * AI 聊天角色 Mapper | |
| 15 | + * | |
| 16 | + * @author fansili | |
| 17 | + */ | |
| 18 | +@Mapper | |
| 19 | +public interface AiChatRoleMapper extends BaseMapperX<AiChatRoleDO> { | |
| 20 | + | |
| 21 | + default PageResult<AiChatRoleDO> selectPage(AiChatRolePageReqVO reqVO) { | |
| 22 | + return selectPage(reqVO, new LambdaQueryWrapperX<AiChatRoleDO>() | |
| 23 | + .likeIfPresent(AiChatRoleDO::getName, reqVO.getName()) | |
| 24 | + .eqIfPresent(AiChatRoleDO::getCategory, reqVO.getCategory()) | |
| 25 | + .eqIfPresent(AiChatRoleDO::getPublicStatus, reqVO.getPublicStatus()) | |
| 26 | + .orderByAsc(AiChatRoleDO::getSort)); | |
| 27 | + } | |
| 28 | + | |
| 29 | + default PageResult<AiChatRoleDO> selectPageByMy(AiChatRolePageReqVO reqVO, Long userId) { | |
| 30 | + return selectPage(reqVO, new LambdaQueryWrapperX<AiChatRoleDO>() | |
| 31 | + .likeIfPresent(AiChatRoleDO::getName, reqVO.getName()) | |
| 32 | + .eqIfPresent(AiChatRoleDO::getCategory, reqVO.getCategory()) | |
| 33 | + // 情况一:公开 | |
| 34 | + .eq(Boolean.TRUE.equals(reqVO.getPublicStatus()), AiChatRoleDO::getPublicStatus, reqVO.getPublicStatus()) | |
| 35 | + // 情况二:私有 | |
| 36 | + .eq(Boolean.FALSE.equals(reqVO.getPublicStatus()), AiChatRoleDO::getUserId, userId) | |
| 37 | + .eq(Boolean.FALSE.equals(reqVO.getPublicStatus()), AiChatRoleDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) | |
| 38 | + .orderByAsc(AiChatRoleDO::getSort)); | |
| 39 | + } | |
| 40 | + | |
| 41 | + default List<AiChatRoleDO> selectListGroupByCategory(Integer status) { | |
| 42 | + return selectList(new LambdaQueryWrapperX<AiChatRoleDO>() | |
| 43 | + .select(AiChatRoleDO::getCategory) | |
| 44 | + .eq(AiChatRoleDO::getStatus, status) | |
| 45 | + .groupBy(AiChatRoleDO::getCategory)); | |
| 46 | + } | |
| 47 | + | |
| 48 | + default List<AiChatRoleDO> selectListByName(String name) { | |
| 49 | + return selectList(new LambdaQueryWrapperX<AiChatRoleDO>() | |
| 50 | + .likeIfPresent(AiChatRoleDO::getName, name) | |
| 51 | + .orderByAsc(AiChatRoleDO::getSort)); | |
| 52 | + } | |
| 53 | + | |
| 54 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/music/AiMusicMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.mysql.music; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | |
| 6 | +import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiMusicPageReqVO; | |
| 7 | +import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO; | |
| 8 | +import org.apache.ibatis.annotations.Mapper; | |
| 9 | + | |
| 10 | +import java.util.List; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * AI 音乐 Mapper | |
| 14 | + * | |
| 15 | + * @author xiaoxin | |
| 16 | + */ | |
| 17 | +@Mapper | |
| 18 | +public interface AiMusicMapper extends BaseMapperX<AiMusicDO> { | |
| 19 | + | |
| 20 | + default List<AiMusicDO> selectListByStatus(Integer status) { | |
| 21 | + return selectList(AiMusicDO::getStatus, status); | |
| 22 | + } | |
| 23 | + | |
| 24 | + default PageResult<AiMusicDO> selectPage(AiMusicPageReqVO reqVO) { | |
| 25 | + return selectPage(reqVO, new LambdaQueryWrapperX<AiMusicDO>() | |
| 26 | + .eqIfPresent(AiMusicDO::getUserId, reqVO.getUserId()) | |
| 27 | + .eqIfPresent(AiMusicDO::getTitle, reqVO.getTitle()) | |
| 28 | + .eqIfPresent(AiMusicDO::getStatus, reqVO.getStatus()) | |
| 29 | + .eqIfPresent(AiMusicDO::getGenerateMode, reqVO.getGenerateMode()) | |
| 30 | + .betweenIfPresent(AiMusicDO::getCreateTime, reqVO.getCreateTime()) | |
| 31 | + .eqIfPresent(AiMusicDO::getPublicStatus, reqVO.getPublicStatus()) | |
| 32 | + .orderByDesc(AiMusicDO::getId)); | |
| 33 | + } | |
| 34 | + | |
| 35 | + default PageResult<AiMusicDO> selectPageByMy(AiMusicPageReqVO reqVO, Long userId) { | |
| 36 | + return selectPage(reqVO, new LambdaQueryWrapperX<AiMusicDO>() | |
| 37 | + // 情况一:公开 | |
| 38 | + .eq(Boolean.TRUE.equals(reqVO.getPublicStatus()), AiMusicDO::getPublicStatus, reqVO.getPublicStatus()) | |
| 39 | + // 情况二:私有 | |
| 40 | + .eq(Boolean.FALSE.equals(reqVO.getPublicStatus()), AiMusicDO::getUserId, userId) | |
| 41 | + .orderByAsc(AiMusicDO::getId)); | |
| 42 | + } | |
| 43 | + | |
| 44 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/write/AiWriteMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.mysql.write; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | |
| 6 | +import cn.iocoder.yudao.module.ai.controller.admin.write.vo.AiWritePageReqVO; | |
| 7 | +import cn.iocoder.yudao.module.ai.dal.dataobject.write.AiWriteDO; | |
| 8 | +import org.apache.ibatis.annotations.Mapper; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * AI 写作 Mapper | |
| 12 | + * | |
| 13 | + * @author xiaoxin | |
| 14 | + */ | |
| 15 | +@Mapper | |
| 16 | +public interface AiWriteMapper extends BaseMapperX<AiWriteDO> { | |
| 17 | + | |
| 18 | + default PageResult<AiWriteDO> selectPage(AiWritePageReqVO reqVO) { | |
| 19 | + return selectPage(reqVO, new LambdaQueryWrapperX<AiWriteDO>() | |
| 20 | + .eqIfPresent(AiWriteDO::getUserId, reqVO.getUserId()) | |
| 21 | + .eqIfPresent(AiWriteDO::getType, reqVO.getType()) | |
| 22 | + .eqIfPresent(AiWriteDO::getPlatform, reqVO.getPlatform()) | |
| 23 | + .betweenIfPresent(AiWriteDO::getCreateTime, reqVO.getCreateTime()) | |
| 24 | + .orderByDesc(AiWriteDO::getId)); | |
| 25 | + } | |
| 26 | + | |
| 27 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/job/image/AiMidjourneySyncJob.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.job.image; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; | |
| 4 | +import cn.iocoder.yudao.module.ai.service.image.AiImageService; | |
| 5 | +import jakarta.annotation.Resource; | |
| 6 | +import lombok.extern.slf4j.Slf4j; | |
| 7 | +import org.springframework.stereotype.Component; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * Midjourney 同步 Job:定时拉去 midjourney 绘制状态 | |
| 11 | + * | |
| 12 | + * @author fansili | |
| 13 | + */ | |
| 14 | +@Component | |
| 15 | +@Slf4j | |
| 16 | +public class AiMidjourneySyncJob implements JobHandler { | |
| 17 | + | |
| 18 | + @Resource | |
| 19 | + private AiImageService imageService; | |
| 20 | + | |
| 21 | + @Override | |
| 22 | + public String execute(String param) { | |
| 23 | + Integer count = imageService.midjourneySync(); | |
| 24 | + log.info("[execute][同步 Midjourney ({}) 个]", count); | |
| 25 | + return String.format("同步 Midjourney %s 个", count); | |
| 26 | + } | |
| 27 | + | |
| 28 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/job/music/AiSunoSyncJob.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.job.music; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; | |
| 4 | +import cn.iocoder.yudao.module.ai.service.music.AiMusicService; | |
| 5 | +import jakarta.annotation.Resource; | |
| 6 | +import lombok.extern.slf4j.Slf4j; | |
| 7 | +import org.springframework.stereotype.Component; | |
| 8 | + | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * 同步 Suno 任务状态以及回写对应的音乐信息 Job | |
| 12 | + * | |
| 13 | + * @author xiaoxin | |
| 14 | + */ | |
| 15 | +@Component | |
| 16 | +@Slf4j | |
| 17 | +public class AiSunoSyncJob implements JobHandler { | |
| 18 | + | |
| 19 | + @Resource | |
| 20 | + private AiMusicService musicService; | |
| 21 | + | |
| 22 | + @Override | |
| 23 | + public String execute(String param) { | |
| 24 | + Integer count = musicService.syncMusic(); | |
| 25 | + log.info("[execute][同步 Suno ({}) 个]", count); | |
| 26 | + return String.format("同步 Suno %s 个", count); | |
| 27 | + } | |
| 28 | + | |
| 29 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatConversationService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.chat; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO; | |
| 5 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationPageReqVO; | |
| 6 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO; | |
| 7 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO; | |
| 8 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; | |
| 9 | + | |
| 10 | +import java.util.List; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * AI 聊天对话 Service 接口 | |
| 14 | + * | |
| 15 | + * @author fansili | |
| 16 | + */ | |
| 17 | +public interface AiChatConversationService { | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 创建【我的】聊天对话 | |
| 21 | + * | |
| 22 | + * @param createReqVO 创建信息 | |
| 23 | + * @param userId 用户编号 | |
| 24 | + * @return 编号 | |
| 25 | + */ | |
| 26 | + Long createChatConversationMy(AiChatConversationCreateMyReqVO createReqVO, Long userId); | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * 更新【我的】聊天对话 | |
| 30 | + * | |
| 31 | + * @param updateReqVO 更新信息 | |
| 32 | + * @param userId 用户编号 | |
| 33 | + */ | |
| 34 | + void updateChatConversationMy(AiChatConversationUpdateMyReqVO updateReqVO, Long userId); | |
| 35 | + | |
| 36 | + /** | |
| 37 | + * 获得【我的】聊天对话列表 | |
| 38 | + * | |
| 39 | + * @param userId 用户编号 | |
| 40 | + * @return 聊天对话列表 | |
| 41 | + */ | |
| 42 | + List<AiChatConversationDO> getChatConversationListByUserId(Long userId); | |
| 43 | + | |
| 44 | + /** | |
| 45 | + * 获得聊天对话 | |
| 46 | + * | |
| 47 | + * @param id 编号 | |
| 48 | + * @return 聊天对话 | |
| 49 | + */ | |
| 50 | + AiChatConversationDO getChatConversation(Long id); | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * 删除【我的】聊天对话 | |
| 54 | + * | |
| 55 | + * @param id 编号 | |
| 56 | + * @param userId 用户编号 | |
| 57 | + */ | |
| 58 | + void deleteChatConversationMy(Long id, Long userId); | |
| 59 | + | |
| 60 | + /** | |
| 61 | + * 【管理员】删除聊天对话 | |
| 62 | + * | |
| 63 | + * @param id 编号 | |
| 64 | + */ | |
| 65 | + void deleteChatConversationByAdmin(Long id); | |
| 66 | + | |
| 67 | + /** | |
| 68 | + * 校验聊天对话是否存在 | |
| 69 | + * | |
| 70 | + * @param id 编号 | |
| 71 | + * @return 聊天对话 | |
| 72 | + */ | |
| 73 | + AiChatConversationDO validateChatConversationExists(Long id); | |
| 74 | + | |
| 75 | + /** | |
| 76 | + * 删除【我的】 + 非置顶的聊天对话 | |
| 77 | + * | |
| 78 | + * @param userId 用户编号 | |
| 79 | + */ | |
| 80 | + void deleteChatConversationMyByUnpinned(Long userId); | |
| 81 | + | |
| 82 | + /** | |
| 83 | + * 获得聊天对话的分页列表 | |
| 84 | + * | |
| 85 | + * @param pageReqVO 分页查询 | |
| 86 | + * @return 聊天对话的分页列表 | |
| 87 | + */ | |
| 88 | + PageResult<AiChatConversationDO> getChatConversationPage(AiChatConversationPageReqVO pageReqVO); | |
| 89 | + | |
| 90 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatConversationServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.chat; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.lang.Assert; | |
| 5 | +import cn.hutool.core.util.ObjUtil; | |
| 6 | +import cn.hutool.core.util.ObjectUtil; | |
| 7 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 8 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 9 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO; | |
| 10 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationPageReqVO; | |
| 11 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO; | |
| 12 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; | |
| 13 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | |
| 14 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | |
| 15 | +import cn.iocoder.yudao.module.ai.dal.mysql.chat.AiChatConversationMapper; | |
| 16 | +import cn.iocoder.yudao.module.ai.service.model.AiChatModelService; | |
| 17 | +import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService; | |
| 18 | +import jakarta.annotation.Resource; | |
| 19 | +import lombok.extern.slf4j.Slf4j; | |
| 20 | +import org.springframework.stereotype.Service; | |
| 21 | +import org.springframework.validation.annotation.Validated; | |
| 22 | + | |
| 23 | +import java.time.LocalDateTime; | |
| 24 | +import java.util.List; | |
| 25 | + | |
| 26 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 27 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 28 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_CONVERSATION_MODEL_ERROR; | |
| 29 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS; | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * AI 聊天对话 Service 实现类 | |
| 33 | + * | |
| 34 | + * @author fansili | |
| 35 | + */ | |
| 36 | +@Service | |
| 37 | +@Validated | |
| 38 | +@Slf4j | |
| 39 | +public class AiChatConversationServiceImpl implements AiChatConversationService { | |
| 40 | + | |
| 41 | + @Resource | |
| 42 | + private AiChatConversationMapper chatConversationMapper; | |
| 43 | + | |
| 44 | + @Resource | |
| 45 | + private AiChatModelService chatModalService; | |
| 46 | + @Resource | |
| 47 | + private AiChatRoleService chatRoleService; | |
| 48 | + | |
| 49 | + @Override | |
| 50 | + public Long createChatConversationMy(AiChatConversationCreateMyReqVO createReqVO, Long userId) { | |
| 51 | + // 1.1 获得 AiChatRoleDO 聊天角色 | |
| 52 | + AiChatRoleDO role = createReqVO.getRoleId() != null ? chatRoleService.validateChatRole(createReqVO.getRoleId()) : null; | |
| 53 | + // 1.2 获得 AiChatModelDO 聊天模型 | |
| 54 | + AiChatModelDO model = role != null && role.getModelId() != null ? chatModalService.validateChatModel(role.getModelId()) | |
| 55 | + : chatModalService.getRequiredDefaultChatModel(); | |
| 56 | + Assert.notNull(model, "必须找到默认模型"); | |
| 57 | + validateChatModel(model); | |
| 58 | + | |
| 59 | + // 2. 创建 AiChatConversationDO 聊天对话 | |
| 60 | + AiChatConversationDO conversation = new AiChatConversationDO().setUserId(userId).setPinned(false) | |
| 61 | + .setModelId(model.getId()).setModel(model.getModel()) | |
| 62 | + .setTemperature(model.getTemperature()).setMaxTokens(model.getMaxTokens()).setMaxContexts(model.getMaxContexts()); | |
| 63 | + if (role != null) { | |
| 64 | + conversation.setTitle(role.getName()).setRoleId(role.getId()).setSystemMessage(role.getSystemMessage()); | |
| 65 | + } else { | |
| 66 | + conversation.setTitle(AiChatConversationDO.TITLE_DEFAULT); | |
| 67 | + } | |
| 68 | + chatConversationMapper.insert(conversation); | |
| 69 | + return conversation.getId(); | |
| 70 | + } | |
| 71 | + | |
| 72 | + @Override | |
| 73 | + public void updateChatConversationMy(AiChatConversationUpdateMyReqVO updateReqVO, Long userId) { | |
| 74 | + // 1.1 校验对话是否存在 | |
| 75 | + AiChatConversationDO conversation = validateChatConversationExists(updateReqVO.getId()); | |
| 76 | + if (ObjUtil.notEqual(conversation.getUserId(), userId)) { | |
| 77 | + throw exception(CHAT_CONVERSATION_NOT_EXISTS); | |
| 78 | + } | |
| 79 | + // 1.2 校验模型是否存在(修改模型的情况) | |
| 80 | + AiChatModelDO model = null; | |
| 81 | + if (updateReqVO.getModelId() != null) { | |
| 82 | + model = chatModalService.validateChatModel(updateReqVO.getModelId()); | |
| 83 | + } | |
| 84 | + | |
| 85 | + // 2. 更新对话信息 | |
| 86 | + AiChatConversationDO updateObj = BeanUtils.toBean(updateReqVO, AiChatConversationDO.class); | |
| 87 | + if (Boolean.TRUE.equals(updateReqVO.getPinned())) { | |
| 88 | + updateObj.setPinnedTime(LocalDateTime.now()); | |
| 89 | + } | |
| 90 | + if (model != null) { | |
| 91 | + updateObj.setModel(model.getModel()); | |
| 92 | + } | |
| 93 | + chatConversationMapper.updateById(updateObj); | |
| 94 | + } | |
| 95 | + | |
| 96 | + @Override | |
| 97 | + public List<AiChatConversationDO> getChatConversationListByUserId(Long userId) { | |
| 98 | + return chatConversationMapper.selectListByUserId(userId); | |
| 99 | + } | |
| 100 | + | |
| 101 | + @Override | |
| 102 | + public AiChatConversationDO getChatConversation(Long id) { | |
| 103 | + return chatConversationMapper.selectById(id); | |
| 104 | + } | |
| 105 | + | |
| 106 | + @Override | |
| 107 | + public void deleteChatConversationMy(Long id, Long userId) { | |
| 108 | + // 1. 校验对话是否存在 | |
| 109 | + AiChatConversationDO conversation = validateChatConversationExists(id); | |
| 110 | + if (conversation == null || ObjUtil.notEqual(conversation.getUserId(), userId)) { | |
| 111 | + throw exception(CHAT_CONVERSATION_NOT_EXISTS); | |
| 112 | + } | |
| 113 | + // 2. 执行删除 | |
| 114 | + chatConversationMapper.deleteById(id); | |
| 115 | + } | |
| 116 | + | |
| 117 | + @Override | |
| 118 | + public void deleteChatConversationByAdmin(Long id) { | |
| 119 | + // 1. 校验对话是否存在 | |
| 120 | + AiChatConversationDO conversation = validateChatConversationExists(id); | |
| 121 | + if (conversation == null) { | |
| 122 | + throw exception(CHAT_CONVERSATION_NOT_EXISTS); | |
| 123 | + } | |
| 124 | + // 2. 执行删除 | |
| 125 | + chatConversationMapper.deleteById(id); | |
| 126 | + } | |
| 127 | + | |
| 128 | + private void validateChatModel(AiChatModelDO model) { | |
| 129 | + if (ObjectUtil.isAllNotEmpty(model.getTemperature(), model.getMaxTokens(), model.getMaxContexts())) { | |
| 130 | + return; | |
| 131 | + } | |
| 132 | + throw exception(CHAT_CONVERSATION_MODEL_ERROR); | |
| 133 | + } | |
| 134 | + | |
| 135 | + public AiChatConversationDO validateChatConversationExists(Long id) { | |
| 136 | + AiChatConversationDO conversation = chatConversationMapper.selectById(id); | |
| 137 | + if (conversation == null) { | |
| 138 | + throw exception(CHAT_CONVERSATION_NOT_EXISTS); | |
| 139 | + } | |
| 140 | + return conversation; | |
| 141 | + } | |
| 142 | + | |
| 143 | + @Override | |
| 144 | + public void deleteChatConversationMyByUnpinned(Long userId) { | |
| 145 | + List<AiChatConversationDO> list = chatConversationMapper.selectListByUserIdAndPinned(userId, false); | |
| 146 | + if (CollUtil.isEmpty(list)) { | |
| 147 | + return; | |
| 148 | + } | |
| 149 | + chatConversationMapper.deleteBatchIds(convertList(list, AiChatConversationDO::getId)); | |
| 150 | + } | |
| 151 | + | |
| 152 | + @Override | |
| 153 | + public PageResult<AiChatConversationDO> getChatConversationPage(AiChatConversationPageReqVO pageReqVO) { | |
| 154 | + return chatConversationMapper.selectChatConversationPage(pageReqVO); | |
| 155 | + } | |
| 156 | + | |
| 157 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.chat; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 5 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO; | |
| 6 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO; | |
| 7 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendRespVO; | |
| 8 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; | |
| 9 | +import reactor.core.publisher.Flux; | |
| 10 | + | |
| 11 | +import java.util.Collection; | |
| 12 | +import java.util.List; | |
| 13 | +import java.util.Map; | |
| 14 | + | |
| 15 | +/** | |
| 16 | + * AI 聊天消息 Service 接口 | |
| 17 | + * | |
| 18 | + * @author fansili | |
| 19 | + */ | |
| 20 | +public interface AiChatMessageService { | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * 发送消息 | |
| 24 | + * | |
| 25 | + * @param sendReqVO 发送信息 | |
| 26 | + * @param userId 用户编号 | |
| 27 | + * @return 发送结果 | |
| 28 | + */ | |
| 29 | + AiChatMessageSendRespVO sendMessage(AiChatMessageSendReqVO sendReqVO, Long userId); | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * 发送消息 | |
| 33 | + * | |
| 34 | + * @param sendReqVO 发送信息 | |
| 35 | + * @param userId 用户编号 | |
| 36 | + * @return 发送结果 | |
| 37 | + */ | |
| 38 | + Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId); | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * 获得指定对话的消息列表 | |
| 42 | + * | |
| 43 | + * @param conversationId 对话编号 | |
| 44 | + * @return 消息列表 | |
| 45 | + */ | |
| 46 | + List<AiChatMessageDO> getChatMessageListByConversationId(Long conversationId); | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * 删除消息 | |
| 50 | + * | |
| 51 | + * @param id 消息编号 | |
| 52 | + * @param userId 用户编号 | |
| 53 | + */ | |
| 54 | + void deleteChatMessage(Long id, Long userId); | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * 删除指定对话的消息 | |
| 58 | + * | |
| 59 | + * @param conversationId 对话编号 | |
| 60 | + * @param userId 用户编号 | |
| 61 | + */ | |
| 62 | + void deleteChatMessageByConversationId(Long conversationId, Long userId); | |
| 63 | + | |
| 64 | + /** | |
| 65 | + * 【管理员】删除消息 | |
| 66 | + * | |
| 67 | + * @param id 消息编号 | |
| 68 | + */ | |
| 69 | + void deleteChatMessageByAdmin(Long id); | |
| 70 | + | |
| 71 | + /** | |
| 72 | + * 获得聊天对话的消息数量 Map | |
| 73 | + * | |
| 74 | + * @param conversationIds 对话编号数组 | |
| 75 | + * @return 消息数量 Map | |
| 76 | + */ | |
| 77 | + Map<Long, Integer> getChatMessageCountMap(Collection<Long> conversationIds); | |
| 78 | + | |
| 79 | + /** | |
| 80 | + * 获得聊天消息的分页 | |
| 81 | + * | |
| 82 | + * @param pageReqVO 分页查询 | |
| 83 | + * @return 聊天消息的分页 | |
| 84 | + */ | |
| 85 | + PageResult<AiChatMessageDO> getChatMessagePage(AiChatMessagePageReqVO pageReqVO); | |
| 86 | + | |
| 87 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.chat; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.util.ObjUtil; | |
| 5 | +import cn.hutool.core.util.StrUtil; | |
| 6 | +import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; | |
| 7 | +import cn.iocoder.yudao.framework.ai.core.util.AiUtils; | |
| 8 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 9 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 10 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 11 | +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | |
| 12 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO; | |
| 13 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO; | |
| 14 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendRespVO; | |
| 15 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; | |
| 16 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; | |
| 17 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | |
| 18 | +import cn.iocoder.yudao.module.ai.dal.mysql.chat.AiChatMessageMapper; | |
| 19 | +import cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants; | |
| 20 | +import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService; | |
| 21 | +import cn.iocoder.yudao.module.ai.service.model.AiChatModelService; | |
| 22 | +import jakarta.annotation.Resource; | |
| 23 | +import lombok.extern.slf4j.Slf4j; | |
| 24 | +import org.springframework.ai.chat.messages.*; | |
| 25 | +import org.springframework.ai.chat.model.ChatModel; | |
| 26 | +import org.springframework.ai.chat.model.ChatResponse; | |
| 27 | +import org.springframework.ai.chat.model.StreamingChatModel; | |
| 28 | +import org.springframework.ai.chat.prompt.ChatOptions; | |
| 29 | +import org.springframework.ai.chat.prompt.Prompt; | |
| 30 | +import org.springframework.stereotype.Service; | |
| 31 | +import org.springframework.transaction.annotation.Transactional; | |
| 32 | +import reactor.core.publisher.Flux; | |
| 33 | + | |
| 34 | +import java.time.LocalDateTime; | |
| 35 | +import java.util.*; | |
| 36 | + | |
| 37 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 38 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error; | |
| 39 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 40 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 41 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS; | |
| 42 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_MESSAGE_NOT_EXIST; | |
| 43 | + | |
| 44 | +/** | |
| 45 | + * AI 聊天消息 Service 实现类 | |
| 46 | + * | |
| 47 | + * @author fansili | |
| 48 | + */ | |
| 49 | +@Service | |
| 50 | +@Slf4j | |
| 51 | +public class AiChatMessageServiceImpl implements AiChatMessageService { | |
| 52 | + | |
| 53 | + @Resource | |
| 54 | + private AiChatMessageMapper chatMessageMapper; | |
| 55 | + | |
| 56 | + @Resource | |
| 57 | + private AiChatConversationService chatConversationService; | |
| 58 | + @Resource | |
| 59 | + private AiChatModelService chatModalService; | |
| 60 | + @Resource | |
| 61 | + private AiApiKeyService apiKeyService; | |
| 62 | + | |
| 63 | + @Transactional(rollbackFor = Exception.class) | |
| 64 | + public AiChatMessageSendRespVO sendMessage(AiChatMessageSendReqVO sendReqVO, Long userId) { | |
| 65 | + // 1.1 校验对话存在 | |
| 66 | + AiChatConversationDO conversation = chatConversationService.validateChatConversationExists(sendReqVO.getConversationId()); | |
| 67 | + if (ObjUtil.notEqual(conversation.getUserId(), userId)) { | |
| 68 | + throw exception(CHAT_CONVERSATION_NOT_EXISTS); | |
| 69 | + } | |
| 70 | + List<AiChatMessageDO> historyMessages = chatMessageMapper.selectListByConversationId(conversation.getId()); | |
| 71 | + // 1.2 校验模型 | |
| 72 | + AiChatModelDO model = chatModalService.validateChatModel(conversation.getModelId()); | |
| 73 | + ChatModel chatModel = apiKeyService.getChatModel(model.getKeyId()); | |
| 74 | + | |
| 75 | + // 2. 插入 user 发送消息 | |
| 76 | + AiChatMessageDO userMessage = createChatMessage(conversation.getId(), null, model, | |
| 77 | + userId, conversation.getRoleId(), MessageType.USER, sendReqVO.getContent(), sendReqVO.getUseContext()); | |
| 78 | + | |
| 79 | + // 3.1 插入 assistant 接收消息 | |
| 80 | + AiChatMessageDO assistantMessage = createChatMessage(conversation.getId(), userMessage.getId(), model, | |
| 81 | + userId, conversation.getRoleId(), MessageType.ASSISTANT, "", sendReqVO.getUseContext()); | |
| 82 | + | |
| 83 | + // 3.2 创建 chat 需要的 Prompt | |
| 84 | + Prompt prompt = buildPrompt(conversation, historyMessages, model, sendReqVO); | |
| 85 | + ChatResponse chatResponse = chatModel.call(prompt); | |
| 86 | + | |
| 87 | + // 3.3 段式返回 | |
| 88 | + String newContent = chatResponse.getResult().getOutput().getContent(); | |
| 89 | + chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(newContent)); | |
| 90 | + return new AiChatMessageSendRespVO().setSend(BeanUtils.toBean(userMessage, AiChatMessageSendRespVO.Message.class)) | |
| 91 | + .setReceive(BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class).setContent(newContent)); | |
| 92 | + } | |
| 93 | + | |
| 94 | + @Override | |
| 95 | + public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId) { | |
| 96 | + // 1.1 校验对话存在 | |
| 97 | + AiChatConversationDO conversation = chatConversationService.validateChatConversationExists(sendReqVO.getConversationId()); | |
| 98 | + if (ObjUtil.notEqual(conversation.getUserId(), userId)) { | |
| 99 | + throw exception(CHAT_CONVERSATION_NOT_EXISTS); | |
| 100 | + } | |
| 101 | + List<AiChatMessageDO> historyMessages = chatMessageMapper.selectListByConversationId(conversation.getId()); | |
| 102 | + // 1.2 校验模型 | |
| 103 | + AiChatModelDO model = chatModalService.validateChatModel(conversation.getModelId()); | |
| 104 | + StreamingChatModel chatModel = apiKeyService.getChatModel(model.getKeyId()); | |
| 105 | + | |
| 106 | + // 2. 插入 user 发送消息 | |
| 107 | + AiChatMessageDO userMessage = createChatMessage(conversation.getId(), null, model, | |
| 108 | + userId, conversation.getRoleId(), MessageType.USER, sendReqVO.getContent(), sendReqVO.getUseContext()); | |
| 109 | + | |
| 110 | + // 3.1 插入 assistant 接收消息 | |
| 111 | + AiChatMessageDO assistantMessage = createChatMessage(conversation.getId(), userMessage.getId(), model, | |
| 112 | + userId, conversation.getRoleId(), MessageType.ASSISTANT, "", sendReqVO.getUseContext()); | |
| 113 | + | |
| 114 | + // 3.2 构建 Prompt,并进行调用 | |
| 115 | + Prompt prompt = buildPrompt(conversation, historyMessages, model, sendReqVO); | |
| 116 | + Flux<ChatResponse> streamResponse = chatModel.stream(prompt); | |
| 117 | + | |
| 118 | + // 3.3 流式返回 | |
| 119 | + // TODO 注意:Schedulers.immediate() 目的是,避免默认 Schedulers.parallel() 并发消费 chunk 导致 SSE 响应前端会乱序问题 | |
| 120 | + StringBuffer contentBuffer = new StringBuffer(); | |
| 121 | + return streamResponse.map(chunk -> { | |
| 122 | + String newContent = chunk.getResult() != null ? chunk.getResult().getOutput().getContent() : null; | |
| 123 | + newContent = StrUtil.nullToDefault(newContent, ""); // 避免 null 的 情况 | |
| 124 | + contentBuffer.append(newContent); | |
| 125 | + // 响应结果 | |
| 126 | + return success(new AiChatMessageSendRespVO().setSend(BeanUtils.toBean(userMessage, AiChatMessageSendRespVO.Message.class)) | |
| 127 | + .setReceive(BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class).setContent(newContent))); | |
| 128 | + }).doOnComplete(() -> { | |
| 129 | + // 忽略租户,因为 Flux 异步无法透传租户 | |
| 130 | + TenantUtils.executeIgnore(() -> | |
| 131 | + chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(contentBuffer.toString()))); | |
| 132 | + }).doOnError(throwable -> { | |
| 133 | + log.error("[sendChatMessageStream][userId({}) sendReqVO({}) 发生异常]", userId, sendReqVO, throwable); | |
| 134 | + // 忽略租户,因为 Flux 异步无法透传租户 | |
| 135 | + TenantUtils.executeIgnore(() -> | |
| 136 | + chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(throwable.getMessage()))); | |
| 137 | + }).onErrorResume(error -> Flux.just(error(ErrorCodeConstants.CHAT_STREAM_ERROR))); | |
| 138 | + } | |
| 139 | + | |
| 140 | + private Prompt buildPrompt(AiChatConversationDO conversation, List<AiChatMessageDO> messages, | |
| 141 | + AiChatModelDO model, AiChatMessageSendReqVO sendReqVO) { | |
| 142 | + // 1. 构建 Prompt Message 列表 | |
| 143 | + List<Message> chatMessages = new ArrayList<>(); | |
| 144 | + // 1.1 system context 角色设定 | |
| 145 | + if (StrUtil.isNotBlank(conversation.getSystemMessage())) { | |
| 146 | + chatMessages.add(new SystemMessage(conversation.getSystemMessage())); | |
| 147 | + } | |
| 148 | + // 1.2 history message 历史消息 | |
| 149 | + List<AiChatMessageDO> contextMessages = filterContextMessages(messages, conversation, sendReqVO); | |
| 150 | + contextMessages.forEach(message -> chatMessages.add(AiUtils.buildMessage(message.getType(), message.getContent()))); | |
| 151 | + // 1.3 user message 新发送消息 | |
| 152 | + chatMessages.add(new UserMessage(sendReqVO.getContent())); | |
| 153 | + | |
| 154 | + // 2. 构建 ChatOptions 对象 | |
| 155 | + AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform()); | |
| 156 | + ChatOptions chatOptions = AiUtils.buildChatOptions(platform, model.getModel(), | |
| 157 | + conversation.getTemperature(), conversation.getMaxTokens()); | |
| 158 | + return new Prompt(chatMessages, chatOptions); | |
| 159 | + } | |
| 160 | + | |
| 161 | + /** | |
| 162 | + * 从历史消息中,获得倒序的 n 组消息作为消息上下文 | |
| 163 | + * | |
| 164 | + * n 组:指的是 user + assistant 形成一组 | |
| 165 | + * | |
| 166 | + * @param messages 消息列表 | |
| 167 | + * @param conversation 对话 | |
| 168 | + * @param sendReqVO 发送请求 | |
| 169 | + * @return 消息上下文 | |
| 170 | + */ | |
| 171 | + private List<AiChatMessageDO> filterContextMessages(List<AiChatMessageDO> messages, | |
| 172 | + AiChatConversationDO conversation, | |
| 173 | + AiChatMessageSendReqVO sendReqVO) { | |
| 174 | + if (conversation.getMaxContexts() == null || ObjUtil.notEqual(sendReqVO.getUseContext(), Boolean.TRUE)) { | |
| 175 | + return Collections.emptyList(); | |
| 176 | + } | |
| 177 | + List<AiChatMessageDO> contextMessages = new ArrayList<>(conversation.getMaxContexts() * 2); | |
| 178 | + for (int i = messages.size() - 1; i >= 0; i--) { | |
| 179 | + AiChatMessageDO assistantMessage = CollUtil.get(messages, i); | |
| 180 | + if (assistantMessage == null || assistantMessage.getReplyId() == null) { | |
| 181 | + continue; | |
| 182 | + } | |
| 183 | + AiChatMessageDO userMessage = CollUtil.get(messages, i - 1); | |
| 184 | + if (userMessage == null || ObjUtil.notEqual(assistantMessage.getReplyId(), userMessage.getId()) | |
| 185 | + || StrUtil.isEmpty(assistantMessage.getContent())) { | |
| 186 | + continue; | |
| 187 | + } | |
| 188 | + // 由于后续要 reverse 反转,所以先添加 assistantMessage | |
| 189 | + contextMessages.add(assistantMessage); | |
| 190 | + contextMessages.add(userMessage); | |
| 191 | + // 超过最大上下文,结束 | |
| 192 | + if (contextMessages.size() >= conversation.getMaxContexts() * 2) { | |
| 193 | + break; | |
| 194 | + } | |
| 195 | + } | |
| 196 | + Collections.reverse(contextMessages); | |
| 197 | + return contextMessages; | |
| 198 | + } | |
| 199 | + | |
| 200 | + private AiChatMessageDO createChatMessage(Long conversationId, Long replyId, | |
| 201 | + AiChatModelDO model, Long userId, Long roleId, | |
| 202 | + MessageType messageType, String content, Boolean useContext) { | |
| 203 | + AiChatMessageDO message = new AiChatMessageDO().setConversationId(conversationId).setReplyId(replyId) | |
| 204 | + .setModel(model.getModel()).setModelId(model.getId()).setUserId(userId).setRoleId(roleId) | |
| 205 | + .setType(messageType.getValue()).setContent(content).setUseContext(useContext); | |
| 206 | + message.setCreateTime(LocalDateTime.now()); | |
| 207 | + chatMessageMapper.insert(message); | |
| 208 | + return message; | |
| 209 | + } | |
| 210 | + | |
| 211 | + @Override | |
| 212 | + public List<AiChatMessageDO> getChatMessageListByConversationId(Long conversationId) { | |
| 213 | + return chatMessageMapper.selectListByConversationId(conversationId); | |
| 214 | + } | |
| 215 | + | |
| 216 | + @Override | |
| 217 | + public void deleteChatMessage(Long id, Long userId) { | |
| 218 | + // 1. 校验消息存在 | |
| 219 | + AiChatMessageDO message = chatMessageMapper.selectById(id); | |
| 220 | + if (message == null || ObjUtil.notEqual(message.getUserId(), userId)) { | |
| 221 | + throw exception(CHAT_MESSAGE_NOT_EXIST); | |
| 222 | + } | |
| 223 | + // 2. 执行删除 | |
| 224 | + chatMessageMapper.deleteById(id); | |
| 225 | + } | |
| 226 | + | |
| 227 | + @Override | |
| 228 | + public void deleteChatMessageByConversationId(Long conversationId, Long userId) { | |
| 229 | + // 1. 校验消息存在 | |
| 230 | + List<AiChatMessageDO> messages = chatMessageMapper.selectListByConversationId(conversationId); | |
| 231 | + if (CollUtil.isEmpty(messages) || ObjUtil.notEqual(messages.get(0).getUserId(), userId)) { | |
| 232 | + throw exception(CHAT_MESSAGE_NOT_EXIST); | |
| 233 | + } | |
| 234 | + // 2. 执行删除 | |
| 235 | + chatMessageMapper.deleteBatchIds(convertList(messages, AiChatMessageDO::getId)); | |
| 236 | + } | |
| 237 | + | |
| 238 | + @Override | |
| 239 | + public void deleteChatMessageByAdmin(Long id) { | |
| 240 | + // 1. 校验消息存在 | |
| 241 | + AiChatMessageDO message = chatMessageMapper.selectById(id); | |
| 242 | + if (message == null) { | |
| 243 | + throw exception(CHAT_MESSAGE_NOT_EXIST); | |
| 244 | + } | |
| 245 | + // 2. 执行删除 | |
| 246 | + chatMessageMapper.deleteById(id); | |
| 247 | + } | |
| 248 | + | |
| 249 | + @Override | |
| 250 | + public Map<Long, Integer> getChatMessageCountMap(Collection<Long> conversationIds) { | |
| 251 | + return chatMessageMapper.selectCountMapByConversationId(conversationIds); | |
| 252 | + } | |
| 253 | + | |
| 254 | + @Override | |
| 255 | + public PageResult<AiChatMessageDO> getChatMessagePage(AiChatMessagePageReqVO pageReqVO) { | |
| 256 | + return chatMessageMapper.selectPage(pageReqVO); | |
| 257 | + } | |
| 258 | + | |
| 259 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.image; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 5 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 6 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDrawReqVO; | |
| 7 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImagePageReqVO; | |
| 8 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageUpdateReqVO; | |
| 9 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.midjourney.AiMidjourneyActionReqVO; | |
| 10 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.midjourney.AiMidjourneyImagineReqVO; | |
| 11 | +import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO; | |
| 12 | +import jakarta.validation.Valid; | |
| 13 | + | |
| 14 | +import java.util.List; | |
| 15 | + | |
| 16 | +/** | |
| 17 | + * AI 绘图 Service 接口 | |
| 18 | + * | |
| 19 | + * @author fansili | |
| 20 | + */ | |
| 21 | +public interface AiImageService { | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * 获取【我的】绘图分页 | |
| 25 | + * | |
| 26 | + * @param userId 用户编号 | |
| 27 | + * @param pageReqVO 分页条件 | |
| 28 | + * @return 绘图分页 | |
| 29 | + */ | |
| 30 | + PageResult<AiImageDO> getImagePageMy(Long userId, PageParam pageReqVO); | |
| 31 | + | |
| 32 | + /** | |
| 33 | + * 获得绘图记录 | |
| 34 | + * | |
| 35 | + * @param id 绘图编号 | |
| 36 | + * @return 绘图记录 | |
| 37 | + */ | |
| 38 | + AiImageDO getImage(Long id); | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * 获得绘图列表 | |
| 42 | + * | |
| 43 | + * @param ids 绘图编号数组 | |
| 44 | + * @return 绘图记录列表 | |
| 45 | + */ | |
| 46 | + List<AiImageDO> getImageList(List<Long> ids); | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * 绘制图片 | |
| 50 | + * | |
| 51 | + * @param userId 用户编号 | |
| 52 | + * @param drawReqVO 绘制请求 | |
| 53 | + * @return 绘画编号 | |
| 54 | + */ | |
| 55 | + Long drawImage(Long userId, AiImageDrawReqVO drawReqVO); | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * 删除【我的】绘画记录 | |
| 59 | + * | |
| 60 | + * @param id 绘画编号 | |
| 61 | + * @param userId 用户编号 | |
| 62 | + */ | |
| 63 | + void deleteImageMy(Long id, Long userId); | |
| 64 | + | |
| 65 | + /** | |
| 66 | + * 获得绘画分页 | |
| 67 | + * | |
| 68 | + * @param pageReqVO 分页查询 | |
| 69 | + * @return 绘画分页 | |
| 70 | + */ | |
| 71 | + PageResult<AiImageDO> getImagePage(AiImagePageReqVO pageReqVO); | |
| 72 | + | |
| 73 | + /** | |
| 74 | + * 更新绘画 | |
| 75 | + * | |
| 76 | + * @param updateReqVO 更新信息 | |
| 77 | + */ | |
| 78 | + void updateImage(@Valid AiImageUpdateReqVO updateReqVO); | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * 删除绘画 | |
| 82 | + * | |
| 83 | + * @param id 编号 | |
| 84 | + */ | |
| 85 | + void deleteImage(Long id); | |
| 86 | + | |
| 87 | + // ================ midjourney 专属 ================ | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * 【Midjourney】生成图片 | |
| 91 | + * | |
| 92 | + * @param userId 用户编号 | |
| 93 | + * @param reqVO 绘制请求 | |
| 94 | + * @return 绘画编号 | |
| 95 | + */ | |
| 96 | + Long midjourneyImagine(Long userId, AiMidjourneyImagineReqVO reqVO); | |
| 97 | + | |
| 98 | + /** | |
| 99 | + * 【Midjourney】同步图片进展 | |
| 100 | + * | |
| 101 | + * @return 同步成功数量 | |
| 102 | + */ | |
| 103 | + Integer midjourneySync(); | |
| 104 | + | |
| 105 | + /** | |
| 106 | + * 【Midjourney】通知图片进展 | |
| 107 | + * | |
| 108 | + * @param notify 通知 | |
| 109 | + */ | |
| 110 | + void midjourneyNotify(MidjourneyApi.Notify notify); | |
| 111 | + | |
| 112 | + /** | |
| 113 | + * 【Midjourney】Action 操作(放大、缩小、U1、U2...) | |
| 114 | + * | |
| 115 | + * @param userId 用户编号 | |
| 116 | + * @param reqVO 绘制请求 | |
| 117 | + * @return 绘画编号 | |
| 118 | + */ | |
| 119 | + Long midjourneyAction(Long userId, AiMidjourneyActionReqVO reqVO); | |
| 120 | + | |
| 121 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.image; | |
| 2 | + | |
| 3 | +import cn.hutool.core.bean.BeanUtil; | |
| 4 | +import cn.hutool.core.codec.Base64; | |
| 5 | +import cn.hutool.core.collection.CollUtil; | |
| 6 | +import cn.hutool.core.map.MapUtil; | |
| 7 | +import cn.hutool.core.util.ObjUtil; | |
| 8 | +import cn.hutool.core.util.StrUtil; | |
| 9 | +import cn.hutool.extra.spring.SpringUtil; | |
| 10 | +import cn.hutool.http.HttpUtil; | |
| 11 | +import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; | |
| 12 | +import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; | |
| 13 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 14 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 15 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 16 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDrawReqVO; | |
| 17 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImagePageReqVO; | |
| 18 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageUpdateReqVO; | |
| 19 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.midjourney.AiMidjourneyActionReqVO; | |
| 20 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.midjourney.AiMidjourneyImagineReqVO; | |
| 21 | +import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO; | |
| 22 | +import cn.iocoder.yudao.module.ai.dal.mysql.image.AiImageMapper; | |
| 23 | +import cn.iocoder.yudao.module.ai.enums.image.AiImageStatusEnum; | |
| 24 | +import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService; | |
| 25 | +import cn.iocoder.yudao.module.infra.api.file.FileApi; | |
| 26 | +import com.alibaba.cloud.ai.tongyi.image.TongYiImagesOptions; | |
| 27 | +import jakarta.annotation.Resource; | |
| 28 | +import lombok.extern.slf4j.Slf4j; | |
| 29 | +import org.springframework.ai.image.ImageModel; | |
| 30 | +import org.springframework.ai.image.ImageOptions; | |
| 31 | +import org.springframework.ai.image.ImagePrompt; | |
| 32 | +import org.springframework.ai.image.ImageResponse; | |
| 33 | +import org.springframework.ai.openai.OpenAiImageOptions; | |
| 34 | +import org.springframework.ai.qianfan.QianFanImageOptions; | |
| 35 | +import org.springframework.ai.stabilityai.api.StabilityAiImageOptions; | |
| 36 | +import org.springframework.scheduling.annotation.Async; | |
| 37 | +import org.springframework.stereotype.Service; | |
| 38 | +import org.springframework.transaction.annotation.Transactional; | |
| 39 | + | |
| 40 | +import java.time.LocalDateTime; | |
| 41 | +import java.util.Collections; | |
| 42 | +import java.util.List; | |
| 43 | +import java.util.Map; | |
| 44 | + | |
| 45 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 46 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | |
| 47 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | |
| 48 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.*; | |
| 49 | + | |
| 50 | +/** | |
| 51 | + * AI 绘画 Service 实现类 | |
| 52 | + * | |
| 53 | + * @author fansili | |
| 54 | + */ | |
| 55 | +@Service | |
| 56 | +@Slf4j | |
| 57 | +public class AiImageServiceImpl implements AiImageService { | |
| 58 | + | |
| 59 | + @Resource | |
| 60 | + private AiImageMapper imageMapper; | |
| 61 | + | |
| 62 | + @Resource | |
| 63 | + private FileApi fileApi; | |
| 64 | + | |
| 65 | + @Resource | |
| 66 | + private AiApiKeyService apiKeyService; | |
| 67 | + | |
| 68 | + @Override | |
| 69 | + public PageResult<AiImageDO> getImagePageMy(Long userId, PageParam pageReqVO) { | |
| 70 | + return imageMapper.selectPage(userId, pageReqVO); | |
| 71 | + } | |
| 72 | + | |
| 73 | + @Override | |
| 74 | + public AiImageDO getImage(Long id) { | |
| 75 | + return imageMapper.selectById(id); | |
| 76 | + } | |
| 77 | + | |
| 78 | + @Override | |
| 79 | + public List<AiImageDO> getImageList(List<Long> ids) { | |
| 80 | + if (CollUtil.isEmpty(ids)) { | |
| 81 | + return Collections.emptyList(); | |
| 82 | + } | |
| 83 | + return imageMapper.selectBatchIds(ids); | |
| 84 | + } | |
| 85 | + | |
| 86 | + @Override | |
| 87 | + public Long drawImage(Long userId, AiImageDrawReqVO drawReqVO) { | |
| 88 | + // 1. 保存数据库 | |
| 89 | + AiImageDO image = BeanUtils.toBean(drawReqVO, AiImageDO.class).setUserId(userId).setPublicStatus(false) | |
| 90 | + .setStatus(AiImageStatusEnum.IN_PROGRESS.getStatus()); | |
| 91 | + imageMapper.insert(image); | |
| 92 | + // 2. 异步绘制,后续前端通过返回的 id 进行轮询结果 | |
| 93 | + getSelf().executeDrawImage(image, drawReqVO); | |
| 94 | + return image.getId(); | |
| 95 | + } | |
| 96 | + | |
| 97 | + @Async | |
| 98 | + public void executeDrawImage(AiImageDO image, AiImageDrawReqVO req) { | |
| 99 | + try { | |
| 100 | + // 1.1 构建请求 | |
| 101 | + ImageOptions request = buildImageOptions(req); | |
| 102 | + // 1.2 执行请求 | |
| 103 | + ImageModel imageModel = apiKeyService.getImageModel(AiPlatformEnum.validatePlatform(req.getPlatform())); | |
| 104 | + ImageResponse response = imageModel.call(new ImagePrompt(req.getPrompt(), request)); | |
| 105 | + | |
| 106 | + // 2. 上传到文件服务 | |
| 107 | + byte[] fileContent = Base64.decode(response.getResult().getOutput().getB64Json()); | |
| 108 | + String filePath = fileApi.createFile(fileContent); | |
| 109 | + | |
| 110 | + // 3. 更新数据库 | |
| 111 | + imageMapper.updateById(new AiImageDO().setId(image.getId()).setStatus(AiImageStatusEnum.SUCCESS.getStatus()) | |
| 112 | + .setPicUrl(filePath).setFinishTime(LocalDateTime.now())); | |
| 113 | + } catch (Exception ex) { | |
| 114 | + log.error("[doDall][image({}) 生成异常]", image, ex); | |
| 115 | + imageMapper.updateById(new AiImageDO().setId(image.getId()) | |
| 116 | + .setStatus(AiImageStatusEnum.FAIL.getStatus()) | |
| 117 | + .setErrorMessage(ex.getMessage()).setFinishTime(LocalDateTime.now())); | |
| 118 | + } | |
| 119 | + } | |
| 120 | + | |
| 121 | + private static ImageOptions buildImageOptions(AiImageDrawReqVO draw) { | |
| 122 | + if (ObjUtil.equal(draw.getPlatform(), AiPlatformEnum.OPENAI.getPlatform())) { | |
| 123 | + // https://platform.openai.com/docs/api-reference/images/create | |
| 124 | + return OpenAiImageOptions.builder().withModel(draw.getModel()) | |
| 125 | + .withHeight(draw.getHeight()).withWidth(draw.getWidth()) | |
| 126 | + .withStyle(MapUtil.getStr(draw.getOptions(), "style")) // 风格 | |
| 127 | + .withResponseFormat("b64_json") | |
| 128 | + .build(); | |
| 129 | + } else if (ObjUtil.equal(draw.getPlatform(), AiPlatformEnum.STABLE_DIFFUSION.getPlatform())) { | |
| 130 | + // https://platform.stability.ai/docs/api-reference#tag/SDXL-and-SD1.6/operation/textToImage | |
| 131 | + // https://platform.stability.ai/docs/api-reference#tag/Text-to-Image/operation/textToImage | |
| 132 | + return StabilityAiImageOptions.builder().withModel(draw.getModel()) | |
| 133 | + .withHeight(draw.getHeight()).withWidth(draw.getWidth()) | |
| 134 | + .withSeed(Long.valueOf(draw.getOptions().get("seed"))) | |
| 135 | + .withCfgScale(Float.valueOf(draw.getOptions().get("scale"))) | |
| 136 | + .withSteps(Integer.valueOf(draw.getOptions().get("steps"))) | |
| 137 | + .withSampler(String.valueOf(draw.getOptions().get("sampler"))) | |
| 138 | + .withStylePreset(String.valueOf(draw.getOptions().get("stylePreset"))) | |
| 139 | + .withClipGuidancePreset(String.valueOf(draw.getOptions().get("clipGuidancePreset"))) | |
| 140 | + .build(); | |
| 141 | + } else if (ObjUtil.equal(draw.getPlatform(), AiPlatformEnum.TONG_YI.getPlatform())) { | |
| 142 | + return TongYiImagesOptions.builder() | |
| 143 | + .withModel(draw.getModel()).withN(1) | |
| 144 | + .withHeight(draw.getHeight()).withWidth(draw.getWidth()) | |
| 145 | + .build(); | |
| 146 | + } else if (ObjUtil.equal(draw.getPlatform(), AiPlatformEnum.YI_YAN.getPlatform())) { | |
| 147 | + return QianFanImageOptions.builder() | |
| 148 | + .withModel(draw.getModel()).withN(1) | |
| 149 | + .withHeight(draw.getHeight()).withWidth(draw.getWidth()) | |
| 150 | + .build(); | |
| 151 | + } | |
| 152 | + throw new IllegalArgumentException("不支持的 AI 平台:" + draw.getPlatform()); | |
| 153 | + } | |
| 154 | + | |
| 155 | + @Override | |
| 156 | + public void deleteImageMy(Long id, Long userId) { | |
| 157 | + // 1. 校验是否存在 | |
| 158 | + AiImageDO image = validateImageExists(id); | |
| 159 | + if (ObjUtil.notEqual(image.getUserId(), userId)) { | |
| 160 | + throw exception(IMAGE_NOT_EXISTS); | |
| 161 | + } | |
| 162 | + // 2. 删除记录 | |
| 163 | + imageMapper.deleteById(id); | |
| 164 | + } | |
| 165 | + | |
| 166 | + @Override | |
| 167 | + public PageResult<AiImageDO> getImagePage(AiImagePageReqVO pageReqVO) { | |
| 168 | + return imageMapper.selectPage(pageReqVO); | |
| 169 | + } | |
| 170 | + | |
| 171 | + @Override | |
| 172 | + public void updateImage(AiImageUpdateReqVO updateReqVO) { | |
| 173 | + // 1. 校验存在 | |
| 174 | + validateImageExists(updateReqVO.getId()); | |
| 175 | + // 2. 更新发布状态 | |
| 176 | + imageMapper.updateById(BeanUtils.toBean(updateReqVO, AiImageDO.class)); | |
| 177 | + } | |
| 178 | + | |
| 179 | + @Override | |
| 180 | + public void deleteImage(Long id) { | |
| 181 | + // 1. 校验存在 | |
| 182 | + validateImageExists(id); | |
| 183 | + // 2. 删除 | |
| 184 | + imageMapper.deleteById(id); | |
| 185 | + } | |
| 186 | + | |
| 187 | + private AiImageDO validateImageExists(Long id) { | |
| 188 | + AiImageDO image = imageMapper.selectById(id); | |
| 189 | + if (image == null) { | |
| 190 | + throw exception(IMAGE_NOT_EXISTS); | |
| 191 | + } | |
| 192 | + return image; | |
| 193 | + } | |
| 194 | + | |
| 195 | + // ================ midjourney 专属 ================ | |
| 196 | + | |
| 197 | + @Override | |
| 198 | + @Transactional(rollbackFor = Exception.class) | |
| 199 | + public Long midjourneyImagine(Long userId, AiMidjourneyImagineReqVO reqVO) { | |
| 200 | + MidjourneyApi midjourneyApi = apiKeyService.getMidjourneyApi(); | |
| 201 | + // 1. 保存数据库 | |
| 202 | + AiImageDO image = BeanUtils.toBean(reqVO, AiImageDO.class).setUserId(userId).setPublicStatus(false) | |
| 203 | + .setStatus(AiImageStatusEnum.IN_PROGRESS.getStatus()) | |
| 204 | + .setPlatform(AiPlatformEnum.MIDJOURNEY.getPlatform()); | |
| 205 | + imageMapper.insert(image); | |
| 206 | + | |
| 207 | + // 2. 调用 Midjourney Proxy 提交任务 | |
| 208 | + List<String> base64Array = StrUtil.isBlank(reqVO.getReferImageUrl()) ? null : | |
| 209 | + Collections.singletonList("data:image/jpeg;base64,".concat(Base64.encode(HttpUtil.downloadBytes(reqVO.getReferImageUrl())))); | |
| 210 | + MidjourneyApi.ImagineRequest imagineRequest = new MidjourneyApi.ImagineRequest( | |
| 211 | + base64Array, reqVO.getPrompt(),null, | |
| 212 | + MidjourneyApi.ImagineRequest.buildState(reqVO.getWidth(), | |
| 213 | + reqVO.getHeight(), reqVO.getVersion(), reqVO.getModel())); | |
| 214 | + MidjourneyApi.SubmitResponse imagineResponse = midjourneyApi.imagine(imagineRequest); | |
| 215 | + | |
| 216 | + // 3. 情况一【失败】:抛出业务异常 | |
| 217 | + if (!MidjourneyApi.SubmitCodeEnum.SUCCESS_CODES.contains(imagineResponse.code())) { | |
| 218 | + String description = imagineResponse.description().contains("quota_not_enough") ? | |
| 219 | + "账户余额不足" : imagineResponse.description(); | |
| 220 | + throw exception(IMAGE_MIDJOURNEY_SUBMIT_FAIL, description); | |
| 221 | + } | |
| 222 | + | |
| 223 | + // 4. 情况二【成功】:更新 taskId 和参数 | |
| 224 | + imageMapper.updateById(new AiImageDO().setId(image.getId()) | |
| 225 | + .setTaskId(imagineResponse.result()).setOptions(BeanUtil.beanToMap(reqVO))); | |
| 226 | + return image.getId(); | |
| 227 | + } | |
| 228 | + | |
| 229 | + @Override | |
| 230 | + public Integer midjourneySync() { | |
| 231 | + MidjourneyApi midjourneyApi = apiKeyService.getMidjourneyApi(); | |
| 232 | + // 1.1 获取 Midjourney 平台,状态在 “进行中” 的 image | |
| 233 | + List<AiImageDO> imageList = imageMapper.selectListByStatusAndPlatform( | |
| 234 | + AiImageStatusEnum.IN_PROGRESS.getStatus(), AiPlatformEnum.MIDJOURNEY.getPlatform()); | |
| 235 | + if (CollUtil.isEmpty(imageList)) { | |
| 236 | + return 0; | |
| 237 | + } | |
| 238 | + // 1.2 调用 Midjourney Proxy 获取任务进展 | |
| 239 | + List<MidjourneyApi.Notify> taskList = midjourneyApi.getTaskList(convertSet(imageList, AiImageDO::getTaskId)); | |
| 240 | + Map<String, MidjourneyApi.Notify> taskMap = convertMap(taskList, MidjourneyApi.Notify::id); | |
| 241 | + | |
| 242 | + // 2. 逐个处理,更新进展 | |
| 243 | + int count = 0; | |
| 244 | + for (AiImageDO image : imageList) { | |
| 245 | + MidjourneyApi.Notify notify = taskMap.get(image.getTaskId()); | |
| 246 | + if (notify == null) { | |
| 247 | + log.error("[midjourneySync][image({}) 查询不到进展]", image); | |
| 248 | + continue; | |
| 249 | + } | |
| 250 | + count++; | |
| 251 | + updateMidjourneyStatus(image, notify); | |
| 252 | + } | |
| 253 | + return count; | |
| 254 | + } | |
| 255 | + | |
| 256 | + @Override | |
| 257 | + public void midjourneyNotify(MidjourneyApi.Notify notify) { | |
| 258 | + // 1. 校验 image 存在 | |
| 259 | + AiImageDO image = imageMapper.selectByTaskId(notify.id()); | |
| 260 | + if (image == null) { | |
| 261 | + log.warn("[midjourneyNotify][回调任务({}) 不存在]", notify.id()); | |
| 262 | + return; | |
| 263 | + } | |
| 264 | + // 2. 更新状态 | |
| 265 | + updateMidjourneyStatus(image, notify); | |
| 266 | + } | |
| 267 | + | |
| 268 | + private void updateMidjourneyStatus(AiImageDO image, MidjourneyApi.Notify notify) { | |
| 269 | + // 1. 转换状态 | |
| 270 | + Integer status = null; | |
| 271 | + LocalDateTime finishTime = null; | |
| 272 | + if (StrUtil.isNotBlank(notify.status())) { | |
| 273 | + MidjourneyApi.TaskStatusEnum taskStatusEnum = MidjourneyApi.TaskStatusEnum.valueOf(notify.status()); | |
| 274 | + if (MidjourneyApi.TaskStatusEnum.SUCCESS == taskStatusEnum) { | |
| 275 | + status = AiImageStatusEnum.SUCCESS.getStatus(); | |
| 276 | + finishTime = LocalDateTime.now(); | |
| 277 | + } else if (MidjourneyApi.TaskStatusEnum.FAILURE == taskStatusEnum) { | |
| 278 | + status = AiImageStatusEnum.FAIL.getStatus(); | |
| 279 | + finishTime = LocalDateTime.now(); | |
| 280 | + } | |
| 281 | + } | |
| 282 | + | |
| 283 | + // 2. 上传图片 | |
| 284 | + String picUrl = null; | |
| 285 | + if (StrUtil.isNotBlank(notify.imageUrl())) { | |
| 286 | + try { | |
| 287 | + picUrl = fileApi.createFile(HttpUtil.downloadBytes(notify.imageUrl())); | |
| 288 | + } catch (Exception e) { | |
| 289 | + picUrl = notify.imageUrl(); | |
| 290 | + log.warn("[updateMidjourneyStatus][图片({}) 地址({}) 上传失败]", image.getId(), notify.imageUrl(), e); | |
| 291 | + } | |
| 292 | + } | |
| 293 | + | |
| 294 | + // 3. 更新 image 状态 | |
| 295 | + imageMapper.updateById(new AiImageDO().setId(image.getId()).setStatus(status) | |
| 296 | + .setPicUrl(picUrl).setButtons(notify.buttons()).setErrorMessage(notify.failReason()) | |
| 297 | + .setFinishTime(finishTime)); | |
| 298 | + } | |
| 299 | + | |
| 300 | + @Override | |
| 301 | + public Long midjourneyAction(Long userId, AiMidjourneyActionReqVO reqVO) { | |
| 302 | + MidjourneyApi midjourneyApi = apiKeyService.getMidjourneyApi(); | |
| 303 | + // 1.1 检查 image | |
| 304 | + AiImageDO image = validateImageExists(reqVO.getId()); | |
| 305 | + if (ObjUtil.notEqual(userId, image.getUserId())) { | |
| 306 | + throw exception(IMAGE_NOT_EXISTS); | |
| 307 | + } | |
| 308 | + // 1.2 检查 customId | |
| 309 | + MidjourneyApi.Button button = CollUtil.findOne(image.getButtons(), | |
| 310 | + buttonX -> buttonX.customId().equals(reqVO.getCustomId())); | |
| 311 | + if (button == null) { | |
| 312 | + throw exception(IMAGE_CUSTOM_ID_NOT_EXISTS); | |
| 313 | + } | |
| 314 | + | |
| 315 | + // 2. 调用 Midjourney Proxy 提交任务 | |
| 316 | + MidjourneyApi.SubmitResponse actionResponse = midjourneyApi.action( | |
| 317 | + new MidjourneyApi.ActionRequest(button.customId(), image.getTaskId(), null)); | |
| 318 | + if (!MidjourneyApi.SubmitCodeEnum.SUCCESS_CODES.contains(actionResponse.code())) { | |
| 319 | + String description = actionResponse.description().contains("quota_not_enough") ? | |
| 320 | + "账户余额不足" : actionResponse.description(); | |
| 321 | + throw exception(IMAGE_MIDJOURNEY_SUBMIT_FAIL, description); | |
| 322 | + } | |
| 323 | + | |
| 324 | + // 3. 新增 image 记录 | |
| 325 | + AiImageDO newImage = new AiImageDO().setUserId(image.getUserId()).setPublicStatus(false).setPrompt(image.getPrompt()) | |
| 326 | + .setStatus(AiImageStatusEnum.IN_PROGRESS.getStatus()) | |
| 327 | + .setPlatform(AiPlatformEnum.MIDJOURNEY.getPlatform()) | |
| 328 | + .setModel(image.getModel()).setWidth(image.getWidth()).setHeight(image.getHeight()) | |
| 329 | + .setOptions(image.getOptions()).setTaskId(actionResponse.result()); | |
| 330 | + imageMapper.insert(newImage); | |
| 331 | + return newImage.getId(); | |
| 332 | + } | |
| 333 | + | |
| 334 | + /** | |
| 335 | + * 获得自身的代理对象,解决 AOP 生效问题 | |
| 336 | + * | |
| 337 | + * @return 自己 | |
| 338 | + */ | |
| 339 | + private AiImageServiceImpl getSelf() { | |
| 340 | + return SpringUtil.getBean(getClass()); | |
| 341 | + } | |
| 342 | + | |
| 343 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/mindmap/AiMindMapService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.mindmap; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 4 | +import cn.iocoder.yudao.module.ai.controller.admin.mindmap.vo.AiMindMapGenerateReqVO; | |
| 5 | +import reactor.core.publisher.Flux; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * AI 思维导图 Service 接口 | |
| 9 | + * | |
| 10 | + * @author xiaoxin | |
| 11 | + */ | |
| 12 | +public interface AiMindMapService { | |
| 13 | + | |
| 14 | + /** | |
| 15 | + * 生成思维导图内容 | |
| 16 | + * | |
| 17 | + * @param generateReqVO 请求参数 | |
| 18 | + * @param userId 用户编号 | |
| 19 | + * @return 生成结果 | |
| 20 | + */ | |
| 21 | + Flux<CommonResult<String>> generateMindMap(AiMindMapGenerateReqVO generateReqVO, Long userId); | |
| 22 | + | |
| 23 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/mindmap/AiMindMapServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.mindmap; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.lang.Assert; | |
| 5 | +import cn.hutool.core.util.StrUtil; | |
| 6 | +import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; | |
| 7 | +import cn.iocoder.yudao.framework.ai.core.util.AiUtils; | |
| 8 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 9 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 10 | +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | |
| 11 | +import cn.iocoder.yudao.module.ai.controller.admin.mindmap.vo.AiMindMapGenerateReqVO; | |
| 12 | +import cn.iocoder.yudao.module.ai.dal.dataobject.mindmap.AiMindMapDO; | |
| 13 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | |
| 14 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | |
| 15 | +import cn.iocoder.yudao.module.ai.dal.mysql.mindmap.AiMindMapMapper; | |
| 16 | +import cn.iocoder.yudao.module.ai.enums.AiChatRoleEnum; | |
| 17 | +import cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants; | |
| 18 | +import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService; | |
| 19 | +import cn.iocoder.yudao.module.ai.service.model.AiChatModelService; | |
| 20 | +import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService; | |
| 21 | +import jakarta.annotation.Resource; | |
| 22 | +import lombok.extern.slf4j.Slf4j; | |
| 23 | +import org.springframework.ai.chat.messages.Message; | |
| 24 | +import org.springframework.ai.chat.messages.SystemMessage; | |
| 25 | +import org.springframework.ai.chat.messages.UserMessage; | |
| 26 | +import org.springframework.ai.chat.model.ChatModel; | |
| 27 | +import org.springframework.ai.chat.model.ChatResponse; | |
| 28 | +import org.springframework.ai.chat.prompt.ChatOptions; | |
| 29 | +import org.springframework.ai.chat.prompt.Prompt; | |
| 30 | +import org.springframework.stereotype.Service; | |
| 31 | +import reactor.core.publisher.Flux; | |
| 32 | + | |
| 33 | +import java.util.ArrayList; | |
| 34 | +import java.util.List; | |
| 35 | + | |
| 36 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error; | |
| 37 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 38 | + | |
| 39 | +/** | |
| 40 | + * AI 思维导图 Service 实现类 | |
| 41 | + * | |
| 42 | + * @author xiaoxin | |
| 43 | + */ | |
| 44 | +@Service | |
| 45 | +@Slf4j | |
| 46 | +public class AiMindMapServiceImpl implements AiMindMapService { | |
| 47 | + | |
| 48 | + @Resource | |
| 49 | + private AiApiKeyService apiKeyService; | |
| 50 | + @Resource | |
| 51 | + private AiChatModelService chatModalService; | |
| 52 | + @Resource | |
| 53 | + private AiChatRoleService chatRoleService; | |
| 54 | + | |
| 55 | + @Resource | |
| 56 | + private AiMindMapMapper mindMapMapper; | |
| 57 | + | |
| 58 | + @Override | |
| 59 | + public Flux<CommonResult<String>> generateMindMap(AiMindMapGenerateReqVO generateReqVO, Long userId) { | |
| 60 | + // 1. 获取脑图模型。尝试获取思维导图助手角色,如果没有则使用默认模型 | |
| 61 | + AiChatRoleDO role = CollUtil.getFirst( | |
| 62 | + chatRoleService.getChatRoleListByName(AiChatRoleEnum.AI_MIND_MAP_ROLE.getName())); | |
| 63 | + // 1.1 获取脑图执行模型 | |
| 64 | + AiChatModelDO model = getModel(role); | |
| 65 | + // 1.2 获取角色设定消息 | |
| 66 | + String systemMessage = role != null && StrUtil.isNotBlank(role.getSystemMessage()) | |
| 67 | + ? role.getSystemMessage() : AiChatRoleEnum.AI_MIND_MAP_ROLE.getSystemMessage(); | |
| 68 | + // 1.3 校验平台 | |
| 69 | + AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform()); | |
| 70 | + ChatModel chatModel = apiKeyService.getChatModel(model.getKeyId()); | |
| 71 | + | |
| 72 | + // 2. 插入思维导图信息 | |
| 73 | + AiMindMapDO mindMapDO = BeanUtils.toBean(generateReqVO, AiMindMapDO.class, | |
| 74 | + mindMap -> mindMap.setUserId(userId).setModel(model.getModel()).setPlatform(platform.getPlatform())); | |
| 75 | + mindMapMapper.insert(mindMapDO); | |
| 76 | + | |
| 77 | + // 3.1 构建 Prompt,并进行调用 | |
| 78 | + Prompt prompt = buildPrompt(generateReqVO, model, systemMessage); | |
| 79 | + Flux<ChatResponse> streamResponse = chatModel.stream(prompt); | |
| 80 | + | |
| 81 | + // 3.2 流式返回 | |
| 82 | + StringBuffer contentBuffer = new StringBuffer(); | |
| 83 | + return streamResponse.map(chunk -> { | |
| 84 | + String newContent = chunk.getResult() != null ? chunk.getResult().getOutput().getContent() : null; | |
| 85 | + newContent = StrUtil.nullToDefault(newContent, ""); // 避免 null 的 情况 | |
| 86 | + contentBuffer.append(newContent); | |
| 87 | + // 响应结果 | |
| 88 | + return success(newContent); | |
| 89 | + }).doOnComplete(() -> { | |
| 90 | + // 忽略租户,因为 Flux 异步无法透传租户 | |
| 91 | + TenantUtils.executeIgnore(() -> | |
| 92 | + mindMapMapper.updateById(new AiMindMapDO().setId(mindMapDO.getId()).setGeneratedContent(contentBuffer.toString()))); | |
| 93 | + }).doOnError(throwable -> { | |
| 94 | + log.error("[generateWriteContent][generateReqVO({}) 发生异常]", generateReqVO, throwable); | |
| 95 | + // 忽略租户,因为 Flux 异步无法透传租户 | |
| 96 | + TenantUtils.executeIgnore(() -> | |
| 97 | + mindMapMapper.updateById(new AiMindMapDO().setId(mindMapDO.getId()).setErrorMessage(throwable.getMessage()))); | |
| 98 | + }).onErrorResume(error -> Flux.just(error(ErrorCodeConstants.WRITE_STREAM_ERROR))); | |
| 99 | + | |
| 100 | + } | |
| 101 | + | |
| 102 | + private Prompt buildPrompt(AiMindMapGenerateReqVO generateReqVO, AiChatModelDO model, String systemMessage) { | |
| 103 | + // 1. 构建 message 列表 | |
| 104 | + List<Message> chatMessages = buildMessages(generateReqVO, systemMessage); | |
| 105 | + // 2. 构建 options 对象 | |
| 106 | + AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform()); | |
| 107 | + ChatOptions options = AiUtils.buildChatOptions(platform, model.getModel(), model.getTemperature(), model.getMaxTokens()); | |
| 108 | + return new Prompt(chatMessages, options); | |
| 109 | + } | |
| 110 | + | |
| 111 | + private static List<Message> buildMessages(AiMindMapGenerateReqVO generateReqVO, String systemMessage) { | |
| 112 | + List<Message> chatMessages = new ArrayList<>(); | |
| 113 | + // 1. 角色设定 | |
| 114 | + if (StrUtil.isNotBlank(systemMessage)) { | |
| 115 | + chatMessages.add(new SystemMessage(systemMessage)); | |
| 116 | + } | |
| 117 | + // 2. 用户输入 | |
| 118 | + chatMessages.add(new UserMessage(generateReqVO.getPrompt())); | |
| 119 | + return chatMessages; | |
| 120 | + } | |
| 121 | + | |
| 122 | + private AiChatModelDO getModel(AiChatRoleDO role) { | |
| 123 | + AiChatModelDO model = null; | |
| 124 | + if (role != null && role.getModelId() != null) { | |
| 125 | + model = chatModalService.getChatModel(role.getModelId()); | |
| 126 | + } | |
| 127 | + if (model != null) { | |
| 128 | + model = chatModalService.getRequiredDefaultChatModel(); | |
| 129 | + } | |
| 130 | + Assert.notNull(model, "[AI] 获取不到模型"); | |
| 131 | + return model; | |
| 132 | + } | |
| 133 | + | |
| 134 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiApiKeyService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.model; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; | |
| 4 | +import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; | |
| 5 | +import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi; | |
| 6 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 7 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeyPageReqVO; | |
| 8 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeySaveReqVO; | |
| 9 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO; | |
| 10 | +import jakarta.validation.Valid; | |
| 11 | +import org.springframework.ai.chat.model.ChatModel; | |
| 12 | +import org.springframework.ai.image.ImageModel; | |
| 13 | + | |
| 14 | +import java.util.List; | |
| 15 | + | |
| 16 | +/** | |
| 17 | + * AI API 密钥 Service 接口 | |
| 18 | + * | |
| 19 | + * @author 芋道源码 | |
| 20 | + */ | |
| 21 | +public interface AiApiKeyService { | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * 创建 API 密钥 | |
| 25 | + * | |
| 26 | + * @param createReqVO 创建信息 | |
| 27 | + * @return 编号 | |
| 28 | + */ | |
| 29 | + Long createApiKey(@Valid AiApiKeySaveReqVO createReqVO); | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * 更新 API 密钥 | |
| 33 | + * | |
| 34 | + * @param updateReqVO 更新信息 | |
| 35 | + */ | |
| 36 | + void updateApiKey(@Valid AiApiKeySaveReqVO updateReqVO); | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * 删除 API 密钥 | |
| 40 | + * | |
| 41 | + * @param id 编号 | |
| 42 | + */ | |
| 43 | + void deleteApiKey(Long id); | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * 获得 API 密钥 | |
| 47 | + * | |
| 48 | + * @param id 编号 | |
| 49 | + * @return API 密钥 | |
| 50 | + */ | |
| 51 | + AiApiKeyDO getApiKey(Long id); | |
| 52 | + | |
| 53 | + /** | |
| 54 | + * 校验 API 密钥 | |
| 55 | + * | |
| 56 | + * @param id 比那好 | |
| 57 | + * @return API 密钥 | |
| 58 | + */ | |
| 59 | + AiApiKeyDO validateApiKey(Long id); | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * 获得 API 密钥分页 | |
| 63 | + * | |
| 64 | + * @param pageReqVO 分页查询 | |
| 65 | + * @return API 密钥分页 | |
| 66 | + */ | |
| 67 | + PageResult<AiApiKeyDO> getApiKeyPage(AiApiKeyPageReqVO pageReqVO); | |
| 68 | + | |
| 69 | + /** | |
| 70 | + * 获得 API 密钥列表 | |
| 71 | + * | |
| 72 | + * @return API 密钥列表 | |
| 73 | + */ | |
| 74 | + List<AiApiKeyDO> getApiKeyList(); | |
| 75 | + | |
| 76 | + // ========== 与 spring-ai 集成 ========== | |
| 77 | + | |
| 78 | + /** | |
| 79 | + * 获得 ChatModel 对象 | |
| 80 | + * | |
| 81 | + * @param id 编号 | |
| 82 | + * @return ChatModel 对象 | |
| 83 | + */ | |
| 84 | + ChatModel getChatModel(Long id); | |
| 85 | + | |
| 86 | + /** | |
| 87 | + * 获得 ImageModel 对象 | |
| 88 | + * | |
| 89 | + * TODO 可优化点:目前默认获取 platform 对应的第一个开启的配置用于绘画;后续可以支持配置选择 | |
| 90 | + * | |
| 91 | + * @param platform 平台 | |
| 92 | + * @return ImageModel 对象 | |
| 93 | + */ | |
| 94 | + ImageModel getImageModel(AiPlatformEnum platform); | |
| 95 | + | |
| 96 | + /** | |
| 97 | + * 获得 MidjourneyApi 对象 | |
| 98 | + * | |
| 99 | + * TODO 可优化点:目前默认获取 Midjourney 对应的第一个开启的配置用于绘画;后续可以支持配置选择 | |
| 100 | + * | |
| 101 | + * @return MidjourneyApi 对象 | |
| 102 | + */ | |
| 103 | + MidjourneyApi getMidjourneyApi(); | |
| 104 | + | |
| 105 | + /** | |
| 106 | + * 获得 SunoApi 对象 | |
| 107 | + * | |
| 108 | + * TODO 可优化点:目前默认获取 Suno 对应的第一个开启的配置用于音乐;后续可以支持配置选择 | |
| 109 | + * | |
| 110 | + * @return SunoApi 对象 | |
| 111 | + */ | |
| 112 | + SunoApi getSunoApi(); | |
| 113 | + | |
| 114 | +} | |
| 0 | 115 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiApiKeyServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.model; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; | |
| 4 | +import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactory; | |
| 5 | +import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; | |
| 6 | +import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi; | |
| 7 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 8 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 9 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 10 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeyPageReqVO; | |
| 11 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeySaveReqVO; | |
| 12 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO; | |
| 13 | +import cn.iocoder.yudao.module.ai.dal.mysql.model.AiApiKeyMapper; | |
| 14 | +import jakarta.annotation.Resource; | |
| 15 | +import org.springframework.ai.chat.model.ChatModel; | |
| 16 | +import org.springframework.ai.image.ImageModel; | |
| 17 | +import org.springframework.stereotype.Service; | |
| 18 | +import org.springframework.validation.annotation.Validated; | |
| 19 | + | |
| 20 | +import java.util.List; | |
| 21 | + | |
| 22 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 23 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.*; | |
| 24 | + | |
| 25 | +/** | |
| 26 | + * AI API 密钥 Service 实现类 | |
| 27 | + * | |
| 28 | + * @author 芋道源码 | |
| 29 | + */ | |
| 30 | +@Service | |
| 31 | +@Validated | |
| 32 | +public class AiApiKeyServiceImpl implements AiApiKeyService { | |
| 33 | + | |
| 34 | + @Resource | |
| 35 | + private AiApiKeyMapper apiKeyMapper; | |
| 36 | + | |
| 37 | + @Resource | |
| 38 | + private AiModelFactory modelFactory; | |
| 39 | + | |
| 40 | + @Override | |
| 41 | + public Long createApiKey(AiApiKeySaveReqVO createReqVO) { | |
| 42 | + // 插入 | |
| 43 | + AiApiKeyDO apiKey = BeanUtils.toBean(createReqVO, AiApiKeyDO.class); | |
| 44 | + apiKeyMapper.insert(apiKey); | |
| 45 | + // 返回 | |
| 46 | + return apiKey.getId(); | |
| 47 | + } | |
| 48 | + | |
| 49 | + @Override | |
| 50 | + public void updateApiKey(AiApiKeySaveReqVO updateReqVO) { | |
| 51 | + // 校验存在 | |
| 52 | + validateApiKeyExists(updateReqVO.getId()); | |
| 53 | + // 更新 | |
| 54 | + AiApiKeyDO updateObj = BeanUtils.toBean(updateReqVO, AiApiKeyDO.class); | |
| 55 | + apiKeyMapper.updateById(updateObj); | |
| 56 | + } | |
| 57 | + | |
| 58 | + @Override | |
| 59 | + public void deleteApiKey(Long id) { | |
| 60 | + // 校验存在 | |
| 61 | + validateApiKeyExists(id); | |
| 62 | + // 删除 | |
| 63 | + apiKeyMapper.deleteById(id); | |
| 64 | + } | |
| 65 | + | |
| 66 | + private AiApiKeyDO validateApiKeyExists(Long id) { | |
| 67 | + AiApiKeyDO apiKey = apiKeyMapper.selectById(id); | |
| 68 | + if (apiKey == null) { | |
| 69 | + throw exception(API_KEY_NOT_EXISTS); | |
| 70 | + } | |
| 71 | + return apiKey; | |
| 72 | + } | |
| 73 | + | |
| 74 | + @Override | |
| 75 | + public AiApiKeyDO getApiKey(Long id) { | |
| 76 | + return apiKeyMapper.selectById(id); | |
| 77 | + } | |
| 78 | + | |
| 79 | + @Override | |
| 80 | + public AiApiKeyDO validateApiKey(Long id) { | |
| 81 | + AiApiKeyDO apiKey = validateApiKeyExists(id); | |
| 82 | + if (CommonStatusEnum.isDisable(apiKey.getStatus())) { | |
| 83 | + throw exception(API_KEY_DISABLE); | |
| 84 | + } | |
| 85 | + return apiKey; | |
| 86 | + } | |
| 87 | + | |
| 88 | + @Override | |
| 89 | + public PageResult<AiApiKeyDO> getApiKeyPage(AiApiKeyPageReqVO pageReqVO) { | |
| 90 | + return apiKeyMapper.selectPage(pageReqVO); | |
| 91 | + } | |
| 92 | + | |
| 93 | + @Override | |
| 94 | + public List<AiApiKeyDO> getApiKeyList() { | |
| 95 | + return apiKeyMapper.selectList(); | |
| 96 | + } | |
| 97 | + | |
| 98 | + // ========== 与 spring-ai 集成 ========== | |
| 99 | + | |
| 100 | + @Override | |
| 101 | + public ChatModel getChatModel(Long id) { | |
| 102 | + AiApiKeyDO apiKey = validateApiKey(id); | |
| 103 | + AiPlatformEnum platform = AiPlatformEnum.validatePlatform(apiKey.getPlatform()); | |
| 104 | + return modelFactory.getOrCreateChatModel(platform, apiKey.getApiKey(), apiKey.getUrl()); | |
| 105 | + } | |
| 106 | + | |
| 107 | + @Override | |
| 108 | + public ImageModel getImageModel(AiPlatformEnum platform) { | |
| 109 | + AiApiKeyDO apiKey = apiKeyMapper.selectFirstByPlatformAndStatus(platform.getPlatform(), CommonStatusEnum.ENABLE.getStatus()); | |
| 110 | + if (apiKey == null) { | |
| 111 | + throw exception(API_KEY_IMAGE_NODE_FOUND, platform.getName()); | |
| 112 | + } | |
| 113 | + return modelFactory.getOrCreateImageModel(platform, apiKey.getApiKey(), apiKey.getUrl()); | |
| 114 | + } | |
| 115 | + | |
| 116 | + @Override | |
| 117 | + public MidjourneyApi getMidjourneyApi() { | |
| 118 | + AiApiKeyDO apiKey = apiKeyMapper.selectFirstByPlatformAndStatus( | |
| 119 | + AiPlatformEnum.MIDJOURNEY.getPlatform(), CommonStatusEnum.ENABLE.getStatus()); | |
| 120 | + if (apiKey == null) { | |
| 121 | + throw exception(API_KEY_MIDJOURNEY_NOT_FOUND); | |
| 122 | + } | |
| 123 | + return modelFactory.getOrCreateMidjourneyApi(apiKey.getApiKey(), apiKey.getUrl()); | |
| 124 | + } | |
| 125 | + | |
| 126 | + @Override | |
| 127 | + public SunoApi getSunoApi() { | |
| 128 | + AiApiKeyDO apiKey = apiKeyMapper.selectFirstByPlatformAndStatus( | |
| 129 | + AiPlatformEnum.SUNO.getPlatform(), CommonStatusEnum.ENABLE.getStatus()); | |
| 130 | + if (apiKey == null) { | |
| 131 | + throw exception(API_KEY_SUNO_NOT_FOUND); | |
| 132 | + } | |
| 133 | + return modelFactory.getOrCreateSunoApi(apiKey.getApiKey(), apiKey.getUrl()); | |
| 134 | + } | |
| 135 | +} | |
| 0 | 136 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatModelService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.model; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatModel.AiChatModelPageReqVO; | |
| 5 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatModel.AiChatModelSaveReqVO; | |
| 6 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | |
| 7 | +import jakarta.validation.Valid; | |
| 8 | + | |
| 9 | +import java.util.Collection; | |
| 10 | +import java.util.List; | |
| 11 | + | |
| 12 | +import java.util.Set; | |
| 13 | + | |
| 14 | +/** | |
| 15 | + * AI 聊天模型 Service 接口 | |
| 16 | + * | |
| 17 | + * @author fansili | |
| 18 | + * @since 2024/4/24 19:42 | |
| 19 | + */ | |
| 20 | +public interface AiChatModelService { | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * 创建聊天模型 | |
| 24 | + * | |
| 25 | + * @param createReqVO 创建信息 | |
| 26 | + * @return 编号 | |
| 27 | + */ | |
| 28 | + Long createChatModel(@Valid AiChatModelSaveReqVO createReqVO); | |
| 29 | + | |
| 30 | + /** | |
| 31 | + * 更新聊天模型 | |
| 32 | + * | |
| 33 | + * @param updateReqVO 更新信息 | |
| 34 | + */ | |
| 35 | + void updateChatModel(@Valid AiChatModelSaveReqVO updateReqVO); | |
| 36 | + | |
| 37 | + /** | |
| 38 | + * 删除聊天模型 | |
| 39 | + * | |
| 40 | + * @param id 编号 | |
| 41 | + */ | |
| 42 | + void deleteChatModel(Long id); | |
| 43 | + | |
| 44 | + /** | |
| 45 | + * 获得聊天模型 | |
| 46 | + * | |
| 47 | + * @param id 编号 | |
| 48 | + * @return 聊天模型 | |
| 49 | + */ | |
| 50 | + AiChatModelDO getChatModel(Long id); | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * 获得默认的聊天模型 | |
| 54 | + * | |
| 55 | + * 如果获取不到,则抛出 {@link cn.iocoder.yudao.framework.common.exception.ServiceException} 业务异常 | |
| 56 | + * | |
| 57 | + * @return 聊天模型 | |
| 58 | + */ | |
| 59 | + AiChatModelDO getRequiredDefaultChatModel(); | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * 获得聊天模型分页 | |
| 63 | + * | |
| 64 | + * @param pageReqVO 分页查询 | |
| 65 | + * @return 聊天模型分页 | |
| 66 | + */ | |
| 67 | + PageResult<AiChatModelDO> getChatModelPage(AiChatModelPageReqVO pageReqVO); | |
| 68 | + | |
| 69 | + /** | |
| 70 | + * 校验聊天模型 | |
| 71 | + * | |
| 72 | + * @param id 编号 | |
| 73 | + * @return 聊天模型 | |
| 74 | + */ | |
| 75 | + AiChatModelDO validateChatModel(Long id); | |
| 76 | + | |
| 77 | + /** | |
| 78 | + * 获得聊天模型列表 | |
| 79 | + * | |
| 80 | + * @param status 状态 | |
| 81 | + * @return 聊天模型列表 | |
| 82 | + */ | |
| 83 | + List<AiChatModelDO> getChatModelListByStatus(Integer status); | |
| 84 | + | |
| 85 | + /** | |
| 86 | + * 获得聊天模型列表 | |
| 87 | + * | |
| 88 | + * @param ids 编号数组 | |
| 89 | + * @return 模型列表 | |
| 90 | + */ | |
| 91 | + List<AiChatModelDO> getChatModelList(Collection<Long> ids); | |
| 92 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatModelServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.model; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; | |
| 4 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 5 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 6 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 7 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatModel.AiChatModelPageReqVO; | |
| 8 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatModel.AiChatModelSaveReqVO; | |
| 9 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | |
| 10 | +import cn.iocoder.yudao.module.ai.dal.mysql.model.AiChatModelMapper; | |
| 11 | +import jakarta.annotation.Resource; | |
| 12 | +import org.springframework.stereotype.Service; | |
| 13 | +import org.springframework.validation.annotation.Validated; | |
| 14 | + | |
| 15 | +import java.util.Collection; | |
| 16 | +import java.util.List; | |
| 17 | + | |
| 18 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 19 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.*; | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * AI 聊天模型 Service 实现类 | |
| 23 | + * | |
| 24 | + * @author fansili | |
| 25 | + */ | |
| 26 | +@Service | |
| 27 | +@Validated | |
| 28 | +public class AiChatModelServiceImpl implements AiChatModelService { | |
| 29 | + | |
| 30 | + @Resource | |
| 31 | + private AiApiKeyService apiKeyService; | |
| 32 | + | |
| 33 | + @Resource | |
| 34 | + private AiChatModelMapper chatModelMapper; | |
| 35 | + | |
| 36 | + @Override | |
| 37 | + public Long createChatModel(AiChatModelSaveReqVO createReqVO) { | |
| 38 | + // 1. 校验 | |
| 39 | + AiPlatformEnum.validatePlatform(createReqVO.getPlatform()); | |
| 40 | + apiKeyService.validateApiKey(createReqVO.getKeyId()); | |
| 41 | + | |
| 42 | + // 2. 插入 | |
| 43 | + AiChatModelDO chatModel = BeanUtils.toBean(createReqVO, AiChatModelDO.class); | |
| 44 | + chatModelMapper.insert(chatModel); | |
| 45 | + return chatModel.getId(); | |
| 46 | + } | |
| 47 | + | |
| 48 | + @Override | |
| 49 | + public void updateChatModel(AiChatModelSaveReqVO updateReqVO) { | |
| 50 | + // 1. 校验 | |
| 51 | + validateChatModelExists(updateReqVO.getId()); | |
| 52 | + AiPlatformEnum.validatePlatform(updateReqVO.getPlatform()); | |
| 53 | + apiKeyService.validateApiKey(updateReqVO.getKeyId()); | |
| 54 | + | |
| 55 | + // 2. 更新 | |
| 56 | + AiChatModelDO updateObj = BeanUtils.toBean(updateReqVO, AiChatModelDO.class); | |
| 57 | + chatModelMapper.updateById(updateObj); | |
| 58 | + } | |
| 59 | + | |
| 60 | + @Override | |
| 61 | + public void deleteChatModel(Long id) { | |
| 62 | + // 校验存在 | |
| 63 | + validateChatModelExists(id); | |
| 64 | + // 删除 | |
| 65 | + chatModelMapper.deleteById(id); | |
| 66 | + } | |
| 67 | + | |
| 68 | + private AiChatModelDO validateChatModelExists(Long id) { | |
| 69 | + AiChatModelDO model = chatModelMapper.selectById(id); | |
| 70 | + if (chatModelMapper.selectById(id) == null) { | |
| 71 | + throw exception(CHAT_MODEL_NOT_EXISTS); | |
| 72 | + } | |
| 73 | + return model; | |
| 74 | + } | |
| 75 | + | |
| 76 | + @Override | |
| 77 | + public AiChatModelDO getChatModel(Long id) { | |
| 78 | + return chatModelMapper.selectById(id); | |
| 79 | + } | |
| 80 | + | |
| 81 | + @Override | |
| 82 | + public AiChatModelDO getRequiredDefaultChatModel() { | |
| 83 | + AiChatModelDO model = chatModelMapper.selectFirstByStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 84 | + if (model == null) { | |
| 85 | + throw exception(CHAT_MODEL_DEFAULT_NOT_EXISTS); | |
| 86 | + } | |
| 87 | + return model; | |
| 88 | + } | |
| 89 | + | |
| 90 | + @Override | |
| 91 | + public PageResult<AiChatModelDO> getChatModelPage(AiChatModelPageReqVO pageReqVO) { | |
| 92 | + return chatModelMapper.selectPage(pageReqVO); | |
| 93 | + } | |
| 94 | + | |
| 95 | + @Override | |
| 96 | + public AiChatModelDO validateChatModel(Long id) { | |
| 97 | + AiChatModelDO model = validateChatModelExists(id); | |
| 98 | + if (CommonStatusEnum.isDisable(model.getStatus())) { | |
| 99 | + throw exception(CHAT_MODEL_DISABLE); | |
| 100 | + } | |
| 101 | + return model; | |
| 102 | + } | |
| 103 | + | |
| 104 | + @Override | |
| 105 | + public List<AiChatModelDO> getChatModelListByStatus(Integer status) { | |
| 106 | + return chatModelMapper.selectList(status); | |
| 107 | + } | |
| 108 | + | |
| 109 | + @Override | |
| 110 | + public List<AiChatModelDO> getChatModelList(Collection<Long> ids) { | |
| 111 | + return chatModelMapper.selectBatchIds(ids); | |
| 112 | + } | |
| 113 | + | |
| 114 | +} | |
| 0 | 115 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.model; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRolePageReqVO; | |
| 5 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveMyReqVO; | |
| 6 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveReqVO; | |
| 7 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | |
| 8 | +import jakarta.validation.Valid; | |
| 9 | + | |
| 10 | +import java.util.Collection; | |
| 11 | +import java.util.List; | |
| 12 | +import java.util.Map; | |
| 13 | + | |
| 14 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | |
| 15 | + | |
| 16 | +/** | |
| 17 | + * AI 聊天角色 Service 接口 | |
| 18 | + * | |
| 19 | + * @author fansili | |
| 20 | + */ | |
| 21 | +public interface AiChatRoleService { | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * 创建聊天角色 | |
| 25 | + * | |
| 26 | + * @param createReqVO 创建信息 | |
| 27 | + * @return 编号 | |
| 28 | + */ | |
| 29 | + Long createChatRole(@Valid AiChatRoleSaveReqVO createReqVO); | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * 创建【我的】聊天角色 | |
| 33 | + * | |
| 34 | + * @param createReqVO 创建信息 | |
| 35 | + * @param userId 用户编号 | |
| 36 | + * @return 编号 | |
| 37 | + */ | |
| 38 | + Long createChatRoleMy(AiChatRoleSaveMyReqVO createReqVO, Long userId); | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * 更新聊天角色 | |
| 42 | + * | |
| 43 | + * @param updateReqVO 更新信息 | |
| 44 | + */ | |
| 45 | + void updateChatRole(@Valid AiChatRoleSaveReqVO updateReqVO); | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * 创建【我的】聊天角色 | |
| 49 | + * | |
| 50 | + * @param updateReqVO 更新信息 | |
| 51 | + * @param userId 用户编号 | |
| 52 | + */ | |
| 53 | + void updateChatRoleMy(AiChatRoleSaveMyReqVO updateReqVO, Long userId); | |
| 54 | + | |
| 55 | + /** | |
| 56 | + * 删除聊天角色 | |
| 57 | + * | |
| 58 | + * @param id 编号 | |
| 59 | + */ | |
| 60 | + void deleteChatRole(Long id); | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * 删除【我的】聊天角色 | |
| 64 | + * | |
| 65 | + * @param id 编号 | |
| 66 | + * @param userId 用户编号 | |
| 67 | + */ | |
| 68 | + void deleteChatRoleMy(Long id, Long userId); | |
| 69 | + | |
| 70 | + /** | |
| 71 | + * 获得聊天角色 | |
| 72 | + * | |
| 73 | + * @param id 编号 | |
| 74 | + * @return AI 聊天角色 | |
| 75 | + */ | |
| 76 | + AiChatRoleDO getChatRole(Long id); | |
| 77 | + | |
| 78 | + /** | |
| 79 | + * 获得聊天角色列表 | |
| 80 | + * | |
| 81 | + * @param ids 编号数组 | |
| 82 | + * @return 聊天角色列表 | |
| 83 | + */ | |
| 84 | + List<AiChatRoleDO> getChatRoleList(Collection<Long> ids); | |
| 85 | + | |
| 86 | + default Map<Long, AiChatRoleDO> getChatRoleMap(Collection<Long> ids) { | |
| 87 | + return convertMap(getChatRoleList(ids), AiChatRoleDO::getId); | |
| 88 | + } | |
| 89 | + | |
| 90 | + /** | |
| 91 | + * 校验聊天角色是否合法 | |
| 92 | + * | |
| 93 | + * @param id 角色编号 | |
| 94 | + */ | |
| 95 | + AiChatRoleDO validateChatRole(Long id); | |
| 96 | + | |
| 97 | + /** | |
| 98 | + * 获得聊天角色分页 | |
| 99 | + * | |
| 100 | + * @param pageReqVO 分页查询 | |
| 101 | + * @return 聊天角色分页 | |
| 102 | + */ | |
| 103 | + PageResult<AiChatRoleDO> getChatRolePage(AiChatRolePageReqVO pageReqVO); | |
| 104 | + | |
| 105 | + /** | |
| 106 | + * 获得【我的】聊天角色分页 | |
| 107 | + * | |
| 108 | + * @param pageReqVO 分页查询 | |
| 109 | + * @param userId 用户编号 | |
| 110 | + * @return 聊天角色分页 | |
| 111 | + */ | |
| 112 | + PageResult<AiChatRoleDO> getChatRoleMyPage(AiChatRolePageReqVO pageReqVO, Long userId); | |
| 113 | + | |
| 114 | + /** | |
| 115 | + * 获得聊天角色的分类列表 | |
| 116 | + * | |
| 117 | + * @return 分类列表 | |
| 118 | + */ | |
| 119 | + List<String> getChatRoleCategoryList(); | |
| 120 | + | |
| 121 | + /** | |
| 122 | + * 根据名字获得聊天角色 | |
| 123 | + * | |
| 124 | + * @param name 名字 | |
| 125 | + * @return 聊天角色列表 | |
| 126 | + */ | |
| 127 | + List<AiChatRoleDO> getChatRoleListByName(String name); | |
| 128 | + | |
| 129 | +} | |
| 0 | 130 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.model; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.util.ObjectUtil; | |
| 5 | +import cn.hutool.core.util.StrUtil; | |
| 6 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 7 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 8 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 9 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRolePageReqVO; | |
| 10 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveMyReqVO; | |
| 11 | +import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveReqVO; | |
| 12 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | |
| 13 | +import cn.iocoder.yudao.module.ai.dal.mysql.model.AiChatRoleMapper; | |
| 14 | +import jakarta.annotation.Resource; | |
| 15 | +import lombok.extern.slf4j.Slf4j; | |
| 16 | +import org.springframework.stereotype.Service; | |
| 17 | + | |
| 18 | +import java.util.Collection; | |
| 19 | +import java.util.Collections; | |
| 20 | +import java.util.List; | |
| 21 | + | |
| 22 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 23 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 24 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.*; | |
| 25 | + | |
| 26 | +/** | |
| 27 | + * AI 聊天角色 Service 实现类 | |
| 28 | + * | |
| 29 | + * @author fansili | |
| 30 | + */ | |
| 31 | +@Service | |
| 32 | +@Slf4j | |
| 33 | +public class AiChatRoleServiceImpl implements AiChatRoleService { | |
| 34 | + | |
| 35 | + @Resource | |
| 36 | + private AiChatRoleMapper chatRoleMapper; | |
| 37 | + | |
| 38 | + @Override | |
| 39 | + public Long createChatRole(AiChatRoleSaveReqVO createReqVO) { | |
| 40 | + AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class); | |
| 41 | + chatRoleMapper.insert(chatRole); | |
| 42 | + return chatRole.getId(); | |
| 43 | + } | |
| 44 | + | |
| 45 | + @Override | |
| 46 | + public Long createChatRoleMy(AiChatRoleSaveMyReqVO createReqVO, Long userId) { | |
| 47 | + AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class).setUserId(userId) | |
| 48 | + .setStatus(CommonStatusEnum.ENABLE.getStatus()).setPublicStatus(false); | |
| 49 | + chatRoleMapper.insert(chatRole); | |
| 50 | + return chatRole.getId(); | |
| 51 | + } | |
| 52 | + | |
| 53 | + @Override | |
| 54 | + public void updateChatRole(AiChatRoleSaveReqVO updateReqVO) { | |
| 55 | + // 校验存在 | |
| 56 | + validateChatRoleExists(updateReqVO.getId()); | |
| 57 | + // 更新 | |
| 58 | + AiChatRoleDO updateObj = BeanUtils.toBean(updateReqVO, AiChatRoleDO.class); | |
| 59 | + chatRoleMapper.updateById(updateObj); | |
| 60 | + } | |
| 61 | + | |
| 62 | + @Override | |
| 63 | + public void updateChatRoleMy(AiChatRoleSaveMyReqVO updateReqVO, Long userId) { | |
| 64 | + // 校验存在 | |
| 65 | + AiChatRoleDO chatRole = validateChatRoleExists(updateReqVO.getId()); | |
| 66 | + if (ObjectUtil.notEqual(chatRole.getUserId(), userId)) { | |
| 67 | + throw exception(CHAT_ROLE_NOT_EXISTS); | |
| 68 | + } | |
| 69 | + | |
| 70 | + // 更新 | |
| 71 | + AiChatRoleDO updateObj = BeanUtils.toBean(updateReqVO, AiChatRoleDO.class); | |
| 72 | + chatRoleMapper.updateById(updateObj); | |
| 73 | + } | |
| 74 | + | |
| 75 | + @Override | |
| 76 | + public void deleteChatRole(Long id) { | |
| 77 | + // 校验存在 | |
| 78 | + validateChatRoleExists(id); | |
| 79 | + // 删除 | |
| 80 | + chatRoleMapper.deleteById(id); | |
| 81 | + } | |
| 82 | + | |
| 83 | + @Override | |
| 84 | + public void deleteChatRoleMy(Long id, Long userId) { | |
| 85 | + // 校验存在 | |
| 86 | + AiChatRoleDO chatRole = validateChatRoleExists(id); | |
| 87 | + if (ObjectUtil.notEqual(chatRole.getUserId(), userId)) { | |
| 88 | + throw exception(CHAT_ROLE_NOT_EXISTS); | |
| 89 | + } | |
| 90 | + // 删除 | |
| 91 | + chatRoleMapper.deleteById(id); | |
| 92 | + } | |
| 93 | + | |
| 94 | + private AiChatRoleDO validateChatRoleExists(Long id) { | |
| 95 | + AiChatRoleDO chatRole = chatRoleMapper.selectById(id); | |
| 96 | + if (chatRole == null) { | |
| 97 | + throw exception(CHAT_ROLE_NOT_EXISTS); | |
| 98 | + } | |
| 99 | + return chatRole; | |
| 100 | + } | |
| 101 | + | |
| 102 | + @Override | |
| 103 | + public AiChatRoleDO getChatRole(Long id) { | |
| 104 | + return chatRoleMapper.selectById(id); | |
| 105 | + } | |
| 106 | + | |
| 107 | + @Override | |
| 108 | + public List<AiChatRoleDO> getChatRoleList(Collection<Long> ids) { | |
| 109 | + if (CollUtil.isEmpty(ids)) { | |
| 110 | + return Collections.emptyList(); | |
| 111 | + } | |
| 112 | + return chatRoleMapper.selectBatchIds(ids); | |
| 113 | + } | |
| 114 | + | |
| 115 | + @Override | |
| 116 | + public AiChatRoleDO validateChatRole(Long id) { | |
| 117 | + AiChatRoleDO chatRole = validateChatRoleExists(id); | |
| 118 | + if (CommonStatusEnum.isDisable(chatRole.getStatus())) { | |
| 119 | + throw exception(CHAT_ROLE_DISABLE, chatRole.getName()); | |
| 120 | + } | |
| 121 | + return chatRole; | |
| 122 | + } | |
| 123 | + | |
| 124 | + @Override | |
| 125 | + public PageResult<AiChatRoleDO> getChatRolePage(AiChatRolePageReqVO pageReqVO) { | |
| 126 | + return chatRoleMapper.selectPage(pageReqVO); | |
| 127 | + } | |
| 128 | + | |
| 129 | + @Override | |
| 130 | + public PageResult<AiChatRoleDO> getChatRoleMyPage(AiChatRolePageReqVO pageReqVO, Long userId) { | |
| 131 | + return chatRoleMapper.selectPageByMy(pageReqVO, userId); | |
| 132 | + } | |
| 133 | + | |
| 134 | + @Override | |
| 135 | + public List<String> getChatRoleCategoryList() { | |
| 136 | + List<AiChatRoleDO> list = chatRoleMapper.selectListGroupByCategory(CommonStatusEnum.ENABLE.getStatus()); | |
| 137 | + return convertList(list, AiChatRoleDO::getCategory, role -> role != null && StrUtil.isNotBlank(role.getCategory())); | |
| 138 | + } | |
| 139 | + | |
| 140 | + @Override | |
| 141 | + public List<AiChatRoleDO> getChatRoleListByName(String name) { | |
| 142 | + return chatRoleMapper.selectListByName(name); | |
| 143 | + } | |
| 144 | + | |
| 145 | +} | |
| 146 | + | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/music/AiMusicService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.music; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.module.ai.controller.admin.music.vo.*; | |
| 5 | +import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO; | |
| 6 | +import jakarta.validation.Valid; | |
| 7 | + | |
| 8 | +import java.util.List; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * AI 音乐 Service 接口 | |
| 12 | + * | |
| 13 | + * @author xiaoxin | |
| 14 | + */ | |
| 15 | +public interface AiMusicService { | |
| 16 | + | |
| 17 | + /** | |
| 18 | + * 音乐生成 | |
| 19 | + * | |
| 20 | + * @param userId 用户编号 | |
| 21 | + * @param reqVO 请求参数 | |
| 22 | + * @return 生成的音乐ID | |
| 23 | + */ | |
| 24 | + List<Long> generateMusic(Long userId, AiSunoGenerateReqVO reqVO); | |
| 25 | + | |
| 26 | + /** | |
| 27 | + * 同步音乐任务 | |
| 28 | + * | |
| 29 | + * @return 同步数量 | |
| 30 | + */ | |
| 31 | + Integer syncMusic(); | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 更新音乐发布状态 | |
| 35 | + * | |
| 36 | + * @param updateReqVO 更新信息 | |
| 37 | + */ | |
| 38 | + void updateMusic(@Valid AiMusicUpdateReqVO updateReqVO); | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * 更新我的音乐 | |
| 42 | + * | |
| 43 | + * @param updateReqVO 更新信息 | |
| 44 | + */ | |
| 45 | + void updateMyMusic(@Valid AiMusicUpdateMyReqVO updateReqVO, Long userId); | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * 删除AI 音乐 | |
| 49 | + * | |
| 50 | + * @param id 编号 | |
| 51 | + */ | |
| 52 | + void deleteMusic(Long id); | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * 删除【我的】音乐记录 | |
| 56 | + * | |
| 57 | + * @param id 音乐编号 | |
| 58 | + * @param userId 用户编号 | |
| 59 | + */ | |
| 60 | + void deleteMusicMy(Long id, Long userId); | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * 获得AI 音乐 | |
| 64 | + * | |
| 65 | + * @param id 音乐编号 | |
| 66 | + * @return 音乐内容 | |
| 67 | + */ | |
| 68 | + AiMusicDO getMusic(Long id); | |
| 69 | + | |
| 70 | + /** | |
| 71 | + * 获得音乐分页 | |
| 72 | + * | |
| 73 | + * @param pageReqVO 分页查询 | |
| 74 | + * @return 音乐分页 | |
| 75 | + */ | |
| 76 | + PageResult<AiMusicDO> getMusicPage(AiMusicPageReqVO pageReqVO); | |
| 77 | + | |
| 78 | + /** | |
| 79 | + * 获得【我的】音乐分页 | |
| 80 | + * | |
| 81 | + * @param pageReqVO 分页查询 | |
| 82 | + * @param userId 用户编号 | |
| 83 | + * @return 音乐分页 | |
| 84 | + */ | |
| 85 | + PageResult<AiMusicDO> getMusicMyPage(AiMusicPageReqVO pageReqVO, Long userId); | |
| 86 | + | |
| 87 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/music/AiMusicServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.music; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.text.StrPool; | |
| 5 | +import cn.hutool.core.util.ObjUtil; | |
| 6 | +import cn.hutool.core.util.ObjectUtil; | |
| 7 | +import cn.hutool.core.util.StrUtil; | |
| 8 | +import cn.hutool.http.HttpUtil; | |
| 9 | +import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi; | |
| 10 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 11 | +import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiMusicPageReqVO; | |
| 12 | +import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiMusicUpdateMyReqVO; | |
| 13 | +import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiMusicUpdateReqVO; | |
| 14 | +import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiSunoGenerateReqVO; | |
| 15 | +import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO; | |
| 16 | +import cn.iocoder.yudao.module.ai.dal.mysql.music.AiMusicMapper; | |
| 17 | +import cn.iocoder.yudao.module.ai.enums.music.AiMusicGenerateModeEnum; | |
| 18 | +import cn.iocoder.yudao.module.ai.enums.music.AiMusicStatusEnum; | |
| 19 | +import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService; | |
| 20 | +import cn.iocoder.yudao.module.infra.api.file.FileApi; | |
| 21 | +import jakarta.annotation.Resource; | |
| 22 | +import lombok.extern.slf4j.Slf4j; | |
| 23 | +import org.springframework.stereotype.Service; | |
| 24 | +import org.springframework.transaction.annotation.Transactional; | |
| 25 | + | |
| 26 | +import java.util.*; | |
| 27 | + | |
| 28 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 29 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 30 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | |
| 31 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.IMAGE_NOT_EXISTS; | |
| 32 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.MUSIC_NOT_EXISTS; | |
| 33 | + | |
| 34 | +/** | |
| 35 | + * AI 音乐 Service 实现类 | |
| 36 | + * | |
| 37 | + * @author xiaoxin | |
| 38 | + */ | |
| 39 | +@Service | |
| 40 | +@Slf4j | |
| 41 | +public class AiMusicServiceImpl implements AiMusicService { | |
| 42 | + | |
| 43 | + @Resource | |
| 44 | + private AiApiKeyService apiKeyService; | |
| 45 | + | |
| 46 | + @Resource | |
| 47 | + private AiMusicMapper musicMapper; | |
| 48 | + | |
| 49 | + @Resource | |
| 50 | + private FileApi fileApi; | |
| 51 | + | |
| 52 | + @Override | |
| 53 | + @Transactional(rollbackFor = Exception.class) | |
| 54 | + public List<Long> generateMusic(Long userId, AiSunoGenerateReqVO reqVO) { | |
| 55 | + // 1. 调用 Suno 生成音乐 | |
| 56 | + SunoApi sunoApi = apiKeyService.getSunoApi(); | |
| 57 | + List<SunoApi.MusicData> musicDataList; | |
| 58 | + if (Objects.equals(AiMusicGenerateModeEnum.DESCRIPTION.getMode(), reqVO.getGenerateMode())) { | |
| 59 | + // 1.1 描述模式 | |
| 60 | + SunoApi.MusicGenerateRequest generateRequest = new SunoApi.MusicGenerateRequest( | |
| 61 | + reqVO.getPrompt(), reqVO.getModel(), reqVO.getMakeInstrumental()); | |
| 62 | + musicDataList = sunoApi.generate(generateRequest); | |
| 63 | + } else if (Objects.equals(AiMusicGenerateModeEnum.LYRIC.getMode(), reqVO.getGenerateMode())) { | |
| 64 | + // 1.2 歌词模式 | |
| 65 | + SunoApi.MusicGenerateRequest generateRequest = new SunoApi.MusicGenerateRequest( | |
| 66 | + reqVO.getPrompt(), reqVO.getModel(), CollUtil.join(reqVO.getTags(), StrPool.COMMA), reqVO.getTitle()); | |
| 67 | + musicDataList = sunoApi.customGenerate(generateRequest); | |
| 68 | + } else { | |
| 69 | + throw new IllegalArgumentException(StrUtil.format("未知生成模式({})", reqVO)); | |
| 70 | + } | |
| 71 | + | |
| 72 | + // 2. 插入数据库 | |
| 73 | + if (CollUtil.isEmpty(musicDataList)) { | |
| 74 | + return Collections.emptyList(); | |
| 75 | + } | |
| 76 | + List<AiMusicDO> musicList = buildMusicDOList(musicDataList); | |
| 77 | + musicList.forEach(music -> music.setUserId(userId).setPlatform(reqVO.getPlatform()).setGenerateMode(reqVO.getGenerateMode())); | |
| 78 | + musicMapper.insertBatch(musicList); | |
| 79 | + return convertList(musicList, AiMusicDO::getId); | |
| 80 | + } | |
| 81 | + | |
| 82 | + @Override | |
| 83 | + public Integer syncMusic() { | |
| 84 | + List<AiMusicDO> streamingTask = musicMapper.selectListByStatus(AiMusicStatusEnum.IN_PROGRESS.getStatus()); | |
| 85 | + if (CollUtil.isEmpty(streamingTask)) { | |
| 86 | + return 0; | |
| 87 | + } | |
| 88 | + log.info("[syncMusic][Suno 开始同步, 共 ({}) 个任务]", streamingTask.size()); | |
| 89 | + | |
| 90 | + // GET 请求,为避免参数过长,分批次处理 | |
| 91 | + SunoApi sunoApi = apiKeyService.getSunoApi(); | |
| 92 | + CollUtil.split(streamingTask, 36).forEach(chunkList -> { | |
| 93 | + Map<String, Long> taskIdMap = convertMap(chunkList, AiMusicDO::getTaskId, AiMusicDO::getId); | |
| 94 | + List<SunoApi.MusicData> musicTaskList = sunoApi.getMusicList(new ArrayList<>(taskIdMap.keySet())); | |
| 95 | + if (CollUtil.isEmpty(musicTaskList)) { | |
| 96 | + log.warn("Suno 任务同步失败, 任务ID: [{}]", taskIdMap.keySet()); | |
| 97 | + return; | |
| 98 | + } | |
| 99 | + // 更新进度 | |
| 100 | + List<AiMusicDO> updateMusicList = buildMusicDOList(musicTaskList); | |
| 101 | + updateMusicList.forEach(music -> music.setId(taskIdMap.get(music.getTaskId()))); | |
| 102 | + musicMapper.updateBatch(updateMusicList); | |
| 103 | + }); | |
| 104 | + return streamingTask.size(); | |
| 105 | + } | |
| 106 | + | |
| 107 | + @Override | |
| 108 | + public void updateMusic(AiMusicUpdateReqVO updateReqVO) { | |
| 109 | + // 校验存在 | |
| 110 | + validateMusicExists(updateReqVO.getId()); | |
| 111 | + // 更新 | |
| 112 | + musicMapper.updateById(new AiMusicDO().setId(updateReqVO.getId()).setPublicStatus(updateReqVO.getPublicStatus())); | |
| 113 | + } | |
| 114 | + | |
| 115 | + @Override | |
| 116 | + public void updateMyMusic(AiMusicUpdateMyReqVO updateReqVO, Long userId) { | |
| 117 | + // 校验音乐是否存在 | |
| 118 | + AiMusicDO musicDO = validateMusicExists(updateReqVO.getId()); | |
| 119 | + if (ObjUtil.notEqual(musicDO.getUserId(), userId)) { | |
| 120 | + throw exception(MUSIC_NOT_EXISTS); | |
| 121 | + } | |
| 122 | + // 更新 | |
| 123 | + musicMapper.updateById(new AiMusicDO().setId(updateReqVO.getId()).setTitle(updateReqVO.getTitle())); | |
| 124 | + } | |
| 125 | + | |
| 126 | + @Override | |
| 127 | + public void deleteMusic(Long id) { | |
| 128 | + // 校验存在 | |
| 129 | + validateMusicExists(id); | |
| 130 | + // 删除 | |
| 131 | + musicMapper.deleteById(id); | |
| 132 | + } | |
| 133 | + | |
| 134 | + @Override | |
| 135 | + public void deleteMusicMy(Long id, Long userId) { | |
| 136 | + // 1. 校验是否存在 | |
| 137 | + AiMusicDO music = validateMusicExists(id); | |
| 138 | + if (ObjUtil.notEqual(music.getUserId(), userId)) { | |
| 139 | + throw exception(IMAGE_NOT_EXISTS); | |
| 140 | + } | |
| 141 | + // 2. 删除记录 | |
| 142 | + musicMapper.deleteById(id); | |
| 143 | + } | |
| 144 | + | |
| 145 | + @Override | |
| 146 | + public AiMusicDO getMusic(Long id) { | |
| 147 | + return musicMapper.selectById(id); | |
| 148 | + } | |
| 149 | + | |
| 150 | + @Override | |
| 151 | + public PageResult<AiMusicDO> getMusicPage(AiMusicPageReqVO pageReqVO) { | |
| 152 | + return musicMapper.selectPage(pageReqVO); | |
| 153 | + } | |
| 154 | + | |
| 155 | + @Override | |
| 156 | + public PageResult<AiMusicDO> getMusicMyPage(AiMusicPageReqVO pageReqVO, Long userId) { | |
| 157 | + return musicMapper.selectPageByMy(pageReqVO, userId); | |
| 158 | + } | |
| 159 | + | |
| 160 | + /** | |
| 161 | + * 构建 AiMusicDO 集合 | |
| 162 | + * | |
| 163 | + * @param musicList suno 音乐任务列表 | |
| 164 | + * @return AiMusicDO 集合 | |
| 165 | + */ | |
| 166 | + private List<AiMusicDO> buildMusicDOList(List<SunoApi.MusicData> musicList) { | |
| 167 | + return convertList(musicList, musicData -> { | |
| 168 | + Integer status = Objects.equals("complete", musicData.status()) ? AiMusicStatusEnum.SUCCESS.getStatus() | |
| 169 | + : Objects.equals("error", musicData.status()) ? AiMusicStatusEnum.FAIL.getStatus() | |
| 170 | + : AiMusicStatusEnum.IN_PROGRESS.getStatus(); | |
| 171 | + return new AiMusicDO() | |
| 172 | + .setTaskId(musicData.id()).setModel(musicData.modelName()) | |
| 173 | + .setDescription(musicData.gptDescriptionPrompt()) | |
| 174 | + .setAudioUrl(downloadFile(status, musicData.audioUrl())) | |
| 175 | + .setVideoUrl(downloadFile(status, musicData.videoUrl())) | |
| 176 | + .setImageUrl(downloadFile(status, musicData.imageUrl())) | |
| 177 | + .setTitle(musicData.title()).setDuration(musicData.duration()) | |
| 178 | + .setLyric(musicData.lyric()).setTags(StrUtil.split(musicData.tags(), StrPool.COMMA)) | |
| 179 | + .setErrorMessage(musicData.errorMessage()) | |
| 180 | + .setStatus(status); | |
| 181 | + }); | |
| 182 | + } | |
| 183 | + | |
| 184 | + /** | |
| 185 | + * 音乐生成好后,将音频文件上传到文件服务器 | |
| 186 | + * | |
| 187 | + * @param status 音乐状态 | |
| 188 | + * @param url 音频文件地址 | |
| 189 | + * @return 内部文件地址 | |
| 190 | + */ | |
| 191 | + private String downloadFile(Integer status, String url) { | |
| 192 | + if (StrUtil.isBlank(url) || ObjectUtil.notEqual(status, AiMusicStatusEnum.SUCCESS.getStatus())) { | |
| 193 | + return url; | |
| 194 | + } | |
| 195 | + try { | |
| 196 | + byte[] bytes = HttpUtil.downloadBytes(url); | |
| 197 | + return fileApi.createFile(bytes); | |
| 198 | + } catch (Exception e) { | |
| 199 | + log.error("[downloadFile][url({}) 下载失败]", url, e); | |
| 200 | + return url; | |
| 201 | + } | |
| 202 | + } | |
| 203 | + | |
| 204 | + /** | |
| 205 | + * 校验音乐是否存在 | |
| 206 | + * | |
| 207 | + * @param id 音乐编号 | |
| 208 | + * @return 音乐信息 | |
| 209 | + */ | |
| 210 | + private AiMusicDO validateMusicExists(Long id) { | |
| 211 | + AiMusicDO music = musicMapper.selectById(id); | |
| 212 | + if (music == null) { | |
| 213 | + throw exception(MUSIC_NOT_EXISTS); | |
| 214 | + } | |
| 215 | + return music; | |
| 216 | + } | |
| 217 | + | |
| 218 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/write/AiWriteService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.write; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 5 | +import cn.iocoder.yudao.module.ai.controller.admin.write.vo.AiWriteGenerateReqVO; | |
| 6 | +import cn.iocoder.yudao.module.ai.controller.admin.write.vo.AiWritePageReqVO; | |
| 7 | +import cn.iocoder.yudao.module.ai.dal.dataobject.write.AiWriteDO; | |
| 8 | +import reactor.core.publisher.Flux; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * AI 写作 Service 接口 | |
| 12 | + * | |
| 13 | + * @author xiaoxin | |
| 14 | + */ | |
| 15 | +public interface AiWriteService { | |
| 16 | + | |
| 17 | + /** | |
| 18 | + * 生成写作内容 | |
| 19 | + * | |
| 20 | + * @param generateReqVO 作文生成请求参数 | |
| 21 | + * @param userId 用户编号 | |
| 22 | + * @return 生成结果 | |
| 23 | + */ | |
| 24 | + Flux<CommonResult<String>> generateWriteContent(AiWriteGenerateReqVO generateReqVO, Long userId); | |
| 25 | + | |
| 26 | + /** | |
| 27 | + * 删除写作 | |
| 28 | + * | |
| 29 | + * @param id 编号 | |
| 30 | + */ | |
| 31 | + void deleteWrite(Long id); | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 获得写作分页 | |
| 35 | + * | |
| 36 | + * @param pageReqVO 分页查询 | |
| 37 | + * @return AI 写作分页 | |
| 38 | + */ | |
| 39 | + PageResult<AiWriteDO> getWritePage(AiWritePageReqVO pageReqVO); | |
| 40 | + | |
| 41 | +} | ... | ... |