Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yd-ai
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
xingmin
yd-ai
Commits
a9695ca8
Commit
a9695ca8
authored
Apr 23, 2026
by
zhangxingmin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
push
parent
f9b8b265
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
21 additions
and
39 deletions
+21
-39
yd-ai-api/src/main/java/com/yd/ai/api/controller/ApiAiStreamController.java
+5
-12
yd-ai-api/src/main/java/com/yd/ai/api/service/ApiAiStreamService.java
+4
-5
yd-ai-api/src/main/java/com/yd/ai/api/service/impl/ApiAiStreamServiceImpl.java
+12
-22
No files found.
yd-ai-api/src/main/java/com/yd/ai/api/controller/ApiAiStreamController.java
View file @
a9695ca8
...
@@ -2,11 +2,8 @@ package com.yd.ai.api.controller;
...
@@ -2,11 +2,8 @@ package com.yd.ai.api.controller;
import
com.yd.ai.api.service.ApiAiStreamService
;
import
com.yd.ai.api.service.ApiAiStreamService
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.codec.ServerSentEvent
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.bind.annotation.*
;
import
reactor.core.publisher.Flux
;
import
reactor.core.publisher.Mono
;
@RestController
@RestController
@RequestMapping
(
"/api/ai"
)
@RequestMapping
(
"/api/ai"
)
...
@@ -16,14 +13,11 @@ public class ApiAiStreamController {
...
@@ -16,14 +13,11 @@ public class ApiAiStreamController {
private
ApiAiStreamService
apiAiStreamService
;
private
ApiAiStreamService
apiAiStreamService
;
/**
/**
* 调用大模型接口获取AI输出的流信息
* 调用大模型接口获取AI回答(非流式)
* @param question
* @return
*/
*/
@CrossOrigin
(
origins
=
"*"
)
// 开发时允许跨域
@CrossOrigin
(
origins
=
"*"
)
@GetMapping
(
value
=
"/stream"
,
produces
=
MediaType
.
TEXT_EVENT_STREAM_VALUE
)
@GetMapping
(
value
=
"/stream"
)
public
Flux
<
ServerSentEvent
<
String
>
>
streamChat
(
@RequestParam
String
question
)
{
public
Mono
<
String
>
streamChat
(
@RequestParam
String
question
)
{
return
apiAiStreamService
.
streamChat
(
question
);
return
apiAiStreamService
.
streamChat
(
question
);
}
}
}
}
\ No newline at end of file
yd-ai-api/src/main/java/com/yd/ai/api/service/ApiAiStreamService.java
View file @
a9695ca8
package
com
.
yd
.
ai
.
api
.
service
;
package
com
.
yd
.
ai
.
api
.
service
;
import
org.springframework.http.codec.ServerSentEvent
;
import
reactor.core.publisher.Mono
;
import
reactor.core.publisher.Flux
;
public
interface
ApiAiStreamService
{
public
interface
ApiAiStreamService
{
Mono
<
String
>
streamChat
(
String
question
);
Flux
<
ServerSentEvent
<
String
>>
streamChat
(
String
question
);
}
}
\ No newline at end of file
yd-ai-api/src/main/java/com/yd/ai/api/service/impl/ApiAiStreamServiceImpl.java
View file @
a9695ca8
...
@@ -17,9 +17,7 @@ import com.yd.notice.feign.client.ApiNotificationTaskFeignClient;
...
@@ -17,9 +17,7 @@ import com.yd.notice.feign.client.ApiNotificationTaskFeignClient;
import
com.yd.notice.feign.request.ApiSendRequest
;
import
com.yd.notice.feign.request.ApiSendRequest
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.codec.ServerSentEvent
;
import
org.springframework.stereotype.Service
;
import
org.springframework.stereotype.Service
;
import
reactor.core.publisher.Flux
;
import
reactor.core.publisher.Mono
;
import
reactor.core.publisher.Mono
;
import
reactor.core.scheduler.Schedulers
;
import
reactor.core.scheduler.Schedulers
;
...
@@ -36,21 +34,18 @@ public class ApiAiStreamServiceImpl implements ApiAiStreamService {
...
@@ -36,21 +34,18 @@ public class ApiAiStreamServiceImpl implements ApiAiStreamService {
private
ApiNotificationTaskFeignClient
apiNotificationTaskFeignClient
;
private
ApiNotificationTaskFeignClient
apiNotificationTaskFeignClient
;
/**
/**
* 调用大模型接口获取AI输出的流信息(非流式,一次性返回完整内容)
* 调用大模型接口获取AI回答(非流式,返回完整字符串)
* @param question
* @return
*/
*/
@Override
@Override
public
Flux
<
ServerSentEvent
<
String
>
>
streamChat
(
String
question
)
{
public
Mono
<
String
>
streamChat
(
String
question
)
{
// 敏感词校验
(保持不变)
// 敏感词校验
try
{
try
{
apiSensitiveWordDetailService
.
checkWord
(
question
);
apiSensitiveWordDetailService
.
checkWord
(
question
);
}
catch
(
BusinessException
e
)
{
}
catch
(
BusinessException
e
)
{
int
code
=
e
.
getCode
();
int
code
=
e
.
getCode
();
if
(
code
==
ResultCode
.
SENSITIVE_WORDS_EXIST
.
getCode
())
{
if
(
code
==
ResultCode
.
SENSITIVE_WORDS_EXIST
.
getCode
())
{
log
.
info
(
"检测到禁用敏感词,返回提示语"
);
log
.
info
(
"检测到禁用敏感词,返回提示语"
);
String
tipMsg
=
"抱歉,您输入的内容包含敏感词汇,无法为您提供服务。请调整后重新提问。"
;
return
Mono
.
just
(
"抱歉,您输入的内容包含敏感词汇,无法为您提供服务。请调整后重新提问。"
);
return
Flux
.
just
(
ServerSentEvent
.
builder
(
tipMsg
).
build
());
}
else
if
(
code
==
ResultCode
.
SENSITIVE_TZ_WORDS_EXIST
.
getCode
())
{
}
else
if
(
code
==
ResultCode
.
SENSITIVE_TZ_WORDS_EXIST
.
getCode
())
{
log
.
info
(
"检测到通知类型敏感词,发送企业微信通知"
);
log
.
info
(
"检测到通知类型敏感词,发送企业微信通知"
);
AuthUserDto
authUserDto
=
SecurityUtil
.
getCurrentLoginUser
();
AuthUserDto
authUserDto
=
SecurityUtil
.
getCurrentLoginUser
();
...
@@ -63,17 +58,14 @@ public class ApiAiStreamServiceImpl implements ApiAiStreamService {
...
@@ -63,17 +58,14 @@ public class ApiAiStreamServiceImpl implements ApiAiStreamService {
request
.
setParams
(
params
);
request
.
setParams
(
params
);
apiNotificationTaskFeignClient
.
send
(
request
);
apiNotificationTaskFeignClient
.
send
(
request
);
return
Flux
.
just
(
// 注意:此处前端需要特殊处理,可通过自定义响应头或约定特定字符串
ServerSentEvent
.<
String
>
builder
()
// 简便做法:返回一个特殊标记字符串,前端检测到后展示产品列表
.
event
(
"sensitive_notification"
)
return
Mono
.
just
(
"__SENSITIVE_NOTIFICATION__"
);
.
data
(
"show_products"
)
.
build
()
);
}
}
throw
e
;
throw
e
;
}
}
//
========== 核心修改:改用非流式调用,一次性获取完整回答 ==========
//
正常调用大模型非流式接口
Generation
gen
=
new
Generation
();
Generation
gen
=
new
Generation
();
Message
systemMsg
=
Message
.
builder
()
Message
systemMsg
=
Message
.
builder
()
.
role
(
Role
.
SYSTEM
.
getValue
())
.
role
(
Role
.
SYSTEM
.
getValue
())
...
@@ -89,14 +81,12 @@ public class ApiAiStreamServiceImpl implements ApiAiStreamService {
...
@@ -89,14 +81,12 @@ public class ApiAiStreamServiceImpl implements ApiAiStreamService {
.
model
(
"qwen3-max"
)
.
model
(
"qwen3-max"
)
.
messages
(
Arrays
.
asList
(
systemMsg
,
userMsg
))
.
messages
(
Arrays
.
asList
(
systemMsg
,
userMsg
))
.
resultFormat
(
GenerationParam
.
ResultFormat
.
MESSAGE
)
.
resultFormat
(
GenerationParam
.
ResultFormat
.
MESSAGE
)
.
incrementalOutput
(
false
)
// 关闭增量输出
,一次性返回完整答案
.
incrementalOutput
(
false
)
// 关闭增量输出
.
build
();
.
build
();
// 使用 Mono.fromCallable 包装同步调用,并指定在弹性线程池执行
return
Mono
.
fromCallable
(()
->
{
return
Mono
.
fromCallable
(()
->
{
try
{
try
{
GenerationResult
result
=
gen
.
call
(
param
);
GenerationResult
result
=
gen
.
call
(
param
);
// 提取完整回答文本
return
result
.
getOutput
().
getChoices
().
get
(
0
).
getMessage
().
getContent
();
return
result
.
getOutput
().
getChoices
().
get
(
0
).
getMessage
().
getContent
();
}
catch
(
NoApiKeyException
e
)
{
}
catch
(
NoApiKeyException
e
)
{
log
.
error
(
"NoApiKeyException: {}"
,
e
.
getMessage
());
log
.
error
(
"NoApiKeyException: {}"
,
e
.
getMessage
());
...
@@ -106,11 +96,10 @@ public class ApiAiStreamServiceImpl implements ApiAiStreamService {
...
@@ -106,11 +96,10 @@ public class ApiAiStreamServiceImpl implements ApiAiStreamService {
return
"系统错误:输入参数异常"
;
return
"系统错误:输入参数异常"
;
}
}
})
})
.
subscribeOn
(
Schedulers
.
boundedElastic
())
// 避免阻塞主线程
.
subscribeOn
(
Schedulers
.
boundedElastic
())
.
flatMapMany
(
fullAnswer
->
Flux
.
just
(
ServerSentEvent
.
builder
(
fullAnswer
).
build
()))
.
onErrorResume
(
e
->
{
.
onErrorResume
(
e
->
{
log
.
error
(
"非流式响应处理出错: {}"
,
e
.
getMessage
());
log
.
error
(
"非流式响应处理出错: {}"
,
e
.
getMessage
());
return
Flux
.
just
(
ServerSentEvent
.
builder
(
"系统繁忙,请稍后重试"
).
build
()
);
return
Mono
.
just
(
"系统繁忙,请稍后重试"
);
});
});
}
}
}
}
\ No newline at end of file
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