From 9b68de814d07c5a736c7fbdeb22ba8b666a02cad Mon Sep 17 00:00:00 2001 From: Administrator <15274802129@163.com> Date: Fri, 29 Aug 2025 10:40:49 +0800 Subject: [PATCH] feat(ai): 添加流式AI对话功能 --- src/main/java/cc/mrbird/febs/ai/controller/TestController.java | 128 ++++++++++++++++++++++++++++++++++++++++++ pom.xml | 11 +++ 2 files changed, 136 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 9fa5ea9..077754b 100644 --- a/pom.xml +++ b/pom.xml @@ -29,7 +29,16 @@ <dependencies> - + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.8.9</version> + </dependency> + <dependency> + <groupId>com.alibaba</groupId> + <artifactId>dashscope-sdk-java</artifactId> + <version>2.21.5</version> + </dependency> <dependency> <groupId>io.netty</groupId> diff --git a/src/main/java/cc/mrbird/febs/ai/controller/TestController.java b/src/main/java/cc/mrbird/febs/ai/controller/TestController.java index a019a22..4d63bf5 100644 --- a/src/main/java/cc/mrbird/febs/ai/controller/TestController.java +++ b/src/main/java/cc/mrbird/febs/ai/controller/TestController.java @@ -2,8 +2,8 @@ import cc.mrbird.febs.ai.entity.AiMember; import cc.mrbird.febs.ai.mapper.AiMemberMapper; -import cc.mrbird.febs.ai.req.product.ApiProductInfoDto; -import cc.mrbird.febs.ai.res.product.ApiProductInfoVo; +import cc.mrbird.febs.ai.req.talk.AiTalkAnswerStream; +import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkStreamVo; import cc.mrbird.febs.ai.utils.UUID; import cc.mrbird.febs.common.entity.FebsResponse; import cc.mrbird.febs.common.utils.AppContants; @@ -15,8 +15,11 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.asymmetric.KeyType; import cn.hutool.crypto.asymmetric.RSA; +import cn.hutool.json.JSONUtil; +import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import io.reactivex.Flowable; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; @@ -26,6 +29,17 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import com.alibaba.dashscope.aigc.generation.Generation; +import com.alibaba.dashscope.aigc.generation.GenerationParam; +import com.alibaba.dashscope.aigc.generation.GenerationResult; +import com.alibaba.dashscope.common.Message; +import com.alibaba.dashscope.common.Role; +import com.alibaba.dashscope.exception.ApiException; +import com.alibaba.dashscope.exception.InputRequiredException; +import com.alibaba.dashscope.exception.NoApiKeyException; +import reactor.core.publisher.Flux; + +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -84,4 +98,114 @@ //去掉时间戳 return rsa.encryptBase64(token, KeyType.PublicKey); } + + + + @ApiOperation("提问AI(流式)V2") + @ApiResponses({ + @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVo.class), + }) + @PostMapping("/answer-streamV2") + public Flux<FebsResponse> answerStreamV2(@RequestBody @Validated AiTalkAnswerStream dto) { + if (StrUtil.isEmpty(dto.getQuestion())){ + return Flux.just(new FebsResponse().fail().message("请输入问题")); + } + + long startTime = System.currentTimeMillis(); + + Flowable<GenerationResult> result; + try { + result = callWithMessage(); + } catch (NoApiKeyException | InputRequiredException e) { + e.printStackTrace(); + return Flux.just(new FebsResponse().fail().message("调用AI服务失败: " + e.getMessage())); + } + + return Flux.from(result) + .map(message -> { + String content = message.getOutput().getChoices().get(0).getMessage().getContent(); + System.out.print(content); + return new FebsResponse().success().message(content); + }) + .doOnComplete(() -> { + long endTime = System.currentTimeMillis(); + System.out.println("运行时间:" + (endTime - startTime) + "毫秒"); + }) + .doOnError(error -> { + long endTime = System.currentTimeMillis(); + System.err.println("运行时间:" + (endTime - startTime) + "毫秒,发生错误:" + error.getMessage()); + }); + } + + + public static Flowable<GenerationResult> callWithMessage() throws NoApiKeyException, InputRequiredException { + Generation gen = new Generation(); + Message systemMsg = Message.builder() + .role(Role.SYSTEM.getValue()) + .content("You are a helpful assistant.") + .build(); + Message userMsg = Message.builder() + .role(Role.USER.getValue()) + .content("你是谁?") + .build(); + GenerationParam param = GenerationParam.builder() + // 若没有配置环境变量,请用阿里云百炼API Key将下行替换为:.apiKey("sk-xxx") + .apiKey("sk-babdcf8799144134915cee2683794b2f") + // 模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models + .model("qwen-plus") +// .model("deepseek-r1") +// .model("qwen-turbo-0624-ft-202508281725-c2dc") + .messages(Arrays.asList(systemMsg, userMsg)) +// .resultFormat(GenerationParam.ResultFormat.TEXT) + .resultFormat(GenerationParam.ResultFormat.MESSAGE) + .incrementalOutput(true) + .build(); + return gen.streamCall(param); + } + public static void main(String[] args) { + //定义一个开始时间为启动这个main方法的开始时间,用于计算运行时间 + long startTime = System.currentTimeMillis(); + + Flowable<GenerationResult> result = null; + try { + result = callWithMessage(); + } catch (NoApiKeyException e) { + e.printStackTrace(); + } catch (InputRequiredException e) { + e.printStackTrace(); + } + Flux.from(result) + .doOnNext(message -> { + String content = message.getOutput().getChoices().get(0).getMessage().getContent(); + System.out.print(content); + }) + .subscribe(); + long endTime = System.currentTimeMillis(); + System.out.println("运行时间:" + (endTime - startTime) + "毫秒"); +// result.blockingForEach(item -> { +//// log.info("item: {}", JSONUtil.toJsonStr(item)); +// // 提取文本内容 +// if (item.getOutput() != null && item.getOutput().getChoices() != null) { +// item.getOutput().getChoices().forEach(choice -> { +// if (choice.getMessage() != null) { +// // 根据实际 API 文档确定使用哪个方法 +//// if (choice.getMessage().getContents() != null) { +//// try { +//// choice.getMessage().getContents().forEach(content -> { +//// if (content != null) { +//// System.out.print(content.getType()); +//// } +//// }); +//// } catch (NullPointerException e) { +//// log.error("Error processing contents", e); +//// } +//// } +// if (choice.getMessage().getContent() != null) { +// System.out.print(choice.getMessage().getContent()); +// } +// } +// }); +// } +// }); + } } -- Gitblit v1.9.1