diff --git a/sql/postgresql/quartz.sql b/sql/postgresql/quartz.sql
index 4ec390c527..46bb938431 100644
--- a/sql/postgresql/quartz.sql
+++ b/sql/postgresql/quartz.sql
@@ -1,253 +1,208 @@
--- ----------------------------
--- qrtz_blob_triggers
--- ----------------------------
-CREATE TABLE qrtz_blob_triggers
+-- https://github.com/quartz-scheduler/quartz/blob/main/quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_postgres.sql
+-- Thanks to Patrick Lightbody for submitting this...
+--
+-- In your Quartz properties file, you'll need to set
+-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
+
+DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
+DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
+DROP TABLE IF EXISTS QRTZ_LOCKS;
+DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
+DROP TABLE IF EXISTS QRTZ_CALENDARS;
+
+CREATE TABLE QRTZ_JOB_DETAILS
(
- sched_name varchar(120) NOT NULL,
- trigger_name varchar(190) NOT NULL,
- trigger_group varchar(190) NOT NULL,
- blob_data bytea NULL,
- PRIMARY KEY (sched_name, trigger_name, trigger_group)
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ JOB_NAME VARCHAR(200) NOT NULL,
+ JOB_GROUP VARCHAR(200) NOT NULL,
+ DESCRIPTION VARCHAR(250) NULL,
+ JOB_CLASS_NAME VARCHAR(250) NOT NULL,
+ IS_DURABLE BOOL NOT NULL,
+ IS_NONCONCURRENT BOOL NOT NULL,
+ IS_UPDATE_DATA BOOL NOT NULL,
+ REQUESTS_RECOVERY BOOL NOT NULL,
+ JOB_DATA BYTEA NULL,
+ PRIMARY KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)
);
-CREATE INDEX idx_qrtz_blob_triggers_sched_name ON qrtz_blob_triggers (sched_name, trigger_name, trigger_group);
-
--- ----------------------------
--- qrtz_calendars
--- ----------------------------
-CREATE TABLE qrtz_calendars
+CREATE TABLE QRTZ_TRIGGERS
(
- sched_name varchar(120) NOT NULL,
- calendar_name varchar(190) NOT NULL,
- calendar bytea NOT NULL,
- PRIMARY KEY (sched_name, calendar_name)
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ JOB_NAME VARCHAR(200) NOT NULL,
+ JOB_GROUP VARCHAR(200) NOT NULL,
+ DESCRIPTION VARCHAR(250) NULL,
+ NEXT_FIRE_TIME BIGINT NULL,
+ PREV_FIRE_TIME BIGINT NULL,
+ PRIORITY INTEGER NULL,
+ TRIGGER_STATE VARCHAR(16) NOT NULL,
+ TRIGGER_TYPE VARCHAR(8) NOT NULL,
+ START_TIME BIGINT NOT NULL,
+ END_TIME BIGINT NULL,
+ CALENDAR_NAME VARCHAR(200) NULL,
+ MISFIRE_INSTR SMALLINT NULL,
+ JOB_DATA BYTEA NULL,
+ PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
+ FOREIGN KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)
+ REFERENCES QRTZ_JOB_DETAILS (SCHED_NAME, JOB_NAME, JOB_GROUP)
+);
+
+CREATE TABLE QRTZ_SIMPLE_TRIGGERS
+(
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ REPEAT_COUNT BIGINT NOT NULL,
+ REPEAT_INTERVAL BIGINT NOT NULL,
+ TIMES_TRIGGERED BIGINT NOT NULL,
+ PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
+ FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+ REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+);
+
+CREATE TABLE QRTZ_CRON_TRIGGERS
+(
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ CRON_EXPRESSION VARCHAR(120) NOT NULL,
+ TIME_ZONE_ID VARCHAR(80),
+ PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
+ FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+ REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+);
+
+CREATE TABLE QRTZ_SIMPROP_TRIGGERS
+(
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ STR_PROP_1 VARCHAR(512) NULL,
+ STR_PROP_2 VARCHAR(512) NULL,
+ STR_PROP_3 VARCHAR(512) NULL,
+ INT_PROP_1 INT NULL,
+ INT_PROP_2 INT NULL,
+ LONG_PROP_1 BIGINT NULL,
+ LONG_PROP_2 BIGINT NULL,
+ DEC_PROP_1 NUMERIC(13, 4) NULL,
+ DEC_PROP_2 NUMERIC(13, 4) NULL,
+ BOOL_PROP_1 BOOL NULL,
+ BOOL_PROP_2 BOOL NULL,
+ PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
+ FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+ REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+);
+
+CREATE TABLE QRTZ_BLOB_TRIGGERS
+(
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ BLOB_DATA BYTEA NULL,
+ PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
+ FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+ REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+);
+
+CREATE TABLE QRTZ_CALENDARS
+(
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ CALENDAR_NAME VARCHAR(200) NOT NULL,
+ CALENDAR BYTEA NOT NULL,
+ PRIMARY KEY (SCHED_NAME, CALENDAR_NAME)
);
--- ----------------------------
--- qrtz_cron_triggers
--- ----------------------------
-CREATE TABLE qrtz_cron_triggers
+CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
(
- sched_name varchar(120) NOT NULL,
- trigger_name varchar(190) NOT NULL,
- trigger_group varchar(190) NOT NULL,
- cron_expression varchar(120) NOT NULL,
- time_zone_id varchar(80) NULL DEFAULT NULL,
- PRIMARY KEY (sched_name, trigger_name, trigger_group)
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ PRIMARY KEY (SCHED_NAME, TRIGGER_GROUP)
);
--- @formatter:off
-BEGIN;
-COMMIT;
--- @formatter:on
-
--- ----------------------------
--- qrtz_fired_triggers
--- ----------------------------
-CREATE TABLE qrtz_fired_triggers
+CREATE TABLE QRTZ_FIRED_TRIGGERS
(
- sched_name varchar(120) NOT NULL,
- entry_id varchar(95) NOT NULL,
- trigger_name varchar(190) NOT NULL,
- trigger_group varchar(190) NOT NULL,
- instance_name varchar(190) NOT NULL,
- fired_time int8 NOT NULL,
- sched_time int8 NOT NULL,
- priority int4 NOT NULL,
- state varchar(16) NOT NULL,
- job_name varchar(190) NULL DEFAULT NULL,
- job_group varchar(190) NULL DEFAULT NULL,
- is_nonconcurrent varchar(1) NULL DEFAULT NULL,
- requests_recovery varchar(1) NULL DEFAULT NULL,
- PRIMARY KEY (sched_name, entry_id)
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ ENTRY_ID VARCHAR(95) NOT NULL,
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ INSTANCE_NAME VARCHAR(200) NOT NULL,
+ FIRED_TIME BIGINT NOT NULL,
+ SCHED_TIME BIGINT NOT NULL,
+ PRIORITY INTEGER NOT NULL,
+ STATE VARCHAR(16) NOT NULL,
+ JOB_NAME VARCHAR(200) NULL,
+ JOB_GROUP VARCHAR(200) NULL,
+ IS_NONCONCURRENT BOOL NULL,
+ REQUESTS_RECOVERY BOOL NULL,
+ PRIMARY KEY (SCHED_NAME, ENTRY_ID)
);
-CREATE INDEX idx_qrtz_ft_trig_inst_name ON qrtz_fired_triggers (sched_name, instance_name);
-CREATE INDEX idx_qrtz_ft_inst_job_req_rcvry ON qrtz_fired_triggers (sched_name, instance_name, requests_recovery);
-CREATE INDEX idx_qrtz_ft_j_g ON qrtz_fired_triggers (sched_name, job_name, job_group);
-CREATE INDEX idx_qrtz_ft_jg ON qrtz_fired_triggers (sched_name, job_group);
-CREATE INDEX idx_qrtz_ft_t_g ON qrtz_fired_triggers (sched_name, trigger_name, trigger_group);
-CREATE INDEX idx_qrtz_ft_tg ON qrtz_fired_triggers (sched_name, trigger_group);
-
--- ----------------------------
--- qrtz_job_details
--- ----------------------------
-CREATE TABLE qrtz_job_details
+CREATE TABLE QRTZ_SCHEDULER_STATE
(
- sched_name varchar(120) NOT NULL,
- job_name varchar(190) NOT NULL,
- job_group varchar(190) NOT NULL,
- description varchar(250) NULL DEFAULT NULL,
- job_class_name varchar(250) NOT NULL,
- is_durable varchar(1) NOT NULL,
- is_nonconcurrent varchar(1) NOT NULL,
- is_update_data varchar(1) NOT NULL,
- requests_recovery varchar(1) NOT NULL,
- job_data bytea NULL,
- PRIMARY KEY (sched_name, job_name, job_group)
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ INSTANCE_NAME VARCHAR(200) NOT NULL,
+ LAST_CHECKIN_TIME BIGINT NOT NULL,
+ CHECKIN_INTERVAL BIGINT NOT NULL,
+ PRIMARY KEY (SCHED_NAME, INSTANCE_NAME)
);
-CREATE INDEX idx_qrtz_j_req_recovery ON qrtz_job_details (sched_name, requests_recovery);
-CREATE INDEX idx_qrtz_j_grp ON qrtz_job_details (sched_name, job_group);
-
--- @formatter:off
-BEGIN;
-COMMIT;
--- @formatter:on
-
--- ----------------------------
--- qrtz_locks
--- ----------------------------
-CREATE TABLE qrtz_locks
+CREATE TABLE QRTZ_LOCKS
(
- sched_name varchar(120) NOT NULL,
- lock_name varchar(40) NOT NULL,
- PRIMARY KEY (sched_name, lock_name)
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ LOCK_NAME VARCHAR(40) NOT NULL,
+ PRIMARY KEY (SCHED_NAME, LOCK_NAME)
);
--- @formatter:off
-BEGIN;
-COMMIT;
--- @formatter:on
+CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY
+ ON QRTZ_JOB_DETAILS (SCHED_NAME, REQUESTS_RECOVERY);
+CREATE INDEX IDX_QRTZ_J_GRP
+ ON QRTZ_JOB_DETAILS (SCHED_NAME, JOB_GROUP);
--- ----------------------------
--- qrtz_paused_trigger_grps
--- ----------------------------
-CREATE TABLE qrtz_paused_trigger_grps
-(
- sched_name varchar(120) NOT NULL,
- trigger_group varchar(190) NOT NULL,
- PRIMARY KEY (sched_name, trigger_group)
-);
+CREATE INDEX IDX_QRTZ_T_J
+ ON QRTZ_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
+CREATE INDEX IDX_QRTZ_T_JG
+ ON QRTZ_TRIGGERS (SCHED_NAME, JOB_GROUP);
+CREATE INDEX IDX_QRTZ_T_C
+ ON QRTZ_TRIGGERS (SCHED_NAME, CALENDAR_NAME);
+CREATE INDEX IDX_QRTZ_T_G
+ ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
+CREATE INDEX IDX_QRTZ_T_STATE
+ ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE);
+CREATE INDEX IDX_QRTZ_T_N_STATE
+ ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP, TRIGGER_STATE);
+CREATE INDEX IDX_QRTZ_T_N_G_STATE
+ ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP, TRIGGER_STATE);
+CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME
+ ON QRTZ_TRIGGERS (SCHED_NAME, NEXT_FIRE_TIME);
+CREATE INDEX IDX_QRTZ_T_NFT_ST
+ ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE, NEXT_FIRE_TIME);
+CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE
+ ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME);
+CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE
+ ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_STATE);
+CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP
+ ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_GROUP, TRIGGER_STATE);
--- ----------------------------
--- qrtz_scheduler_state
--- ----------------------------
-CREATE TABLE qrtz_scheduler_state
-(
- sched_name varchar(120) NOT NULL,
- instance_name varchar(190) NOT NULL,
- last_checkin_time int8 NOT NULL,
- checkin_interval int8 NOT NULL,
- PRIMARY KEY (sched_name, instance_name)
-);
-
--- @formatter:off
-BEGIN;
-COMMIT;
--- @formatter:on
-
--- ----------------------------
--- qrtz_simple_triggers
--- ----------------------------
-CREATE TABLE qrtz_simple_triggers
-(
- sched_name varchar(120) NOT NULL,
- trigger_name varchar(190) NOT NULL,
- trigger_group varchar(190) NOT NULL,
- repeat_count int8 NOT NULL,
- repeat_interval int8 NOT NULL,
- times_triggered int8 NOT NULL,
- PRIMARY KEY (sched_name, trigger_name, trigger_group)
-);
-
--- ----------------------------
--- qrtz_simprop_triggers
--- ----------------------------
-CREATE TABLE qrtz_simprop_triggers
-(
- sched_name varchar(120) NOT NULL,
- trigger_name varchar(190) NOT NULL,
- trigger_group varchar(190) NOT NULL,
- str_prop_1 varchar(512) NULL DEFAULT NULL,
- str_prop_2 varchar(512) NULL DEFAULT NULL,
- str_prop_3 varchar(512) NULL DEFAULT NULL,
- int_prop_1 int4 NULL DEFAULT NULL,
- int_prop_2 int4 NULL DEFAULT NULL,
- long_prop_1 int8 NULL DEFAULT NULL,
- long_prop_2 int8 NULL DEFAULT NULL,
- dec_prop_1 numeric(13, 4) NULL DEFAULT NULL,
- dec_prop_2 numeric(13, 4) NULL DEFAULT NULL,
- bool_prop_1 varchar(1) NULL DEFAULT NULL,
- bool_prop_2 varchar(1) NULL DEFAULT NULL,
- PRIMARY KEY (sched_name, trigger_name, trigger_group)
-);
-
--- ----------------------------
--- qrtz_triggers
--- ----------------------------
-CREATE TABLE qrtz_triggers
-(
- sched_name varchar(120) NOT NULL,
- trigger_name varchar(190) NOT NULL,
- trigger_group varchar(190) NOT NULL,
- job_name varchar(190) NOT NULL,
- job_group varchar(190) NOT NULL,
- description varchar(250) NULL DEFAULT NULL,
- next_fire_time int8 NULL DEFAULT NULL,
- prev_fire_time int8 NULL DEFAULT NULL,
- priority int4 NULL DEFAULT NULL,
- trigger_state varchar(16) NOT NULL,
- trigger_type varchar(8) NOT NULL,
- start_time int8 NOT NULL,
- end_time int8 NULL DEFAULT NULL,
- calendar_name varchar(190) NULL DEFAULT NULL,
- misfire_instr int2 NULL DEFAULT NULL,
- job_data bytea NULL,
- PRIMARY KEY (sched_name, trigger_name, trigger_group)
-);
-
-CREATE INDEX idx_qrtz_t_j ON qrtz_triggers (sched_name, job_name, job_group);
-CREATE INDEX idx_qrtz_t_jg ON qrtz_triggers (sched_name, job_group);
-CREATE INDEX idx_qrtz_t_c ON qrtz_triggers (sched_name, calendar_name);
-CREATE INDEX idx_qrtz_t_g ON qrtz_triggers (sched_name, trigger_group);
-CREATE INDEX idx_qrtz_t_state ON qrtz_triggers (sched_name, trigger_state);
-CREATE INDEX idx_qrtz_t_n_state ON qrtz_triggers (sched_name, trigger_name, trigger_group, trigger_state);
-CREATE INDEX idx_qrtz_t_n_g_state ON qrtz_triggers (sched_name, trigger_group, trigger_state);
-CREATE INDEX idx_qrtz_t_next_fire_time ON qrtz_triggers (sched_name, next_fire_time);
-CREATE INDEX idx_qrtz_t_nft_st ON qrtz_triggers (sched_name, trigger_state, next_fire_time);
-CREATE INDEX idx_qrtz_t_nft_misfire ON qrtz_triggers (sched_name, misfire_instr, next_fire_time);
-CREATE INDEX idx_qrtz_t_nft_st_misfire ON qrtz_triggers (sched_name, misfire_instr, next_fire_time, trigger_state);
-CREATE INDEX idx_qrtz_t_nft_st_misfire_grp ON qrtz_triggers (sched_name, misfire_instr, next_fire_time, trigger_group,
- trigger_state);
-
--- @formatter:off
-BEGIN;
-COMMIT;
--- @formatter:on
+CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME
+ ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME);
+CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY
+ ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME, REQUESTS_RECOVERY);
+CREATE INDEX IDX_QRTZ_FT_J_G
+ ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
+CREATE INDEX IDX_QRTZ_FT_JG
+ ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_GROUP);
+CREATE INDEX IDX_QRTZ_FT_T_G
+ ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);
+CREATE INDEX IDX_QRTZ_FT_TG
+ ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
--- ----------------------------
--- FK: qrtz_blob_triggers
--- ----------------------------
-ALTER TABLE qrtz_blob_triggers
- ADD CONSTRAINT qrtz_blob_triggers_ibfk_1 FOREIGN KEY (sched_name, trigger_name, trigger_group) REFERENCES qrtz_triggers (sched_name,
- trigger_name,
- trigger_group);
-
--- ----------------------------
--- FK: qrtz_cron_triggers
--- ----------------------------
-ALTER TABLE qrtz_cron_triggers
- ADD CONSTRAINT qrtz_cron_triggers_ibfk_1 FOREIGN KEY (sched_name, trigger_name, trigger_group) REFERENCES qrtz_triggers (sched_name, trigger_name, trigger_group);
-
--- ----------------------------
--- FK: qrtz_simple_triggers
--- ----------------------------
-ALTER TABLE qrtz_simple_triggers
- ADD CONSTRAINT qrtz_simple_triggers_ibfk_1 FOREIGN KEY (sched_name, trigger_name, trigger_group) REFERENCES qrtz_triggers (sched_name,
- trigger_name,
- trigger_group);
-
--- ----------------------------
--- FK: qrtz_simprop_triggers
--- ----------------------------
-ALTER TABLE qrtz_simprop_triggers
- ADD CONSTRAINT qrtz_simprop_triggers_ibfk_1 FOREIGN KEY (sched_name, trigger_name, trigger_group) REFERENCES qrtz_triggers (sched_name, trigger_name, trigger_group);
-
--- ----------------------------
--- FK: qrtz_triggers
--- ----------------------------
-ALTER TABLE qrtz_triggers
- ADD CONSTRAINT qrtz_triggers_ibfk_1 FOREIGN KEY (sched_name, job_name, job_group) REFERENCES qrtz_job_details (sched_name, job_name, job_group);
+COMMIT;
\ No newline at end of file
diff --git a/yudao-module-ai/pom.xml b/yudao-module-ai/pom.xml
index 4b02a7e00f..4a2323bcfa 100644
--- a/yudao-module-ai/pom.xml
+++ b/yudao-module-ai/pom.xml
@@ -19,7 +19,8 @@
国外:OpenAI、Ollama、Midjourney、StableDiffusion、Suno
- 1.0.0-M6
+ 1.0.0
+ 1.0.0.2
1.0.2
@@ -75,65 +76,73 @@
org.springframework.ai
- spring-ai-openai-spring-boot-starter
+ spring-ai-starter-model-openai
${spring-ai.version}
org.springframework.ai
- spring-ai-azure-openai-spring-boot-starter
+ spring-ai-starter-model-azure-openai
${spring-ai.version}
org.springframework.ai
- spring-ai-ollama-spring-boot-starter
+ spring-ai-starter-model-deepseek
${spring-ai.version}
org.springframework.ai
- spring-ai-stability-ai-spring-boot-starter
+ spring-ai-starter-model-ollama
${spring-ai.version}
-
- com.alibaba.cloud.ai
- spring-ai-alibaba-starter
- ${spring-ai.version}.1
-
-
-
org.springframework.ai
- spring-ai-qianfan-spring-boot-starter
+ spring-ai-starter-model-stability-ai
${spring-ai.version}
org.springframework.ai
- spring-ai-zhipuai-spring-boot-starter
+ spring-ai-starter-model-zhipuai
${spring-ai.version}
org.springframework.ai
- spring-ai-minimax-spring-boot-starter
+ spring-ai-starter-model-minimax
${spring-ai.version}
+
- org.springframework.ai
- spring-ai-moonshot-spring-boot-starter
- ${spring-ai.version}
+
+ com.alibaba.cloud.ai
+ spring-ai-alibaba-starter-dashscope
+ ${alibaba-ai.version}
+
+
+
+
+ org.springaicommunity
+ qianfan-spring-boot-starter
+ 1.0.0
+
+
+
+ org.springaicommunity
+ moonshot-spring-boot-starter
+ 1.0.0
org.springframework.ai
- spring-ai-qdrant-store
+ spring-ai-starter-vector-store-qdrant
${spring-ai.version}
org.springframework.ai
- spring-ai-redis-store
+ spring-ai-starter-vector-store-redis
${spring-ai.version}
@@ -144,7 +153,7 @@
org.springframework.ai
- spring-ai-milvus-store
+ spring-ai-starter-vector-store-milvus
${spring-ai.version}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
index a28d726b90..4ff7c9e4dc 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
@@ -5,7 +5,6 @@ import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.module.ai.framework.ai.core.AiModelFactory;
import cn.iocoder.yudao.module.ai.framework.ai.core.AiModelFactoryImpl;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.baichuan.BaiChuanChatModel;
-import cn.iocoder.yudao.module.ai.framework.ai.core.model.deepseek.DeepSeekChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.doubao.DouBaoChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.hunyuan.HunYuanChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;
@@ -14,10 +13,6 @@ import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlo
import cn.iocoder.yudao.module.ai.framework.ai.core.model.suno.api.SunoApi;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.xinghuo.XingHuoChatModel;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusServiceClientProperties;
-import org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusVectorStoreProperties;
-import org.springframework.ai.autoconfigure.vectorstore.qdrant.QdrantVectorStoreProperties;
-import org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreProperties;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.model.tool.ToolCallingManager;
@@ -26,6 +21,10 @@ import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.tokenizer.JTokkitTokenCountEstimator;
import org.springframework.ai.tokenizer.TokenCountEstimator;
+import org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusServiceClientProperties;
+import org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreProperties;
+import org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreProperties;
+import org.springframework.ai.vectorstore.redis.autoconfigure.RedisVectorStoreProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -52,33 +51,6 @@ public class AiAutoConfiguration {
// ========== 各种 AI Client 创建 ==========
- @Bean
- @ConditionalOnProperty(value = "yudao.ai.deepseek.enable", havingValue = "true")
- public DeepSeekChatModel deepSeekChatModel(YudaoAiProperties yudaoAiProperties) {
- YudaoAiProperties.DeepSeekProperties properties = yudaoAiProperties.getDeepseek();
- return buildDeepSeekChatModel(properties);
- }
-
- public DeepSeekChatModel buildDeepSeekChatModel(YudaoAiProperties.DeepSeekProperties properties) {
- if (StrUtil.isEmpty(properties.getModel())) {
- properties.setModel(DeepSeekChatModel.MODEL_DEFAULT);
- }
- OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiApi(OpenAiApi.builder()
- .baseUrl(DeepSeekChatModel.BASE_URL)
- .apiKey(properties.getApiKey())
- .build())
- .defaultOptions(OpenAiChatOptions.builder()
- .model(properties.getModel())
- .temperature(properties.getTemperature())
- .maxTokens(properties.getMaxTokens())
- .topP(properties.getTopP())
- .build())
- .toolCallingManager(getToolCallingManager())
- .build();
- return new DeepSeekChatModel(openAiChatModel);
- }
-
@Bean
@ConditionalOnProperty(value = "yudao.ai.doubao.enable", havingValue = "true")
public DouBaoChatModel douBaoChatClient(YudaoAiProperties yudaoAiProperties) {
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
index 7f8046768a..7c26aa89ca 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
@@ -13,12 +13,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
public class YudaoAiProperties {
- /**
- * DeepSeek
- */
- @SuppressWarnings("SpellCheckingInspection")
- private DeepSeekProperties deepseek;
-
/**
* 字节豆包
*/
@@ -60,19 +54,6 @@ public class YudaoAiProperties {
@SuppressWarnings("SpellCheckingInspection")
private SunoProperties suno;
- @Data
- public static class DeepSeekProperties {
-
- private String enable;
- private String apiKey;
-
- private String model;
- private Double temperature;
- private Integer maxTokens;
- private Double topP;
-
- }
-
@Data
public static class DouBaoProperties {
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactoryImpl.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactoryImpl.java
index f258ffaf1b..f7b42e30ae 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactoryImpl.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactoryImpl.java
@@ -8,11 +8,11 @@ import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
+import cn.iocoder.yudao.framework.common.util.spring.SpringUtils;
+import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
import cn.iocoder.yudao.module.ai.framework.ai.config.AiAutoConfiguration;
import cn.iocoder.yudao.module.ai.framework.ai.config.YudaoAiProperties;
-import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.baichuan.BaiChuanChatModel;
-import cn.iocoder.yudao.module.ai.framework.ai.core.model.deepseek.DeepSeekChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.doubao.DouBaoChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.hunyuan.HunYuanChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;
@@ -22,8 +22,9 @@ import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlo
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowImageModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.suno.api.SunoApi;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.xinghuo.XingHuoChatModel;
-import cn.iocoder.yudao.framework.common.util.spring.SpringUtils;
-import com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAutoConfiguration;
+import com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeChatAutoConfiguration;
+import com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeEmbeddingAutoConfiguration;
+import com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeImageAutoConfiguration;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.api.DashScopeImageApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
@@ -32,47 +33,55 @@ import com.alibaba.cloud.ai.dashscope.embedding.DashScopeEmbeddingModel;
import com.alibaba.cloud.ai.dashscope.embedding.DashScopeEmbeddingOptions;
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageModel;
import com.azure.ai.openai.OpenAIClientBuilder;
+import com.azure.core.credential.KeyCredential;
import io.micrometer.observation.ObservationRegistry;
import io.milvus.client.MilvusServiceClient;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import lombok.SneakyThrows;
-import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiAutoConfiguration;
-import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiChatProperties;
-import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiConnectionProperties;
-import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiEmbeddingProperties;
-import org.springframework.ai.autoconfigure.minimax.MiniMaxAutoConfiguration;
-import org.springframework.ai.autoconfigure.moonshot.MoonshotAutoConfiguration;
-import org.springframework.ai.autoconfigure.ollama.OllamaAutoConfiguration;
-import org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration;
-import org.springframework.ai.autoconfigure.qianfan.QianFanAutoConfiguration;
-import org.springframework.ai.autoconfigure.stabilityai.StabilityAiImageAutoConfiguration;
-import org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusServiceClientConnectionDetails;
-import org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusServiceClientProperties;
-import org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusVectorStoreAutoConfiguration;
-import org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusVectorStoreProperties;
-import org.springframework.ai.autoconfigure.vectorstore.qdrant.QdrantVectorStoreAutoConfiguration;
-import org.springframework.ai.autoconfigure.vectorstore.qdrant.QdrantVectorStoreProperties;
-import org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreAutoConfiguration;
-import org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreProperties;
-import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiAutoConfiguration;
+import org.springaicommunity.moonshot.MoonshotChatModel;
+import org.springaicommunity.moonshot.MoonshotChatOptions;
+import org.springaicommunity.moonshot.api.MoonshotApi;
+import org.springaicommunity.moonshot.autoconfigure.MoonshotChatAutoConfiguration;
+import org.springaicommunity.qianfan.QianFanChatModel;
+import org.springaicommunity.qianfan.QianFanEmbeddingModel;
+import org.springaicommunity.qianfan.QianFanEmbeddingOptions;
+import org.springaicommunity.qianfan.QianFanImageModel;
+import org.springaicommunity.qianfan.api.QianFanApi;
+import org.springaicommunity.qianfan.api.QianFanImageApi;
+import org.springaicommunity.qianfan.autoconfigure.QianFanChatAutoConfiguration;
+import org.springaicommunity.qianfan.autoconfigure.QianFanEmbeddingAutoConfiguration;
import org.springframework.ai.azure.openai.AzureOpenAiChatModel;
import org.springframework.ai.azure.openai.AzureOpenAiEmbeddingModel;
import org.springframework.ai.chat.model.ChatModel;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import org.springframework.ai.deepseek.DeepSeekChatOptions;
+import org.springframework.ai.deepseek.api.DeepSeekApi;
import org.springframework.ai.document.MetadataMode;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
+import org.springframework.ai.embedding.observation.EmbeddingModelObservationConvention;
import org.springframework.ai.image.ImageModel;
import org.springframework.ai.minimax.MiniMaxChatModel;
import org.springframework.ai.minimax.MiniMaxChatOptions;
import org.springframework.ai.minimax.MiniMaxEmbeddingModel;
import org.springframework.ai.minimax.MiniMaxEmbeddingOptions;
import org.springframework.ai.minimax.api.MiniMaxApi;
-import org.springframework.ai.model.function.FunctionCallbackResolver;
+import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiChatAutoConfiguration;
+import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiEmbeddingAutoConfiguration;
+import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiEmbeddingProperties;
+import org.springframework.ai.model.deepseek.autoconfigure.DeepSeekChatAutoConfiguration;
+import org.springframework.ai.model.minimax.autoconfigure.MiniMaxChatAutoConfiguration;
+import org.springframework.ai.model.minimax.autoconfigure.MiniMaxEmbeddingAutoConfiguration;
+import org.springframework.ai.model.ollama.autoconfigure.OllamaChatAutoConfiguration;
+import org.springframework.ai.model.openai.autoconfigure.OpenAiChatAutoConfiguration;
+import org.springframework.ai.model.openai.autoconfigure.OpenAiEmbeddingAutoConfiguration;
+import org.springframework.ai.model.openai.autoconfigure.OpenAiImageAutoConfiguration;
+import org.springframework.ai.model.stabilityai.autoconfigure.StabilityAiImageAutoConfiguration;
import org.springframework.ai.model.tool.ToolCallingManager;
-import org.springframework.ai.moonshot.MoonshotChatModel;
-import org.springframework.ai.moonshot.MoonshotChatOptions;
-import org.springframework.ai.moonshot.api.MoonshotApi;
+import org.springframework.ai.model.zhipuai.autoconfigure.ZhiPuAiChatAutoConfiguration;
+import org.springframework.ai.model.zhipuai.autoconfigure.ZhiPuAiEmbeddingAutoConfiguration;
+import org.springframework.ai.model.zhipuai.autoconfigure.ZhiPuAiImageAutoConfiguration;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.ollama.OllamaEmbeddingModel;
import org.springframework.ai.ollama.api.OllamaApi;
@@ -84,21 +93,23 @@ import org.springframework.ai.openai.OpenAiImageModel;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.openai.api.OpenAiImageApi;
import org.springframework.ai.openai.api.common.OpenAiApiConstants;
-import org.springframework.ai.qianfan.QianFanChatModel;
-import org.springframework.ai.qianfan.QianFanEmbeddingModel;
-import org.springframework.ai.qianfan.QianFanEmbeddingOptions;
-import org.springframework.ai.qianfan.QianFanImageModel;
-import org.springframework.ai.qianfan.api.QianFanApi;
-import org.springframework.ai.qianfan.api.QianFanImageApi;
import org.springframework.ai.stabilityai.StabilityAiImageModel;
import org.springframework.ai.stabilityai.api.StabilityAiApi;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.milvus.MilvusVectorStore;
+import org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusServiceClientConnectionDetails;
+import org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusServiceClientProperties;
+import org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreAutoConfiguration;
+import org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreProperties;
import org.springframework.ai.vectorstore.observation.DefaultVectorStoreObservationConvention;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.ai.vectorstore.qdrant.QdrantVectorStore;
+import org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreAutoConfiguration;
+import org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreProperties;
import org.springframework.ai.vectorstore.redis.RedisVectorStore;
+import org.springframework.ai.vectorstore.redis.autoconfigure.RedisVectorStoreAutoConfiguration;
+import org.springframework.ai.vectorstore.redis.autoconfigure.RedisVectorStoreProperties;
import org.springframework.ai.zhipuai.*;
import org.springframework.ai.zhipuai.api.ZhiPuAiApi;
import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi;
@@ -190,7 +201,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
case XING_HUO:
return SpringUtil.getBean(XingHuoChatModel.class);
case BAI_CHUAN:
- return SpringUtil.getBean(AzureOpenAiChatModel.class);
+ return SpringUtil.getBean(BaiChuanChatModel.class);
case OPENAI:
return SpringUtil.getBean(OpenAiChatModel.class);
case AZURE_OPENAI:
@@ -319,27 +330,34 @@ public class AiModelFactoryImpl implements AiModelFactory {
// ========== 各种创建 spring-ai 客户端的方法 ==========
/**
- * 可参考 {@link DashScopeAutoConfiguration} 的 dashscopeChatModel 方法
+ * 可参考 {@link DashScopeChatAutoConfiguration} 的 dashscopeChatModel 方法
*/
private static DashScopeChatModel buildTongYiChatModel(String key) {
- DashScopeApi dashScopeApi = new DashScopeApi(key);
+ DashScopeApi dashScopeApi = DashScopeApi.builder().apiKey(key).build();
DashScopeChatOptions options = DashScopeChatOptions.builder().withModel(DashScopeApi.DEFAULT_CHAT_MODEL)
.withTemperature(0.7).build();
- return new DashScopeChatModel(dashScopeApi, options, getFunctionCallbackResolver(), DEFAULT_RETRY_TEMPLATE);
+ return DashScopeChatModel.builder()
+ .dashScopeApi(dashScopeApi)
+ .defaultOptions(options)
+ .toolCallingManager(getToolCallingManager())
+ .build();
}
/**
- * 可参考 {@link DashScopeAutoConfiguration} 的 dashScopeImageModel 方法
+ * 可参考 {@link DashScopeImageAutoConfiguration} 的 dashScopeImageModel 方法
*/
private static DashScopeImageModel buildTongYiImagesModel(String key) {
DashScopeImageApi dashScopeImageApi = new DashScopeImageApi(key);
- return new DashScopeImageModel(dashScopeImageApi);
+ return DashScopeImageModel.builder()
+ .dashScopeApi(dashScopeImageApi)
+ .build();
}
/**
- * 可参考 {@link QianFanAutoConfiguration} 的 qianFanChatModel 方法
+ * 可参考 {@link QianFanChatAutoConfiguration} 的 qianFanChatModel 方法
*/
private static QianFanChatModel buildYiYanChatModel(String key) {
+ // TODO spring ai qianfan 有 bug,无法使用 https://github.com/spring-ai-community/qianfan/issues/6
List keys = StrUtil.split(key, '|');
Assert.equals(keys.size(), 2, "YiYanChatClient 的密钥需要 (appKey|secretKey) 格式");
String appKey = keys.get(0);
@@ -349,9 +367,10 @@ public class AiModelFactoryImpl implements AiModelFactory {
}
/**
- * 可参考 {@link QianFanAutoConfiguration} 的 qianFanImageModel 方法
+ * 可参考 {@link QianFanEmbeddingAutoConfiguration} 的 qianFanImageModel 方法
*/
private QianFanImageModel buildQianFanImageModel(String key) {
+ // TODO spring ai qianfan 有 bug,无法使用 https://github.com/spring-ai-community/qianfan/issues/6
List keys = StrUtil.split(key, '|');
Assert.equals(keys.size(), 2, "YiYanChatClient 的密钥需要 (appKey|secretKey) 格式");
String appKey = keys.get(0);
@@ -361,12 +380,17 @@ public class AiModelFactoryImpl implements AiModelFactory {
}
/**
- * 可参考 {@link AiAutoConfiguration#deepSeekChatModel(YudaoAiProperties)}
+ * 可参考 {@link DeepSeekChatAutoConfiguration} 的 deepSeekChatModel 方法
*/
private static DeepSeekChatModel buildDeepSeekChatModel(String apiKey) {
- YudaoAiProperties.DeepSeekProperties properties = new YudaoAiProperties.DeepSeekProperties()
- .setApiKey(apiKey);
- return new AiAutoConfiguration().buildDeepSeekChatModel(properties);
+ DeepSeekApi deepSeekApi = DeepSeekApi.builder().apiKey(apiKey).build();
+ DeepSeekChatOptions options = DeepSeekChatOptions.builder().model(DeepSeekApi.DEFAULT_CHAT_MODEL)
+ .temperature(0.7).build();
+ return DeepSeekChatModel.builder()
+ .deepSeekApi(deepSeekApi)
+ .defaultOptions(options)
+ .toolCallingManager(getToolCallingManager())
+ .build();
}
/**
@@ -397,17 +421,18 @@ public class AiModelFactoryImpl implements AiModelFactory {
}
/**
- * 可参考 {@link ZhiPuAiAutoConfiguration} 的 zhiPuAiChatModel 方法
+ * 可参考 {@link ZhiPuAiChatAutoConfiguration} 的 zhiPuAiChatModel 方法
*/
private ZhiPuAiChatModel buildZhiPuChatModel(String apiKey, String url) {
ZhiPuAiApi zhiPuAiApi = StrUtil.isEmpty(url) ? new ZhiPuAiApi(apiKey)
: new ZhiPuAiApi(url, apiKey);
ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder().model(ZhiPuAiApi.DEFAULT_CHAT_MODEL).temperature(0.7).build();
- return new ZhiPuAiChatModel(zhiPuAiApi, options, getFunctionCallbackResolver(), DEFAULT_RETRY_TEMPLATE);
+ return new ZhiPuAiChatModel(zhiPuAiApi, options, getToolCallingManager(), DEFAULT_RETRY_TEMPLATE,
+ getObservationRegistry().getIfAvailable());
}
/**
- * 可参考 {@link ZhiPuAiAutoConfiguration} 的 zhiPuAiImageModel 方法
+ * 可参考 {@link ZhiPuAiImageAutoConfiguration} 的 zhiPuAiImageModel 方法
*/
private ZhiPuAiImageModel buildZhiPuAiImageModel(String apiKey, String url) {
ZhiPuAiImageApi zhiPuAiApi = StrUtil.isEmpty(url) ? new ZhiPuAiImageApi(apiKey)
@@ -416,23 +441,30 @@ public class AiModelFactoryImpl implements AiModelFactory {
}
/**
- * 可参考 {@link MiniMaxAutoConfiguration} 的 miniMaxChatModel 方法
+ * 可参考 {@link MiniMaxChatAutoConfiguration} 的 miniMaxChatModel 方法
*/
private MiniMaxChatModel buildMiniMaxChatModel(String apiKey, String url) {
MiniMaxApi miniMaxApi = StrUtil.isEmpty(url) ? new MiniMaxApi(apiKey)
: new MiniMaxApi(url, apiKey);
MiniMaxChatOptions options = MiniMaxChatOptions.builder().model(MiniMaxApi.DEFAULT_CHAT_MODEL).temperature(0.7).build();
- return new MiniMaxChatModel(miniMaxApi, options, getFunctionCallbackResolver(), DEFAULT_RETRY_TEMPLATE);
+ return new MiniMaxChatModel(miniMaxApi, options, getToolCallingManager(), DEFAULT_RETRY_TEMPLATE);
}
/**
- * 可参考 {@link MoonshotAutoConfiguration} 的 moonshotChatModel 方法
+ * 可参考 {@link MoonshotChatAutoConfiguration} 的 moonshotChatModel 方法
*/
private MoonshotChatModel buildMoonshotChatModel(String apiKey, String url) {
- MoonshotApi moonshotApi = StrUtil.isEmpty(url)? new MoonshotApi(apiKey)
- : new MoonshotApi(url, apiKey);
+ MoonshotApi.Builder moonshotApiBuilder = MoonshotApi.builder()
+ .apiKey(apiKey);
+ if (StrUtil.isNotEmpty(url)) {
+ moonshotApiBuilder.baseUrl(url);
+ }
MoonshotChatOptions options = MoonshotChatOptions.builder().model(MoonshotApi.DEFAULT_CHAT_MODEL).build();
- return new MoonshotChatModel(moonshotApi, options, getFunctionCallbackResolver(), DEFAULT_RETRY_TEMPLATE);
+ return MoonshotChatModel.builder()
+ .moonshotApi(moonshotApiBuilder.build())
+ .defaultOptions(options)
+ .toolCallingManager(getToolCallingManager())
+ .build();
}
/**
@@ -456,33 +488,32 @@ public class AiModelFactoryImpl implements AiModelFactory {
}
/**
- * 可参考 {@link OpenAiAutoConfiguration} 的 openAiChatModel 方法
+ * 可参考 {@link OpenAiChatAutoConfiguration} 的 openAiChatModel 方法
*/
private static OpenAiChatModel buildOpenAiChatModel(String openAiToken, String url) {
url = StrUtil.blankToDefault(url, OpenAiApiConstants.DEFAULT_BASE_URL);
OpenAiApi openAiApi = OpenAiApi.builder().baseUrl(url).apiKey(openAiToken).build();
- return OpenAiChatModel.builder().openAiApi(openAiApi).toolCallingManager(getToolCallingManager()).build();
+ return OpenAiChatModel.builder()
+ .openAiApi(openAiApi)
+ .toolCallingManager(getToolCallingManager())
+ .build();
}
- // TODO @芋艿:手头暂时没密钥,使用建议再测试下
/**
- * 可参考 {@link AzureOpenAiAutoConfiguration}
+ * 可参考 {@link AzureOpenAiChatAutoConfiguration}
*/
private static AzureOpenAiChatModel buildAzureOpenAiChatModel(String apiKey, String url) {
- AzureOpenAiAutoConfiguration azureOpenAiAutoConfiguration = new AzureOpenAiAutoConfiguration();
- // 创建 OpenAIClient 对象
- AzureOpenAiConnectionProperties connectionProperties = new AzureOpenAiConnectionProperties();
- connectionProperties.setApiKey(apiKey);
- connectionProperties.setEndpoint(url);
- OpenAIClientBuilder openAIClient = azureOpenAiAutoConfiguration.openAIClientBuilder(connectionProperties, null);
- // 获取 AzureOpenAiChatProperties 对象
- AzureOpenAiChatProperties chatProperties = SpringUtil.getBean(AzureOpenAiChatProperties.class);
- return azureOpenAiAutoConfiguration.azureOpenAiChatModel(openAIClient, chatProperties,
- getToolCallingManager(), null, null);
+ // TODO @芋艿:使用前,请测试,暂时没密钥!!!
+ OpenAIClientBuilder openAIClientBuilder = new OpenAIClientBuilder()
+ .endpoint(url).credential(new KeyCredential(apiKey));
+ return AzureOpenAiChatModel.builder()
+ .openAIClientBuilder(openAIClientBuilder)
+ .toolCallingManager(getToolCallingManager())
+ .build();
}
/**
- * 可参考 {@link OpenAiAutoConfiguration} 的 openAiImageModel 方法
+ * 可参考 {@link OpenAiImageAutoConfiguration} 的 openAiImageModel 方法
*/
private OpenAiImageModel buildOpenAiImageModel(String openAiToken, String url) {
url = StrUtil.blankToDefault(url, OpenAiApiConstants.DEFAULT_BASE_URL);
@@ -500,11 +531,14 @@ public class AiModelFactoryImpl implements AiModelFactory {
}
/**
- * 可参考 {@link OllamaAutoConfiguration} 的 ollamaApi 方法
+ * 可参考 {@link OllamaChatAutoConfiguration} 的 ollamaChatModel 方法
*/
private static OllamaChatModel buildOllamaChatModel(String url) {
- OllamaApi ollamaApi = new OllamaApi(url);
- return OllamaChatModel.builder().ollamaApi(ollamaApi).toolCallingManager(getToolCallingManager()).build();
+ OllamaApi ollamaApi = OllamaApi.builder().baseUrl(url).build();
+ return OllamaChatModel.builder()
+ .ollamaApi(ollamaApi)
+ .toolCallingManager(getToolCallingManager())
+ .build();
}
/**
@@ -519,16 +553,16 @@ public class AiModelFactoryImpl implements AiModelFactory {
// ========== 各种创建 EmbeddingModel 的方法 ==========
/**
- * 可参考 {@link DashScopeAutoConfiguration} 的 dashscopeEmbeddingModel 方法
+ * 可参考 {@link DashScopeEmbeddingAutoConfiguration} 的 dashscopeEmbeddingModel 方法
*/
private DashScopeEmbeddingModel buildTongYiEmbeddingModel(String apiKey, String model) {
- DashScopeApi dashScopeApi = new DashScopeApi(apiKey);
+ DashScopeApi dashScopeApi = DashScopeApi.builder().apiKey(apiKey).build();
DashScopeEmbeddingOptions dashScopeEmbeddingOptions = DashScopeEmbeddingOptions.builder().withModel(model).build();
return new DashScopeEmbeddingModel(dashScopeApi, MetadataMode.EMBED, dashScopeEmbeddingOptions);
}
/**
- * 可参考 {@link ZhiPuAiAutoConfiguration} 的 zhiPuAiEmbeddingModel 方法
+ * 可参考 {@link ZhiPuAiEmbeddingAutoConfiguration} 的 zhiPuAiEmbeddingModel 方法
*/
private ZhiPuAiEmbeddingModel buildZhiPuEmbeddingModel(String apiKey, String url, String model) {
ZhiPuAiApi zhiPuAiApi = StrUtil.isEmpty(url) ? new ZhiPuAiApi(apiKey)
@@ -538,7 +572,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
}
/**
- * 可参考 {@link MiniMaxAutoConfiguration} 的 miniMaxEmbeddingModel 方法
+ * 可参考 {@link MiniMaxEmbeddingAutoConfiguration} 的 miniMaxEmbeddingModel 方法
*/
private EmbeddingModel buildMiniMaxEmbeddingModel(String apiKey, String url, String model) {
MiniMaxApi miniMaxApi = StrUtil.isEmpty(url)? new MiniMaxApi(apiKey)
@@ -548,7 +582,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
}
/**
- * 可参考 {@link QianFanAutoConfiguration} 的 qianFanEmbeddingModel 方法
+ * 可参考 {@link QianFanEmbeddingAutoConfiguration} 的 qianFanEmbeddingModel 方法
*/
private QianFanEmbeddingModel buildYiYanEmbeddingModel(String key, String model) {
List keys = StrUtil.split(key, '|');
@@ -561,13 +595,16 @@ public class AiModelFactoryImpl implements AiModelFactory {
}
private OllamaEmbeddingModel buildOllamaEmbeddingModel(String url, String model) {
- OllamaApi ollamaApi = new OllamaApi(url);
+ OllamaApi ollamaApi = OllamaApi.builder().baseUrl(url).build();
OllamaOptions ollamaOptions = OllamaOptions.builder().model(model).build();
- return OllamaEmbeddingModel.builder().ollamaApi(ollamaApi).defaultOptions(ollamaOptions).build();
+ return OllamaEmbeddingModel.builder()
+ .ollamaApi(ollamaApi)
+ .defaultOptions(ollamaOptions)
+ .build();
}
/**
- * 可参考 {@link OpenAiAutoConfiguration} 的 openAiEmbeddingModel 方法
+ * 可参考 {@link OpenAiEmbeddingAutoConfiguration} 的 openAiEmbeddingModel 方法
*/
private OpenAiEmbeddingModel buildOpenAiEmbeddingModel(String openAiToken, String url, String model) {
url = StrUtil.blankToDefault(url, OpenAiApiConstants.DEFAULT_BASE_URL);
@@ -576,21 +613,19 @@ public class AiModelFactoryImpl implements AiModelFactory {
return new OpenAiEmbeddingModel(openAiApi, MetadataMode.EMBED, openAiEmbeddingProperties);
}
- // TODO @芋艿:手头暂时没密钥,使用建议再测试下
/**
- * 可参考 {@link AzureOpenAiAutoConfiguration} 的 azureOpenAiEmbeddingModel 方法
+ * 可参考 {@link AzureOpenAiEmbeddingAutoConfiguration} 的 azureOpenAiEmbeddingModel 方法
*/
private AzureOpenAiEmbeddingModel buildAzureOpenAiEmbeddingModel(String apiKey, String url, String model) {
- AzureOpenAiAutoConfiguration azureOpenAiAutoConfiguration = new AzureOpenAiAutoConfiguration();
- // 创建 OpenAIClient 对象
- AzureOpenAiConnectionProperties connectionProperties = new AzureOpenAiConnectionProperties();
- connectionProperties.setApiKey(apiKey);
- connectionProperties.setEndpoint(url);
- OpenAIClientBuilder openAIClient = azureOpenAiAutoConfiguration.openAIClientBuilder(connectionProperties, null);
+ // TODO @芋艿:手头暂时没密钥,使用建议再测试下
+ AzureOpenAiEmbeddingAutoConfiguration azureOpenAiAutoConfiguration = new AzureOpenAiEmbeddingAutoConfiguration();
+ // 创建 OpenAIClientBuilder 对象
+ OpenAIClientBuilder openAIClientBuilder = new OpenAIClientBuilder()
+ .endpoint(url).credential(new KeyCredential(apiKey));
// 获取 AzureOpenAiChatProperties 对象
AzureOpenAiEmbeddingProperties embeddingProperties = SpringUtil.getBean(AzureOpenAiEmbeddingProperties.class);
- return azureOpenAiAutoConfiguration.azureOpenAiEmbeddingModel(openAIClient, embeddingProperties,
- null, null);
+ return azureOpenAiAutoConfiguration.azureOpenAiEmbeddingModel(openAIClientBuilder, embeddingProperties,
+ getObservationRegistry(), getEmbeddingModelObservationConvention());
}
// ========== 各种创建 VectorStore 的方法 ==========
@@ -655,12 +690,12 @@ public class AiModelFactoryImpl implements AiModelFactory {
Map> metadataFields) {
// 创建 JedisPooled 对象
RedisProperties redisProperties = SpringUtils.getBean(RedisProperties.class);
- JedisPooled jedisPooled = new JedisPooled(redisProperties.getHost(), redisProperties.getPort());
+ JedisPooled jedisPooled = new JedisPooled(redisProperties.getHost(), redisProperties.getPort(),
+ redisProperties.getUsername(), redisProperties.getPassword());
// 创建 RedisVectorStoreProperties 对象
- RedisVectorStoreAutoConfiguration configuration = new RedisVectorStoreAutoConfiguration();
RedisVectorStoreProperties properties = SpringUtil.getBean(RedisVectorStoreProperties.class);
RedisVectorStore redisVectorStore = RedisVectorStore.builder(jedisPooled, embeddingModel)
- .indexName(properties.getIndex()).prefix(properties.getPrefix())
+ .indexName(properties.getIndexName()).prefix(properties.getPrefix())
.initializeSchema(properties.isInitializeSchema())
.metadataFields(convertList(metadataFields.entrySet(), entry -> {
String fieldName = entry.getKey();
@@ -730,10 +765,12 @@ public class AiModelFactoryImpl implements AiModelFactory {
private static ObjectProvider getCustomObservationConvention() {
return new ObjectProvider<>() {
+
@Override
public VectorStoreObservationConvention getObject() throws BeansException {
return new DefaultVectorStoreObservationConvention();
}
+
};
}
@@ -745,8 +782,15 @@ public class AiModelFactoryImpl implements AiModelFactory {
return SpringUtil.getBean(ToolCallingManager.class);
}
- private static FunctionCallbackResolver getFunctionCallbackResolver() {
- return SpringUtil.getBean(FunctionCallbackResolver.class);
+ private static ObjectProvider getEmbeddingModelObservationConvention() {
+ return new ObjectProvider<>() {
+
+ @Override
+ public EmbeddingModelObservationConvention getObject() throws BeansException {
+ return SpringUtil.getBean(EmbeddingModelObservationConvention.class);
+ }
+
+ };
}
}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/deepseek/DeepSeekChatModel.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/deepseek/DeepSeekChatModel.java
deleted file mode 100644
index d603abf6b0..0000000000
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/deepseek/DeepSeekChatModel.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package cn.iocoder.yudao.module.ai.framework.ai.core.model.deepseek;
-
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.ai.chat.model.ChatModel;
-import org.springframework.ai.chat.model.ChatResponse;
-import org.springframework.ai.chat.prompt.ChatOptions;
-import org.springframework.ai.chat.prompt.Prompt;
-import org.springframework.ai.openai.OpenAiChatModel;
-import reactor.core.publisher.Flux;
-
-/**
- * DeepSeek {@link ChatModel} 实现类
- *
- * @author fansili
- */
-@Slf4j
-@RequiredArgsConstructor
-public class DeepSeekChatModel implements ChatModel {
-
- public static final String BASE_URL = "https://api.deepseek.com";
-
- public static final String MODEL_DEFAULT = "deepseek-chat";
-
- /**
- * 兼容 OpenAI 接口,进行复用
- */
- private final OpenAiChatModel openAiChatModel;
-
- @Override
- public ChatResponse call(Prompt prompt) {
- return openAiChatModel.call(prompt);
- }
-
- @Override
- public Flux stream(Prompt prompt) {
- return openAiChatModel.stream(prompt);
- }
-
- @Override
- public ChatOptions getDefaultOptions() {
- return openAiChatModel.getDefaultOptions();
- }
-
-}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageModel.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageModel.java
index 43f8ad2168..44a652309e 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageModel.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageModel.java
@@ -89,7 +89,7 @@ public class SiliconFlowImageModel implements ImageModel {
var observationContext = ImageModelObservationContext.builder()
.imagePrompt(imagePrompt)
.provider(SiliconFlowApiConstants.PROVIDER_NAME)
- .requestOptions(imagePrompt.getOptions())
+ .imagePrompt(imagePrompt)
.build();
return ImageModelObservationDocumentation.IMAGE_MODEL_OPERATION
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java
index 671098a704..79214a0325 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java
@@ -9,9 +9,6 @@ import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.http.HttpUtil;
-import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
-import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;
-import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowImageOptions;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDrawReqVO;
@@ -24,17 +21,20 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO;
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO;
import cn.iocoder.yudao.module.ai.dal.mysql.image.AiImageMapper;
import cn.iocoder.yudao.module.ai.enums.image.AiImageStatusEnum;
+import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowImageOptions;
import cn.iocoder.yudao.module.ai.service.model.AiModelService;
import cn.iocoder.yudao.module.infra.api.file.FileApi;
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageOptions;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
+import org.springaicommunity.qianfan.QianFanImageOptions;
import org.springframework.ai.image.ImageModel;
import org.springframework.ai.image.ImageOptions;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.ai.openai.OpenAiImageOptions;
-import org.springframework.ai.qianfan.QianFanImageOptions;
import org.springframework.ai.stabilityai.api.StabilityAiImageOptions;
import org.springframework.ai.zhipuai.ZhiPuAiImageOptions;
import org.springframework.scheduling.annotation.Async;
@@ -140,10 +140,10 @@ public class AiImageServiceImpl implements AiImageService {
private static ImageOptions buildImageOptions(AiImageDrawReqVO draw, AiModelDO model) {
if (ObjUtil.equal(model.getPlatform(), AiPlatformEnum.OPENAI.getPlatform())) {
// https://platform.openai.com/docs/api-reference/images/create
- return OpenAiImageOptions.builder().withModel(model.getModel())
- .withHeight(draw.getHeight()).withWidth(draw.getWidth())
- .withStyle(MapUtil.getStr(draw.getOptions(), "style")) // 风格
- .withResponseFormat("b64_json")
+ return OpenAiImageOptions.builder().model(model.getModel())
+ .height(draw.getHeight()).width(draw.getWidth())
+ .style(MapUtil.getStr(draw.getOptions(), "style")) // 风格
+ .responseFormat("b64_json")
.build();
} else if (ObjUtil.equal(model.getPlatform(), AiPlatformEnum.SILICON_FLOW.getPlatform())) {
// https://docs.siliconflow.cn/cn/api-reference/images/images-generations
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/model/tool/UserProfileQueryToolFunction.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/model/tool/UserProfileQueryToolFunction.java
index 6e0ba51c9e..5656d39292 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/model/tool/UserProfileQueryToolFunction.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/model/tool/UserProfileQueryToolFunction.java
@@ -7,6 +7,8 @@ import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.fasterxml.jackson.annotation.JsonClassDescription;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -17,7 +19,7 @@ import org.springframework.stereotype.Component;
import java.util.function.BiFunction;
/**
- * 工具:当前用户信息查询
+ * 工具:用户信息查询
*
* 同时,也是展示 ToolContext 上下文的使用
*
@@ -31,8 +33,17 @@ public class UserProfileQueryToolFunction
private AdminUserApi adminUserApi;
@Data
- @JsonClassDescription("当前用户信息查询")
- public static class Request { }
+ @JsonClassDescription("用户信息查询")
+ public static class Request {
+
+ /**
+ * 用户编号
+ */
+ @JsonProperty(value = "id")
+ @JsonPropertyDescription("用户编号,例如说:1。如果查询自己,则 id 为空")
+ private Long id;
+
+ }
@Data
@AllArgsConstructor
@@ -61,13 +72,19 @@ public class UserProfileQueryToolFunction
@Override
public Response apply(Request request, ToolContext toolContext) {
- LoginUser loginUser = (LoginUser) toolContext.getContext().get(AiUtils.TOOL_CONTEXT_LOGIN_USER);
Long tenantId = (Long) toolContext.getContext().get(AiUtils.TOOL_CONTEXT_TENANT_ID);
- if (loginUser == null | tenantId == null) {
- return null;
+ if (tenantId == null) {
+ return new Response();
+ }
+ if (request.getId() == null) {
+ LoginUser loginUser = (LoginUser) toolContext.getContext().get(AiUtils.TOOL_CONTEXT_LOGIN_USER);
+ if (loginUser == null) {
+ return new Response();
+ }
+ request.setId(loginUser.getId());
}
return TenantUtils.execute(tenantId, () -> {
- AdminUserRespDTO user = adminUserApi.getUser(loginUser.getId());
+ AdminUserRespDTO user = adminUserApi.getUser(request.getId());
return BeanUtils.toBean(user, Response.class);
});
}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
index ac3ff39a49..0744ff6307 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
@@ -2,18 +2,18 @@ package cn.iocoder.yudao.module.ai.util;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
-import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
+import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
+import org.springaicommunity.moonshot.MoonshotChatOptions;
+import org.springaicommunity.qianfan.QianFanChatOptions;
import org.springframework.ai.azure.openai.AzureOpenAiChatOptions;
import org.springframework.ai.chat.messages.*;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.minimax.MiniMaxChatOptions;
-import org.springframework.ai.moonshot.MoonshotChatOptions;
import org.springframework.ai.ollama.api.OllamaOptions;
import org.springframework.ai.openai.OpenAiChatOptions;
-import org.springframework.ai.qianfan.QianFanChatOptions;
import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
import java.util.Collections;
@@ -43,18 +43,18 @@ public class AiUtils {
switch (platform) {
case TONG_YI:
return DashScopeChatOptions.builder().withModel(model).withTemperature(temperature).withMaxToken(maxTokens)
- .withFunctions(toolNames).withToolContext(toolContext).build();
+ .withToolNames(toolNames).withToolContext(toolContext).build();
case YI_YAN:
return QianFanChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
case ZHI_PU:
return ZhiPuAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
- .functions(toolNames).toolContext(toolContext).build();
+ .toolNames(toolNames).toolContext(toolContext).build();
case MINI_MAX:
return MiniMaxChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
- .functions(toolNames).toolContext(toolContext).build();
+ .toolNames(toolNames).toolContext(toolContext).build();
case MOONSHOT:
return MoonshotChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
- .functions(toolNames).toolContext(toolContext).build();
+ .toolNames(toolNames).toolContext(toolContext).build();
case OPENAI:
case DEEP_SEEK: // 复用 OpenAI 客户端
case DOU_BAO: // 复用 OpenAI 客户端
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AzureOpenAIChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AzureOpenAIChatModelTests.java
index 5c924a5823..69776d8e68 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AzureOpenAIChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AzureOpenAIChatModelTests.java
@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
-import com.azure.core.util.ClientOptions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.azure.openai.AzureOpenAiChatModel;
@@ -17,7 +16,7 @@ import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
-import static org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiChatProperties.DEFAULT_DEPLOYMENT_NAME;
+import static org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiChatProperties.DEFAULT_DEPLOYMENT_NAME;
/**
* {@link AzureOpenAiChatModel} 集成测试
@@ -29,10 +28,13 @@ public class AzureOpenAIChatModelTests {
// TODO @芋艿:晚点在调整
private final OpenAIClientBuilder openAiApi = new OpenAIClientBuilder()
.endpoint("https://eastusprejade.openai.azure.com")
- .credential(new AzureKeyCredential("xxx"))
- .clientOptions((new ClientOptions()).setApplicationId("spring-ai"));
- private final AzureOpenAiChatModel chatModel = new AzureOpenAiChatModel(openAiApi,
- AzureOpenAiChatOptions.builder().deploymentName(DEFAULT_DEPLOYMENT_NAME).build());
+ .credential(new AzureKeyCredential("xxx"));
+ private final AzureOpenAiChatModel chatModel = AzureOpenAiChatModel.builder()
+ .openAIClientBuilder(openAiApi)
+ .defaultOptions(AzureOpenAiChatOptions.builder()
+ .deploymentName(DEFAULT_DEPLOYMENT_NAME)
+ .build())
+ .build();
@Test
@Disabled
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/BaiChuanChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/BaiChuanChatModelTests.java
index d1cc381fb9..06b0b25653 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/BaiChuanChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/BaiChuanChatModelTests.java
@@ -1,7 +1,6 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.baichuan.BaiChuanChatModel;
-import cn.iocoder.yudao.module.ai.framework.ai.core.model.deepseek.DeepSeekChatModel;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
@@ -35,7 +34,7 @@ public class BaiChuanChatModelTests {
.build())
.build();
- private final DeepSeekChatModel chatModel = new DeepSeekChatModel(openAiChatModel);
+ private final BaiChuanChatModel chatModel = new BaiChuanChatModel(openAiChatModel);
@Test
@Disabled
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DeepSeekChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DeepSeekChatModelTests.java
index d20a1761f6..7b51df1662 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DeepSeekChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DeepSeekChatModelTests.java
@@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
-import cn.iocoder.yudao.module.ai.framework.ai.core.model.deepseek.DeepSeekChatModel;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
@@ -8,9 +7,9 @@ import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
-import org.springframework.ai.openai.OpenAiChatModel;
-import org.springframework.ai.openai.OpenAiChatOptions;
-import org.springframework.ai.openai.api.OpenAiApi;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import org.springframework.ai.deepseek.DeepSeekChatOptions;
+import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
@@ -23,19 +22,16 @@ import java.util.List;
*/
public class DeepSeekChatModelTests {
- private final OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiApi(OpenAiApi.builder()
- .baseUrl(DeepSeekChatModel.BASE_URL)
- .apiKey("sk-e52047409b144d97b791a6a46a2d") // apiKey
+ private final DeepSeekChatModel chatModel = DeepSeekChatModel.builder()
+ .deepSeekApi(DeepSeekApi.builder()
+ .apiKey("sk-eaf4172a057344dd9bc64b1f806b6axx") // apiKey
.build())
- .defaultOptions(OpenAiChatOptions.builder()
+ .defaultOptions(DeepSeekChatOptions.builder()
.model("deepseek-chat") // 模型
.temperature(0.7)
.build())
.build();
- private final DeepSeekChatModel chatModel = new DeepSeekChatModel(openAiChatModel);
-
@Test
@Disabled
public void testCall() {
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/LlamaChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/LlamaChatModelTests.java
index 153342d44c..69e2c1daaa 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/LlamaChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/LlamaChatModelTests.java
@@ -1,20 +1,6 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
-import org.springframework.ai.chat.messages.Message;
-import org.springframework.ai.chat.messages.SystemMessage;
-import org.springframework.ai.chat.messages.UserMessage;
-import org.springframework.ai.chat.model.ChatResponse;
-import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.ollama.OllamaChatModel;
-import org.springframework.ai.ollama.api.OllamaApi;
-import org.springframework.ai.ollama.api.OllamaModel;
-import org.springframework.ai.ollama.api.OllamaOptions;
-import reactor.core.publisher.Flux;
-
-import java.util.ArrayList;
-import java.util.List;
/**
* {@link OllamaChatModel} 集成测试
@@ -23,43 +9,43 @@ import java.util.List;
*/
public class LlamaChatModelTests {
- private final OllamaChatModel chatModel = OllamaChatModel.builder()
- .ollamaApi(new OllamaApi("http://127.0.0.1:11434")) // Ollama 服务地址
- .defaultOptions(OllamaOptions.builder()
- .model(OllamaModel.LLAMA3.getName()) // 模型
- .build())
- .build();
-
- @Test
- @Disabled
- public void testCall() {
- // 准备参数
- List messages = new ArrayList<>();
- messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
- messages.add(new UserMessage("1 + 1 = ?"));
-
- // 调用
- ChatResponse response = chatModel.call(new Prompt(messages));
- // 打印结果
- System.out.println(response);
- System.out.println(response.getResult().getOutput());
- }
-
- @Test
- @Disabled
- public void testStream() {
- // 准备参数
- List messages = new ArrayList<>();
- messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
- messages.add(new UserMessage("1 + 1 = ?"));
-
- // 调用
- Flux flux = chatModel.stream(new Prompt(messages));
- // 打印结果
- flux.doOnNext(response -> {
-// System.out.println(response);
- System.out.println(response.getResult().getOutput());
- }).then().block();
- }
+// private final OllamaChatModel chatModel = OllamaChatModel.builder()
+// .ollamaApi(new OllamaApi("http://127.0.0.1:11434")) // Ollama 服务地址
+// .defaultOptions(OllamaOptions.builder()
+// .model(OllamaModel.LLAMA3.getName()) // 模型
+// .build())
+// .build();
+//
+// @Test
+// @Disabled
+// public void testCall() {
+// // 准备参数
+// List messages = new ArrayList<>();
+// messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
+// messages.add(new UserMessage("1 + 1 = ?"));
+//
+// // 调用
+// ChatResponse response = chatModel.call(new Prompt(messages));
+// // 打印结果
+// System.out.println(response);
+// System.out.println(response.getResult().getOutput());
+// }
+//
+// @Test
+// @Disabled
+// public void testStream() {
+// // 准备参数
+// List messages = new ArrayList<>();
+// messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
+// messages.add(new UserMessage("1 + 1 = ?"));
+//
+// // 调用
+// Flux flux = chatModel.stream(new Prompt(messages));
+// // 打印结果
+// flux.doOnNext(response -> {
+//// System.out.println(response);
+// System.out.println(response.getResult().getOutput());
+// }).then().block();
+// }
}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MoonshotChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MoonshotChatModelTests.java
index 7de7fd709c..992334b4d9 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MoonshotChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MoonshotChatModelTests.java
@@ -2,14 +2,14 @@ package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
+import org.springaicommunity.moonshot.MoonshotChatModel;
+import org.springaicommunity.moonshot.MoonshotChatOptions;
+import org.springaicommunity.moonshot.api.MoonshotApi;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
-import org.springframework.ai.moonshot.MoonshotChatModel;
-import org.springframework.ai.moonshot.MoonshotChatOptions;
-import org.springframework.ai.moonshot.api.MoonshotApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
@@ -22,11 +22,15 @@ import java.util.List;
*/
public class MoonshotChatModelTests {
- private final MoonshotChatModel chatModel = new MoonshotChatModel(
- new MoonshotApi("sk-aHYYV1SARscItye5QQRRNbXij4fy65Ee7pNZlC9gsSQnUKXA"), // 密钥
- MoonshotChatOptions.builder()
- .model("moonshot-v1-8k") // 模型
- .build());
+ private final MoonshotChatModel chatModel = MoonshotChatModel.builder()
+ .moonshotApi(MoonshotApi.builder()
+ .apiKey("sk-aHYYV1SARscItye5QQRRNbXij4fy65Ee7pNZlC9gsSQnUKXA") // 密钥
+ .build())
+ .defaultOptions(MoonshotChatOptions.builder()
+ .model("kimi-k2-0711-preview") // 模型
+ .build())
+ .build();
+
@Test
@Disabled
public void testCall() {
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OllamaChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OllamaChatModelTests.java
index f86e67a667..d2bf68812b 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OllamaChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OllamaChatModelTests.java
@@ -23,7 +23,9 @@ import java.util.List;
public class OllamaChatModelTests {
private final OllamaChatModel chatModel = OllamaChatModel.builder()
- .ollamaApi(new OllamaApi("http://127.0.0.1:11434")) // Ollama 服务地址
+ .ollamaApi(OllamaApi.builder()
+ .baseUrl("http://127.0.0.1:11434") // Ollama 服务地址
+ .build())
.defaultOptions(OllamaOptions.builder()
// .model("qwen") // 模型(https://ollama.com/library/qwen)
.model("deepseek-r1") // 模型(https://ollama.com/library/deepseek-r1)
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OpenAIChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OpenAIChatModelTests.java
index ff866fe40b..c650fd0420 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OpenAIChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OpenAIChatModelTests.java
@@ -25,10 +25,10 @@ public class OpenAIChatModelTests {
private final OpenAiChatModel chatModel = OpenAiChatModel.builder()
.openAiApi(OpenAiApi.builder()
.baseUrl("https://api.holdai.top")
- .apiKey("sk-aN6nWn3fILjrgLFT0fC4Aa60B72e4253826c77B29dC94f17") // apiKey
+ .apiKey("sk-PytRecQlmjEteoa2RRN6cGnwslo72UUPLQVNEMS6K9yjbmpD") // apiKey
.build())
.defaultOptions(OpenAiChatOptions.builder()
- .model(OpenAiApi.ChatModel.GPT_4_O) // 模型
+ .model(OpenAiApi.ChatModel.GPT_4_1_NANO) // 模型
.temperature(0.7)
.build())
.build();
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/TongYiChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/TongYiChatModelTests.java
index 4f0efdb20c..4f2e27edd2 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/TongYiChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/TongYiChatModelTests.java
@@ -22,14 +22,17 @@ import java.util.List;
*/
public class TongYiChatModelTests {
- private final DashScopeChatModel chatModel = new DashScopeChatModel(
- new DashScopeApi("sk-7d903764249848cfa912733146da12d1"),
- DashScopeChatOptions.builder()
+ private final DashScopeChatModel chatModel = DashScopeChatModel.builder()
+ .dashScopeApi(DashScopeApi.builder()
+ .apiKey("sk-47aa124781be4bfb95244cc62f63f7d0")
+ .build())
+ .defaultOptions( DashScopeChatOptions.builder()
.withModel("qwen1.5-72b-chat") // 模型
// .withModel("deepseek-r1") // 模型(deepseek-r1)
// .withModel("deepseek-v3") // 模型(deepseek-v3)
// .withModel("deepseek-r1-distill-qwen-1.5b") // 模型(deepseek-r1-distill-qwen-1.5b)
- .build());
+ .build())
+ .build();
@Test
@Disabled
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/YiYanChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/YiYanChatModelTests.java
index ab6f642437..cb7be2a296 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/YiYanChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/YiYanChatModelTests.java
@@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
+import org.springaicommunity.qianfan.QianFanChatModel;
+import org.springaicommunity.qianfan.QianFanChatOptions;
+import org.springaicommunity.qianfan.api.QianFanApi;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
-import org.springframework.ai.qianfan.QianFanChatModel;
-import org.springframework.ai.qianfan.QianFanChatOptions;
-import org.springframework.ai.qianfan.api.QianFanApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
@@ -23,9 +23,9 @@ import java.util.List;
public class YiYanChatModelTests {
private final QianFanChatModel chatModel = new QianFanChatModel(
- new QianFanApi("qS8k8dYr2nXunagK4SSU8Xjj", "pHGbx51ql2f0hOyabQvSZezahVC3hh3e"), // 密钥
+ new QianFanApi("DGnyzREuaY7av7c38bOM9Ji2", "9aR8myflEOPDrEeLhoXv0FdqANOAyIZW"), // 密钥
QianFanChatOptions.builder()
- .model(QianFanApi.ChatModel.ERNIE_4_0_8K_Preview.getValue())
+ .model("ERNIE-4.5-8K-Preview")
.build()
);
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/OpenAiImageModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/OpenAiImageModelTests.java
index 49015b9b9e..1b124529de 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/OpenAiImageModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/OpenAiImageModelTests.java
@@ -18,7 +18,7 @@ public class OpenAiImageModelTests {
private final OpenAiImageModel imageModel = new OpenAiImageModel(OpenAiImageApi.builder()
.baseUrl("https://api.holdai.top") // apiKey
- .apiKey("sk-aN6nWn3fILjrgLFT0fC4Aa60B72e4253826c77B29dC94f17")
+ .apiKey("sk-PytRecQlmjEteoa2RRN6cGnwslo72UUPLQVNEMS6K9yjbmpD")
.build());
@Test
@@ -26,8 +26,8 @@ public class OpenAiImageModelTests {
public void testCall() {
// 准备参数
ImageOptions options = OpenAiImageOptions.builder()
- .withModel(OpenAiImageApi.ImageModel.DALL_E_2.getValue()) // 这个模型比较便宜
- .withHeight(256).withWidth(256)
+ .model(OpenAiImageApi.ImageModel.DALL_E_2.getValue()) // 这个模型比较便宜
+ .height(256).width(256)
.build();
ImagePrompt prompt = new ImagePrompt("中国长城!", options);
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/QianFanImageTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/QianFanImageTests.java
index 8f44ab9ad1..156360f255 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/QianFanImageTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/QianFanImageTests.java
@@ -2,11 +2,11 @@ package cn.iocoder.yudao.module.ai.framework.ai.core.model.image;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
+import org.springaicommunity.qianfan.QianFanImageModel;
+import org.springaicommunity.qianfan.QianFanImageOptions;
+import org.springaicommunity.qianfan.api.QianFanImageApi;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
-import org.springframework.ai.qianfan.QianFanImageModel;
-import org.springframework.ai.qianfan.QianFanImageOptions;
-import org.springframework.ai.qianfan.api.QianFanImageApi;
import static cn.iocoder.yudao.module.ai.framework.ai.core.model.image.StabilityAiImageModelTests.viewImage;
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/StabilityAiImageModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/StabilityAiImageModelTests.java
index b58e6df00e..8cf556d9f8 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/StabilityAiImageModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/StabilityAiImageModelTests.java
@@ -31,8 +31,8 @@ public class StabilityAiImageModelTests {
public void testCall() {
// 准备参数
ImageOptions options = OpenAiImageOptions.builder()
- .withModel("stable-diffusion-v1-6")
- .withHeight(320).withWidth(320)
+ .model("stable-diffusion-v1-6")
+ .height(320).width(320)
.build();
ImagePrompt prompt = new ImagePrompt("great wall", options);
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
index 0795f9d3a6..712f12021a 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
@@ -142,6 +142,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
updateBusinessProduct(updateObj.getId(), businessProducts);
// 3. 记录操作日志上下文
+ updateReqVO.setOwnerUserId(oldBusiness.getOwnerUserId()); // 避免操作日志出现“删除负责人”的情况
LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldBusiness, CrmBusinessSaveReqVO.class));
LogRecordContext.putVariable("businessName", oldBusiness.getName());
}
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java
index 618ecf8f7e..d45635c116 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java
@@ -92,19 +92,20 @@ public class CrmClueServiceImpl implements CrmClueService {
@Transactional(rollbackFor = Exception.class)
@LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
success = CRM_CLUE_UPDATE_SUCCESS)
- @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#updateReq.id", level = CrmPermissionLevelEnum.OWNER)
- public void updateClue(CrmClueSaveReqVO updateReq) {
- Assert.notNull(updateReq.getId(), "线索编号不能为空");
+ @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.OWNER)
+ public void updateClue(CrmClueSaveReqVO updateReqVO) {
+ Assert.notNull(updateReqVO.getId(), "线索编号不能为空");
// 1.1 校验线索是否存在
- CrmClueDO oldClue = validateClueExists(updateReq.getId());
+ CrmClueDO oldClue = validateClueExists(updateReqVO.getId());
// 1.2 校验关联数据
- validateRelationDataExists(updateReq);
+ validateRelationDataExists(updateReqVO);
// 2. 更新线索
- CrmClueDO updateObj = BeanUtils.toBean(updateReq, CrmClueDO.class);
+ CrmClueDO updateObj = BeanUtils.toBean(updateReqVO, CrmClueDO.class);
clueMapper.updateById(updateObj);
// 3. 记录操作日志上下文
+ updateReqVO.setOwnerUserId(oldClue.getOwnerUserId()); // 避免操作日志出现“删除负责人”的情况
LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldClue, CrmCustomerSaveReqVO.class));
LogRecordContext.putVariable("clueName", oldClue.getName());
}
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java
index 136342b254..9920359d51 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java
@@ -114,6 +114,7 @@ public class CrmContactServiceImpl implements CrmContactService {
contactMapper.updateById(updateObj);
// 3. 记录操作日志
+ updateReqVO.setOwnerUserId(oldContact.getOwnerUserId()); // 避免操作日志出现“删除负责人”的情况
LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldContact, CrmContactSaveReqVO.class));
LogRecordContext.putVariable("contactName", oldContact.getName());
}
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
index cccce4b265..67b1e15317 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
@@ -140,9 +140,9 @@ public class CrmContractServiceImpl implements CrmContractService {
Assert.notNull(updateReqVO.getId(), "合同编号不能为空");
updateReqVO.setOwnerUserId(null); // 不允许更新的字段
// 1.1 校验存在
- CrmContractDO contract = validateContractExists(updateReqVO.getId());
+ CrmContractDO oldContract = validateContractExists(updateReqVO.getId());
// 1.2 只有草稿、审批中,可以编辑;
- if (!ObjectUtils.equalsAny(contract.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(),
+ if (!ObjectUtils.equalsAny(oldContract.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(),
CrmAuditStatusEnum.PROCESS.getStatus())) {
throw exception(CONTRACT_UPDATE_FAIL_NOT_DRAFT);
}
@@ -159,8 +159,9 @@ public class CrmContractServiceImpl implements CrmContractService {
updateContractProduct(updateReqVO.getId(), contractProducts);
// 3. 记录操作日志上下文
- LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(contract, CrmContractSaveReqVO.class));
- LogRecordContext.putVariable("contractName", contract.getName());
+ updateReqVO.setOwnerUserId(oldContract.getOwnerUserId()); // 避免操作日志出现“删除负责人”的情况
+ LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldContract, CrmContractSaveReqVO.class));
+ LogRecordContext.putVariable("contractName", oldContract.getName());
}
private void updateContractProduct(Long id, List newList) {
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java
index a91dcc6bba..24fe33301e 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java
@@ -137,6 +137,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
customerMapper.updateById(updateObj);
// 3. 记录操作日志上下文
+ updateReqVO.setOwnerUserId(oldCustomer.getOwnerUserId()); // 避免操作日志出现“删除负责人”的情况
LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldCustomer, CrmCustomerSaveReqVO.class));
LogRecordContext.putVariable("customerName", oldCustomer.getName());
}
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java
index bee61c65c1..9e7d9c0de9 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java
@@ -210,12 +210,12 @@ public class CrmPermissionServiceImpl implements CrmPermissionService {
CrmPermissionDO oldPermission = permissionMapper.selectByBizTypeAndBizIdByUserId(
transferReqBO.getBizType(), transferReqBO.getBizId(), transferReqBO.getUserId());
String bizTypeName = CrmBizTypeEnum.getNameByType(transferReqBO.getBizType());
- if (oldPermission == null // 不是拥有者,并且不是超管
- || (!isOwner(oldPermission.getLevel()) && !CrmPermissionUtils.isCrmAdmin())) {
+ if ((oldPermission == null || !isOwner(oldPermission.getLevel()))
+ && !CrmPermissionUtils.isCrmAdmin()) { // 并且不是超管
throw exception(CRM_PERMISSION_DENIED, bizTypeName);
}
// 1.1 校验转移对象是否已经是该负责人
- if (ObjUtil.equal(transferReqBO.getNewOwnerUserId(), oldPermission.getUserId())) {
+ if (oldPermission != null && ObjUtil.equal(transferReqBO.getNewOwnerUserId(), oldPermission.getUserId())) {
throw exception(CRM_PERMISSION_MODEL_TRANSFER_FAIL_OWNER_USER_EXISTS, bizTypeName);
}
// 1.2 校验新负责人是否存在
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java
index 063aeb4a23..52a4cdb635 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java
@@ -104,6 +104,7 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService {
receivablePlanMapper.updateById(updateObj);
// 3. 记录操作日志上下文
+ updateReqVO.setOwnerUserId(oldReceivablePlan.getOwnerUserId()); // 避免操作日志出现“删除负责人”的情况
LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldReceivablePlan, CrmReceivablePlanSaveReqVO.class));
LogRecordContext.putVariable("receivablePlan", oldReceivablePlan);
}
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java
index 4f5df21dcc..03bf7035bc 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java
@@ -162,14 +162,14 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
Assert.notNull(updateReqVO.getId(), "回款编号不能为空");
updateReqVO.setOwnerUserId(null).setCustomerId(null).setContractId(null).setPlanId(null); // 不允许修改的字段
// 1.1 校验存在
- CrmReceivableDO receivable = validateReceivableExists(updateReqVO.getId());
- updateReqVO.setOwnerUserId(receivable.getOwnerUserId()).setCustomerId(receivable.getCustomerId())
- .setContractId(receivable.getContractId()).setPlanId(receivable.getPlanId()); // 设置已存在的值
+ CrmReceivableDO oldReceivable = validateReceivableExists(updateReqVO.getId());
+ updateReqVO.setOwnerUserId(oldReceivable.getOwnerUserId()).setCustomerId(oldReceivable.getCustomerId())
+ .setContractId(oldReceivable.getContractId()).setPlanId(oldReceivable.getPlanId()); // 设置已存在的值
// 1.2 校验可回款金额超过上限
validateReceivablePriceExceedsLimit(updateReqVO);
// 1.3 只有草稿、审批中,可以编辑;
- if (!ObjectUtils.equalsAny(receivable.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(),
+ if (!ObjectUtils.equalsAny(oldReceivable.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(),
CrmAuditStatusEnum.PROCESS.getStatus())) {
throw exception(RECEIVABLE_UPDATE_FAIL_EDITING_PROHIBITED);
}
@@ -179,9 +179,10 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
receivableMapper.updateById(updateObj);
// 3. 记录操作日志上下文
- LogRecordContext.putVariable("receivable", receivable);
- LogRecordContext.putVariable("period", getReceivablePeriod(receivable.getPlanId()));
- LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(receivable, CrmReceivableSaveReqVO.class));
+ updateReqVO.setOwnerUserId(oldReceivable.getOwnerUserId()); // 避免操作日志出现“删除负责人”的情况
+ LogRecordContext.putVariable("oldReceivable", oldReceivable);
+ LogRecordContext.putVariable("period", getReceivablePeriod(oldReceivable.getPlanId()));
+ LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldReceivable, CrmReceivableSaveReqVO.class));
}
private Integer getReceivablePeriod(Long planId) {
diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileUploadReqVO.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileUploadReqVO.java
index 918ea89028..44e8b65d76 100644
--- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileUploadReqVO.java
+++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileUploadReqVO.java
@@ -1,11 +1,13 @@
package cn.iocoder.yudao.module.infra.controller.admin.file.vo.file;
+import cn.hutool.core.util.StrUtil;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.AssertTrue;
+import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;
-import javax.validation.constraints.NotNull;
-
@Schema(description = "管理后台 - 上传文件 Request VO")
@Data
public class FileUploadReqVO {
@@ -17,4 +19,10 @@ public class FileUploadReqVO {
@Schema(description = "文件目录", example = "XXX/YYY")
private String directory;
+ @AssertTrue(message = "文件目录不正确")
+ @JsonIgnore
+ public boolean isDirectoryValid() {
+ return !StrUtil.containsAny(directory, "..", "/", "\\");
+ }
+
}
diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/vo/AppFileUploadReqVO.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/vo/AppFileUploadReqVO.java
index c274652220..d10a21cc49 100644
--- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/vo/AppFileUploadReqVO.java
+++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/vo/AppFileUploadReqVO.java
@@ -1,11 +1,13 @@
package cn.iocoder.yudao.module.infra.controller.app.file.vo;
+import cn.hutool.core.util.StrUtil;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.AssertTrue;
+import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;
-import javax.validation.constraints.NotNull;
-
@Schema(description = "用户 App - 上传文件 Request VO")
@Data
public class AppFileUploadReqVO {
@@ -17,4 +19,10 @@ public class AppFileUploadReqVO {
@Schema(description = "文件目录", example = "XXX/YYY")
private String directory;
+ @AssertTrue(message = "文件目录不正确")
+ @JsonIgnore
+ public boolean isDirectoryValid() {
+ return !StrUtil.containsAny(directory, "..", "/", "\\");
+ }
+
}
diff --git a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java
index 91216bf184..59ee95fb12 100644
--- a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java
+++ b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java
@@ -31,9 +31,13 @@ import java.util.List;
public class CouponTemplateDO extends BaseDO {
/**
- * 不限制领取数量
+ * 领取数量 - 不限制
*/
- public static final Integer TIME_LIMIT_COUNT_MAX = -1;
+ public static final Integer TAKE_LIMIT_COUNT_MAX = -1;
+ /**
+ * 发放数量 - 不限制
+ */
+ public static final Integer TOTAL_COUNT_MAX = -1;
// ========== 基本信息 BEGIN ==========
/**
diff --git a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java
index 3096a49f3c..84e98f3dbd 100755
--- a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java
+++ b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java
@@ -40,10 +40,16 @@ public interface CouponTemplateMapper extends BaseMapperX {
.orderByDesc(CouponTemplateDO::getId));
}
- default void updateTakeCount(Long id, Integer incrCount) {
- update(null, new LambdaUpdateWrapper()
+ default int updateTakeCount(Long id, Integer incrCount) {
+ LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper()
.eq(CouponTemplateDO::getId, id)
- .setSql("take_count = take_count + " + incrCount));
+ .setSql("take_count = take_count + " + incrCount);
+ // 增加已领取的数量(incrCount 为正数),需要考虑发放数量 totalCount 的限制
+ if (incrCount > 0) {
+ updateWrapper.and(i -> i.apply("take_count < total_count")
+ .or().eq(CouponTemplateDO::getTotalCount, CouponTemplateDO.TOTAL_COUNT_MAX));
+ }
+ return update(updateWrapper);
}
default List selectListByTakeType(Integer takeType) {
diff --git a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
index 62781d3b23..463a840be2 100644
--- a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
+++ b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
@@ -137,7 +137,6 @@ public class CouponServiceImpl implements CouponService {
// 4. 增加优惠劵模板的领取数量
couponTemplateService.updateCouponTemplateTakeCount(template.getId(), userIds.size());
-
return convertMultiMap(couponList, CouponDO::getUserId, CouponDO::getId);
}
@@ -281,7 +280,7 @@ public class CouponServiceImpl implements CouponService {
}
// 校验发放数量不能过小(仅在 CouponTakeTypeEnum.USER 用户领取时)
if (CouponTakeTypeEnum.isUser(couponTemplate.getTakeType())
- && ObjUtil.notEqual(couponTemplate.getTakeLimitCount(), CouponTemplateDO.TIME_LIMIT_COUNT_MAX) // 非不限制
+ && ObjUtil.notEqual(couponTemplate.getTakeLimitCount(), CouponTemplateDO.TAKE_LIMIT_COUNT_MAX) // 非不限制
&& couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) {
throw exception(COUPON_TEMPLATE_NOT_ENOUGH);
}
diff --git a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java
index f4ca4d13f0..c71febfbfa 100755
--- a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java
+++ b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java
@@ -22,8 +22,7 @@ import java.util.List;
import java.util.Objects;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_TEMPLATE_NOT_EXISTS;
-import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
/**
* 优惠劵模板 Service 实现类
@@ -60,7 +59,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
CouponTemplateDO couponTemplate = validateCouponTemplateExists(updateReqVO.getId());
// 校验发放数量不能过小(仅在 CouponTakeTypeEnum.USER 用户领取时)
if (CouponTakeTypeEnum.isUser(couponTemplate.getTakeType())
- && ObjUtil.notEqual(couponTemplate.getTakeLimitCount(), CouponTemplateDO.TIME_LIMIT_COUNT_MAX) // 非不限制
+ && ObjUtil.notEqual(couponTemplate.getTakeLimitCount(), CouponTemplateDO.TAKE_LIMIT_COUNT_MAX) // 非不限制
&& updateReqVO.getTotalCount() < couponTemplate.getTakeCount()) {
throw exception(COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL, couponTemplate.getTakeCount());
}
@@ -116,7 +115,10 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
@Override
public void updateCouponTemplateTakeCount(Long id, int incrCount) {
- couponTemplateMapper.updateTakeCount(id, incrCount);
+ int updateCount = couponTemplateMapper.updateTakeCount(id, incrCount);
+ if (updateCount == 0) {
+ throw exception(COUPON_TEMPLATE_NOT_ENOUGH);
+ }
}
@Override
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java
index 488c3ca7c3..892a34b6af 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java
@@ -127,6 +127,8 @@ public class AuthController {
@PostMapping("/sms-login")
@PermitAll
@Operation(summary = "使用短信验证码登录")
+ // 可按需开启限流:https://github.com/YunaiV/ruoyi-vue-pro/issues/851
+ // @RateLimiter(time = 60, count = 6, keyResolver = ExpressionRateLimiterKeyResolver.class, keyArg = "#reqVO.mobile")
public CommonResult smsLogin(@RequestBody @Valid AuthSmsLoginReqVO reqVO) {
return success(authService.smsLogin(reqVO));
}
diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml
index 3bd07a9801..b18e3d726a 100644
--- a/yudao-server/src/main/resources/application-dev.yaml
+++ b/yudao-server/src/main/resources/application-dev.yaml
@@ -6,8 +6,8 @@ server:
spring:
autoconfigure:
exclude:
- - org.springframework.ai.autoconfigure.vectorstore.qdrant.QdrantVectorStoreAutoConfiguration # 禁用 AI 模块的 Qdrant,手动创建
- - org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusVectorStoreAutoConfiguration # 禁用 AI 模块的 Milvus,手动创建
+ - org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreAutoConfiguration # 禁用 AI 模块的 Qdrant,手动创建
+ - org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreAutoConfiguration # 禁用 AI 模块的 Milvus,手动创建
# 数据源配置项
autoconfigure:
exclude:
diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml
index 6501a5292a..71c78da2d7 100644
--- a/yudao-server/src/main/resources/application-local.yaml
+++ b/yudao-server/src/main/resources/application-local.yaml
@@ -11,8 +11,8 @@ spring:
- de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration # 禁用 Spring Boot Admin 的 Server 的自动配置
- de.codecentric.boot.admin.server.ui.config.AdminServerUiAutoConfiguration # 禁用 Spring Boot Admin 的 Server UI 的自动配置
- de.codecentric.boot.admin.client.config.SpringBootAdminClientAutoConfiguration # 禁用 Spring Boot Admin 的 Client 的自动配置
- - org.springframework.ai.autoconfigure.vectorstore.qdrant.QdrantVectorStoreAutoConfiguration # 禁用 AI 模块的 Qdrant,手动创建
- - org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusVectorStoreAutoConfiguration # 禁用 AI 模块的 Milvus,手动创建
+ - org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreAutoConfiguration # 禁用 AI 模块的 Qdrant,手动创建
+ - org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreAutoConfiguration # 禁用 AI 模块的 Milvus,手动创建
# 数据源配置项
datasource:
druid: # Druid 【监控】相关的全局配置
diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml
index 37b783d57d..12a4abf896 100644
--- a/yudao-server/src/main/resources/application.yaml
+++ b/yudao-server/src/main/resources/application.yaml
@@ -150,7 +150,7 @@ spring:
vectorstore: # 向量存储
redis:
initialize-schema: true
- index: knowledge_index # Redis 中向量索引的名称:用于存储和检索向量数据的索引标识符,所有相关的向量搜索操作都会基于这个索引进行
+ index-name: knowledge_index # Redis 中向量索引的名称:用于存储和检索向量数据的索引标识符,所有相关的向量搜索操作都会基于这个索引进行
prefix: "knowledge_segment:" # Redis 中存储向量数据的键名前缀:这个前缀会添加到每个存储在 Redis 中的向量数据键名前,每个 document 都是一个 hash 结构
qdrant:
initialize-schema: true
@@ -188,13 +188,14 @@ spring:
api-key: xxxx
moonshot: # 月之暗灭(KIMI)
api-key: sk-abc
+ deepseek: # DeepSeek
+ api-key: sk-e94db327cc7d457d99a8de8810fc6b12
+ chat:
+ options:
+ model: deepseek-chat
yudao:
ai:
- deep-seek: # DeepSeek
- enable: true
- api-key: sk-e94db327cc7d457d99a8de8810fc6b12
- model: deepseek-chat
doubao: # 字节豆包
enable: true
api-key: 5c1b5747-26d2-4ebd-a4e0-dd0e8d8b4272