Commit b1367155 authored by ligaowei's avatar ligaowei

Merge branch 'develop_yxj' into 'main'

+ [增加差旅助手工具]

See merge request !2
parents 9a664ed4 5fae7eda
......@@ -8,6 +8,11 @@ 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.agent.sse.UserSseService;
import pangea.hiagent.tool.impl.HisenseTripTool;
import pangea.hiagent.tool.impl.VisitorAppointmentTool;
import pangea.hiagent.web.service.AgentService;
import pangea.hiagent.web.service.InfoCollectorService;
import pangea.hiagent.workpanel.IWorkPanelDataCollector;
import pangea.hiagent.agent.service.ErrorHandlerService;
import pangea.hiagent.agent.service.TokenConsumerWithCompletion;
......@@ -62,7 +67,14 @@ public class DefaultReactExecutor implements ReactExecutor {
@Autowired
private ErrorHandlerService errorHandlerService;
@Autowired
private InfoCollectorService infoCollectorService;
@Autowired
private AgentService agentService;
private final AgentToolManager agentToolManager;
@Autowired
private UserSseService userSseService;
public DefaultReactExecutor(AgentToolManager agentToolManager) {
this.agentToolManager = agentToolManager;
......@@ -179,7 +191,7 @@ public class DefaultReactExecutor implements ReactExecutor {
memoryService.getHistoryMessages(sessionId, historyLength);
// 添加历史消息到Prompt
messages.addAll(historyMessages);
// messages.addAll(historyMessages);
// 将当前用户消息添加到内存中,以便下次对话使用
memoryService.addUserMessageToMemory(sessionId, userInput);
......@@ -234,10 +246,11 @@ public class DefaultReactExecutor implements ReactExecutor {
// 构建Prompt,包含历史对话记录
Prompt prompt = buildPromptWithHistory(DEFAULT_SYSTEM_PROMPT, userInput, agent);
VisitorAppointmentTool hisenseTripTool = new VisitorAppointmentTool(agentService,infoCollectorService,userSseService);
hisenseTripTool.initialize();
// 订阅流式响应
chatClient.prompt(prompt)
.tools(agentTools.toArray())
.tools(hisenseTripTool)
.stream()
.chatResponse()
.subscribe(
......
......@@ -121,6 +121,7 @@ public class AgentChatService {
// 创建 SSE emitter
SseEmitter emitter = workPanelSseService.createEmitter();
workPanelSseService.registerEmitter("worker1", emitter);
// 将userId设为final以在Lambda表达式中使用
final String finalUserId = userId;
......
......@@ -552,4 +552,12 @@ public class UserSseService {
Thread.currentThread().interrupt();
}
}
public void registerEmitter(String id,SseEmitter emitter) {
this.userEmitters.put(id, emitter);
}
public SseEmitter getEmitter(String id) {
return userEmitters.get(id);
}
}
\ No newline at end of file
package pangea.hiagent.common.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" +
" \"label_tag\": {\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" +
"}";
}
package pangea.hiagent.common.utils;
import java.security.SecureRandom;
import java.util.concurrent.atomic.AtomicLong;
public class HybridUniqueLongGenerator {
private static final SecureRandom random = new SecureRandom();
private static final AtomicLong counter = new AtomicLong(0);
public static long generateUnique13DigitNumber() {
long timestamp = System.currentTimeMillis();
long count = counter.incrementAndGet();
// 使用时间戳的前10位 + 计数器的后3位
long timestampPart = (timestamp / 1000) * 1000;
long counterPart = count % 1000;
return timestampPart + counterPart;
}
// 更随机的版本,但仍保证唯一
public static synchronized long generateRandomUnique() {
long timestamp = System.currentTimeMillis();
// 在时间戳基础上加上一个小的随机偏移
int randomOffset = random.nextInt(100);
long result = timestamp * 100 + randomOffset;
// 确保是13位
while (result >= 10000000000000L) {
result /= 10;
}
while (result < 1000000000000L) {
result *= 10;
result += random.nextInt(10);
}
return result;
}
}
\ No newline at end of file
package pangea.hiagent.common.utils;
import java.security.SecureRandom;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.atomic.AtomicLong;
public class InputCodeGenerator {
private static final String CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
private static final SecureRandom random = new SecureRandom();
private static final AtomicLong sequence = new AtomicLong(0);
public static String generateUniqueInputCode(String prefix) {
// 当前时间戳(毫秒)
long timestamp = System.currentTimeMillis();
// 序列号
long seq = sequence.incrementAndGet();
// 组合时间戳和序列号
long combined = (timestamp << 10) | (seq & 0x3FF); // 取序列号后10位
// 转为36进制
String code = Long.toString(Math.abs(combined), 36).toUpperCase();
// 确保8位长度
if (code.length() > 8) {
code = code.substring(code.length() - 8);
} else if (code.length() < 8) {
// 前面补随机字符
StringBuilder sb = new StringBuilder();
for (int i = code.length(); i < 8; i++) {
sb.append(CHARS.charAt(random.nextInt(CHARS.length())));
}
code = sb.toString() + code;
}
return prefix + code;
}
}
package pangea.hiagent.web.service;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import pangea.hiagent.tool.impl.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;
}
}
spring:
application:
name: hiagent
# 数据源配置
datasource:
url: jdbc:mysql://${DB_HOST:127.0.0.1}:3306/hiagent2?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?}
hikari:
maximum-pool-size: 10
minimum-idle: 2
connection-timeout: 30000
# 禁用Milvus自动配置
autoconfigure:
exclude:
- org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusVectorStoreAutoConfiguration
# SQL初始化配置
sql:
init:
schema-locations: classpath:schema.sql
mode: never
# mode: always
# JPA/Hibernate配置
jpa:
database-platform: org.hibernate.dialect.MySQL8Dialect
# hibernate:
# ddl-auto: create-drop
show-sql: false
properties:
hibernate:
format_sql: true
# H2 Console配置(仅开发环境)
# h2:
# console:
# enabled: true
# path: /h2-console
# Redis配置
data:
redis:
host: localhost
port: 6379
password:
timeout: 2000
database: 0
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
max-wait: -1
# RabbitMQ配置
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
connection-timeout: 15000
# Jackson配置
jackson:
serialization:
write-dates-as-timestamps: false
deserialization:
fail-on-unknown-properties: false
default-property-inclusion: non_null
# Web配置
web:
resources:
add-mappings: true
# servlet配置
servlet:
multipart:
max-file-size: 100MB
max-request-size: 100MB
# 默认性异步请求配置
mvc:
async:
request-timeout: 300000 # 5分钟,与SSE保持一致
# Spring AI配置
ai:
openai:
enabled: false
ollama:
enabled: false
# MyBatis Plus配置
mybatis-plus:
type-aliases-package: pangea.hiagent.model
mapper-locations: classpath:mapper/*.xml
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
cache-enabled: true
use-generated-keys: true
global-config:
db-config:
id-type: assign_uuid
table-underline: true
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
# Logging配置
logging:
level:
root: INFO
pangea.hiagent: DEBUG
org.springframework: INFO
org.springframework.security: DEBUG
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
file:
name: logs/hiagent.log
max-size: 10MB
max-history: 30
charset:
console: UTF-8
file: UTF-8
# Server配置
server:
port: 8080
servlet:
context-path: /
compression:
enabled: true
min-response-size: 1024
# SSE和异步请求超时配置
request-timeout: 300000 # 5分钟(毫秒)
# Undertow配置
undertow:
# IO线程数,默认为处理器数量
io-threads: 4
# 工作线程数
worker-threads: 50
# 缓冲区配置
buffer-size: 65536
# 是否直接分配缓冲区
direct-buffers: true
# HTTP/2支持
enable-http2: true
# 最大HTTP头大小
max-http-header-size: 8192
# 最大参数数量
max-parameters: 1000
# 最大请求头数量
max-headers: 200
# 最大cookies数量
max-cookies: 100
# URL编码字符集
url-charset: UTF-8
# 访问日志配置
accesslog:
enabled: false
pattern: common
dir: logs
prefix: access_log.
# SSL配置
ssl:
# SSL引擎
engine:
# 密码套件
enabled-protocols: TLSv1.2,TLSv1.3
# WebSocket配置
websocket:
# WebSocket消息缓冲区大小
buffer-size: 1048576
# 最大WebSocket帧大小
max-frame-size: 10485760
# 应用自定义配置
hiagent:
# JWT配置
jwt:
secret: ${JWT_SECRET:hiagent-secret-key-for-production-change-this}
expiration: 7200000 # 2小时
refresh-expiration: 604800000 # 7天
# Agent配置
agent:
default-model: deepseek-chat
default-temperature: 0.7
default-max-tokens: 4096
history-length: 10
# LLM配置
llm:
providers:
deepseek:
default-api-key: ${DEEPSEEK_API_KEY:sk-e8ef4359d20b413696512db21c09db87}
default-model: deepseek-chat
base-url: https://api.deepseek.com
openai:
default-api-key: ${OPENAI_API_KEY:}
default-model: gpt-3.5-turbo
base-url: https://api.openai.com/v1
ollama:
default-model: llama2
base-url: http://localhost:11434
# RAG配置
rag:
chunk-size: 512
chunk-overlap: 50
top-k: 5
score-threshold: 0.8
# Milvus Lite配置
milvus:
data-dir: ./milvus_data
db-name: hiagent
collection-name: document_embeddings
# ChatMemory配置
app:
chat-memory:
# 实现类型: caffeine, redis, hybrid
implementation: caffeine
caffeine:
# 是否启用Caffeine缓存
enabled: true
redis:
# 是否启用Redis缓存
enabled: false
\ No newline at end of file
......@@ -4,7 +4,7 @@ spring:
# 配置文件激活
profiles:
active: dev
active: test
# 启用懒加载初始化
main:
......
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