Commit a9695ca8 by zhangxingmin

push

parent f9b8b265
...@@ -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
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
...@@ -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
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