diff --git a/sql/postgresql/ruoyi-vue-pro.sql b/sql/postgresql/ruoyi-vue-pro.sql index f85884776..859c6c383 100644 --- a/sql/postgresql/ruoyi-vue-pro.sql +++ b/sql/postgresql/ruoyi-vue-pro.sql @@ -33,7 +33,7 @@ INSERT INTO dual VALUES (1); DROP TABLE IF EXISTS infra_api_access_log; CREATE TABLE infra_api_access_log ( - id int8 NOT NULL, + id int8 NOT NULL DEFAULT NEXTVAL('infra_api_access_log_seq'), trace_id varchar(64) NOT NULL DEFAULT '', user_id int8 NOT NULL DEFAULT 0, user_type int2 NOT NULL DEFAULT 0, @@ -102,7 +102,7 @@ CREATE SEQUENCE infra_api_access_log_seq DROP TABLE IF EXISTS infra_api_error_log; CREATE TABLE infra_api_error_log ( - id int8 NOT NULL, + id int8 NOT NULL DEFAULT NEXTVAL('infra_api_error_log_seq'), trace_id varchar(64) NOT NULL, user_id int8 NOT NULL DEFAULT 0, user_type int2 NOT NULL DEFAULT 0, @@ -175,7 +175,7 @@ CREATE SEQUENCE infra_api_error_log_seq DROP TABLE IF EXISTS infra_codegen_column; CREATE TABLE infra_codegen_column ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('infra_codegen_column_seq'), table_id int8 NOT NULL, column_name varchar(200) NOT NULL, data_type varchar(100) NOT NULL, @@ -238,7 +238,7 @@ CREATE SEQUENCE infra_codegen_column_seq DROP TABLE IF EXISTS infra_codegen_table; CREATE TABLE infra_codegen_table ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('infra_codegen_table_seq'), data_source_config_id int8 NOT NULL, scene int2 NOT NULL DEFAULT 1, table_name varchar(200) NOT NULL DEFAULT '', @@ -303,7 +303,7 @@ CREATE SEQUENCE infra_codegen_table_seq DROP TABLE IF EXISTS infra_config; CREATE TABLE infra_config ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('infra_config_seq'), category varchar(50) NOT NULL, type int2 NOT NULL, name varchar(100) NOT NULL DEFAULT '', @@ -362,7 +362,7 @@ CREATE SEQUENCE infra_config_seq DROP TABLE IF EXISTS infra_data_source_config; CREATE TABLE infra_data_source_config ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('infra_data_source_config_seq'), name varchar(100) NOT NULL DEFAULT '', url varchar(1024) NOT NULL, username varchar(255) NOT NULL, @@ -399,7 +399,7 @@ CREATE SEQUENCE infra_data_source_config_seq DROP TABLE IF EXISTS infra_file; CREATE TABLE infra_file ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('infra_file_seq'), config_id int8 NULL DEFAULT NULL, name varchar(256) NULL DEFAULT NULL, path varchar(512) NOT NULL, @@ -440,7 +440,7 @@ CREATE SEQUENCE infra_file_seq DROP TABLE IF EXISTS infra_file_config; CREATE TABLE infra_file_config ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('infra_file_config_seq'), name varchar(63) NOT NULL, storage int2 NOT NULL, remark varchar(255) NULL DEFAULT NULL, @@ -496,7 +496,7 @@ CREATE SEQUENCE infra_file_config_seq DROP TABLE IF EXISTS infra_file_content; CREATE TABLE infra_file_content ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('infra_file_content_seq'), config_id int8 NOT NULL, path varchar(512) NOT NULL, content bytea NOT NULL, @@ -531,7 +531,7 @@ CREATE SEQUENCE infra_file_content_seq DROP TABLE IF EXISTS infra_job; CREATE TABLE infra_job ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('infra_job_seq'), name varchar(32) NOT NULL, status int2 NOT NULL, handler_name varchar(64) NOT NULL, @@ -597,7 +597,7 @@ CREATE SEQUENCE infra_job_seq DROP TABLE IF EXISTS infra_job_log; CREATE TABLE infra_job_log ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('infra_job_log_seq'), job_id int8 NOT NULL, handler_name varchar(64) NOT NULL, handler_param varchar(255) NULL DEFAULT NULL, @@ -644,7 +644,7 @@ CREATE SEQUENCE infra_job_log_seq DROP TABLE IF EXISTS system_dept; CREATE TABLE system_dept ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_dept_seq'), name varchar(30) NOT NULL DEFAULT '', parent_id int8 NOT NULL DEFAULT 0, sort int4 NOT NULL DEFAULT 0, @@ -711,7 +711,7 @@ CREATE SEQUENCE system_dept_seq DROP TABLE IF EXISTS system_dict_data; CREATE TABLE system_dict_data ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_dict_data_seq'), sort int4 NOT NULL DEFAULT 0, label varchar(100) NOT NULL DEFAULT '', value varchar(100) NOT NULL DEFAULT '', @@ -1367,7 +1367,7 @@ CREATE SEQUENCE system_dict_data_seq DROP TABLE IF EXISTS system_dict_type; CREATE TABLE system_dict_type ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_dict_type_seq'), name varchar(100) NOT NULL DEFAULT '', type varchar(100) NOT NULL DEFAULT '', status int2 NOT NULL DEFAULT 0, @@ -1521,7 +1521,7 @@ CREATE SEQUENCE system_dict_type_seq DROP TABLE IF EXISTS system_login_log; CREATE TABLE system_login_log ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_login_log_seq'), log_type int8 NOT NULL, trace_id varchar(64) NOT NULL DEFAULT '', user_id int8 NOT NULL DEFAULT 0, @@ -1568,7 +1568,7 @@ CREATE SEQUENCE system_login_log_seq DROP TABLE IF EXISTS system_mail_account; CREATE TABLE system_mail_account ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_mail_account_seq'), mail varchar(255) NOT NULL, username varchar(255) NOT NULL, password varchar(255) NOT NULL, @@ -1623,7 +1623,7 @@ CREATE SEQUENCE system_mail_account_seq DROP TABLE IF EXISTS system_mail_log; CREATE TABLE system_mail_log ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_mail_log_seq'), user_id int8 NULL DEFAULT NULL, user_type int2 NULL DEFAULT NULL, to_mail varchar(255) NOT NULL, @@ -1682,7 +1682,7 @@ CREATE SEQUENCE system_mail_log_seq DROP TABLE IF EXISTS system_mail_template; CREATE TABLE system_mail_template ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_mail_template_seq'), name varchar(63) NOT NULL, code varchar(63) NOT NULL, account_id int8 NOT NULL, @@ -1740,7 +1740,7 @@ CREATE SEQUENCE system_mail_template_seq DROP TABLE IF EXISTS system_menu; CREATE TABLE system_menu ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_menu_seq'), name varchar(50) NOT NULL, permission varchar(100) NOT NULL DEFAULT '', type int2 NOT NULL, @@ -2714,7 +2714,7 @@ CREATE SEQUENCE system_menu_seq DROP TABLE IF EXISTS system_notice; CREATE TABLE system_notice ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_notice_seq'), title varchar(50) NOT NULL, content text NOT NULL, type int2 NOT NULL, @@ -2764,7 +2764,7 @@ CREATE SEQUENCE system_notice_seq DROP TABLE IF EXISTS system_notify_message; CREATE TABLE system_notify_message ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_notify_message_seq'), user_id int8 NOT NULL, user_type int2 NOT NULL, template_id int8 NOT NULL, @@ -2832,7 +2832,7 @@ CREATE SEQUENCE system_notify_message_seq DROP TABLE IF EXISTS system_notify_template; CREATE TABLE system_notify_template ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_notify_template_seq'), name varchar(63) NOT NULL, code varchar(64) NOT NULL, nickname varchar(255) NOT NULL, @@ -2877,7 +2877,7 @@ CREATE SEQUENCE system_notify_template_seq DROP TABLE IF EXISTS system_oauth2_access_token; CREATE TABLE system_oauth2_access_token ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_oauth2_access_token_seq'), user_id int8 NOT NULL, user_type int2 NOT NULL, user_info varchar(512) NOT NULL, @@ -2927,7 +2927,7 @@ CREATE SEQUENCE system_oauth2_access_token_seq DROP TABLE IF EXISTS system_oauth2_approve; CREATE TABLE system_oauth2_approve ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_oauth2_approve_seq'), user_id int8 NOT NULL, user_type int2 NOT NULL, client_id varchar(255) NOT NULL, @@ -2970,7 +2970,7 @@ CREATE SEQUENCE system_oauth2_approve_seq DROP TABLE IF EXISTS system_oauth2_client; CREATE TABLE system_oauth2_client ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_oauth2_client_seq'), client_id varchar(255) NOT NULL, secret varchar(255) NOT NULL, name varchar(255) NOT NULL, @@ -3041,7 +3041,7 @@ CREATE SEQUENCE system_oauth2_client_seq DROP TABLE IF EXISTS system_oauth2_code; CREATE TABLE system_oauth2_code ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_oauth2_code_seq'), user_id int8 NOT NULL, user_type int2 NOT NULL, code varchar(32) NOT NULL, @@ -3088,7 +3088,7 @@ CREATE SEQUENCE system_oauth2_code_seq DROP TABLE IF EXISTS system_oauth2_refresh_token; CREATE TABLE system_oauth2_refresh_token ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_oauth2_refresh_token_seq'), user_id int8 NOT NULL, refresh_token varchar(32) NOT NULL, user_type int2 NOT NULL, @@ -3131,7 +3131,7 @@ CREATE SEQUENCE system_oauth2_refresh_token_seq DROP TABLE IF EXISTS system_operate_log; CREATE TABLE system_operate_log ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_operate_log_seq'), trace_id varchar(64) NOT NULL DEFAULT '', user_id int8 NOT NULL, user_type int2 NOT NULL DEFAULT 0, @@ -3188,7 +3188,7 @@ CREATE SEQUENCE system_operate_log_seq DROP TABLE IF EXISTS system_post; CREATE TABLE system_post ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_post_seq'), code varchar(64) NOT NULL, name varchar(50) NOT NULL, sort int4 NOT NULL, @@ -3241,7 +3241,7 @@ CREATE SEQUENCE system_post_seq DROP TABLE IF EXISTS system_role; CREATE TABLE system_role ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_role_seq'), name varchar(30) NOT NULL, code varchar(100) NOT NULL, sort int4 NOT NULL, @@ -3304,7 +3304,7 @@ CREATE SEQUENCE system_role_seq DROP TABLE IF EXISTS system_role_menu; CREATE TABLE system_role_menu ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_role_menu_seq'), role_id int8 NOT NULL, menu_id int8 NOT NULL, creator varchar(64) NULL DEFAULT '', @@ -4210,7 +4210,7 @@ CREATE SEQUENCE system_role_menu_seq DROP TABLE IF EXISTS system_sms_channel; CREATE TABLE system_sms_channel ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_sms_channel_seq'), signature varchar(12) NOT NULL, code varchar(63) NOT NULL, status int2 NOT NULL, @@ -4264,7 +4264,7 @@ CREATE SEQUENCE system_sms_channel_seq DROP TABLE IF EXISTS system_sms_code; CREATE TABLE system_sms_code ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_sms_code_seq'), mobile varchar(11) NOT NULL, code varchar(6) NOT NULL, create_ip varchar(15) NOT NULL, @@ -4313,7 +4313,7 @@ CREATE SEQUENCE system_sms_code_seq DROP TABLE IF EXISTS system_sms_log; CREATE TABLE system_sms_log ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_sms_log_seq'), channel_id int8 NOT NULL, channel_code varchar(63) NOT NULL, template_id int8 NOT NULL, @@ -4384,7 +4384,7 @@ CREATE SEQUENCE system_sms_log_seq DROP TABLE IF EXISTS system_sms_template; CREATE TABLE system_sms_template ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_sms_template_seq'), type int2 NOT NULL, status int2 NOT NULL, code varchar(63) NOT NULL, @@ -4456,7 +4456,7 @@ CREATE SEQUENCE system_sms_template_seq DROP TABLE IF EXISTS system_social_client; CREATE TABLE system_social_client ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_social_client_seq'), name varchar(255) NOT NULL, social_type int2 NOT NULL, user_type int2 NOT NULL, @@ -4514,7 +4514,7 @@ CREATE SEQUENCE system_social_client_seq DROP TABLE IF EXISTS system_social_user; CREATE TABLE system_social_user ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_social_user_seq'), type int2 NOT NULL, openid varchar(32) NOT NULL, token varchar(256) NULL DEFAULT NULL, @@ -4563,7 +4563,7 @@ CREATE SEQUENCE system_social_user_seq DROP TABLE IF EXISTS system_social_user_bind; CREATE TABLE system_social_user_bind ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_social_user_bind_seq'), user_id int8 NOT NULL, user_type int2 NOT NULL, social_type int2 NOT NULL, @@ -4602,7 +4602,7 @@ CREATE SEQUENCE system_social_user_bind_seq DROP TABLE IF EXISTS system_tenant; CREATE TABLE system_tenant ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_tenant_seq'), name varchar(30) NOT NULL, contact_user_id int8 NULL DEFAULT NULL, contact_name varchar(30) NOT NULL, @@ -4660,7 +4660,7 @@ CREATE SEQUENCE system_tenant_seq DROP TABLE IF EXISTS system_tenant_package; CREATE TABLE system_tenant_package ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_tenant_package_seq'), name varchar(30) NOT NULL, status int2 NOT NULL DEFAULT 0, remark varchar(256) NULL DEFAULT '', @@ -4707,7 +4707,7 @@ CREATE SEQUENCE system_tenant_package_seq DROP TABLE IF EXISTS system_user_post; CREATE TABLE system_user_post ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_user_post_seq'), user_id int8 NOT NULL DEFAULT 0, post_id int8 NOT NULL DEFAULT 0, creator varchar(64) NULL DEFAULT '', @@ -4759,7 +4759,7 @@ CREATE SEQUENCE system_user_post_seq DROP TABLE IF EXISTS system_user_role; CREATE TABLE system_user_role ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_user_role_seq'), user_id int8 NOT NULL, role_id int8 NOT NULL, creator varchar(64) NULL DEFAULT '', @@ -4819,7 +4819,7 @@ CREATE SEQUENCE system_user_role_seq DROP TABLE IF EXISTS system_users; CREATE TABLE system_users ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('system_users_seq'), username varchar(30) NOT NULL, password varchar(100) NOT NULL DEFAULT '', nickname varchar(30) NOT NULL, @@ -4902,7 +4902,7 @@ CREATE SEQUENCE system_users_seq DROP TABLE IF EXISTS yudao_demo01_contact; CREATE TABLE yudao_demo01_contact ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('yudao_demo01_contact_seq'), name varchar(100) NOT NULL DEFAULT '', sex int2 NOT NULL, birthday timestamp NOT NULL, @@ -4952,7 +4952,7 @@ CREATE SEQUENCE yudao_demo01_contact_seq DROP TABLE IF EXISTS yudao_demo02_category; CREATE TABLE yudao_demo02_category ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('yudao_demo02_category_seq'), name varchar(100) NOT NULL DEFAULT '', parent_id int8 NOT NULL, creator varchar(64) NULL DEFAULT '', @@ -5001,7 +5001,7 @@ CREATE SEQUENCE yudao_demo02_category_seq DROP TABLE IF EXISTS yudao_demo03_course; CREATE TABLE yudao_demo03_course ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('yudao_demo03_course_seq'), student_id int8 NOT NULL, name varchar(100) NOT NULL DEFAULT '', score int2 NOT NULL, @@ -5063,7 +5063,7 @@ CREATE SEQUENCE yudao_demo03_course_seq DROP TABLE IF EXISTS yudao_demo03_grade; CREATE TABLE yudao_demo03_grade ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('yudao_demo03_grade_seq'), student_id int8 NOT NULL, name varchar(100) NOT NULL DEFAULT '', teacher varchar(255) NOT NULL, @@ -5111,7 +5111,7 @@ CREATE SEQUENCE yudao_demo03_grade_seq DROP TABLE IF EXISTS yudao_demo03_student; CREATE TABLE yudao_demo03_student ( - id int8 NOT NULL, + id int8 NOT NULL default nextval('yudao_demo03_student_seq'), name varchar(100) NOT NULL DEFAULT '', sex int2 NOT NULL, birthday timestamp NOT NULL, diff --git a/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java b/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java index 47a4d2d71..612a91338 100644 --- a/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java +++ b/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java @@ -40,6 +40,7 @@ public enum AiPlatformEnum implements ArrayValuable { STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI MIDJOURNEY("Midjourney", "Midjourney"), // Midjourney SUNO("Suno", "Suno"), // Suno AI + GROK("Grok","Grok"), // Grok ; diff --git a/yudao-module-ai/yudao-module-ai-server/pom.xml b/yudao-module-ai/yudao-module-ai-server/pom.xml index a2ce08ba1..d40ba9247 100644 --- a/yudao-module-ai/yudao-module-ai-server/pom.xml +++ b/yudao-module-ai/yudao-module-ai-server/pom.xml @@ -19,9 +19,9 @@ 国外:OpenAI、Ollama、Midjourney、StableDiffusion、Suno - 1.0.1 - 1.0.0.3 - 1.0.2 + 1.1.0 + 1.0.0.4 + 1.2.6 diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java index 26fbe0ad4..9009cbc8c 100644 --- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java +++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.ai.framework.ai.core.model.AiModelFactoryImpl; import cn.iocoder.yudao.module.ai.framework.ai.core.model.baichuan.BaiChuanChatModel; import cn.iocoder.yudao.module.ai.framework.ai.core.model.doubao.DouBaoChatModel; import cn.iocoder.yudao.module.ai.framework.ai.core.model.gemini.GeminiChatModel; +import cn.iocoder.yudao.module.ai.framework.ai.core.model.grok.GrokChatModel; 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; import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowApiConstants; @@ -16,7 +17,9 @@ import cn.iocoder.yudao.module.ai.framework.ai.core.model.xinghuo.XingHuoChatMod import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.AiWebSearchClient; import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.bocha.AiBoChaWebSearchClient; import cn.iocoder.yudao.module.ai.tool.method.PersonService; +import io.micrometer.observation.ObservationRegistry; import lombok.extern.slf4j.Slf4j; +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; @@ -34,12 +37,14 @@ import org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusServiceClie 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.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.List; +import java.util.Optional; /** * 芋道 AI 自动配置 @@ -60,6 +65,13 @@ public class AiAutoConfiguration { return new AiModelFactoryImpl(); } + @Bean + @ConditionalOnMissingBean + public ObservationRegistry observationRegistry() { + // 特殊:兜底有 ObservationRegistry Bean,避免相关的 ChatModel 创建报错。相关 issue:https://t.zsxq.com/CuPu4 + return ObservationRegistry.NOOP; + } + // ========== 各种 AI Client 创建 ========== @Bean @@ -252,6 +264,28 @@ public class AiAutoConfiguration { return new SunoApi(yudaoAiProperties.getSuno().getBaseUrl()); } + public ChatModel buildGrokChatClient(YudaoAiProperties.Grok properties) { + if (StrUtil.isEmpty(properties.getModel())) { + properties.setModel(GrokChatModel.MODEL_DEFAULT); + } + OpenAiChatModel openAiChatModel = OpenAiChatModel.builder() + .openAiApi(OpenAiApi.builder() + .baseUrl(Optional.ofNullable(properties.getBaseUrl()) + .orElse(GrokChatModel.BASE_URL)) + .completionsPath(GrokChatModel.COMPLETE_PATH) + .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 DouBaoChatModel(openAiChatModel); + } + // ========== RAG 相关 ========== @Bean diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java index 67d3bb5f3..986c24c18 100644 --- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java +++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java @@ -160,6 +160,20 @@ public class YudaoAiProperties { } + @Data + public static class Grok { + + private String enable; + private String apiKey; + private String baseUrl; + + private String model; + private Double temperature; + private Integer maxTokens; + private Double topP; + + } + @Data public static class WebSearch { diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java index 75798ebd2..f8067dea2 100644 --- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java +++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java @@ -87,7 +87,7 @@ import org.springframework.ai.model.zhipuai.autoconfigure.ZhiPuAiImageAutoConfig import org.springframework.ai.ollama.OllamaChatModel; import org.springframework.ai.ollama.OllamaEmbeddingModel; import org.springframework.ai.ollama.api.OllamaApi; -import org.springframework.ai.ollama.api.OllamaOptions; +import org.springframework.ai.ollama.api.OllamaEmbeddingOptions; import org.springframework.ai.openai.OpenAiChatModel; import org.springframework.ai.openai.OpenAiEmbeddingModel; import org.springframework.ai.openai.OpenAiEmbeddingOptions; @@ -178,6 +178,8 @@ public class AiModelFactoryImpl implements AiModelFactory { return buildGeminiChatModel(apiKey); case OLLAMA: return buildOllamaChatModel(url); + case GROK: + return buildGrokChatModel(apiKey,url); default: throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform)); } @@ -436,10 +438,12 @@ public class AiModelFactoryImpl implements AiModelFactory { * 可参考 {@link ZhiPuAiChatAutoConfiguration} 的 zhiPuAiChatModel 方法 */ private ZhiPuAiChatModel buildZhiPuChatModel(String apiKey, String url) { - ZhiPuAiApi zhiPuAiApi = StrUtil.isEmpty(url) ? new ZhiPuAiApi(apiKey) - : new ZhiPuAiApi(url, apiKey); + ZhiPuAiApi.Builder zhiPuAiApiBuilder = ZhiPuAiApi.builder().apiKey(apiKey); + if (StrUtil.isNotEmpty(url)) { + zhiPuAiApiBuilder.baseUrl(url); + } ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder().model(ZhiPuAiApi.DEFAULT_CHAT_MODEL).temperature(0.7).build(); - return new ZhiPuAiChatModel(zhiPuAiApi, options, getToolCallingManager(), DEFAULT_RETRY_TEMPLATE, + return new ZhiPuAiChatModel(zhiPuAiApiBuilder.build(), options, getToolCallingManager(), DEFAULT_RETRY_TEMPLATE, getObservationRegistry().getIfAvailable()); } @@ -586,6 +590,13 @@ public class AiModelFactoryImpl implements AiModelFactory { return new StabilityAiImageModel(stabilityAiApi); } + private ChatModel buildGrokChatModel(String apiKey,String url) { + YudaoAiProperties.Grok properties = new YudaoAiProperties.Grok() + .setBaseUrl(url) + .setApiKey(apiKey); + return new AiAutoConfiguration().buildGrokChatClient(properties); + } + // ========== 各种创建 EmbeddingModel 的方法 ========== /** @@ -601,10 +612,12 @@ public class AiModelFactoryImpl implements AiModelFactory { * 可参考 {@link ZhiPuAiEmbeddingAutoConfiguration} 的 zhiPuAiEmbeddingModel 方法 */ private ZhiPuAiEmbeddingModel buildZhiPuEmbeddingModel(String apiKey, String url, String model) { - ZhiPuAiApi zhiPuAiApi = StrUtil.isEmpty(url) ? new ZhiPuAiApi(apiKey) - : new ZhiPuAiApi(url, apiKey); + ZhiPuAiApi.Builder zhiPuAiApiBuilder = ZhiPuAiApi.builder().apiKey(apiKey); + if (StrUtil.isNotEmpty(url)) { + zhiPuAiApiBuilder.baseUrl(url); + } ZhiPuAiEmbeddingOptions zhiPuAiEmbeddingOptions = ZhiPuAiEmbeddingOptions.builder().model(model).build(); - return new ZhiPuAiEmbeddingModel(zhiPuAiApi, MetadataMode.EMBED, zhiPuAiEmbeddingOptions); + return new ZhiPuAiEmbeddingModel(zhiPuAiApiBuilder.build(), MetadataMode.EMBED, zhiPuAiEmbeddingOptions); } /** @@ -632,7 +645,7 @@ public class AiModelFactoryImpl implements AiModelFactory { private OllamaEmbeddingModel buildOllamaEmbeddingModel(String url, String model) { OllamaApi ollamaApi = OllamaApi.builder().baseUrl(url).build(); - OllamaOptions ollamaOptions = OllamaOptions.builder().model(model).build(); + OllamaEmbeddingOptions ollamaOptions = OllamaEmbeddingOptions.builder().model(model).build(); return OllamaEmbeddingModel.builder() .ollamaApi(ollamaApi) .defaultOptions(ollamaOptions) diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/grok/GrokChatModel.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/grok/GrokChatModel.java new file mode 100644 index 000000000..06eed2504 --- /dev/null +++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/grok/GrokChatModel.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.ai.framework.ai.core.model.grok; + +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 reactor.core.publisher.Flux; + +/** + * Grok {@link ChatModel} 实现类 + * + * + */ +@Slf4j +@RequiredArgsConstructor +public class GrokChatModel implements ChatModel { + + public static final String BASE_URL = "https://api.x.ai"; + public static final String COMPLETE_PATH = "/v1/chat/completions"; + public static final String MODEL_DEFAULT = "grok-4-fast-reasoning"; + + /** + * 兼容 OpenAI 接口,进行复用 + */ + private final ChatModel 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/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/security/config/SecurityConfiguration.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/security/config/SecurityConfiguration.java index 0e7a8ad45..aedd493c3 100644 --- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/security/config/SecurityConfiguration.java +++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/security/config/SecurityConfiguration.java @@ -3,7 +3,8 @@ package cn.iocoder.yudao.module.ai.framework.security.config; import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer; import cn.iocoder.yudao.module.infra.enums.ApiConstants; import jakarta.annotation.Resource; -import org.springframework.ai.mcp.server.autoconfigure.McpServerProperties; +import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerSseProperties; +import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerStreamableHttpProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -18,7 +19,9 @@ import java.util.Optional; public class SecurityConfiguration { @Resource - private Optional serverProperties; + private Optional mcpServerSseProperties; + @Resource + private Optional mcpServerStreamableHttpProperties; @Bean("aiAuthorizeRequestsCustomizer") public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() { @@ -42,10 +45,12 @@ public class SecurityConfiguration { registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll(); // MCP Server - serverProperties.ifPresent(properties -> { + mcpServerSseProperties.ifPresent(properties -> { registry.requestMatchers(properties.getSseEndpoint()).permitAll(); registry.requestMatchers(properties.getSseMessageEndpoint()).permitAll(); }); + mcpServerStreamableHttpProperties.ifPresent(properties -> + registry.requestMatchers(properties.getMcpEndpoint()).permitAll()); } }; diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java index d209c62d4..dab4d5aa4 100644 --- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java +++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java @@ -16,7 +16,7 @@ import org.springframework.ai.chat.prompt.ChatOptions; import org.springframework.ai.deepseek.DeepSeekAssistantMessage; import org.springframework.ai.deepseek.DeepSeekChatOptions; import org.springframework.ai.minimax.MiniMaxChatOptions; -import org.springframework.ai.ollama.api.OllamaOptions; +import org.springframework.ai.ollama.api.OllamaChatOptions; import org.springframework.ai.openai.OpenAiChatOptions; import org.springframework.ai.tool.ToolCallback; import org.springframework.ai.zhipuai.ZhiPuAiChatOptions; @@ -68,6 +68,7 @@ public class AiUtils { case OPENAI: case GEMINI: // 复用 OpenAI 客户端 case BAI_CHUAN: // 复用 OpenAI 客户端 + case GROK: // 复用 OpenAI 客户端 return OpenAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens) .toolCallbacks(toolCallbacks).toolContext(toolContext).build(); case AZURE_OPENAI: @@ -77,7 +78,7 @@ public class AiUtils { return AnthropicChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens) .toolCallbacks(toolCallbacks).toolContext(toolContext).build(); case OLLAMA: - return OllamaOptions.builder().model(model).temperature(temperature).numPredict(maxTokens) + return OllamaChatOptions.builder().model(model).temperature(temperature).numPredict(maxTokens) .toolCallbacks(toolCallbacks).toolContext(toolContext).build(); default: throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform)); diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/resources/application.yaml b/yudao-module-ai/yudao-module-ai-server/src/main/resources/application.yaml index 98c2bf95f..236eb8e6d 100644 --- a/yudao-module-ai/yudao-module-ai-server/src/main/resources/application.yaml +++ b/yudao-module-ai/yudao-module-ai-server/src/main/resources/application.yaml @@ -168,6 +168,8 @@ spring: filesystem: url: http://127.0.0.1:8089 sse-endpoint: /sse + annotation-scanner: + enabled: false # TODO @芋艿:有 bug https://github.com/spring-projects/spring-ai/issues/4917 需要官方修复 yudao: ai: diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index d69205ac6..58a66ea6b 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -235,6 +235,8 @@ spring: filesystem: url: http://127.0.0.1:8089 sse-endpoint: /sse + annotation-scanner: + enabled: false # TODO @芋艿:有 bug https://github.com/spring-projects/spring-ai/issues/4917 需要官方修复 yudao: ai: