diff --git a/modules/cms-ai/README.md b/modules/cms-ai/README.md
index aaa83974..0497bed8 100644
--- a/modules/cms-ai/README.md
+++ b/modules/cms-ai/README.md
@@ -131,7 +131,7 @@ CREATE INDEX ON vector_store_1024 USING HNSW (embedding vector_cosine_ops);
pom.xml 中注释掉 `spring-ai-starter-model-openai`
打开注释 `spring-ai-starter-model-ollama`
-启用 `Ollama` 本地模型进行测试,地址如下:
+启用 `Ollama` 本地模型,测试类:`AiChatServiceTest.java`,或测试地址:
* 文本格式输出
- 源码位置:CmsAiChatService.chatText(message)
diff --git a/modules/cms-ai/src/main/java/com/jeesite/modules/cms/ai/service/CmsAiChatService.java b/modules/cms-ai/src/main/java/com/jeesite/modules/cms/ai/service/CmsAiChatService.java
index 5ef37653..a60b63ea 100644
--- a/modules/cms-ai/src/main/java/com/jeesite/modules/cms/ai/service/CmsAiChatService.java
+++ b/modules/cms-ai/src/main/java/com/jeesite/modules/cms/ai/service/CmsAiChatService.java
@@ -5,6 +5,7 @@
package com.jeesite.modules.cms.ai.service;
import com.jeesite.common.cache.CacheUtils;
+import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.collect.MapUtils;
import com.jeesite.common.idgen.IdGen;
import com.jeesite.common.lang.DateUtils;
@@ -27,6 +28,7 @@ import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.model.Generation;
import org.springframework.ai.chat.prompt.PromptTemplate;
+import org.springframework.ai.content.Media;
import org.springframework.ai.converter.AbstractMessageOutputConverter;
import org.springframework.ai.converter.BeanOutputConverter;
import org.springframework.ai.converter.MapOutputConverter;
@@ -126,8 +128,16 @@ public class CmsAiChatService extends BaseService {
* @author ThinkGem
*/
public Flux chatStream(String conversationId, String message, HttpServletRequest request) {
- ChatClient.ChatClientRequestSpec spec = chatClient.prompt()
- .messages(new UserMessage(StringUtils.replaceEach(message, USER_MESSAGE_SEARCH, USER_MESSAGE_REPLACE)))
+ String text = StringUtils.replaceEach(message, USER_MESSAGE_SEARCH, USER_MESSAGE_REPLACE);
+ List media = ListUtils.newArrayList();
+// List fileUploadList = FileUploadUtils.findFileUpload(conversationId, "cms-chat");
+// for (FileUpload fileUpload : fileUploadList) {
+// File file = new File(fileUpload.getFileEntity().getFileRealPath());
+// MediaType mediaType = MediaType.parseMediaType(FileUtils.getContentType(file.getName()));
+// media.add(Media.builder().mimeType(mediaType).data(file).build());
+// }
+ UserMessage userMessage = UserMessage.builder().text(text).media(media).build();
+ ChatClient.ChatClientRequestSpec spec = chatClient.prompt().messages(userMessage)
.advisors(MessageChatMemoryAdvisor.builder(chatMemory)
.conversationId(conversationId)
.build());
@@ -197,7 +207,7 @@ public class CmsAiChatService extends BaseService {
return chatClient.prompt()
.messages(
new SystemMessage("""
- [ {name:'张三', sex:'男', age:'17'}, {name:'李四', sex:'女', age:'18'} ],返回 json。
+ [{name:'张三', sex:'男', age:'17'}, {name:'李四', sex:'女', age:'18'}],返回 json。
"""),
new UserMessage(StringUtils.replaceEach(message, USER_MESSAGE_SEARCH, USER_MESSAGE_REPLACE))
)
diff --git a/modules/cms-ai/src/main/java/com/jeesite/modules/cms/ai/web/CmsAiChatController.java b/modules/cms-ai/src/main/java/com/jeesite/modules/cms/ai/web/CmsAiChatController.java
index 9ddac068..0cdd1f5b 100644
--- a/modules/cms-ai/src/main/java/com/jeesite/modules/cms/ai/web/CmsAiChatController.java
+++ b/modules/cms-ai/src/main/java/com/jeesite/modules/cms/ai/web/CmsAiChatController.java
@@ -96,9 +96,10 @@ public class CmsAiChatController extends BaseController {
}
/**
- * 聊天对话,结构化输出
+ * 聊天对话,结构化输出 JSON
* @author ThinkGem
* http://127.0.0.1:8980/js/a/cms/chat/json?message=张三
+ * http://127.0.0.1:8980/js/a/cms/chat/json?message=打开客厅的灯
*/
@RequestMapping(value = "/json")
public Map json(@RequestParam String message) {
@@ -106,7 +107,7 @@ public class CmsAiChatController extends BaseController {
}
/**
- * 聊天对话,结构化输出
+ * 聊天对话,结构化输出 Entity
* @author ThinkGem
* http://127.0.0.1:8980/js/a/cms/chat/entity?message=北京
*/
diff --git a/modules/cms-ai/src/test/java/com/jeesite/test/AiChatServiceTest.java b/modules/cms-ai/src/test/java/com/jeesite/test/AiChatServiceTest.java
new file mode 100644
index 00000000..b088eced
--- /dev/null
+++ b/modules/cms-ai/src/test/java/com/jeesite/test/AiChatServiceTest.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2013-Now http://jeesite.com All rights reserved.
+ * No deletion without permission, or be held responsible to law.
+ */
+package com.jeesite.test;
+
+import com.jeesite.common.mapper.JsonMapper;
+import com.jeesite.common.tests.BaseSpringContextTests;
+import com.jeesite.modules.cms.ai.service.CmsAiChatService;
+import com.jeesite.modules.sys.entity.Area;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * AI 对话单元测试
+ * @author ThinkGem
+ * @version 2025-06-06
+ */
+@ActiveProfiles("test")
+@SpringBootApplication
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@SpringBootTest(properties = {"spring.ai.tool-calls=true"})
+public class AiChatServiceTest extends BaseSpringContextTests {
+
+ @Autowired
+ private CmsAiChatService cmsAiChatService;
+
+ @Test
+ public void test01Text() {
+ logger.info("===== 聊天对话,文本输出");
+ String message = "你好";
+ String text = cmsAiChatService.chatText(message);
+ System.out.println(text);
+ }
+
+ @Test
+ public void test02Json() {
+ logger.info("===== 聊天对话,结构化输出 JSON");
+ String message = "张三";
+ Map map = cmsAiChatService.chatJson(message);
+ System.out.println(JsonMapper.toJson(map));
+ }
+
+ @Test
+ public void test03Tool() {
+ logger.info("===== 聊天对话,结构化输出 Tool Calling");
+ String message = "打开客厅的灯";
+ Map map = cmsAiChatService.chatJson(message);
+ System.out.println(JsonMapper.toJson(map));
+ message = "关闭客厅的灯";
+ map = cmsAiChatService.chatJson(message);
+ System.out.println(JsonMapper.toJson(map));
+ }
+
+ @Test
+ public void test04Entity() {
+ logger.info("===== 聊天对话,结构化输出 Entity");
+ String message = "北京";
+ List list = cmsAiChatService.chatArea(message);
+ System.out.println(JsonMapper.toJson(list));
+ }
+
+
+}
diff --git a/modules/cms-ai/src/test/resources/application.yml b/modules/cms-ai/src/test/resources/application.yml
new file mode 100644
index 00000000..f03254a3
--- /dev/null
+++ b/modules/cms-ai/src/test/resources/application.yml
@@ -0,0 +1,28 @@
+
+# 产品或项目名称、软件开发公司名称
+productName: JeeSite Demo
+companyName: ThinkGem
+
+# 产品版本、版权年份
+productVersion: V5.12
+copyrightYear: 2025
+
+
+# 数据库连接
+jdbc:
+
+ # Mysql 数据库配置
+ type: mysql
+ driver: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://127.0.0.1:3306/jeesite_v5?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai
+ username: root
+ password: 123456
+ testSql: SELECT 1
+
+# 日志配置
+logging:
+ config: classpath:logback-test.xml
+
+# 消息推送
+msg:
+ enabled: true
diff --git a/modules/cms-ai/src/test/resources/logback-test.xml b/modules/cms-ai/src/test/resources/logback-test.xml
new file mode 100644
index 00000000..a9a15b7f
--- /dev/null
+++ b/modules/cms-ai/src/test/resources/logback-test.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+ %d{HH:mm:ss.SSS} %clr(%-5p) %clr([%-39logger{39}]){cyan} - %m%n%wEx
+
+
+
+
+
+
+
+
+
\ No newline at end of file