add AiChatServiceTest
This commit is contained in:
@@ -131,7 +131,7 @@ CREATE INDEX ON vector_store_1024 USING HNSW (embedding vector_cosine_ops);
|
|||||||
|
|
||||||
pom.xml 中注释掉 `<artifactId>spring-ai-starter-model-openai</artifactId>`
|
pom.xml 中注释掉 `<artifactId>spring-ai-starter-model-openai</artifactId>`
|
||||||
打开注释 `<artifactId>spring-ai-starter-model-ollama</artifactId>`
|
打开注释 `<artifactId>spring-ai-starter-model-ollama</artifactId>`
|
||||||
启用 `Ollama` 本地模型进行测试,地址如下:
|
启用 `Ollama` 本地模型,测试类:`AiChatServiceTest.java`,或测试地址:
|
||||||
|
|
||||||
* 文本格式输出
|
* 文本格式输出
|
||||||
- 源码位置:CmsAiChatService.chatText(message)
|
- 源码位置:CmsAiChatService.chatText(message)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
package com.jeesite.modules.cms.ai.service;
|
package com.jeesite.modules.cms.ai.service;
|
||||||
|
|
||||||
import com.jeesite.common.cache.CacheUtils;
|
import com.jeesite.common.cache.CacheUtils;
|
||||||
|
import com.jeesite.common.collect.ListUtils;
|
||||||
import com.jeesite.common.collect.MapUtils;
|
import com.jeesite.common.collect.MapUtils;
|
||||||
import com.jeesite.common.idgen.IdGen;
|
import com.jeesite.common.idgen.IdGen;
|
||||||
import com.jeesite.common.lang.DateUtils;
|
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.ChatResponse;
|
||||||
import org.springframework.ai.chat.model.Generation;
|
import org.springframework.ai.chat.model.Generation;
|
||||||
import org.springframework.ai.chat.prompt.PromptTemplate;
|
import org.springframework.ai.chat.prompt.PromptTemplate;
|
||||||
|
import org.springframework.ai.content.Media;
|
||||||
import org.springframework.ai.converter.AbstractMessageOutputConverter;
|
import org.springframework.ai.converter.AbstractMessageOutputConverter;
|
||||||
import org.springframework.ai.converter.BeanOutputConverter;
|
import org.springframework.ai.converter.BeanOutputConverter;
|
||||||
import org.springframework.ai.converter.MapOutputConverter;
|
import org.springframework.ai.converter.MapOutputConverter;
|
||||||
@@ -126,8 +128,16 @@ public class CmsAiChatService extends BaseService {
|
|||||||
* @author ThinkGem
|
* @author ThinkGem
|
||||||
*/
|
*/
|
||||||
public Flux<ChatResponse> chatStream(String conversationId, String message, HttpServletRequest request) {
|
public Flux<ChatResponse> chatStream(String conversationId, String message, HttpServletRequest request) {
|
||||||
ChatClient.ChatClientRequestSpec spec = chatClient.prompt()
|
String text = StringUtils.replaceEach(message, USER_MESSAGE_SEARCH, USER_MESSAGE_REPLACE);
|
||||||
.messages(new UserMessage(StringUtils.replaceEach(message, USER_MESSAGE_SEARCH, USER_MESSAGE_REPLACE)))
|
List<Media> media = ListUtils.newArrayList();
|
||||||
|
// List<FileUpload> 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)
|
.advisors(MessageChatMemoryAdvisor.builder(chatMemory)
|
||||||
.conversationId(conversationId)
|
.conversationId(conversationId)
|
||||||
.build());
|
.build());
|
||||||
@@ -197,7 +207,7 @@ public class CmsAiChatService extends BaseService {
|
|||||||
return chatClient.prompt()
|
return chatClient.prompt()
|
||||||
.messages(
|
.messages(
|
||||||
new SystemMessage("""
|
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))
|
new UserMessage(StringUtils.replaceEach(message, USER_MESSAGE_SEARCH, USER_MESSAGE_REPLACE))
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -96,9 +96,10 @@ public class CmsAiChatController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 聊天对话,结构化输出
|
* 聊天对话,结构化输出 JSON
|
||||||
* @author ThinkGem
|
* @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=张三
|
||||||
|
* http://127.0.0.1:8980/js/a/cms/chat/json?message=打开客厅的灯
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value = "/json")
|
@RequestMapping(value = "/json")
|
||||||
public Map<String, Object> json(@RequestParam String message) {
|
public Map<String, Object> json(@RequestParam String message) {
|
||||||
@@ -106,7 +107,7 @@ public class CmsAiChatController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 聊天对话,结构化输出
|
* 聊天对话,结构化输出 Entity
|
||||||
* @author ThinkGem
|
* @author ThinkGem
|
||||||
* http://127.0.0.1:8980/js/a/cms/chat/entity?message=北京
|
* http://127.0.0.1:8980/js/a/cms/chat/entity?message=北京
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -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<String, Object> map = cmsAiChatService.chatJson(message);
|
||||||
|
System.out.println(JsonMapper.toJson(map));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test03Tool() {
|
||||||
|
logger.info("===== 聊天对话,结构化输出 Tool Calling");
|
||||||
|
String message = "打开客厅的灯";
|
||||||
|
Map<String, Object> 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<Area> list = cmsAiChatService.chatArea(message);
|
||||||
|
System.out.println(JsonMapper.toJson(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
28
modules/cms-ai/src/test/resources/application.yml
Normal file
28
modules/cms-ai/src/test/resources/application.yml
Normal file
@@ -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
|
||||||
20
modules/cms-ai/src/test/resources/logback-test.xml
Normal file
20
modules/cms-ai/src/test/resources/logback-test.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration debug="false" scan="false">
|
||||||
|
|
||||||
|
<!-- Logger level setting -->
|
||||||
|
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
|
||||||
|
<include resource="config/logger-core.xml"/>
|
||||||
|
|
||||||
|
<!-- Console log output -->
|
||||||
|
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{HH:mm:ss.SSS} %clr(%-5p) %clr([%-39logger{39}]){cyan} - %m%n%wEx</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- Level: FATAL 0 ERROR 3 WARN 4 INFO 6 DEBUG 7 -->
|
||||||
|
<root level="WARN">
|
||||||
|
<appender-ref ref="console" />
|
||||||
|
</root>
|
||||||
|
|
||||||
|
</configuration>
|
||||||
Reference in New Issue
Block a user