Commit b48aa988 authored by youxiaoji's avatar youxiaoji

* [增加差旅助手智能体]

parent 53570949
package pangea.hiagent.controller;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
......@@ -29,22 +30,22 @@ import java.util.concurrent.Executors;
@RestController
@RequestMapping("/api/v1/agent")
public class AgentChatController {
@Autowired
private AgentService agentService;
@Autowired
private AgentChatService agentChatService;
@Autowired
private SseEventManager sseEventManager;
private final ExecutorService executorService = Executors.newFixedThreadPool(10);
/**
* 流式对话接口
* 支持 SSE (Server-Sent Events) 格式的流式输出
*
*
* @param agentId Agent ID
* @param chatRequest 对话请求
* @return SSE emitter
......@@ -55,13 +56,13 @@ public class AgentChatController {
@RequestParam String agentId,
@RequestBody ChatRequest chatRequest,
HttpServletResponse response) {
// 将ChatRequest转换为AgentRequest
AgentRequest request = new AgentRequest();
request.setUserMessage(chatRequest.getMessage());
log.info("开始处理流式对话请求,AgentId: {}, 用户消息: {}", agentId, request.getUserMessage());
// 检查用户消息是否为空
if (request.getUserMessage() == null || request.getUserMessage().trim().isEmpty()) {
log.error("用户消息不能为空");
......@@ -70,7 +71,7 @@ public class AgentChatController {
log.warn("响应已经提交,无法发送用户消息为空错误");
return new SseEmitter(300000L); // 返回一个空的emitter
}
SseEmitter emitter = new SseEmitter(300000L);
try {
emitter.send(SseEmitter.event()
......@@ -84,7 +85,6 @@ public class AgentChatController {
}
return emitter;
}
String userId = getCurrentUserId();
if (userId == null) {
log.error("用户未认证");
......
......@@ -587,7 +587,7 @@ public class AgentChatService {
// 这里只需要等待足够的时间让异步的onComplete回调执行完成
try {
// 通过轮询检查是否已完成,最多等待5秒
long maxWaitTime = 5000;
long maxWaitTime = 10*60*1000;
long startTime = System.currentTimeMillis();
while (!isCompleted.get() && (System.currentTimeMillis() - startTime) < maxWaitTime) {
Thread.sleep(100); // 每100ms检查一次
......
......@@ -8,6 +8,9 @@ import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.context.annotation.Lazy;
import pangea.hiagent.service.AgentService;
import pangea.hiagent.service.InfoCollectorService;
import pangea.hiagent.tools.HisenseTripTool;
import pangea.hiagent.workpanel.IWorkPanelDataCollector;
import pangea.hiagent.core.AgentChatService;
import pangea.hiagent.memory.MemoryService;
......@@ -40,6 +43,12 @@ public class DefaultReactExecutor implements ReactExecutor {
@Autowired
private MemoryService memoryService;
@Autowired
private AgentService agentService;
@Autowired
private InfoCollectorService infoCollectorService;
/**
* 添加ReAct回调
......@@ -213,10 +222,12 @@ public class DefaultReactExecutor implements ReactExecutor {
// 构建Prompt,包含历史对话记录
Prompt prompt = buildPromptWithHistory(systemPrompt, userInput, agent);
HisenseTripTool tripTool = new HisenseTripTool(agentService,infoCollectorService);
tripTool.initialize();
// 订阅流式响应
chatClient.prompt(prompt)
.tools(tools.toArray())
.tools(tripTool)
.stream()
.chatResponse()
.subscribe(
......
package pangea.hiagent.service;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import pangea.hiagent.tools.HisenseTripTool;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@Service
@Slf4j
public class InfoCollectorService {
private static final ConcurrentHashMap<String, JSONArray> infos = new ConcurrentHashMap<>(16);
private static final ConcurrentHashMap<String, Object> values = new ConcurrentHashMap<>(16);
public void register(String pageId, JSONArray info) {
infos.put(pageId, info);
}
public boolean exists(String pageId) {
return infos.containsKey(pageId);
}
public JSONArray getInfo(String pageId) {
return infos.get(pageId);
}
public void saveValue(String key, Object value) {
log.info("key {} value {}",key,value);
values.put(key, value);
}
public Object getValue(String key) {
return values.get(key);
}
public Set<String> findLackInfo() {
Set<String> valueKeys = values.keySet();
Set<String> allKeys = infos.get(HisenseTripTool.pageId).stream().map(t -> ((JSONObject) t).getString("field_name")).collect(Collectors.toSet());
allKeys.removeAll(valueKeys);
log.info("lack keys {}", allKeys);
return allKeys;
}
}
package pangea.hiagent.utils;
public class Contants {
public static final String LOCATOR_SCHEMA = "{\n" +
" \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n" +
" \"type\": \"array\",\n" +
" \"items\": {\n" +
" \"type\": \"object\",\n" +
" \"properties\": {\n" +
" \"field_name\": {\n" +
" \"type\": \"string\"\n" +
" },\n" +
" \"locator\": {\n" +
" \"type\": \"string\"\n" +
" },\n" +
" \"attributes\": {\n" +
" \"type\": \"object\",\n" +
" \"properties\": {\n" +
" \"type\": {\n" +
" \"type\": \"string\"\n" +
" },\n" +
" \"maxlength\": {\n" +
" \"type\": \"string\"\n" +
" },\n" +
" \"class\": {\n" +
" \"type\": \"string\"\n" +
" },\n" +
" \"name\": {\n" +
" \"type\": \"string\"\n" +
" },\n" +
" \"value\": {\n" +
" \"type\": \"string\"\n" +
" },\n" +
" \"autocomplete\": {\n" +
" \"type\": \"string\"\n" +
" },\n" +
" \"placeholder\": {\n" +
" \"type\": \"string\"\n" +
" },\n" +
" \"readonly\": {\n" +
" \"type\": \"string\"\n" +
" },\n" +
" \"id\": {\n" +
" \"type\": \"string\"\n" +
" },\n" +
" \"droptreeids\": {\n" +
" \"type\": \"string\"\n" +
" },\n" +
" \"vetitle\": {\n" +
" \"type\": \"string\"\n" +
" },\n" +
" \"contenteditable\": {\n" +
" \"type\": \"string\"\n" +
" },\n" +
" \"style\": {\n" +
" \"type\": \"string\"\n" +
" },\n" +
" \"tipstext\": {\n" +
" \"type\": \"string\"\n" +
" },\n" +
" \"fylx\": {\n" +
" \"type\": \"string\"\n" +
" }\n" +
" },\n" +
" \"additionalProperties\": false,\n" +
" \"required\": [\n" +
" \"class\",\n" +
" \"value\"\n" +
" ]\n" +
" }\n" +
" },\n" +
" \"additionalProperties\": false,\n" +
" \"required\": [\n" +
" \"field_name\",\n" +
" \"locator\",\n" +
" \"attributes\"\n" +
" ]\n" +
" }\n" +
"}";
}
......@@ -4,7 +4,7 @@ spring:
# 数据源配置
datasource:
url: jdbc:mysql://${DB_HOST:192.168.219.129}:3306/hiagent?allowMultiQueries=true&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai
url: jdbc:mysql://${DB_HOST:127.0.0.1}:3306/hiagent?allowMultiQueries=true&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai
driver-class-name: ${DB_DRIVER:com.mysql.cj.jdbc.Driver}
username: ${DB_NAME:root}
password: ${DB_PASSWORD:123456Aa?}
......@@ -195,7 +195,7 @@ hiagent:
llm:
providers:
deepseek:
default-api-key: ${DEEPSEEK_API_KEY:}
default-api-key: ${DEEPSEEK_API_KEY:sk-e8ef4359d20b413696512db21c09db87}
default-model: deepseek-chat
base-url: https://api.deepseek.com
openai:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment