From 8fb018a69984102f721a7323c7a398e2267253ee Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 17 May 2025 08:01:52 +0800 Subject: [PATCH] reactor:将 ai starter 融合到 ai-module 的 framework/ai 里 --- yudao-module-ai/pom.xml | 1 - yudao-module-ai/yudao-module-ai-biz/pom.xml | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java | 2 +- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageRespVO.java | 2 +- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/model/AiModelSaveReqVO.java | 4 ++-- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java | 5 +++-- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/mindmap/AiMindMapDO.java | 2 +- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiApiKeyDO.java | 2 +- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiModelDO.java | 4 ++-- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java | 2 +- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/write/AiWriteDO.java | 2 +- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiModelTypeEnum.java | 41 +++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/enums/package-info.java | 4 ++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java | 253 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactory.java | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactoryImpl.java | 752 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/baichuan/BaiChuanChatModel.java | 45 +++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/deepseek/DeepSeekChatModel.java | 45 +++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/doubao/DouBaoChatModel.java | 45 +++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/hunyuan/HunYuanChatModel.java | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/midjourney/api/MidjourneyApi.java | 351 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowApiConstants.java | 34 ++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowChatModel.java | 43 +++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageApi.java | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageModel.java | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageOptions.java | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/suno/api/SunoApi.java | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/wenduoduo/api/WenDuoDuoPptApi.java | 381 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/xinghuo/XingHuoChatModel.java | 45 +++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/xinghuo/api/XunFeiPptApi.java | 522 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/package-info.java | 13 +++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatConversationServiceImpl.java | 2 +- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java | 4 ++-- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageService.java | 2 +- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java | 6 +++--- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/mindmap/AiMindMapServiceImpl.java | 6 +++--- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiModelService.java | 4 ++-- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiModelServiceImpl.java | 8 ++++---- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/tool/UserProfileQueryToolFunction.java | 2 +- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/music/AiMusicServiceImpl.java | 2 +- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/write/AiWriteServiceImpl.java | 18 ++++++++---------- yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AzureOpenAIChatModelTests.java | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/BaiChuanChatModelTests.java | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/CozeChatModelTests.java | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DeepSeekChatModelTests.java | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DifyChatModelTests.java | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DouBaoChatModelTests.java | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/FastGPTChatModelTests.java | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/HunYuanChatModelTests.java | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/LlamaChatModelTests.java | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MiniMaxChatModelTests.java | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MoonshotChatModelTests.java | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OllamaChatModelTests.java | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OpenAIChatModelTests.java | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/SiliconFlowChatModelTests.java | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/TongYiChatModelTests.java | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/XingHuoChatModelTests.java | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/YiYanChatModelTests.java | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/ZhiPuAiChatModelTests.java | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/MidjourneyApiTests.java | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/OpenAiImageModelTests.java | 40 ++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/QianFanImageTests.java | 43 +++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/SiliconFlowImageModelTests.java | 35 +++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/StabilityAiImageModelTests.java | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/TongYiImagesModelTest.java | 38 ++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/ZhiPuAiImageModelTests.java | 35 +++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/mcp/DouBaoMcpTests.java | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/music/SunoApiTests.java | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/ppt/wdd/WenDuoDuoPptApiTests.java | 315 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/ppt/xunfei/XunFeiPptApiTests.java | 319 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml | 184 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiAutoConfiguration.java | 253 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiProperties.java | 164 -------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/enums/AiModelTypeEnum.java | 41 ----------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/enums/AiPlatformEnum.java | 69 --------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactory.java | 113 ----------------------------------------------------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactoryImpl.java | 752 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/baichuan/BaiChuanChatModel.java | 45 --------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/deepseek/DeepSeekChatModel.java | 45 --------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/doubao/DouBaoChatModel.java | 45 --------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/hunyuan/HunYuanChatModel.java | 52 ---------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/api/MidjourneyApi.java | 351 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/siliconflow/SiliconFlowApiConstants.java | 34 ---------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/siliconflow/SiliconFlowChatModel.java | 43 ------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/siliconflow/SiliconFlowImageApi.java | 115 ------------------------------------------------------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/siliconflow/SiliconFlowImageModel.java | 159 --------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/siliconflow/SiliconFlowImageOptions.java | 105 --------------------------------------------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/suno/api/SunoApi.java | 200 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/wenduoduo/api/WenDuoDuoPptApi.java | 381 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/xinghuo/XingHuoChatModel.java | 45 --------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/xinghuo/api/XunFeiPptApi.java | 522 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/util/AiUtils.java | 100 ---------------------------------------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/package-info.java | 13 ------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports | 1 - yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/AzureOpenAIChatModelTests.java | 69 --------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/BaiChuanChatModelTests.java | 68 -------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/CozeChatModelTests.java | 63 --------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/DeepSeekChatModelTests.java | 67 ------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/DifyChatModelTests.java | 63 --------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/DouBaoChatModelTests.java | 69 --------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/FastGPTChatModelTests.java | 63 --------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/HunYuanChatModelTests.java | 110 -------------------------------------------------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/LlamaChatModelTests.java | 65 ----------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/MiniMaxChatModelTests.java | 62 -------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/MoonshotChatModelTests.java | 62 -------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/OllamaChatModelTests.java | 65 ----------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/OpenAIChatModelTests.java | 68 -------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/SiliconFlowChatModelTests.java | 70 ---------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/TongYiChatModelTests.java | 66 ------------------------------------------------------------------ yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/XingHuoChatModelTests.java | 67 ------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/YiYanChatModelTests.java | 62 -------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/ZhiPuAiChatModelTests.java | 64 ---------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/image/MidjourneyApiTests.java | 62 -------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/image/OpenAiImageModelTests.java | 40 ---------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/image/QianFanImageTests.java | 43 ------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/image/SiliconFlowImageModelTests.java | 35 ----------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/image/StabilityAiImageModelTests.java | 65 ----------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/image/TongYiImagesModelTest.java | 38 -------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/image/ZhiPuAiImageModelTests.java | 35 ----------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/mcp/DouBaoMcpTests.java | 122 -------------------------------------------------------------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/music/SunoApiTests.java | 84 ------------------------------------------------------------------------------------ yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/ppt/wdd/WenDuoDuoPptApiTests.java | 314 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/ppt/xunfei/XunFeiPptApiTests.java | 319 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 126 files changed, 6228 insertions(+), 6256 deletions(-) create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiModelTypeEnum.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/enums/package-info.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactory.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactoryImpl.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/baichuan/BaiChuanChatModel.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/deepseek/DeepSeekChatModel.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/doubao/DouBaoChatModel.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/hunyuan/HunYuanChatModel.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/midjourney/api/MidjourneyApi.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowApiConstants.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowChatModel.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageApi.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageModel.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageOptions.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/suno/api/SunoApi.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/wenduoduo/api/WenDuoDuoPptApi.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/xinghuo/XingHuoChatModel.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/xinghuo/api/XunFeiPptApi.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/package-info.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AzureOpenAIChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/BaiChuanChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/CozeChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DeepSeekChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DifyChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DouBaoChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/FastGPTChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/HunYuanChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/LlamaChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MiniMaxChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MoonshotChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OllamaChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OpenAIChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/SiliconFlowChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/TongYiChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/XingHuoChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/YiYanChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/ZhiPuAiChatModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/MidjourneyApiTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/OpenAiImageModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/QianFanImageTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/SiliconFlowImageModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/StabilityAiImageModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/TongYiImagesModelTest.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/ZhiPuAiImageModelTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/mcp/DouBaoMcpTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/music/SunoApiTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/ppt/wdd/WenDuoDuoPptApiTests.java create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/ppt/xunfei/XunFeiPptApiTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiAutoConfiguration.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiProperties.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/enums/AiModelTypeEnum.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/enums/AiPlatformEnum.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactory.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactoryImpl.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/baichuan/BaiChuanChatModel.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/deepseek/DeepSeekChatModel.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/doubao/DouBaoChatModel.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/hunyuan/HunYuanChatModel.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/api/MidjourneyApi.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/siliconflow/SiliconFlowApiConstants.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/siliconflow/SiliconFlowChatModel.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/siliconflow/SiliconFlowImageApi.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/siliconflow/SiliconFlowImageModel.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/siliconflow/SiliconFlowImageOptions.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/suno/api/SunoApi.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/wenduoduo/api/WenDuoDuoPptApi.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/xinghuo/XingHuoChatModel.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/xinghuo/api/XunFeiPptApi.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/util/AiUtils.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/package-info.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/AzureOpenAIChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/BaiChuanChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/CozeChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/DeepSeekChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/DifyChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/DouBaoChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/FastGPTChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/HunYuanChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/LlamaChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/MiniMaxChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/MoonshotChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/OllamaChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/OpenAIChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/SiliconFlowChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/TongYiChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/XingHuoChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/YiYanChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/ZhiPuAiChatModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/image/MidjourneyApiTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/image/OpenAiImageModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/image/QianFanImageTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/image/SiliconFlowImageModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/image/StabilityAiImageModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/image/TongYiImagesModelTest.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/image/ZhiPuAiImageModelTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/mcp/DouBaoMcpTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/music/SunoApiTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/ppt/wdd/WenDuoDuoPptApiTests.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/ppt/xunfei/XunFeiPptApiTests.java diff --git a/yudao-module-ai/pom.xml b/yudao-module-ai/pom.xml index 69a5e98..1268ee2 100644 --- a/yudao-module-ai/pom.xml +++ b/yudao-module-ai/pom.xml @@ -11,7 +11,6 @@ yudao-module-ai-api yudao-module-ai-biz - yudao-spring-boot-starter-ai pom yudao-module-ai diff --git a/yudao-module-ai/yudao-module-ai-biz/pom.xml b/yudao-module-ai/yudao-module-ai-biz/pom.xml index ec6f8c7..f49e069 100644 --- a/yudao-module-ai/yudao-module-ai-biz/pom.xml +++ b/yudao-module-ai/yudao-module-ai-biz/pom.xml @@ -17,6 +17,10 @@ 国内:通义千问、文心一言、讯飞星火、智谱 GLM、DeepSeek 国外:OpenAI、Ollama、Midjourney、StableDiffusion、Suno + + 1.0.0-M6 + 1.0.2 + @@ -24,14 +28,19 @@ yudao-module-ai-api ${revision} - - cn.iocoder.boot - yudao-spring-boot-starter-ai + yudao-module-system-api + ${revision} + + + cn.iocoder.boot + yudao-module-infra-api ${revision} + + cn.iocoder.boot yudao-spring-boot-starter-biz-tenant @@ -60,5 +69,148 @@ cn.iocoder.boot yudao-spring-boot-starter-test + + + + cn.iocoder.boot + yudao-spring-boot-starter-excel + + + + + org.springframework.ai + spring-ai-openai-spring-boot-starter + ${spring-ai.version} + + + org.springframework.ai + spring-ai-azure-openai-spring-boot-starter + ${spring-ai.version} + + + org.springframework.ai + spring-ai-ollama-spring-boot-starter + ${spring-ai.version} + + + org.springframework.ai + spring-ai-stability-ai-spring-boot-starter + ${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.version} + + + + org.springframework.ai + spring-ai-zhipuai-spring-boot-starter + ${spring-ai.version} + + + org.springframework.ai + spring-ai-minimax-spring-boot-starter + ${spring-ai.version} + + + org.springframework.ai + spring-ai-moonshot-spring-boot-starter + ${spring-ai.version} + + + + + + org.springframework.ai + spring-ai-qdrant-store + ${spring-ai.version} + + + + + org.springframework.ai + spring-ai-redis-store + ${spring-ai.version} + + + cn.iocoder.boot + yudao-spring-boot-starter-redis + + + + + org.springframework.ai + spring-ai-milvus-store + ${spring-ai.version} + + + + org.slf4j + slf4j-reload4j + + + + + + + org.springframework.ai + spring-ai-tika-document-reader + ${spring-ai.version} + + + + spring-cloud-function-context + org.springframework.cloud + + + spring-cloud-function-core + org.springframework.cloud + + + + + + + dev.tinyflow + tinyflow-java-core + ${tinyflow.version} + + + com.jfinal + enjoy + + + + com.agentsflex + agents-flex-store-elasticsearch + + + + org.codehaus.groovy + groovy-all + + + + org.slf4j + slf4j-simple + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.slf4j + slf4j-reload4j + + + \ No newline at end of file diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java index aaa142b..1d9503f 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.ai.controller.admin.image; import cn.hutool.core.util.ObjUtil; -import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; +import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageRespVO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageRespVO.java index f73d05a..fa3a957 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageRespVO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageRespVO.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.ai.controller.admin.image.vo; -import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; +import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/model/AiModelSaveReqVO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/model/AiModelSaveReqVO.java index 281bcd6..95ed6bf 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/model/AiModelSaveReqVO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/model/AiModelSaveReqVO.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.ai.controller.admin.model.vo.model; -import cn.iocoder.yudao.framework.ai.core.enums.AiModelTypeEnum; -import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; +import cn.iocoder.yudao.module.ai.enums.model.AiModelTypeEnum; +import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.validation.InEnum; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java index a18904c..72acf72 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.image; -import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; +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.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO; import cn.iocoder.yudao.module.ai.enums.image.AiImageStatusEnum; @@ -49,7 +50,7 @@ public class AiImageDO extends BaseDO { /** * 平台 * - * 枚举 {@link cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum} + * 枚举 {@link AiPlatformEnum} */ private String platform; /** diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/mindmap/AiMindMapDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/mindmap/AiMindMapDO.java index 6dd5d44..db788b7 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/mindmap/AiMindMapDO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/mindmap/AiMindMapDO.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.mindmap; -import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; +import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO; import com.baomidou.mybatisplus.annotation.KeySequence; diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiApiKeyDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiApiKeyDO.java index 346811f..f2c683a 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiApiKeyDO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiApiKeyDO.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.model; -import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; +import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.KeySequence; diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiModelDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiModelDO.java index b393202..9e54f94 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiModelDO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiModelDO.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.model; -import cn.iocoder.yudao.framework.ai.core.enums.AiModelTypeEnum; -import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; +import cn.iocoder.yudao.module.ai.enums.model.AiModelTypeEnum; +import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.KeySequence; diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java index bfa7394..cc16133 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.music; -import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; +import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.ai.enums.music.AiMusicGenerateModeEnum; import cn.iocoder.yudao.module.ai.enums.music.AiMusicStatusEnum; diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/write/AiWriteDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/write/AiWriteDO.java index e07f994..75e1e29 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/write/AiWriteDO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/write/AiWriteDO.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.write; -import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; +import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO; import cn.iocoder.yudao.module.ai.enums.DictTypeConstants; diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiModelTypeEnum.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiModelTypeEnum.java new file mode 100644 index 0000000..bdba3e8 --- /dev/null +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiModelTypeEnum.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.ai.enums.model; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * AI 模型类型的枚举 + * + * @author 芋道源码 + */ +@Getter +@RequiredArgsConstructor +public enum AiModelTypeEnum implements ArrayValuable { + + CHAT(1, "对话"), + IMAGE(2, "图片"), + VOICE(3, "语音"), + VIDEO(4, "视频"), + EMBEDDING(5, "向量"), + RERANK(6, "重排序"); + + /** + * 类型 + */ + private final Integer type; + /** + * 类型名 + */ + private final String name; + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(AiModelTypeEnum::getType).toArray(Integer[]::new); + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java new file mode 100644 index 0000000..cebe0b9 --- /dev/null +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.ai.enums.model; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * AI 模型平台 + * + * @author fansili + */ +@Getter +@AllArgsConstructor +public enum AiPlatformEnum implements ArrayValuable { + + // ========== 国内平台 ========== + + TONG_YI("TongYi", "通义千问"), // 阿里 + YI_YAN("YiYan", "文心一言"), // 百度 + DEEP_SEEK("DeepSeek", "DeepSeek"), // DeepSeek + ZHI_PU("ZhiPu", "智谱"), // 智谱 AI + XING_HUO("XingHuo", "星火"), // 讯飞 + DOU_BAO("DouBao", "豆包"), // 字节 + HUN_YUAN("HunYuan", "混元"), // 腾讯 + SILICON_FLOW("SiliconFlow", "硅基流动"), // 硅基流动 + MINI_MAX("MiniMax", "MiniMax"), // 稀宇科技 + MOONSHOT("Moonshot", "月之暗灭"), // KIMI + BAI_CHUAN("BaiChuan", "百川智能"), // 百川智能 + + // ========== 国外平台 ========== + + OPENAI("OpenAI", "OpenAI"), // OpenAI 官方 + AZURE_OPENAI("AzureOpenAI", "AzureOpenAI"), // OpenAI 微软 + OLLAMA("Ollama", "Ollama"), + + STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI + MIDJOURNEY("Midjourney", "Midjourney"), // Midjourney + SUNO("Suno", "Suno"), // Suno AI + + ; + + /** + * 平台 + */ + private final String platform; + /** + * 平台名 + */ + private final String name; + + public static final String[] ARRAYS = Arrays.stream(values()).map(AiPlatformEnum::getPlatform).toArray(String[]::new); + + public static AiPlatformEnum validatePlatform(String platform) { + for (AiPlatformEnum platformEnum : AiPlatformEnum.values()) { + if (platformEnum.getPlatform().equals(platform)) { + return platformEnum; + } + } + throw new IllegalArgumentException("非法平台: " + platform); + } + + @Override + public String[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/enums/package-info.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/enums/package-info.java new file mode 100644 index 0000000..17650e4 --- /dev/null +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/enums/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package cn.iocoder.yudao.module.ai.enums; diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java new file mode 100644 index 0000000..a28d726 --- /dev/null +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java @@ -0,0 +1,253 @@ +package cn.iocoder.yudao.module.ai.framework.ai.config; + +import cn.hutool.core.util.StrUtil; +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; +import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowApiConstants; +import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowChatModel; +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; +import org.springframework.ai.openai.OpenAiChatModel; +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.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 芋道 AI 自动配置 + * + * @author fansili + */ +@Configuration +@EnableConfigurationProperties({ YudaoAiProperties.class, + QdrantVectorStoreProperties.class, // 解析 Qdrant 配置 + RedisVectorStoreProperties.class, // 解析 Redis 配置 + MilvusVectorStoreProperties.class, MilvusServiceClientProperties.class // 解析 Milvus 配置 +}) +@Slf4j +public class AiAutoConfiguration { + + @Bean + public AiModelFactory aiModelFactory() { + return new AiModelFactoryImpl(); + } + + // ========== 各种 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) { + YudaoAiProperties.DouBaoProperties properties = yudaoAiProperties.getDoubao(); + return buildDouBaoChatClient(properties); + } + + public DouBaoChatModel buildDouBaoChatClient(YudaoAiProperties.DouBaoProperties properties) { + if (StrUtil.isEmpty(properties.getModel())) { + properties.setModel(DouBaoChatModel.MODEL_DEFAULT); + } + OpenAiChatModel openAiChatModel = OpenAiChatModel.builder() + .openAiApi(OpenAiApi.builder() + .baseUrl(DouBaoChatModel.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 DouBaoChatModel(openAiChatModel); + } + + @Bean + @ConditionalOnProperty(value = "yudao.ai.siliconflow.enable", havingValue = "true") + public SiliconFlowChatModel siliconFlowChatClient(YudaoAiProperties yudaoAiProperties) { + YudaoAiProperties.SiliconFlowProperties properties = yudaoAiProperties.getSiliconflow(); + return buildSiliconFlowChatClient(properties); + } + + public SiliconFlowChatModel buildSiliconFlowChatClient(YudaoAiProperties.SiliconFlowProperties properties) { + if (StrUtil.isEmpty(properties.getModel())) { + properties.setModel(SiliconFlowApiConstants.MODEL_DEFAULT); + } + OpenAiChatModel openAiChatModel = OpenAiChatModel.builder() + .openAiApi(OpenAiApi.builder() + .baseUrl(SiliconFlowApiConstants.DEFAULT_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 SiliconFlowChatModel(openAiChatModel); + } + + @Bean + @ConditionalOnProperty(value = "yudao.ai.hunyuan.enable", havingValue = "true") + public HunYuanChatModel hunYuanChatClient(YudaoAiProperties yudaoAiProperties) { + YudaoAiProperties.HunYuanProperties properties = yudaoAiProperties.getHunyuan(); + return buildHunYuanChatClient(properties); + } + + public HunYuanChatModel buildHunYuanChatClient(YudaoAiProperties.HunYuanProperties properties) { + if (StrUtil.isEmpty(properties.getModel())) { + properties.setModel(HunYuanChatModel.MODEL_DEFAULT); + } + // 特殊:由于混元大模型不提供 deepseek,而是通过知识引擎,所以需要区分下 URL + if (StrUtil.isEmpty(properties.getBaseUrl())) { + properties.setBaseUrl( + StrUtil.startWithIgnoreCase(properties.getModel(), "deepseek") ? HunYuanChatModel.DEEP_SEEK_BASE_URL + : HunYuanChatModel.BASE_URL); + } + // 创建 OpenAiChatModel、HunYuanChatModel 对象 + OpenAiChatModel openAiChatModel = OpenAiChatModel.builder() + .openAiApi(OpenAiApi.builder() + .baseUrl(properties.getBaseUrl()) + .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 HunYuanChatModel(openAiChatModel); + } + + @Bean + @ConditionalOnProperty(value = "yudao.ai.xinghuo.enable", havingValue = "true") + public XingHuoChatModel xingHuoChatClient(YudaoAiProperties yudaoAiProperties) { + YudaoAiProperties.XingHuoProperties properties = yudaoAiProperties.getXinghuo(); + return buildXingHuoChatClient(properties); + } + + public XingHuoChatModel buildXingHuoChatClient(YudaoAiProperties.XingHuoProperties properties) { + if (StrUtil.isEmpty(properties.getModel())) { + properties.setModel(XingHuoChatModel.MODEL_DEFAULT); + } + OpenAiChatModel openAiChatModel = OpenAiChatModel.builder() + .openAiApi(OpenAiApi.builder() + .baseUrl(XingHuoChatModel.BASE_URL) + .apiKey(properties.getAppKey() + ":" + properties.getSecretKey()) + .build()) + .defaultOptions(OpenAiChatOptions.builder() + .model(properties.getModel()) + .temperature(properties.getTemperature()) + .maxTokens(properties.getMaxTokens()) + .topP(properties.getTopP()) + .build()) + .toolCallingManager(getToolCallingManager()) + .build(); + return new XingHuoChatModel(openAiChatModel); + } + + @Bean + @ConditionalOnProperty(value = "yudao.ai.baichuan.enable", havingValue = "true") + public BaiChuanChatModel baiChuanChatClient(YudaoAiProperties yudaoAiProperties) { + YudaoAiProperties.BaiChuanProperties properties = yudaoAiProperties.getBaichuan(); + return buildBaiChuanChatClient(properties); + } + + public BaiChuanChatModel buildBaiChuanChatClient(YudaoAiProperties.BaiChuanProperties properties) { + if (StrUtil.isEmpty(properties.getModel())) { + properties.setModel(BaiChuanChatModel.MODEL_DEFAULT); + } + OpenAiChatModel openAiChatModel = OpenAiChatModel.builder() + .openAiApi(OpenAiApi.builder() + .baseUrl(BaiChuanChatModel.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 BaiChuanChatModel(openAiChatModel); + } + + @Bean + @ConditionalOnProperty(value = "yudao.ai.midjourney.enable", havingValue = "true") + public MidjourneyApi midjourneyApi(YudaoAiProperties yudaoAiProperties) { + YudaoAiProperties.MidjourneyProperties config = yudaoAiProperties.getMidjourney(); + return new MidjourneyApi(config.getBaseUrl(), config.getApiKey(), config.getNotifyUrl()); + } + + @Bean + @ConditionalOnProperty(value = "yudao.ai.suno.enable", havingValue = "true") + public SunoApi sunoApi(YudaoAiProperties yudaoAiProperties) { + return new SunoApi(yudaoAiProperties.getSuno().getBaseUrl()); + } + + // ========== RAG 相关 ========== + + @Bean + public TokenCountEstimator tokenCountEstimator() { + return new JTokkitTokenCountEstimator(); + } + + @Bean + public BatchingStrategy batchingStrategy() { + return new TokenCountBatchingStrategy(); + } + + private static ToolCallingManager getToolCallingManager() { + return SpringUtil.getBean(ToolCallingManager.class); + } + +} \ No newline at end of file diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java new file mode 100644 index 0000000..7f80467 --- /dev/null +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java @@ -0,0 +1,164 @@ +package cn.iocoder.yudao.module.ai.framework.ai.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 芋道 AI 配置类 + * + * @author fansili + * @since 1.0 + */ +@ConfigurationProperties(prefix = "yudao.ai") +@Data +public class YudaoAiProperties { + + /** + * DeepSeek + */ + @SuppressWarnings("SpellCheckingInspection") + private DeepSeekProperties deepseek; + + /** + * 字节豆包 + */ + @SuppressWarnings("SpellCheckingInspection") + private DouBaoProperties doubao; + + /** + * 腾讯混元 + */ + @SuppressWarnings("SpellCheckingInspection") + private HunYuanProperties hunyuan; + + /** + * 硅基流动 + */ + @SuppressWarnings("SpellCheckingInspection") + private SiliconFlowProperties siliconflow; + + /** + * 讯飞星火 + */ + @SuppressWarnings("SpellCheckingInspection") + private XingHuoProperties xinghuo; + + /** + * 百川 + */ + @SuppressWarnings("SpellCheckingInspection") + private BaiChuanProperties baichuan; + + /** + * Midjourney 绘图 + */ + private MidjourneyProperties midjourney; + + /** + * Suno 音乐 + */ + @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 { + + private String enable; + private String apiKey; + + private String model; + private Double temperature; + private Integer maxTokens; + private Double topP; + + } + + @Data + public static class HunYuanProperties { + + private String enable; + private String baseUrl; + private String apiKey; + + private String model; + private Double temperature; + private Integer maxTokens; + private Double topP; + + } + + @Data + public static class SiliconFlowProperties { + + private String enable; + private String apiKey; + + private String model; + private Double temperature; + private Integer maxTokens; + private Double topP; + + } + + @Data + public static class XingHuoProperties { + + private String enable; + private String appId; + private String appKey; + private String secretKey; + + private String model; + private Double temperature; + private Integer maxTokens; + private Double topP; + + } + + @Data + public static class BaiChuanProperties { + + private String enable; + private String apiKey; + + private String model; + private Double temperature; + private Integer maxTokens; + private Double topP; + + } + + @Data + public static class MidjourneyProperties { + + private String enable; + private String baseUrl; + + private String apiKey; + private String notifyUrl; + + } + + @Data + public static class SunoProperties { + + private boolean enable = false; + + private String baseUrl; + + } + +} diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactory.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactory.java new file mode 100644 index 0000000..659fa1f --- /dev/null +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactory.java @@ -0,0 +1,113 @@ +package cn.iocoder.yudao.module.ai.framework.ai.core; + +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.suno.api.SunoApi; +import org.springframework.ai.chat.model.ChatModel; +import org.springframework.ai.embedding.EmbeddingModel; +import org.springframework.ai.image.ImageModel; +import org.springframework.ai.vectorstore.VectorStore; + +import java.util.Map; + +/** + * AI Model 模型工厂的接口类 + * + * @author fansili + */ +public interface AiModelFactory { + + /** + * 基于指定配置,获得 ChatModel 对象 + * + * 如果不存在,则进行创建 + * + * @param platform 平台 + * @param apiKey API KEY + * @param url API URL + * @return ChatModel 对象 + */ + ChatModel getOrCreateChatModel(AiPlatformEnum platform, String apiKey, String url); + + /** + * 基于默认配置,获得 ChatModel 对象 + * + * 默认配置,指的是在 application.yaml 配置文件中的 spring.ai 相关的配置 + * + * @param platform 平台 + * @return ChatModel 对象 + */ + ChatModel getDefaultChatModel(AiPlatformEnum platform); + + /** + * 基于默认配置,获得 ImageModel 对象 + * + * 默认配置,指的是在 application.yaml 配置文件中的 spring.ai 相关的配置 + * + * @param platform 平台 + * @return ImageModel 对象 + */ + ImageModel getDefaultImageModel(AiPlatformEnum platform); + + /** + * 基于指定配置,获得 ImageModel 对象 + * + * 如果不存在,则进行创建 + * + * @param platform 平台 + * @param apiKey API KEY + * @param url API URL + * @return ImageModel 对象 + */ + ImageModel getOrCreateImageModel(AiPlatformEnum platform, String apiKey, String url); + + /** + * 基于指定配置,获得 MidjourneyApi 对象 + * + * 如果不存在,则进行创建 + * + * @param apiKey API KEY + * @param url API URL + * @return MidjourneyApi 对象 + */ + MidjourneyApi getOrCreateMidjourneyApi(String apiKey, String url); + + /** + * 基于指定配置,获得 SunoApi 对象 + * + * 如果不存在,则进行创建 + * + * @param apiKey API KEY + * @param url API URL + * @return SunoApi 对象 + */ + SunoApi getOrCreateSunoApi(String apiKey, String url); + + /** + * 基于指定配置,获得 EmbeddingModel 对象 + * + * 如果不存在,则进行创建 + * + * @param platform 平台 + * @param apiKey API KEY + * @param url API URL + * @param model 模型 + * @return ChatModel 对象 + */ + EmbeddingModel getOrCreateEmbeddingModel(AiPlatformEnum platform, String apiKey, String url, String model); + + /** + * 基于指定配置,获得 VectorStore 对象 + * + * 如果不存在,则进行创建 + * + * @param type 向量存储类型 + * @param embeddingModel 向量模型 + * @param metadataFields 元数据字段 + * @return VectorStore 对象 + */ + VectorStore getOrCreateVectorStore(Class type, + EmbeddingModel embeddingModel, + Map> metadataFields); + +} diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactoryImpl.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactoryImpl.java new file mode 100644 index 0000000..f258ffa --- /dev/null +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactoryImpl.java @@ -0,0 +1,752 @@ +package cn.iocoder.yudao.module.ai.framework.ai.core; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.Singleton; +import cn.hutool.core.lang.func.Func0; +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.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; +import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowApiConstants; +import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowChatModel; +import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowImageApi; +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.dashscope.api.DashScopeApi; +import com.alibaba.cloud.ai.dashscope.api.DashScopeImageApi; +import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel; +import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions; +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 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.springframework.ai.azure.openai.AzureOpenAiChatModel; +import org.springframework.ai.azure.openai.AzureOpenAiEmbeddingModel; +import org.springframework.ai.chat.model.ChatModel; +import org.springframework.ai.document.MetadataMode; +import org.springframework.ai.embedding.BatchingStrategy; +import org.springframework.ai.embedding.EmbeddingModel; +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.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.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.openai.OpenAiChatModel; +import org.springframework.ai.openai.OpenAiEmbeddingModel; +import org.springframework.ai.openai.OpenAiEmbeddingOptions; +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.observation.DefaultVectorStoreObservationConvention; +import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; +import org.springframework.ai.vectorstore.qdrant.QdrantVectorStore; +import org.springframework.ai.vectorstore.redis.RedisVectorStore; +import org.springframework.ai.zhipuai.*; +import org.springframework.ai.zhipuai.api.ZhiPuAiApi; +import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.web.client.RestClient; +import redis.clients.jedis.JedisPooled; + +import java.io.File; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static org.springframework.ai.retry.RetryUtils.DEFAULT_RETRY_TEMPLATE; + +/** + * AI Model 模型工厂的实现类 + * + * @author 芋道源码 + */ +public class AiModelFactoryImpl implements AiModelFactory { + + @Override + public ChatModel getOrCreateChatModel(AiPlatformEnum platform, String apiKey, String url) { + String cacheKey = buildClientCacheKey(ChatModel.class, platform, apiKey, url); + return Singleton.get(cacheKey, (Func0) () -> { + // noinspection EnhancedSwitchMigration + switch (platform) { + case TONG_YI: + return buildTongYiChatModel(apiKey); + case YI_YAN: + return buildYiYanChatModel(apiKey); + case DEEP_SEEK: + return buildDeepSeekChatModel(apiKey); + case DOU_BAO: + return buildDouBaoChatModel(apiKey); + case HUN_YUAN: + return buildHunYuanChatModel(apiKey, url); + case SILICON_FLOW: + return buildSiliconFlowChatModel(apiKey); + case ZHI_PU: + return buildZhiPuChatModel(apiKey, url); + case MINI_MAX: + return buildMiniMaxChatModel(apiKey, url); + case MOONSHOT: + return buildMoonshotChatModel(apiKey, url); + case XING_HUO: + return buildXingHuoChatModel(apiKey); + case BAI_CHUAN: + return buildBaiChuanChatModel(apiKey); + case OPENAI: + return buildOpenAiChatModel(apiKey, url); + case AZURE_OPENAI: + return buildAzureOpenAiChatModel(apiKey, url); + case OLLAMA: + return buildOllamaChatModel(url); + default: + throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform)); + } + }); + } + + @Override + public ChatModel getDefaultChatModel(AiPlatformEnum platform) { + // noinspection EnhancedSwitchMigration + switch (platform) { + case TONG_YI: + return SpringUtil.getBean(DashScopeChatModel.class); + case YI_YAN: + return SpringUtil.getBean(QianFanChatModel.class); + case DEEP_SEEK: + return SpringUtil.getBean(DeepSeekChatModel.class); + case DOU_BAO: + return SpringUtil.getBean(DouBaoChatModel.class); + case HUN_YUAN: + return SpringUtil.getBean(HunYuanChatModel.class); + case SILICON_FLOW: + return SpringUtil.getBean(SiliconFlowChatModel.class); + case ZHI_PU: + return SpringUtil.getBean(ZhiPuAiChatModel.class); + case MINI_MAX: + return SpringUtil.getBean(MiniMaxChatModel.class); + case MOONSHOT: + return SpringUtil.getBean(MoonshotChatModel.class); + case XING_HUO: + return SpringUtil.getBean(XingHuoChatModel.class); + case BAI_CHUAN: + return SpringUtil.getBean(AzureOpenAiChatModel.class); + case OPENAI: + return SpringUtil.getBean(OpenAiChatModel.class); + case AZURE_OPENAI: + return SpringUtil.getBean(AzureOpenAiChatModel.class); + case OLLAMA: + return SpringUtil.getBean(OllamaChatModel.class); + default: + throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform)); + } + } + + @Override + public ImageModel getDefaultImageModel(AiPlatformEnum platform) { + // noinspection EnhancedSwitchMigration + switch (platform) { + case TONG_YI: + return SpringUtil.getBean(DashScopeImageModel.class); + case YI_YAN: + return SpringUtil.getBean(QianFanImageModel.class); + case ZHI_PU: + return SpringUtil.getBean(ZhiPuAiImageModel.class); + case SILICON_FLOW: + return SpringUtil.getBean(SiliconFlowImageModel.class); + case OPENAI: + return SpringUtil.getBean(OpenAiImageModel.class); + case STABLE_DIFFUSION: + return SpringUtil.getBean(StabilityAiImageModel.class); + default: + throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform)); + } + } + + @Override + public ImageModel getOrCreateImageModel(AiPlatformEnum platform, String apiKey, String url) { + // noinspection EnhancedSwitchMigration + switch (platform) { + case TONG_YI: + return buildTongYiImagesModel(apiKey); + case YI_YAN: + return buildQianFanImageModel(apiKey); + case ZHI_PU: + return buildZhiPuAiImageModel(apiKey, url); + case OPENAI: + return buildOpenAiImageModel(apiKey, url); + case SILICON_FLOW: + return buildSiliconFlowImageModel(apiKey,url); + case STABLE_DIFFUSION: + return buildStabilityAiImageModel(apiKey, url); + default: + throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform)); + } + } + + @Override + public MidjourneyApi getOrCreateMidjourneyApi(String apiKey, String url) { + String cacheKey = buildClientCacheKey(MidjourneyApi.class, AiPlatformEnum.MIDJOURNEY.getPlatform(), apiKey, + url); + return Singleton.get(cacheKey, (Func0) () -> { + YudaoAiProperties.MidjourneyProperties properties = SpringUtil.getBean(YudaoAiProperties.class) + .getMidjourney(); + return new MidjourneyApi(url, apiKey, properties.getNotifyUrl()); + }); + } + + @Override + public SunoApi getOrCreateSunoApi(String apiKey, String url) { + String cacheKey = buildClientCacheKey(SunoApi.class, AiPlatformEnum.SUNO.getPlatform(), apiKey, url); + return Singleton.get(cacheKey, (Func0) () -> new SunoApi(url)); + } + + @Override + @SuppressWarnings("EnhancedSwitchMigration") + public EmbeddingModel getOrCreateEmbeddingModel(AiPlatformEnum platform, String apiKey, String url, String model) { + String cacheKey = buildClientCacheKey(EmbeddingModel.class, platform, apiKey, url, model); + return Singleton.get(cacheKey, (Func0) () -> { + switch (platform) { + case TONG_YI: + return buildTongYiEmbeddingModel(apiKey, model); + case YI_YAN: + return buildYiYanEmbeddingModel(apiKey, model); + case ZHI_PU: + return buildZhiPuEmbeddingModel(apiKey, url, model); + case MINI_MAX: + return buildMiniMaxEmbeddingModel(apiKey, url, model); + case OPENAI: + return buildOpenAiEmbeddingModel(apiKey, url, model); + case AZURE_OPENAI: + return buildAzureOpenAiEmbeddingModel(apiKey, url, model); + case OLLAMA: + return buildOllamaEmbeddingModel(url, model); + default: + throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform)); + } + }); + } + + @Override + public VectorStore getOrCreateVectorStore(Class type, + EmbeddingModel embeddingModel, + Map> metadataFields) { + String cacheKey = buildClientCacheKey(VectorStore.class, embeddingModel, type); + return Singleton.get(cacheKey, (Func0) () -> { + if (type == SimpleVectorStore.class) { + return buildSimpleVectorStore(embeddingModel); + } + if (type == QdrantVectorStore.class) { + return buildQdrantVectorStore(embeddingModel); + } + if (type == RedisVectorStore.class) { + return buildRedisVectorStore(embeddingModel, metadataFields); + } + if (type == MilvusVectorStore.class) { + return buildMilvusVectorStore(embeddingModel); + } + throw new IllegalArgumentException(StrUtil.format("未知类型({})", type)); + }); + } + + private static String buildClientCacheKey(Class clazz, Object... params) { + if (ArrayUtil.isEmpty(params)) { + return clazz.getName(); + } + return StrUtil.format("{}#{}", clazz.getName(), ArrayUtil.join(params, "_")); + } + + // ========== 各种创建 spring-ai 客户端的方法 ========== + + /** + * 可参考 {@link DashScopeAutoConfiguration} 的 dashscopeChatModel 方法 + */ + private static DashScopeChatModel buildTongYiChatModel(String key) { + DashScopeApi dashScopeApi = new DashScopeApi(key); + DashScopeChatOptions options = DashScopeChatOptions.builder().withModel(DashScopeApi.DEFAULT_CHAT_MODEL) + .withTemperature(0.7).build(); + return new DashScopeChatModel(dashScopeApi, options, getFunctionCallbackResolver(), DEFAULT_RETRY_TEMPLATE); + } + + /** + * 可参考 {@link DashScopeAutoConfiguration} 的 dashScopeImageModel 方法 + */ + private static DashScopeImageModel buildTongYiImagesModel(String key) { + DashScopeImageApi dashScopeImageApi = new DashScopeImageApi(key); + return new DashScopeImageModel(dashScopeImageApi); + } + + /** + * 可参考 {@link QianFanAutoConfiguration} 的 qianFanChatModel 方法 + */ + private static QianFanChatModel buildYiYanChatModel(String key) { + List keys = StrUtil.split(key, '|'); + Assert.equals(keys.size(), 2, "YiYanChatClient 的密钥需要 (appKey|secretKey) 格式"); + String appKey = keys.get(0); + String secretKey = keys.get(1); + QianFanApi qianFanApi = new QianFanApi(appKey, secretKey); + return new QianFanChatModel(qianFanApi); + } + + /** + * 可参考 {@link QianFanAutoConfiguration} 的 qianFanImageModel 方法 + */ + private QianFanImageModel buildQianFanImageModel(String key) { + List keys = StrUtil.split(key, '|'); + Assert.equals(keys.size(), 2, "YiYanChatClient 的密钥需要 (appKey|secretKey) 格式"); + String appKey = keys.get(0); + String secretKey = keys.get(1); + QianFanImageApi qianFanApi = new QianFanImageApi(appKey, secretKey); + return new QianFanImageModel(qianFanApi); + } + + /** + * 可参考 {@link AiAutoConfiguration#deepSeekChatModel(YudaoAiProperties)} + */ + private static DeepSeekChatModel buildDeepSeekChatModel(String apiKey) { + YudaoAiProperties.DeepSeekProperties properties = new YudaoAiProperties.DeepSeekProperties() + .setApiKey(apiKey); + return new AiAutoConfiguration().buildDeepSeekChatModel(properties); + } + + /** + * 可参考 {@link AiAutoConfiguration#douBaoChatClient(YudaoAiProperties)} + */ + private ChatModel buildDouBaoChatModel(String apiKey) { + YudaoAiProperties.DouBaoProperties properties = new YudaoAiProperties.DouBaoProperties() + .setApiKey(apiKey); + return new AiAutoConfiguration().buildDouBaoChatClient(properties); + } + + /** + * 可参考 {@link AiAutoConfiguration#hunYuanChatClient(YudaoAiProperties)} + */ + private ChatModel buildHunYuanChatModel(String apiKey, String url) { + YudaoAiProperties.HunYuanProperties properties = new YudaoAiProperties.HunYuanProperties() + .setBaseUrl(url).setApiKey(apiKey); + return new AiAutoConfiguration().buildHunYuanChatClient(properties); + } + + /** + * 可参考 {@link AiAutoConfiguration#siliconFlowChatClient(YudaoAiProperties)} + */ + private ChatModel buildSiliconFlowChatModel(String apiKey) { + YudaoAiProperties.SiliconFlowProperties properties = new YudaoAiProperties.SiliconFlowProperties() + .setApiKey(apiKey); + return new AiAutoConfiguration().buildSiliconFlowChatClient(properties); + } + + /** + * 可参考 {@link ZhiPuAiAutoConfiguration} 的 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); + } + + /** + * 可参考 {@link ZhiPuAiAutoConfiguration} 的 zhiPuAiImageModel 方法 + */ + private ZhiPuAiImageModel buildZhiPuAiImageModel(String apiKey, String url) { + ZhiPuAiImageApi zhiPuAiApi = StrUtil.isEmpty(url) ? new ZhiPuAiImageApi(apiKey) + : new ZhiPuAiImageApi(url, apiKey, RestClient.builder()); + return new ZhiPuAiImageModel(zhiPuAiApi); + } + + /** + * 可参考 {@link MiniMaxAutoConfiguration} 的 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); + } + + /** + * 可参考 {@link MoonshotAutoConfiguration} 的 moonshotChatModel 方法 + */ + private MoonshotChatModel buildMoonshotChatModel(String apiKey, String url) { + MoonshotApi moonshotApi = StrUtil.isEmpty(url)? new MoonshotApi(apiKey) + : new MoonshotApi(url, apiKey); + MoonshotChatOptions options = MoonshotChatOptions.builder().model(MoonshotApi.DEFAULT_CHAT_MODEL).build(); + return new MoonshotChatModel(moonshotApi, options, getFunctionCallbackResolver(), DEFAULT_RETRY_TEMPLATE); + } + + /** + * 可参考 {@link AiAutoConfiguration#xingHuoChatClient(YudaoAiProperties)} + */ + private static XingHuoChatModel buildXingHuoChatModel(String key) { + List keys = StrUtil.split(key, '|'); + Assert.equals(keys.size(), 2, "XingHuoChatClient 的密钥需要 (appKey|secretKey) 格式"); + YudaoAiProperties.XingHuoProperties properties = new YudaoAiProperties.XingHuoProperties() + .setAppKey(keys.get(0)).setSecretKey(keys.get(1)); + return new AiAutoConfiguration().buildXingHuoChatClient(properties); + } + + /** + * 可参考 {@link AiAutoConfiguration#baiChuanChatClient(YudaoAiProperties)} + */ + private BaiChuanChatModel buildBaiChuanChatModel(String apiKey) { + YudaoAiProperties.BaiChuanProperties properties = new YudaoAiProperties.BaiChuanProperties() + .setApiKey(apiKey); + return new AiAutoConfiguration().buildBaiChuanChatClient(properties); + } + + /** + * 可参考 {@link OpenAiAutoConfiguration} 的 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(); + } + + // TODO @芋艿:手头暂时没密钥,使用建议再测试下 + /** + * 可参考 {@link AzureOpenAiAutoConfiguration} + */ + 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); + } + + /** + * 可参考 {@link OpenAiAutoConfiguration} 的 openAiImageModel 方法 + */ + private OpenAiImageModel buildOpenAiImageModel(String openAiToken, String url) { + url = StrUtil.blankToDefault(url, OpenAiApiConstants.DEFAULT_BASE_URL); + OpenAiImageApi openAiApi = OpenAiImageApi.builder().baseUrl(url).apiKey(openAiToken).build(); + return new OpenAiImageModel(openAiApi); + } + + /** + * 创建 SiliconFlowImageModel 对象 + */ + private SiliconFlowImageModel buildSiliconFlowImageModel(String apiToken, String url) { + url = StrUtil.blankToDefault(url, SiliconFlowApiConstants.DEFAULT_BASE_URL); + SiliconFlowImageApi openAiApi = new SiliconFlowImageApi(url, apiToken); + return new SiliconFlowImageModel(openAiApi); + } + + /** + * 可参考 {@link OllamaAutoConfiguration} 的 ollamaApi 方法 + */ + private static OllamaChatModel buildOllamaChatModel(String url) { + OllamaApi ollamaApi = new OllamaApi(url); + return OllamaChatModel.builder().ollamaApi(ollamaApi).toolCallingManager(getToolCallingManager()).build(); + } + + /** + * 可参考 {@link StabilityAiImageAutoConfiguration} 的 stabilityAiImageModel 方法 + */ + private StabilityAiImageModel buildStabilityAiImageModel(String apiKey, String url) { + url = StrUtil.blankToDefault(url, StabilityAiApi.DEFAULT_BASE_URL); + StabilityAiApi stabilityAiApi = new StabilityAiApi(apiKey, StabilityAiApi.DEFAULT_IMAGE_MODEL, url); + return new StabilityAiImageModel(stabilityAiApi); + } + + // ========== 各种创建 EmbeddingModel 的方法 ========== + + /** + * 可参考 {@link DashScopeAutoConfiguration} 的 dashscopeEmbeddingModel 方法 + */ + private DashScopeEmbeddingModel buildTongYiEmbeddingModel(String apiKey, String model) { + DashScopeApi dashScopeApi = new DashScopeApi(apiKey); + DashScopeEmbeddingOptions dashScopeEmbeddingOptions = DashScopeEmbeddingOptions.builder().withModel(model).build(); + return new DashScopeEmbeddingModel(dashScopeApi, MetadataMode.EMBED, dashScopeEmbeddingOptions); + } + + /** + * 可参考 {@link ZhiPuAiAutoConfiguration} 的 zhiPuAiEmbeddingModel 方法 + */ + private ZhiPuAiEmbeddingModel buildZhiPuEmbeddingModel(String apiKey, String url, String model) { + ZhiPuAiApi zhiPuAiApi = StrUtil.isEmpty(url) ? new ZhiPuAiApi(apiKey) + : new ZhiPuAiApi(url, apiKey); + ZhiPuAiEmbeddingOptions zhiPuAiEmbeddingOptions = ZhiPuAiEmbeddingOptions.builder().model(model).build(); + return new ZhiPuAiEmbeddingModel(zhiPuAiApi, MetadataMode.EMBED, zhiPuAiEmbeddingOptions); + } + + /** + * 可参考 {@link MiniMaxAutoConfiguration} 的 miniMaxEmbeddingModel 方法 + */ + private EmbeddingModel buildMiniMaxEmbeddingModel(String apiKey, String url, String model) { + MiniMaxApi miniMaxApi = StrUtil.isEmpty(url)? new MiniMaxApi(apiKey) + : new MiniMaxApi(url, apiKey); + MiniMaxEmbeddingOptions miniMaxEmbeddingOptions = MiniMaxEmbeddingOptions.builder().model(model).build(); + return new MiniMaxEmbeddingModel(miniMaxApi, MetadataMode.EMBED, miniMaxEmbeddingOptions); + } + + /** + * 可参考 {@link QianFanAutoConfiguration} 的 qianFanEmbeddingModel 方法 + */ + private QianFanEmbeddingModel buildYiYanEmbeddingModel(String key, String model) { + List keys = StrUtil.split(key, '|'); + Assert.equals(keys.size(), 2, "YiYanChatClient 的密钥需要 (appKey|secretKey) 格式"); + String appKey = keys.get(0); + String secretKey = keys.get(1); + QianFanApi qianFanApi = new QianFanApi(appKey, secretKey); + QianFanEmbeddingOptions qianFanEmbeddingOptions = QianFanEmbeddingOptions.builder().model(model).build(); + return new QianFanEmbeddingModel(qianFanApi, MetadataMode.EMBED, qianFanEmbeddingOptions); + } + + private OllamaEmbeddingModel buildOllamaEmbeddingModel(String url, String model) { + OllamaApi ollamaApi = new OllamaApi(url); + OllamaOptions ollamaOptions = OllamaOptions.builder().model(model).build(); + return OllamaEmbeddingModel.builder().ollamaApi(ollamaApi).defaultOptions(ollamaOptions).build(); + } + + /** + * 可参考 {@link OpenAiAutoConfiguration} 的 openAiEmbeddingModel 方法 + */ + private OpenAiEmbeddingModel buildOpenAiEmbeddingModel(String openAiToken, String url, String model) { + url = StrUtil.blankToDefault(url, OpenAiApiConstants.DEFAULT_BASE_URL); + OpenAiApi openAiApi = OpenAiApi.builder().baseUrl(url).apiKey(openAiToken).build(); + OpenAiEmbeddingOptions openAiEmbeddingProperties = OpenAiEmbeddingOptions.builder().model(model).build(); + return new OpenAiEmbeddingModel(openAiApi, MetadataMode.EMBED, openAiEmbeddingProperties); + } + + // TODO @芋艿:手头暂时没密钥,使用建议再测试下 + /** + * 可参考 {@link AzureOpenAiAutoConfiguration} 的 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); + // 获取 AzureOpenAiChatProperties 对象 + AzureOpenAiEmbeddingProperties embeddingProperties = SpringUtil.getBean(AzureOpenAiEmbeddingProperties.class); + return azureOpenAiAutoConfiguration.azureOpenAiEmbeddingModel(openAIClient, embeddingProperties, + null, null); + } + + // ========== 各种创建 VectorStore 的方法 ========== + + /** + * 注意:仅适合本地测试使用,生产建议还是使用 Qdrant、Milvus 等 + */ + @SneakyThrows + @SuppressWarnings("ResultOfMethodCallIgnored") + private SimpleVectorStore buildSimpleVectorStore(EmbeddingModel embeddingModel) { + SimpleVectorStore vectorStore = SimpleVectorStore.builder(embeddingModel).build(); + // 启动加载 + File file = new File(StrUtil.format("{}/vector_store/simple_{}.json", + FileUtil.getUserHomePath(), embeddingModel.getClass().getSimpleName())); + if (!file.exists()) { + FileUtil.mkParentDirs(file); + file.createNewFile(); + } else if (file.length() > 0) { + vectorStore.load(file); + } + // 定时持久化,每分钟一次 + Timer timer = new Timer("SimpleVectorStoreTimer-" + file.getAbsolutePath()); + timer.scheduleAtFixedRate(new TimerTask() { + + @Override + public void run() { + vectorStore.save(file); + } + + }, Duration.ofMinutes(1).toMillis(), Duration.ofMinutes(1).toMillis()); + // 关闭时,进行持久化 + RuntimeUtil.addShutdownHook(() -> vectorStore.save(file)); + return vectorStore; + } + + /** + * 参考 {@link QdrantVectorStoreAutoConfiguration} 的 vectorStore 方法 + */ + @SneakyThrows + private QdrantVectorStore buildQdrantVectorStore(EmbeddingModel embeddingModel) { + QdrantVectorStoreAutoConfiguration configuration = new QdrantVectorStoreAutoConfiguration(); + QdrantVectorStoreProperties properties = SpringUtil.getBean(QdrantVectorStoreProperties.class); + // 参考 QdrantVectorStoreAutoConfiguration 实现,创建 QdrantClient 对象 + QdrantGrpcClient.Builder grpcClientBuilder = QdrantGrpcClient.newBuilder( + properties.getHost(), properties.getPort(), properties.isUseTls()); + if (StrUtil.isNotEmpty(properties.getApiKey())) { + grpcClientBuilder.withApiKey(properties.getApiKey()); + } + QdrantClient qdrantClient = new QdrantClient(grpcClientBuilder.build()); + // 创建 QdrantVectorStore 对象 + QdrantVectorStore vectorStore = configuration.vectorStore(embeddingModel, properties, qdrantClient, + getObservationRegistry(), getCustomObservationConvention(), getBatchingStrategy()); + // 初始化索引 + vectorStore.afterPropertiesSet(); + return vectorStore; + } + + /** + * 参考 {@link RedisVectorStoreAutoConfiguration} 的 vectorStore 方法 + */ + private RedisVectorStore buildRedisVectorStore(EmbeddingModel embeddingModel, + Map> metadataFields) { + // 创建 JedisPooled 对象 + RedisProperties redisProperties = SpringUtils.getBean(RedisProperties.class); + JedisPooled jedisPooled = new JedisPooled(redisProperties.getHost(), redisProperties.getPort()); + // 创建 RedisVectorStoreProperties 对象 + RedisVectorStoreAutoConfiguration configuration = new RedisVectorStoreAutoConfiguration(); + RedisVectorStoreProperties properties = SpringUtil.getBean(RedisVectorStoreProperties.class); + RedisVectorStore redisVectorStore = RedisVectorStore.builder(jedisPooled, embeddingModel) + .indexName(properties.getIndex()).prefix(properties.getPrefix()) + .initializeSchema(properties.isInitializeSchema()) + .metadataFields(convertList(metadataFields.entrySet(), entry -> { + String fieldName = entry.getKey(); + Class fieldType = entry.getValue(); + if (Number.class.isAssignableFrom(fieldType)) { + return RedisVectorStore.MetadataField.numeric(fieldName); + } + if (Boolean.class.isAssignableFrom(fieldType)) { + return RedisVectorStore.MetadataField.tag(fieldName); + } + return RedisVectorStore.MetadataField.text(fieldName); + })) + .observationRegistry(getObservationRegistry().getObject()) + .customObservationConvention(getCustomObservationConvention().getObject()) + .batchingStrategy(getBatchingStrategy()) + .build(); + // 初始化索引 + redisVectorStore.afterPropertiesSet(); + return redisVectorStore; + } + + /** + * 参考 {@link MilvusVectorStoreAutoConfiguration} 的 vectorStore 方法 + */ + @SneakyThrows + private MilvusVectorStore buildMilvusVectorStore(EmbeddingModel embeddingModel) { + MilvusVectorStoreAutoConfiguration configuration = new MilvusVectorStoreAutoConfiguration(); + // 获取配置属性 + MilvusVectorStoreProperties serverProperties = SpringUtil.getBean(MilvusVectorStoreProperties.class); + MilvusServiceClientProperties clientProperties = SpringUtil.getBean(MilvusServiceClientProperties.class); + + // 创建 MilvusServiceClient 对象 + MilvusServiceClient milvusClient = configuration.milvusClient(serverProperties, clientProperties, + new MilvusServiceClientConnectionDetails() { + + @Override + public String getHost() { + return clientProperties.getHost(); + } + + @Override + public int getPort() { + return clientProperties.getPort(); + } + + } + ); + // 创建 MilvusVectorStore 对象 + MilvusVectorStore vectorStore = configuration.vectorStore(milvusClient, embeddingModel, serverProperties, + getBatchingStrategy(), getObservationRegistry(), getCustomObservationConvention()); + + // 初始化索引 + vectorStore.afterPropertiesSet(); + return vectorStore; + } + + private static ObjectProvider getObservationRegistry() { + return new ObjectProvider<>() { + + @Override + public ObservationRegistry getObject() throws BeansException { + return SpringUtil.getBean(ObservationRegistry.class); + } + + }; + } + + private static ObjectProvider getCustomObservationConvention() { + return new ObjectProvider<>() { + @Override + public VectorStoreObservationConvention getObject() throws BeansException { + return new DefaultVectorStoreObservationConvention(); + } + }; + } + + private static BatchingStrategy getBatchingStrategy() { + return SpringUtil.getBean(BatchingStrategy.class); + } + + private static ToolCallingManager getToolCallingManager() { + return SpringUtil.getBean(ToolCallingManager.class); + } + + private static FunctionCallbackResolver getFunctionCallbackResolver() { + return SpringUtil.getBean(FunctionCallbackResolver.class); + } + +} diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/baichuan/BaiChuanChatModel.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/baichuan/BaiChuanChatModel.java new file mode 100644 index 0000000..5fb71c9 --- /dev/null +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/baichuan/BaiChuanChatModel.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.ai.framework.ai.core.model.baichuan; + +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; + +/** + * 百川 {@link ChatModel} 实现类 + * + * @author 芋道源码 + */ +@Slf4j +@RequiredArgsConstructor +public class BaiChuanChatModel implements ChatModel { + + public static final String BASE_URL = "https://api.baichuan-ai.com"; + + public static final String MODEL_DEFAULT = "Baichuan4-Turbo"; + + /** + * 兼容 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/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/deepseek/DeepSeekChatModel.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/deepseek/DeepSeekChatModel.java new file mode 100644 index 0000000..d603abf --- /dev/null +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/deepseek/DeepSeekChatModel.java @@ -0,0 +1,45 @@ +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/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/doubao/DouBaoChatModel.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/doubao/DouBaoChatModel.java new file mode 100644 index 0000000..6e2bfda --- /dev/null +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/doubao/DouBaoChatModel.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.ai.framework.ai.core.model.doubao; + +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; + +/** + * 字节豆包 {@link ChatModel} 实现类 + * + * @author fansili + */ +@Slf4j +@RequiredArgsConstructor +public class DouBaoChatModel implements ChatModel { + + public static final String BASE_URL = "https://ark.cn-beijing.volces.com/api"; + + public static final String MODEL_DEFAULT = "doubao-1-5-lite-32k-250115"; + + /** + * 兼容 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/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/hunyuan/HunYuanChatModel.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/hunyuan/HunYuanChatModel.java new file mode 100644 index 0000000..debd0a4 --- /dev/null +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/hunyuan/HunYuanChatModel.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.ai.framework.ai.core.model.hunyuan; + +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; + +/** + * 腾云混元 {@link ChatModel} 实现类 + * + * 1. 混元大模型:基于 知识引擎原子能力 实现 + * 2. 知识引擎原子能力:基于 知识引擎原子能力 实现 + * + * @author fansili + */ +@Slf4j +@RequiredArgsConstructor +public class HunYuanChatModel implements ChatModel { + + public static final String BASE_URL = "https://api.hunyuan.cloud.tencent.com"; + + public static final String MODEL_DEFAULT = "hunyuan-turbo"; + + public static final String DEEP_SEEK_BASE_URL = "https://api.lkeap.cloud.tencent.com"; + + public static final String DEEP_SEEK_MODEL_DEFAULT = "deepseek-v3"; + + /** + * 兼容 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/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/midjourney/api/MidjourneyApi.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/midjourney/api/MidjourneyApi.java new file mode 100644 index 0000000..051ef31 --- /dev/null +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/midjourney/api/MidjourneyApi.java @@ -0,0 +1,351 @@ +package cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpRequest; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.MediaType; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * Midjourney API + * + * @author fansili + * @since 1.0 + */ +@Slf4j +public class MidjourneyApi { + + private final Predicate STATUS_PREDICATE = status -> !status.is2xxSuccessful(); + + private final Function>> EXCEPTION_FUNCTION = + reqParam -> response -> response.bodyToMono(String.class).handle((responseBody, sink) -> { + HttpRequest request = response.request(); + log.error("[midjourney-api] 调用失败!请求方式:[{}],请求地址:[{}],请求参数:[{}],响应数据: [{}]", + request.getMethod(), request.getURI(), reqParam, responseBody); + sink.error(new IllegalStateException("[midjourney-api] 调用失败!")); + }); + + private final WebClient webClient; + + /** + * 回调地址 + */ + private final String notifyUrl; + + public MidjourneyApi(String baseUrl, String apiKey, String notifyUrl) { + this.webClient = WebClient.builder() + .baseUrl(baseUrl) + .defaultHeaders(httpHeaders -> { + httpHeaders.setContentType(MediaType.APPLICATION_JSON); + httpHeaders.setBearerAuth(apiKey); + }) + .build(); + this.notifyUrl = notifyUrl; + } + + /** + * imagine - 根据提示词提交绘画任务 + * + * @param request 请求 + * @return 提交结果 + */ + public SubmitResponse imagine(ImagineRequest request) { + if (StrUtil.isEmpty(request.getNotifyHook())) { + request.setNotifyHook(notifyUrl); + } + String response = post("/submit/imagine", request); + return JsonUtils.parseObject(response, SubmitResponse.class); + } + + /** + * action - 放大、缩小、U1、U2... + * + * @param request 请求 + * @return 提交结果 + */ + public SubmitResponse action(ActionRequest request) { + if (StrUtil.isEmpty(request.getNotifyHook())) { + request.setNotifyHook(notifyUrl); + } + String response = post("/submit/action", request); + return JsonUtils.parseObject(response, SubmitResponse.class); + } + + /** + * 批量查询 task 任务 + * + * @param ids 任务编号数组 + * @return task 任务 + */ + public List getTaskList(Collection ids) { + String res = post("/task/list-by-condition", ImmutableMap.of("ids", ids)); + return JsonUtils.parseArray(res, Notify.class); + } + + private String post(String uri, Object body) { + return webClient.post() + .uri(uri) + .body(Mono.just(JsonUtils.toJsonString(body)), String.class) + .retrieve() + .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(body)) + .bodyToMono(String.class) + .block(); + } + + // ========== record 结构 ========== + + /** + * Imagine 请求(生成图片) + */ + @Data + public static final class ImagineRequest { + + /** + * 垫图(参考图) base64 数组 + */ + private List base64Array; + /** + * 提示词 + */ + private String prompt; + /** + * 通知地址 + */ + private String notifyHook; + /** + * 自定义参数 + */ + private String state; + + public ImagineRequest(List base64Array, String prompt, String notifyHook, String state) { + this.base64Array = base64Array; + this.prompt = prompt; + this.notifyHook = notifyHook; + this.state = state; + } + + public static String buildState(Integer width, Integer height, String version, String model) { + StringBuilder params = new StringBuilder(); + // --ar 来设置尺寸 + params.append(String.format(" --ar %s:%s ", width, height)); + // --niji 模型 + if (ModelEnum.NIJI.getModel().equals(model)) { + params.append(String.format(" --niji %s ", version)); + } else { + params.append(String.format(" --v %s ", version)); + } + return params.toString(); + } + + } + + /** + * Action 请求 + */ + @Data + public static final class ActionRequest { + + private String customId; + private String taskId; + private String notifyHook; + + public ActionRequest(String taskId, String customId, String notifyHook) { + this.customId = customId; + this.taskId = taskId; + this.notifyHook = notifyHook; + } + + } + + /** + * Submit 统一返回 + * + * @param code 状态码: 1(提交成功), 21(已存在), 22(排队中), other(错误) + * @param description 描述 + * @param properties 扩展字段 + * @param result 任务ID + */ + public record SubmitResponse(String code, + String description, + Map properties, + String result) { + } + + /** + * 通知 request + * + * @param id job id + * @param action 任务类型 {@link TaskActionEnum} + * @param status 任务状态 {@link TaskStatusEnum} + * @param prompt 提示词 + * @param promptEn 提示词-英文 + * @param description 任务描述 + * @param state 自定义参数 + * @param submitTime 提交时间 + * @param startTime 开始执行时间 + * @param finishTime 结束时间 + * @param imageUrl 图片url + * @param progress 任务进度 + * @param failReason 失败原因 + * @param buttons 任务完成后的可执行按钮 + */ + public record Notify(String id, + String action, + String status, + + String prompt, + String promptEn, + + String description, + String state, + + Long submitTime, + Long startTime, + Long finishTime, + + String imageUrl, + String progress, + String failReason, + List