Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Pangea-Agent
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Gavin-Group
Pangea-Agent
Commits
90b3874a
Commit
90b3874a
authored
Dec 24, 2025
by
ligaowei
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'revert-
b1367155
' into 'main'
Revert "Merge branch 'develop_yxj' into 'main'" See merge request
!5
parents
b1367155
efec36bd
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
6 additions
and
1141 deletions
+6
-1141
DefaultReactExecutor.java
...java/pangea/hiagent/agent/react/DefaultReactExecutor.java
+4
-17
AgentChatService.java
...n/java/pangea/hiagent/agent/service/AgentChatService.java
+1
-2
UserSseService.java
...rc/main/java/pangea/hiagent/agent/sse/UserSseService.java
+0
-8
Contants.java
...d/src/main/java/pangea/hiagent/common/utils/Contants.java
+0
-86
HybridUniqueLongGenerator.java
...angea/hiagent/common/utils/HybridUniqueLongGenerator.java
+0
-40
InputCodeGenerator.java
.../java/pangea/hiagent/common/utils/InputCodeGenerator.java
+0
-39
HisenseTripTool.java
...c/main/java/pangea/hiagent/tool/impl/HisenseTripTool.java
+0
-374
VisitorAppointmentTool.java
...java/pangea/hiagent/tool/impl/VisitorAppointmentTool.java
+0
-288
InfoCollectorService.java
...java/pangea/hiagent/web/service/InfoCollectorService.java
+0
-47
application-test.yml
backend/src/main/resources/application-test.yml
+0
-239
application.yml
backend/src/main/resources/application.yml
+1
-1
No files found.
backend/src/main/java/pangea/hiagent/agent/react/DefaultReactExecutor.java
View file @
90b3874a
...
...
@@ -8,11 +8,6 @@ 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
;
...
...
@@ -66,16 +61,9 @@ 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
;
}
...
...
@@ -191,7 +179,7 @@ public class DefaultReactExecutor implements ReactExecutor {
memoryService
.
getHistoryMessages
(
sessionId
,
historyLength
);
// 添加历史消息到Prompt
//
messages.addAll(historyMessages);
messages
.
addAll
(
historyMessages
);
// 将当前用户消息添加到内存中,以便下次对话使用
memoryService
.
addUserMessageToMemory
(
sessionId
,
userInput
);
...
...
@@ -246,11 +234,10 @@ 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
(
hisenseTripTool
)
.
tools
(
agentTools
.
toArray
()
)
.
stream
()
.
chatResponse
()
.
subscribe
(
...
...
backend/src/main/java/pangea/hiagent/agent/service/AgentChatService.java
View file @
90b3874a
...
...
@@ -121,8 +121,7 @@ public class AgentChatService {
// 创建 SSE emitter
SseEmitter
emitter
=
workPanelSseService
.
createEmitter
();
workPanelSseService
.
registerEmitter
(
"worker1"
,
emitter
);
// 将userId设为final以在Lambda表达式中使用
final
String
finalUserId
=
userId
;
...
...
backend/src/main/java/pangea/hiagent/agent/sse/UserSseService.java
View file @
90b3874a
...
...
@@ -552,12 +552,4 @@ 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
backend/src/main/java/pangea/hiagent/common/utils/Contants.java
deleted
100644 → 0
View file @
b1367155
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"
+
"}"
;
}
backend/src/main/java/pangea/hiagent/common/utils/HybridUniqueLongGenerator.java
deleted
100644 → 0
View file @
b1367155
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
backend/src/main/java/pangea/hiagent/common/utils/InputCodeGenerator.java
deleted
100644 → 0
View file @
b1367155
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
;
}
}
backend/src/main/java/pangea/hiagent/tool/impl/HisenseTripTool.java
deleted
100644 → 0
View file @
b1367155
package
pangea
.
hiagent
.
tool
.
impl
;
import
com.alibaba.fastjson2.JSONArray
;
import
com.alibaba.fastjson2.JSONObject
;
import
com.microsoft.playwright.*
;
import
com.microsoft.playwright.options.Cookie
;
import
com.microsoft.playwright.options.WaitForSelectorState
;
import
com.microsoft.playwright.options.WaitUntilState
;
import
jakarta.annotation.PostConstruct
;
import
jakarta.annotation.PreDestroy
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.ai.chat.client.ChatClient
;
import
org.springframework.ai.tool.annotation.Tool
;
import
org.springframework.ai.tool.annotation.ToolParam
;
import
org.springframework.stereotype.Component
;
import
pangea.hiagent.common.utils.Contants
;
import
pangea.hiagent.model.Agent
;
import
pangea.hiagent.web.service.AgentService
;
import
pangea.hiagent.web.service.InfoCollectorService
;
import
java.io.IOException
;
import
java.net.MalformedURLException
;
import
java.nio.file.Files
;
import
java.nio.file.Paths
;
import
java.time.LocalDateTime
;
import
java.time.format.DateTimeFormatter
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Set
;
@Slf4j
@Component
public
class
HisenseTripTool
{
public
static
final
String
pageId
=
"tripApply"
;
// SSO用户名(从配置文件读取)
private
String
ssoToken
;
// SSO密码(从配置文件读取)
private
String
ldapToken
;
private
String
tripToken
;
// Playwright实例
private
Playwright
playwright
;
// 浏览器实例
private
Browser
browser
;
// 共享的浏览器上下文,用于保持登录状态
private
BrowserContext
sharedContext
;
// 上次登录时间
private
long
lastLoginTime
=
0
;
private
AgentService
agentService
;
private
InfoCollectorService
infoCollectorService
;
// 登录状态有效期(毫秒),设置为30分钟
private
static
final
long
LOGIN_VALIDITY_PERIOD
=
30
*
60
*
1000
;
public
HisenseTripTool
(
AgentService
agentService
,
InfoCollectorService
infoCollectorService
)
{
this
.
agentService
=
agentService
;
this
.
infoCollectorService
=
infoCollectorService
;
this
.
ssoToken
=
"d10bc61aa4e00dcc6f08de64ca42012814fdbcee9b88aa977f7fb07d3a4018f4"
;
this
.
ldapToken
=
"AAECAzY5NDRBNTQ1Njk0NTRFMDV5b3V4aWFvamlaLv+jUGNEEORN24GLIC3OlqcCdw=="
;
this
.
tripToken
=
"c88c2f09a20140e190357ebb68f27e35"
;
}
@PostConstruct
public
void
initialize
()
{
try
{
if
(
StringUtils
.
isEmpty
(
tripToken
)){
}
log
.
info
(
"正在初始化海信SSO认证工具的Playwright..."
);
this
.
playwright
=
Playwright
.
create
();
// 使用chromium浏览器,无头模式(headless=true),适合服务器运行
// 可根据需要修改为有头模式(headless=false)用于调试
this
.
browser
=
playwright
.
chromium
().
launch
(
new
BrowserType
.
LaunchOptions
().
setHeadless
(
true
));
// 初始化共享上下文
this
.
sharedContext
=
browser
.
newContext
();
// 检查是否已有有效的登录会话
Cookie
ssoTokenCookie
=
new
Cookie
(
"ssoLoginToken"
,
ssoToken
);
ssoTokenCookie
.
setDomain
(
".hisense.com"
);
ssoTokenCookie
.
setPath
(
"/"
);
Cookie
ldapTokenCookie
=
new
Cookie
(
"LtpaToken"
,
ldapToken
);
ldapTokenCookie
.
setDomain
(
".hisense.com"
);
ldapTokenCookie
.
setPath
(
"/"
);
Cookie
tripCookie
=
new
Cookie
(
"FCC_SESSION"
,
tripToken
);
tripCookie
.
setDomain
(
"trip.hisense.com"
);
tripCookie
.
setPath
(
"/"
);
List
<
Cookie
>
cookies
=
new
ArrayList
<>();
cookies
.
add
(
ssoTokenCookie
);
cookies
.
add
(
ldapTokenCookie
);
cookies
.
add
(
tripCookie
);
sharedContext
.
addCookies
(
cookies
);
log
.
info
(
"海信SSO认证工具的Playwright初始化成功"
);
}
catch
(
Exception
e
)
{
log
.
error
(
"海信SSO认证工具的Playwright初始化失败: "
,
e
);
}
}
/**
* 销毁Playwright资源
*/
@PreDestroy
public
void
destroy
()
{
try
{
if
(
sharedContext
!=
null
)
{
sharedContext
.
close
();
log
.
info
(
"海信SSO认证工具的共享浏览器上下文已关闭"
);
}
if
(
browser
!=
null
)
{
browser
.
close
();
log
.
info
(
"海信SSO认证工具的浏览器实例已关闭"
);
}
if
(
playwright
!=
null
)
{
playwright
.
close
();
log
.
info
(
"海信SSO认证工具的Playwright实例已关闭"
);
}
}
catch
(
Exception
e
)
{
log
.
error
(
"海信SSO认证工具的Playwright资源释放失败: "
,
e
);
}
}
@Tool
(
description
=
"提交出差申请"
)
public
String
apply
(){
String
tripApplyUrl
=
"https://trip.hisense.com/fcc/fcapply/ccsqd/add.html?state=1"
;
long
startTime
=
System
.
currentTimeMillis
();
Page
page
=
null
;
try
{
page
=
sharedContext
.
newPage
();
page
.
setDefaultTimeout
(
60
*
1000
);
// 访问业务系统页面
log
.
info
(
"正在访问业务系统页面: {}"
,
tripApplyUrl
);
page
.
navigate
(
tripApplyUrl
,
new
Page
.
NavigateOptions
().
setWaitUntil
(
WaitUntilState
.
NETWORKIDLE
));
// 检查是否重定向到了SSO登录页面
String
currentUrl
=
page
.
url
();
log
.
info
(
"当前页面URL: {}"
,
currentUrl
);
// 如果页面尚未导航到业务系统URL,则导航到该URL
if
(!
page
.
url
().
equals
(
tripApplyUrl
)
&&
!
page
.
url
().
startsWith
(
tripApplyUrl
))
{
log
.
info
(
"正在访问业务系统页面: {}"
,
tripApplyUrl
);
page
.
navigate
(
tripApplyUrl
,
new
Page
.
NavigateOptions
().
setWaitUntil
(
WaitUntilState
.
NETWORKIDLE
));
}
sharedContext
.
tracing
().
start
(
new
Tracing
.
StartOptions
()
.
setScreenshots
(
true
)
.
setSnapshots
(
true
)
.
setSources
(
true
));
JSONArray
jsonArray
=
infoCollectorService
.
getInfo
(
pageId
);
Locator
.
WaitForOptions
waitForOptions
=
new
Locator
.
WaitForOptions
();
waitForOptions
.
setTimeout
(
5
*
1000
);
Locator
.
WaitForOptions
waitUntilOptions
=
new
Locator
.
WaitForOptions
();
waitUntilOptions
.
setState
(
WaitForSelectorState
.
ATTACHED
);
page
.
locator
(
"[id^='layui-layer-shade']"
).
waitFor
(
waitUntilOptions
);
final
Locator
btnLocator
=
page
.
locator
(
"[class^='jsAgreed btn']"
);
page
.
waitForCondition
(()
->
(
boolean
)
btnLocator
.
evaluate
(
"el => !el.classList.contains('active')"
)
);
btnLocator
.
click
();
for
(
int
i
=
0
;
i
<
jsonArray
.
size
();
i
++){
log
.
info
(
"index {} "
,
i
);
JSONObject
obj
=
jsonArray
.
getJSONObject
(
i
);
log
.
info
(
"json {}"
,
obj
);
String
fieldName
=
obj
.
getString
(
"field_name"
);
String
fieldValue
=
infoCollectorService
.
getValue
(
fieldName
).
toString
();
String
locator
=
obj
.
getString
(
"locator"
);
JSONObject
attributes
=
obj
.
getJSONObject
(
"attributes"
);
if
(
attributes
.
containsKey
(
"class"
)){
Locator
.
FillOptions
fillOptions
=
new
Locator
.
FillOptions
();
fillOptions
.
setForce
(
true
);
List
<
Locator
>
list
=
page
.
locator
(
"[class*='"
+
attributes
.
getString
(
"class"
)+
"']"
).
all
();
for
(
Locator
loc
:
list
){
String
tagName
=
(
String
)
loc
.
evaluate
(
"el => el.tagName"
);
log
.
info
(
"标签类型: {}"
,
tagName
);
if
(
tagName
.
toLowerCase
().
contains
(
"div"
)
||
tagName
.
toLowerCase
().
contains
(
"span"
)
||
(
tagName
.
compareToIgnoreCase
(
"a"
)==
0
)){
continue
;
}
loc
.
fill
(
fieldValue
,
fillOptions
);
page
.
mouse
().
click
(
0
,
0
);
this
.
saveScreenShot
(
page
.
screenshot
(),
obj
.
getString
(
"field_name"
));
}
//page.locator(locator).and(page.locator("[class*='"+attributes.getString("class")+"']")).fill(fieldValue,fillOptions);
}
else
{
page
.
locator
(
locator
).
fill
(
fieldValue
);
page
.
mouse
().
click
(
0
,
0
);
this
.
saveScreenShot
(
page
.
screenshot
(),
obj
.
getString
(
"field_name"
));
}
}
page
.
mouse
().
click
(
0
,
0
);
page
.
locator
(
"[class='jsCostDepart validate[required]']"
).
click
();
page
.
locator
(
".layui-layer[type='dialog']"
).
waitFor
(
new
Locator
.
WaitForOptions
()
.
setState
(
WaitForSelectorState
.
DETACHED
));
saveScreenShot
(
page
.
screenshot
(),
"list"
);
List
<
Locator
>
itemList
=
page
.
locator
(
"[class^='zdyTable-checkItem jsZdyTableChecks']"
).
all
();
itemList
.
get
(
1
).
click
();
saveScreenShot
(
page
.
screenshot
(),
"choose"
);
page
.
locator
(
"[class='btn jsCheckData']"
).
click
();
// page.onDialog(dialog -> dialog.accept());
saveScreenShot
(
page
.
screenshot
(),
"filled"
);
page
.
locator
(
"[class*='btn theme jsSave']"
).
click
(
new
Locator
.
ClickOptions
().
setForce
(
true
));
Locator
locator
=
page
.
locator
(
"[class*='layui-layer layui-layer-dialog layer-anim']"
);
locator
.
waitFor
(
waitForOptions
);
//page.locator("[id^='layui-layer-shade']").click();
saveScreenShot
(
page
.
screenshot
(),
"confirm"
);
page
.
locator
(
"[class^='layui-layer-btn0']"
).
click
(
new
Locator
.
ClickOptions
().
setForce
(
true
));
saveScreenShot
(
page
.
screenshot
(),
"submit"
);
//.page.locator("text=操作成功").waitFor();
Locator
successMsg
=
page
.
locator
(
"text=操作成功"
);
successMsg
.
waitFor
();
successMsg
.
waitFor
(
new
Locator
.
WaitForOptions
().
setState
(
WaitForSelectorState
.
HIDDEN
).
setTimeout
(
10000
));
saveScreenShot
(
page
.
screenshot
(),
"saved"
);
return
"申请已暂存,请进入信息提交"
;
}
catch
(
Exception
e
)
{
long
endTime
=
System
.
currentTimeMillis
();
String
errorMsg
=
"获取海信出差申请页面内容失败: "
+
e
.
getMessage
();
log
.
error
(
"获取海信海信出差申请内容失败,耗时: {} ms"
,
endTime
-
startTime
,
e
);
return
errorMsg
;
}
finally
{
// 释放页面资源
if
(
page
!=
null
)
{
try
{
saveScreenShot
(
page
.
screenshot
(),
"closed"
);
page
.
close
();
}
catch
(
Exception
e
)
{
log
.
warn
(
"关闭页面时发生异常: {}"
,
e
.
getMessage
());
}
}
sharedContext
.
tracing
().
stop
(
new
Tracing
.
StopOptions
()
.
setPath
(
Paths
.
get
(
"trace.zip"
)));
}
}
private
void
saveScreenShot
(
byte
[]
bytes
,
String
suffix
){
// 生成一个唯一的文件名,防止覆盖
String
timestamp
=
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyyMMdd_HHmmss"
));
String
fileName
=
"screenshot_"
+
timestamp
+
"_"
+
suffix
+
".png"
;
try
{
// Paths.get() 指定存储路径,默认在项目根目录
Files
.
write
(
Paths
.
get
(
fileName
),
bytes
);
log
.
info
(
"截图已保存至: {}"
,
fileName
);
}
catch
(
IOException
e
)
{
log
.
info
(
"保存截图失败: "
+
e
.
getMessage
());
e
.
printStackTrace
();
}
}
@Tool
(
description
=
"存储用户提交的出差申请信息"
)
public
String
applyInfoSave
(
@ToolParam
(
required
=
true
)
JSONObject
infos
){
infos
.
keySet
().
forEach
(
key
->
{
infoCollectorService
.
saveValue
(
key
,
infos
.
get
(
key
));
});
Set
<
String
>
keys
=
infoCollectorService
.
findLackInfo
();
StringBuilder
sb
=
new
StringBuilder
();
if
(
keys
.
isEmpty
()){
sb
.
append
(
"用户已提交全部数据,提示用户提交申请"
);
}
else
{
sb
.
append
(
"用户还有以下信息未提交:"
);
sb
.
append
(
"\n"
);
for
(
String
key:
keys
){
sb
.
append
(
key
);
sb
.
append
(
"\n"
);
}
sb
.
append
(
"提示用户继续以json格式提交信息"
);
}
return
sb
.
toString
();
}
/**
* 工具方法:获取海信差旅平台出差申请的网页内容
*
* @return 页面内容(HTML文本)
*/
@Tool
(
description
=
"获取出差申请必要信息"
)
public
String
getTripApplyNecessaryInfo
()
{
String
tripApplyUrl
=
"https://trip.hisense.com/fcc/fcapply/ccsqd/add.html?state=1"
;
long
startTime
=
System
.
currentTimeMillis
();
Page
page
=
null
;
try
{
page
=
sharedContext
.
newPage
();
page
.
setDefaultTimeout
(
60
*
1000
);
// 访问业务系统页面
log
.
info
(
"正在访问业务系统页面: {}"
,
tripApplyUrl
);
page
.
navigate
(
tripApplyUrl
,
new
Page
.
NavigateOptions
().
setWaitUntil
(
WaitUntilState
.
NETWORKIDLE
));
// 检查是否重定向到了SSO登录页面
String
currentUrl
=
page
.
url
();
log
.
info
(
"当前页面URL: {}"
,
currentUrl
);
// 如果页面尚未导航到业务系统URL,则导航到该URL
if
(!
page
.
url
().
equals
(
tripApplyUrl
)
&&
!
page
.
url
().
startsWith
(
tripApplyUrl
))
{
log
.
info
(
"正在访问业务系统页面: {}"
,
tripApplyUrl
);
page
.
navigate
(
tripApplyUrl
,
new
Page
.
NavigateOptions
().
setWaitUntil
(
WaitUntilState
.
NETWORKIDLE
));
}
JSONArray
jsonArray
=
null
;
if
(!
infoCollectorService
.
exists
(
pageId
))
{
JSONArray
tmp
=
getLocators
(
page
.
locator
(
"body"
).
innerHTML
());
jsonArray
=
tmp
;
infoCollectorService
.
register
(
pageId
,
tmp
);
}
else
{
jsonArray
=
infoCollectorService
.
getInfo
(
pageId
);
}
StringBuilder
stringBuilder
=
new
StringBuilder
();
stringBuilder
.
append
(
"用户需要提供的信息包括:"
);
stringBuilder
.
append
(
"\n"
);
for
(
int
i
=
0
;
i
<
jsonArray
.
size
();
i
++){
log
.
info
(
"index {} "
,
i
);
JSONObject
obj
=
jsonArray
.
getJSONObject
(
i
);
stringBuilder
.
append
(
obj
.
getString
(
"field_name"
));
stringBuilder
.
append
(
"\n"
);
}
stringBuilder
.
append
(
"提示用户以json格式提交信息"
);
// 提取页面内容
String
content
=
stringBuilder
.
toString
();
long
endTime
=
System
.
currentTimeMillis
();
log
.
info
(
"成功获取海信出差申请页面内容,耗时: {} ms"
,
endTime
-
startTime
);
log
.
info
(
"用户需要提交的信息包括:{}"
,
content
);
return
content
;
}
catch
(
Exception
e
)
{
long
endTime
=
System
.
currentTimeMillis
();
String
errorMsg
=
"获取海信出差申请页面内容失败: "
+
e
.
getMessage
();
log
.
error
(
"获取海信海信出差申请内容失败,耗时: {} ms"
,
endTime
-
startTime
,
e
);
return
errorMsg
;
}
finally
{
// 释放页面资源
if
(
page
!=
null
)
{
try
{
page
.
close
();
}
catch
(
Exception
e
)
{
log
.
warn
(
"关闭页面时发生异常: {}"
,
e
.
getMessage
());
}
}
}
}
private
JSONArray
getLocators
(
String
html
)
throws
MalformedURLException
{
System
.
out
.
println
(
"----------------------------------------"
);
System
.
out
.
println
(
html
);
System
.
out
.
println
(
"----------------------------------------"
);
Agent
agent
=
agentService
.
getAgent
(
"agent-7"
);
ChatClient
chatClient
=
ChatClient
.
builder
(
agentService
.
getChatModelForAgent
(
agent
)).
build
();
String
systemPrompt
=
"你是一个网页解析助手,你可以将html {htmlData} 中所有的必填项的名称标题和对应的html元素的定位表达式,attributes完整的解析出来;无论元素是否动态生成,都需要解析;以{jsonSchema}格式告诉我;定位表达式可以被playwright直接用来定位元素"
;
JSONArray
response
=
chatClient
.
prompt
().
user
(
u
->
u
.
text
(
systemPrompt
).
param
(
"htmlData"
,
html
).
param
(
"jsonSchema"
,
Contants
.
LOCATOR_SCHEMA
))
.
call
()
.
entity
(
JSONArray
.
class
);
// 获取响应文本
// String responseText = response.getResult().getOutput().getText();
log
.
info
(
response
.
toJSONString
());
return
response
;
}
}
backend/src/main/java/pangea/hiagent/tool/impl/VisitorAppointmentTool.java
deleted
100644 → 0
View file @
b1367155
package
pangea
.
hiagent
.
tool
.
impl
;
import
com.alibaba.fastjson2.JSON
;
import
com.alibaba.fastjson2.JSONArray
;
import
com.alibaba.fastjson2.JSONObject
;
import
com.microsoft.playwright.*
;
import
com.microsoft.playwright.options.Cookie
;
import
com.microsoft.playwright.options.WaitUntilState
;
import
jakarta.annotation.PostConstruct
;
import
jakarta.annotation.PreDestroy
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.ai.chat.client.ChatClient
;
import
org.springframework.ai.tool.annotation.Tool
;
import
org.springframework.ai.tool.annotation.ToolParam
;
import
org.springframework.web.servlet.mvc.method.annotation.SseEmitter
;
import
pangea.hiagent.agent.sse.UserSseService
;
import
pangea.hiagent.common.utils.Contants
;
import
pangea.hiagent.common.utils.HybridUniqueLongGenerator
;
import
pangea.hiagent.common.utils.InputCodeGenerator
;
import
pangea.hiagent.model.Agent
;
import
pangea.hiagent.web.service.AgentService
;
import
pangea.hiagent.web.service.InfoCollectorService
;
import
java.net.MalformedURLException
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Set
;
@Slf4j
public
class
VisitorAppointmentTool
{
public
static
final
String
pageId
=
"visitorAppointment"
;
private
static
final
String
destUrl
=
"https://vrms-proxy.hisense.com/ipark/hichat/#/Liteapp"
;
private
String
ssoToken
;
// SSO密码(从配置文件读取)
private
String
ldapToken
;
private
String
iparkToken
;
// Playwright实例
private
Playwright
playwright
;
// 浏览器实例
private
Browser
browser
;
// 共享的浏览器上下文,用于保持登录状态
private
BrowserContext
sharedContext
;
// 上次登录时间
private
long
lastLoginTime
=
0
;
private
AgentService
agentService
;
private
InfoCollectorService
infoCollectorService
;
private
UserSseService
userSseService
;
// 登录状态有效期(毫秒),设置为30分钟
private
static
final
long
LOGIN_VALIDITY_PERIOD
=
30
*
60
*
1000
;
public
VisitorAppointmentTool
(
AgentService
agentService
,
InfoCollectorService
infoCollectorService
,
UserSseService
userSseService
)
{
this
.
agentService
=
agentService
;
this
.
infoCollectorService
=
infoCollectorService
;
this
.
ssoToken
=
"d10bc61aa4e00dcc6f08de64ca42012814fdbcee9b88aa977f7fb07d3a4018f4"
;
this
.
ldapToken
=
"AAECAzY5NDRBNTQ1Njk0NTRFMDV5b3V4aWFvamlaLv+jUGNEEORN24GLIC3OlqcCdw=="
;
this
.
iparkToken
=
"208a55e4-59bc-400b-971f-a4ed3a5379ca"
;
this
.
userSseService
=
userSseService
;
}
@PostConstruct
public
void
initialize
()
{
try
{
log
.
info
(
"正在初始化海信SSO认证工具的Playwright..."
);
this
.
playwright
=
Playwright
.
create
();
// 使用chromium浏览器,无头模式(headless=true),适合服务器运行
// 可根据需要修改为有头模式(headless=false)用于调试
this
.
browser
=
playwright
.
chromium
().
launch
(
new
BrowserType
.
LaunchOptions
().
setHeadless
(
true
));
// 初始化共享上下文
this
.
sharedContext
=
browser
.
newContext
();
// 检查是否已有有效的登录会话
Cookie
ssoTokenCookie
=
new
Cookie
(
"ssoLoginToken"
,
ssoToken
);
ssoTokenCookie
.
setDomain
(
".hisense.com"
);
ssoTokenCookie
.
setPath
(
"/"
);
Cookie
ldapTokenCookie
=
new
Cookie
(
"LtpaToken"
,
ldapToken
);
ldapTokenCookie
.
setDomain
(
".hisense.com"
);
ldapTokenCookie
.
setPath
(
"/"
);
Cookie
tripCookie
=
new
Cookie
(
"jwtToken"
,
iparkToken
);
tripCookie
.
setDomain
(
"trip.hisense.com"
);
tripCookie
.
setPath
(
"/"
);
// String userName= SecurityContextHolder.getContext().getAuthentication().getName();
List
<
Cookie
>
cookies
=
new
ArrayList
<>();
cookies
.
add
(
ssoTokenCookie
);
cookies
.
add
(
ldapTokenCookie
);
cookies
.
add
(
tripCookie
);
sharedContext
.
addCookies
(
cookies
);
log
.
info
(
"海信SSO认证工具的Playwright初始化成功"
);
}
catch
(
Exception
e
)
{
log
.
error
(
"海信SSO认证工具的Playwright初始化失败: "
,
e
);
}
}
/**
* 销毁Playwright资源
*/
@PreDestroy
public
void
destroy
()
{
try
{
if
(
sharedContext
!=
null
)
{
sharedContext
.
close
();
log
.
info
(
"海信SSO认证工具的共享浏览器上下文已关闭"
);
}
if
(
browser
!=
null
)
{
browser
.
close
();
log
.
info
(
"海信SSO认证工具的浏览器实例已关闭"
);
}
if
(
playwright
!=
null
)
{
playwright
.
close
();
log
.
info
(
"海信SSO认证工具的Playwright实例已关闭"
);
}
}
catch
(
Exception
e
)
{
log
.
error
(
"海信SSO认证工具的Playwright资源释放失败: "
,
e
);
}
}
@Tool
(
description
=
"存储用户提交的访客预约申请信息"
,
returnDirect
=
true
)
public
String
applyInfoSave
(
@ToolParam
(
required
=
true
)
JSONObject
infos
)
{
log
.
info
(
"applyInfoSave(infos={})"
,
infos
);
infos
.
keySet
().
forEach
(
key
->
{
infoCollectorService
.
saveValue
(
key
,
infos
.
get
(
key
));
});
Set
<
String
>
keys
=
infoCollectorService
.
findLackInfo
();
StringBuilder
sb
=
new
StringBuilder
();
if
(
keys
.
isEmpty
())
{
sb
.
append
(
"用户已提交全部数据,提示用户提交申请"
);
}
else
{
sb
.
append
(
"用户还有以下信息未提交:"
);
sb
.
append
(
"\n"
);
for
(
String
key
:
keys
)
{
sb
.
append
(
key
);
sb
.
append
(
"\n"
);
}
sb
.
append
(
"提示用户继续以json格式提交信息"
);
}
return
sb
.
toString
();
}
/**
* 工具方法:获取海信访客预约申请的网页内容
*
* @return 页面内容(HTML文本)
*/
@Tool
(
description
=
"获取访客预约申请必要信息"
)
public
String
getTripApplyNecessaryInfo
()
{
long
startTime
=
System
.
currentTimeMillis
();
Page
page
=
null
;
try
{
page
=
sharedContext
.
newPage
();
page
.
setDefaultTimeout
(
2
*
60
*
1000
);
// 访问业务系统页面
log
.
info
(
"正在访问业务系统页面: {}"
,
destUrl
);
String
faviconUrl
=
"https://vrms-proxy.hisense.com/favicon.ico"
;
page
.
navigate
(
faviconUrl
);
page
.
evaluate
(
"() => sessionStorage.setItem('Access-Token', '208a55e4-59bc-400b-971f-a4ed3a5379ca')"
);
page
.
navigate
(
destUrl
,
new
Page
.
NavigateOptions
().
setWaitUntil
(
WaitUntilState
.
NETWORKIDLE
));
// 检查是否重定向到了SSO登录页面
String
currentUrl
=
page
.
url
();
log
.
info
(
"当前页面URL: {}"
,
currentUrl
);
// 如果页面尚未导航到业务系统URL,则导航到该URL
if
(!
page
.
url
().
equals
(
destUrl
)
&&
!
page
.
url
().
startsWith
(
destUrl
))
{
log
.
info
(
"正在访问业务系统页面: {}"
,
destUrl
);
page
.
navigate
(
destUrl
,
new
Page
.
NavigateOptions
().
setWaitUntil
(
WaitUntilState
.
NETWORKIDLE
));
}
JSONArray
jsonArray
=
null
;
if
(!
infoCollectorService
.
exists
(
pageId
))
{
JSONArray
tmp
=
getLocators
(
page
.
locator
(
"body"
).
innerHTML
());
jsonArray
=
tmp
;
infoCollectorService
.
register
(
pageId
,
tmp
);
}
else
{
jsonArray
=
infoCollectorService
.
getInfo
(
pageId
);
}
StringBuilder
stringBuilder
=
new
StringBuilder
();
// stringBuilder.append("用户需要提供的信息包括:");
// stringBuilder.append("\n");
// for(int i=0;i<jsonArray.size();i++){
// log.info("index {} ",i);
// JSONObject obj = jsonArray.getJSONObject(i);
// stringBuilder.append(obj.getString("field_name"));
// stringBuilder.append("\n");
// }
// stringBuilder.append("提示用户以json格式提交信息");
//stringBuilder.append("从FORMSTART开始到FORMEND结束是要返回给用户的数据,直接展示给用户就可以。FORM START:");
JSONObject
jsonObject
=
new
JSONObject
();
jsonObject
.
put
(
"FORM"
,
jsonArray
);
stringBuilder
.
append
(
jsonArray
.
toJSONString
());
//stringBuilder.append("FORM END");
// 提取页面内容
String
content
=
stringBuilder
.
toString
();
SseEmitter
sseEmitter
=
userSseService
.
getEmitter
(
"worker1"
);
JSONObject
formMessage
=
generateJson
(
jsonArray
);
log
.
info
(
"Send Form Message {}"
,
formMessage
);
sseEmitter
.
send
(
SseEmitter
.
event
().
name
(
"form"
).
data
(
formMessage
));
long
endTime
=
System
.
currentTimeMillis
();
log
.
info
(
"成功获取海信出差申请页面内容,耗时: {} ms"
,
endTime
-
startTime
);
log
.
info
(
"用户需要提交的信息包括:{}"
,
content
);
return
"获取成功"
;
}
catch
(
Exception
e
)
{
long
endTime
=
System
.
currentTimeMillis
();
String
errorMsg
=
"获取海信出差申请页面内容失败: "
+
e
.
getMessage
();
log
.
error
(
"获取海信海信出差申请内容失败,耗时: {} ms"
,
endTime
-
startTime
,
e
);
return
errorMsg
;
}
finally
{
// 释放页面资源
if
(
page
!=
null
)
{
try
{
page
.
close
();
}
catch
(
Exception
e
)
{
log
.
warn
(
"关闭页面时发生异常: {}"
,
e
.
getMessage
());
}
}
}
}
public
JSONObject
generateJson
(
JSONArray
jsonArray
)
{
JSONArray
components
=
new
JSONArray
();
for
(
int
i
=
0
;
i
<
jsonArray
.
size
();
i
++)
{
JSONObject
tmp
=
jsonArray
.
getJSONObject
(
i
);
JSONObject
obj
=
buildComponents
(
tmp
);
tmp
.
put
(
"code"
,
obj
.
getJSONObject
(
"props"
).
getString
(
"name"
));
components
.
add
(
obj
);
}
JSONObject
obj
=
new
JSONObject
();
obj
.
put
(
"coms"
,
components
);
return
obj
;
}
private
JSONObject
buildComponents
(
JSONObject
source
)
{
JSONObject
obj
=
new
JSONObject
();
obj
.
put
(
"key"
,
HybridUniqueLongGenerator
.
generateUnique13DigitNumber
());
obj
.
put
(
"name"
,
"输入框"
);
String
name
=
InputCodeGenerator
.
generateUniqueInputCode
(
"INPUT_"
);
if
(
source
.
getString
(
"field_name"
).
contains
(
"日期"
))
{
obj
.
put
(
"code"
,
"HiDatePicker"
);
name
=
InputCodeGenerator
.
generateUniqueInputCode
(
"DATE_"
);
}
else
{
obj
.
put
(
"code"
,
"HiInput"
);
}
JSONObject
props
=
new
JSONObject
();
props
.
put
(
"title"
,
source
.
getString
(
"field_name"
));
props
.
put
(
"status"
,
"default"
);
props
.
put
(
"name"
,
name
);
obj
.
put
(
"props"
,
props
);
return
obj
;
}
private
JSONArray
getLocators
(
String
html
)
throws
MalformedURLException
{
// System.out.println("----------------------------------------");
// System.out.println(html);
//
// System.out.println("----------------------------------------");
Agent
agent
=
agentService
.
getAgent
(
"agent-7"
);
ChatClient
chatClient
=
ChatClient
.
builder
(
agentService
.
getChatModelForAgent
(
agent
)).
build
();
String
systemPrompt
=
"你是一个网页解析助手,你可以将html {htmlData} 中所有的必填项的名称标题和对应的html元素的唯一的定位表达式,html标签类型,attributes完整的解析出来;无论元素是否动态生成,都需要解析;以{jsonSchema}格式告诉我;定位表达式要求可以直接被playwright使用,准确并且可以定位唯一元素"
;
JSONArray
response
=
chatClient
.
prompt
().
user
(
u
->
u
.
text
(
systemPrompt
).
param
(
"htmlData"
,
html
).
param
(
"jsonSchema"
,
Contants
.
LOCATOR_SCHEMA
))
.
call
()
.
entity
(
JSONArray
.
class
);
// 获取响应文本
// String responseText = response.getResult().getOutput().getText();
log
.
info
(
response
.
toJSONString
());
return
response
;
}
}
backend/src/main/java/pangea/hiagent/web/service/InfoCollectorService.java
deleted
100644 → 0
View file @
b1367155
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
;
}
}
backend/src/main/resources/application-test.yml
deleted
100644 → 0
View file @
b1367155
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
backend/src/main/resources/application.yml
View file @
90b3874a
...
...
@@ -4,7 +4,7 @@ spring:
# 配置文件激活
profiles
:
active
:
test
active
:
dev
# 启用懒加载初始化
main
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment