From 38e807600ebd75ea434edf9a0e566a26d913f8aa Mon Sep 17 00:00:00 2001 From: huangyongxing <1473504781@qq.com> Date: Fri, 3 Apr 2026 21:43:17 +0800 Subject: [PATCH] =?UTF-8?q?=E6=99=BA=E8=83=BD=E5=AE=A2=E6=9C=8D=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E6=A1=88=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...baba 智能客服+语音合成项目笔记.docx | Bin 0 -> 25509 bytes .../controller/CustomerServiceController.java | 177 -------------- .../SpringAiAlibabaApplication.class | Bin 788 -> 0 bytes .../controller/CustomerServiceController.class | Bin 7240 -> 0 bytes .../.mvn/wrapper/maven-wrapper.properties | 0 .../SpringAIAlibaba/SpringAIAlibaba.iml | 0 .../SpringAIAlibaba/pom.xml | 8 +- .../SpringAiAlibabaApplication.java | 0 .../controller/CustomerServiceController.java | 230 ++++++++++++++++++ .../example/springaialibaba/controller/Main.java | 97 ++++++++ .../controller/SpeechSynthesisController.java | 118 +++++++++ .../springaialibaba/pojo/StreamResponse.java | 14 ++ .../service/AudioGenerationService.java | 107 +++++++++ .../service/SpeechSynthesisService.java | 82 +++++++ .../src/main/resources/application.yml | 1 + .../src/main/resources/static/index.html | 263 +++++++++++++++++++++ .../SpringAiAlibabaApplicationTests.java | 0 .../SpringAIAlibaba/target/classes/application.yml | 1 + .../SpringAiAlibabaApplication.class | Bin 0 -> 788 bytes .../controller/CustomerServiceController.class | Bin 0 -> 13054 bytes .../springaialibaba/controller/Main$1.class | Bin 0 -> 2172 bytes .../example/springaialibaba/controller/Main.class | Bin 0 -> 4898 bytes .../springaialibaba/controller/TimeUtils.class | Bin 0 -> 865 bytes .../springaialibaba/pojo/StreamResponse.class | Bin 0 -> 572 bytes .../service/SpeechSynthesisService.class | Bin 0 -> 7137 bytes .../target/classes/static/index.html | 263 +++++++++++++++++++++ .../compile/default-compile/createdFiles.lst | 0 .../compile/default-compile/inputFiles.lst | 4 + .../SpringAiAlibabaApplicationTests.class | Bin 29 files changed, 1187 insertions(+), 178 deletions(-) create mode 100644 黄永兴学习笔记/Spring AI Alibaba 智能客服+语音合成项目笔记.docx delete mode 100644 黄永兴学习笔记/智能客服demo/SpringAIAlibaba/src/main/java/com/example/springaialibaba/controller/CustomerServiceController.java delete mode 100644 黄永兴学习笔记/智能客服demo/SpringAIAlibaba/target/classes/com/example/springaialibaba/SpringAiAlibabaApplication.class delete mode 100644 黄永兴学习笔记/智能客服demo/SpringAIAlibaba/target/classes/com/example/springaialibaba/controller/CustomerServiceController.class rename 黄永兴学习笔记/{智能客服demo => 智能客服案例}/SpringAIAlibaba/.mvn/wrapper/maven-wrapper.properties (100%) rename 黄永兴学习笔记/{智能客服demo => 智能客服案例}/SpringAIAlibaba/SpringAIAlibaba.iml (100%) rename 黄永兴学习笔记/{智能客服demo => 智能客服案例}/SpringAIAlibaba/pom.xml (94%) rename 黄永兴学习笔记/{智能客服demo => 智能客服案例}/SpringAIAlibaba/src/main/java/com/example/springaialibaba/SpringAiAlibabaApplication.java (100%) create mode 100644 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/controller/CustomerServiceController.java create mode 100644 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/controller/Main.java create mode 100644 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/controller/SpeechSynthesisController.java create mode 100644 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/pojo/StreamResponse.java create mode 100644 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/service/AudioGenerationService.java create mode 100644 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/service/SpeechSynthesisService.java rename 黄永兴学习笔记/{智能客服demo => 智能客服案例}/SpringAIAlibaba/src/main/resources/application.yml (99%) create mode 100644 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/resources/static/index.html rename 黄永兴学习笔记/{智能客服demo => 智能客服案例}/SpringAIAlibaba/src/test/java/com/example/springaialibaba/SpringAiAlibabaApplicationTests.java (100%) rename 黄永兴学习笔记/{智能客服demo => 智能客服案例}/SpringAIAlibaba/target/classes/application.yml (99%) create mode 100644 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/SpringAiAlibabaApplication.class create mode 100644 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/controller/CustomerServiceController.class create mode 100644 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/controller/Main$1.class create mode 100644 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/controller/Main.class create mode 100644 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/controller/TimeUtils.class create mode 100644 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/pojo/StreamResponse.class create mode 100644 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/service/SpeechSynthesisService.class create mode 100644 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/static/index.html create mode 100644 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst create mode 100644 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst rename 黄永兴学习笔记/{智能客服demo => 智能客服案例}/SpringAIAlibaba/target/test-classes/com/example/springaialibaba/SpringAiAlibabaApplicationTests.class (100%) diff --git a/黄永兴学习笔记/Spring AI Alibaba 智能客服+语音合成项目笔记.docx b/黄永兴学习笔记/Spring AI Alibaba 智能客服+语音合成项目笔记.docx new file mode 100644 index 0000000000000000000000000000000000000000..10b6d005e61eeae5b525d6cec0989d948cd68f73 GIT binary patch literal 25509 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 Z@DCqOO%dT&#lVHWUBp0#24`|F`X9j+9(Di# literal 0 HcmV?d00001 diff --git a/黄永兴学习笔记/智能客服demo/SpringAIAlibaba/src/main/java/com/example/springaialibaba/controller/CustomerServiceController.java b/黄永兴学习笔记/智能客服demo/SpringAIAlibaba/src/main/java/com/example/springaialibaba/controller/CustomerServiceController.java deleted file mode 100644 index d42acb0..0000000 --- a/黄永兴学习笔记/智能客服demo/SpringAIAlibaba/src/main/java/com/example/springaialibaba/controller/CustomerServiceController.java +++ /dev/null @@ -1,177 +0,0 @@ -package com.example.springaialibaba.controller; - - -import com.alibaba.cloud.ai.dashscope.agent.DashScopeAgent; -import com.alibaba.cloud.ai.dashscope.agent.DashScopeAgentOptions; -import com.alibaba.dashscope.app.Application; -import com.alibaba.dashscope.app.ApplicationParam; -import com.alibaba.dashscope.app.ApplicationResult; -import com.alibaba.dashscope.app.FlowStreamMode; -import com.alibaba.dashscope.exception.InputRequiredException; -import com.alibaba.dashscope.exception.NoApiKeyException; -import io.reactivex.Flowable; -import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import reactor.adapter.rxjava.RxJava2Adapter; -import reactor.core.publisher.Flux; - -import java.nio.charset.StandardCharsets; - -@Slf4j -@RestController -@RequiredArgsConstructor //使用RequiredArgsConstructor注解,自动注入final类型的字段 -@RequestMapping("/customer") -public class CustomerServiceController { - - //注入Spring AI Alibaba Agent - //@Autowired - private final DashScopeAgent dashScopeAgent; - - /** - * 智能客服接口(非流式,同步获取结果) - * @param question 用户问题 - * @return 知识库标准答案 - */ - @GetMapping("/service") - public String customerService(@RequestParam("question") String question) { - - try { - /* - DashScopeAgentOptions 是工作流 / 智能体的调用参数,它只负责「触发工作流」,不负责「修改大模型的推理参数」。 - 因为 Spring AI Alibaba 的自动配置在工作流(Agent)模式下不生效! - */ - - // - /* ChatResponse response = dashScopeAgent.call( - new Prompt(question, DashScopeAgentOptions.builder() - .appId("df04e1abf24a416c8702260e88863ac4") - .build() - ) - ); - - return response.getResult().getOutput().getText();*/ - - ApplicationParam param = ApplicationParam.builder() - // 若没有配置环境变量,可用百炼API Key将下行替换为:.apiKey("sk-xxx")。但不建议在生产环境中直接将API Key硬编码到代码中,以减少API Key泄露风险。 - .apiKey(System.getenv("sk-f7d2253302b547c7a2fe257673cb854b")) - .appId("df04e1abf24a416c8702260e88863ac4") - .prompt(question) - .build(); - - Application application = new Application(); - ApplicationResult result = application.call(param); - return result.getOutput().getText(); - - } catch (Exception e) { - log.error("客服调用失败", e); - return "抱歉,智能客服暂时无法响应,请联系人工客服。"; - } - } - - // 官方原生流式调用(1:1对照文档) - @GetMapping(value = "/service2", produces = MediaType.TEXT_HTML_VALUE + ";charset=UTF-8") - public Flux customerService2( - @RequestParam("question") String question, - HttpServletResponse response - ) { - //设置字符编码为UTF-8,解决中文乱码问题 - response.setCharacterEncoding("UTF-8"); - - try { - // ============================================== - // 【官方原版写法】 - // ============================================== - ApplicationParam param = ApplicationParam.builder() - .apiKey("sk-f7d2253302b547c7a2fe257673cb854b") // 你的API Key - .appId("df04e1abf24a416c8702260e88863ac4") - .prompt(question) - .incrementalOutput(true) // 官方:流式必须开 - .flowStreamMode(FlowStreamMode.MESSAGE_FORMAT) // 设置为流模式 - .build(); - - Application application = new Application(); - - // 官方流式调用 - Flowable resultFlowable = application.streamCall(param); - - // 把 RxJava Flowable → Spring Flux(用于SSE输出) - // 正确的流式处理逻辑 - System.out.println(resultFlowable); - -/* return Flux.create(sink -> { - resultFlowable.subscribe( - res -> { - try { - if (res != null && res.getOutput() != null) { - String content = null; - - if ("stop".equals(res.getOutput().getFinishReason())) { - // 流结束 - content = res.getOutput().getText(); - if (content != null && !content.trim().isEmpty()) { - sink.next("data: " + content + "\n\n"); - } - } else { - // 流式输出 - if (res.getOutput().getWorkflowMessage() != null && - res.getOutput().getWorkflowMessage().getMessage() != null) { - - content = res.getOutput().getWorkflowMessage() - .getMessage().getContent(); - - if (content != null && !content.trim().isEmpty()) { - sink.next("data: " + content + "\n\n"); - } - } - } - } - } catch (Exception e) { - log.error("处理响应异常", e); - } - }, - error -> { - log.error("流式调用异常", error); - sink.next("data: 服务调用异常\n\n"); - sink.complete(); - }, - () -> { - log.info("流式调用完成"); - sink.complete(); - } - ); - });*/ - - // RxJava适配器 flowable 转换为 flux - return RxJava2Adapter.flowableToFlux(resultFlowable) - .map(this::extractContent) - .filter(content -> content != null && !content.trim().isEmpty()) - .map(content -> "data: " + content + "\n\n"); - - - } catch (Exception e) { - log.error("客服调用失败", e); - return Flux.error(e); - } - } - - // 从 ApplicationResult 中提取内容 - private String extractContent(ApplicationResult res) { - if (res == null || res.getOutput() == null) return null; - - if ("stop".equals(res.getOutput().getFinishReason())) { - return res.getOutput().getText(); - } else if (res.getOutput().getWorkflowMessage() != null && - res.getOutput().getWorkflowMessage().getMessage() != null) { - return res.getOutput().getWorkflowMessage().getMessage().getContent(); - } - return null; - } -} \ No newline at end of file diff --git a/黄永兴学习笔记/智能客服demo/SpringAIAlibaba/target/classes/com/example/springaialibaba/SpringAiAlibabaApplication.class b/黄永兴学习笔记/智能客服demo/SpringAIAlibaba/target/classes/com/example/springaialibaba/SpringAiAlibabaApplication.class deleted file mode 100644 index a7758aa8ee5f11f56fe04b1d715eb13071464943..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 788 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 + + + org.springframework.boot + spring-boot-starter-webflux + + io.projectreactor.addons reactor-adapter - 3.5.0 @@ -113,6 +118,7 @@ + diff --git a/黄永兴学习笔记/智能客服demo/SpringAIAlibaba/src/main/java/com/example/springaialibaba/SpringAiAlibabaApplication.java b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/SpringAiAlibabaApplication.java similarity index 100% rename from 黄永兴学习笔记/智能客服demo/SpringAIAlibaba/src/main/java/com/example/springaialibaba/SpringAiAlibabaApplication.java rename to 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/SpringAiAlibabaApplication.java diff --git a/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/controller/CustomerServiceController.java b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/controller/CustomerServiceController.java new file mode 100644 index 0000000..db5a87f --- /dev/null +++ b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/controller/CustomerServiceController.java @@ -0,0 +1,230 @@ +package com.example.springaialibaba.controller; + + +import com.alibaba.cloud.ai.dashscope.agent.DashScopeAgent; +import com.alibaba.dashscope.app.*; +import com.example.springaialibaba.pojo.StreamResponse; +import com.example.springaialibaba.service.SpeechSynthesisService; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.reactivex.Flowable; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.nio.ByteBuffer; +import java.util.Base64; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; + +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; +import reactor.adapter.rxjava.RxJava2Adapter; +import reactor.adapter.rxjava.RxJava3Adapter; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Slf4j +@RestController +@RequiredArgsConstructor //使用RequiredArgsConstructor注解,自动注入final类型的字段 +@RequestMapping("/customer") +public class CustomerServiceController { + + //注入Spring AI Alibaba Agent + //@Autowired + private final DashScopeAgent dashScopeAgent; + private final SpeechSynthesisService speechSynthesisService; + + /** + * 智能客服接口(非流式,同步获取结果) + * @param question 用户问题 + * @return 知识库标准答案 + */ + @GetMapping("/service") + public String customerServiceController(@RequestParam("question") String question) { + + try { + /* + DashScopeAgentOptions 是工作流 / 智能体的调用参数,它只负责「触发工作流」,不负责「修改大模型的推理参数」。 + 因为 Spring AI Alibaba 的自动配置在工作流(Agent)模式下不生效! + */ + + // + /* ChatResponse response = dashScopeAgent.call( + new Prompt(question, DashScopeAgentOptions.builder() + .appId("df04e1abf24a416c8702260e88863ac4") + .build() + ) + ); + + return response.getResult().getOutput().getText();*/ + + ApplicationParam param = ApplicationParam.builder() + // 若没有配置环境变量,可用百炼API Key将下行替换为:.apiKey("sk-xxx")。但不建议在生产环境中直接将API Key硬编码到代码中,以减少API Key泄露风险。 + .apiKey(System.getenv("sk-f7d2253302b547c7a2fe257673cb854b")) + .appId("df04e1abf24a416c8702260e88863ac4") + .prompt(question) + .build(); + + Application application = new Application(); + ApplicationResult result = application.call(param); + return result.getOutput().getText(); + + } catch (Exception e) { + log.error("客服调用失败", e); + return "抱歉,智能客服暂时无法响应,请联系人工客服。"; + } + } + + // 官方原生流式调用(1:1对照文档) + @GetMapping(value = "/service2", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public Flux customerService2Controller( + @RequestParam("question") String question, + HttpServletResponse response + ) { + //设置字符编码为UTF-8,解决中文乱码问题 + response.setCharacterEncoding("UTF-8"); + + ObjectMapper objectMapper = new ObjectMapper(); + AtomicInteger counter = new AtomicInteger(0); + + try { + // 【官方原版写法】 + ApplicationParam param = ApplicationParam.builder() + .apiKey("sk-f7d2253302b547c7a2fe257673cb854b") + .appId("df04e1abf24a416c8702260e88863ac4") + .prompt(question) + .flowStreamMode(FlowStreamMode.MESSAGE_FORMAT) + .build(); + + Application application = new Application(); + + // 官方流式调用 + Flowable resultFlowable = application.streamCall(param); + + // RxJava适配器 flowable 转换为 flux Mono是单元素的Flux + return RxJava2Adapter.flowableToFlux(resultFlowable) + .flatMap(res -> { + String content = extractContent(res); + if (content != null && !content.trim().isEmpty()) { + try { + String id = UUID.randomUUID().toString().substring(0, 8); + int seq = counter.incrementAndGet(); + String jsonData = objectMapper.writeValueAsString(new StreamResponse(id, seq, content)); + return Mono.just(jsonData); + } catch (Exception e) { + log.error("JSON序列化失败", e); + return Mono.empty(); + } + } + return Mono.empty(); + }); + + } catch (Exception e) { + log.error("客服调用失败", e); + return Flux.error(e); + } + } + + + // 语音合成接口 - 单向流式返回音频流数据 + @GetMapping(value = "/synthesize", produces = "audio/wav") + public StreamingResponseBody synthesizeSpeech(@RequestParam("text") String text) { + log.info("开始语音合成,文本: {}", text); + + return outputStream -> { + CountDownLatch latch = new CountDownLatch(1); + try { + Flux audioFlux = speechSynthesisService.streamSynthesize(text); + audioFlux.subscribe( + bytes -> { + try { + log.info("Controller收到音频数据,大小: {} 字节,写入输出流", bytes.length); + outputStream.write(bytes); + outputStream.flush(); + log.info("已刷新输出流"); + } catch (Exception e) { + log.error("写入音频数据失败", e); + } + }, + error -> { + log.error("音频流处理错误", error); + latch.countDown(); + }, + () -> { + log.info("音频数据传输完成"); + latch.countDown(); + } + ); + log.info("等待音频流完成..."); + latch.await(); + log.info("音频流完成,结束请求"); + } catch (Exception e) { + log.error("语音合成失败", e); + } + }; + } + + // SSE推送音频数据接口 + @GetMapping(value = "/synthesize-sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public Flux synthesizeSpeechSSE(@RequestParam("text") String text) { + log.info("开始SSE语音合成,文本: {}", text); + + Flux audioFlux = speechSynthesisService.streamSynthesize(text); + AtomicInteger seq = new AtomicInteger(0); + + return audioFlux + .map(bytes -> { + String base64Data = Base64.getEncoder().encodeToString(bytes); + int currentSeq = seq.incrementAndGet(); + String jsonData = String.format("{\"seq\":%d,\"data\":\"%s\",\"size\":%d}", + currentSeq, base64Data, bytes.length); + log.info("SSE推送音频数据块 [{}], 大小: {} 字节", currentSeq, bytes.length); + return "data: " + jsonData + "\n\n"; + }) + .doOnComplete(() -> { + log.info("SSE音频推送完成"); + }) + .doOnError(error -> { + log.error("SSE音频推送错误", error); + }); + } + + // 从 ApplicationResult 中提取内容 + private String extractContent(ApplicationResult res) { + if (res == null || res.getOutput() == null) return null; + if (res.getOutput().getWorkflowMessage() != null) { + WorkflowMessage workflowMessage = res.getOutput().getWorkflowMessage(); + if (workflowMessage != null && workflowMessage.getMessage() != null) { + String nodeId = workflowMessage.getNodeId(); + String content = workflowMessage.getMessage().getContent(); + // 区分不同的nodeId + if ("Output_emZG".equals(nodeId)) { + // 流程输出节点,返回内容 + return content; + } else if ("End_mOtD".equals(nodeId)) { + // 结束节点,不返回内容 + log.debug("流式传输结束,收到完整结果,不返回"); + return null; + } else { + // 其他节点,返回内容 + return content; + } + } + } + return null; + } + + + + + + + + + +} \ No newline at end of file diff --git a/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/controller/Main.java b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/controller/Main.java new file mode 100644 index 0000000..a2764a4 --- /dev/null +++ b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/controller/Main.java @@ -0,0 +1,97 @@ +package com.example.springaialibaba.controller; + +import com.alibaba.dashscope.audio.tts.SpeechSynthesisResult; +import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisAudioFormat; +import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam; +import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer; +import com.alibaba.dashscope.common.ResultCallback; +import com.alibaba.dashscope.utils.Constants; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +class TimeUtils { + private static final DateTimeFormatter formatter = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); + + public static String getTimestamp() { + return LocalDateTime.now().format(formatter); + } +} + + +public class Main { + private static String[] textArray = {"流式文本语音合成SDK,", + "可以将输入的文本", "合成为语音二进制数据,", "相比于非流式语音合成,", + "流式合成的优势在于实时性", "更强。用户在输入文本的同时", + "可以听到接近同步的语音输出,", "极大地提升了交互体验,", + "减少了用户等待时间。", "适用于调用大规模", "语言模型(LLM),以", + "流式输入文本的方式", "进行语音合成的场景。"}; + private static String model = "cosyvoice-v3-flash"; // 模型 + private static String voice = "longanyang"; // 音色 + + public static void streamAudioDataToSpeaker() { + // 配置回调函数 + ResultCallback callback = new ResultCallback() { + @Override + public void onEvent(SpeechSynthesisResult result) { + // System.out.println("收到消息: " + result); + if (result.getAudioFrame() != null) { + // 此处实现处理音频数据的逻辑 + System.out.println(TimeUtils.getTimestamp() + " 收到音频"); + } + } + + @Override + public void onComplete() { + System.out.println(TimeUtils.getTimestamp() + " 收到Complete,语音合成结束"); + } + + @Override + public void onError(Exception e) { + System.out.println("出现异常:" + e.toString()); + } + }; + + // 请求参数 + SpeechSynthesisParam param = + SpeechSynthesisParam.builder() + // 新加坡和北京地域的API Key不同。获取API Key:https://help.aliyun.com/zh/model-studio/get-api-key + // 若没有配置环境变量,请用百炼API Key将下行替换为:.apiKey("sk-xxx") + .apiKey("sk-f7d2253302b547c7a2fe257673cb854b") + .model(model) + .voice(voice) + .format(SpeechSynthesisAudioFormat + .PCM_22050HZ_MONO_16BIT) // 流式合成使用PCM或者MP3 + .build(); + SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback); + // 带Callback的call方法将不会阻塞当前线程 + try { + for (String text : textArray) { + // 发送文本片段,在回调接口的onEvent方法中实时获取二进制音频 + synthesizer.streamingCall(text); + } + // 等待结束流式语音合成 + synthesizer.streamingComplete(); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + // 任务结束关闭websocket连接 + synthesizer.getDuplexApi().close(1000, "bye"); + } + + // 首次发送文本时需建立 WebSocket 连接,因此首包延迟会包含连接建立的耗时 + System.out.println( + "[Metric] requestId为:" + + synthesizer.getLastRequestId() + + ",首包延迟(毫秒)为:" + + synthesizer.getFirstPackageDelay()); + } + + public static void main(String[] args) { + // 以下为北京地域url,若使用新加坡地域的模型,需将url替换为:wss://dashscope-intl.aliyuncs.com/api-ws/v1/inference + Constants.baseWebsocketApiUrl = "wss://dashscope.aliyuncs.com/api-ws/v1/inference"; + streamAudioDataToSpeaker(); + System.exit(0); + } +} \ No newline at end of file diff --git a/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/controller/SpeechSynthesisController.java b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/controller/SpeechSynthesisController.java new file mode 100644 index 0000000..287df03 --- /dev/null +++ b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/controller/SpeechSynthesisController.java @@ -0,0 +1,118 @@ +package com.example.springaialibaba.controller; + +import com.alibaba.dashscope.audio.tts.SpeechSynthesisParam; +import com.alibaba.dashscope.audio.tts.SpeechSynthesizer; +import com.alibaba.dashscope.audio.tts.SpeechSynthesisResult; +import com.alibaba.dashscope.exception.NoApiKeyException; +import com.alibaba.dashscope.utils.Constants; +import io.reactivex.Flowable; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import reactor.adapter.rxjava.RxJava2Adapter; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Base64; + +@Slf4j +@RestController +@RequestMapping("/speech") +public class SpeechSynthesisController { + + private static final String MODEL = "cosyvoice-v3-flash"; + private static final String VOICE = "longanyang"; + + static { + // 北京地域url,若使用新加坡地域的模型,需将url替换为:wss://dashscope-intl.aliyuncs.com/api-ws/v1/inference + Constants.baseWebsocketApiUrl = "wss://dashscope.aliyuncs.com/api-ws/v1/inference"; + } + + @GetMapping(value = "/synthesize", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + public void synthesizeAudio( + @RequestParam("text") String text, + HttpServletResponse response + ) throws NoApiKeyException, IOException { + + // 设置响应头 + response.setContentType("audio/wav"); + response.setHeader("Content-Disposition", "attachment; filename=output.wav"); + + // 请求参数 + SpeechSynthesisParam param = SpeechSynthesisParam.builder() + .apiKey(System.getenv("DASHSCOPE_API_KEY")) + .model(MODEL) + .voice(VOICE) + .build(); + + SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null); + + // 流式获取音频数据 + Flowable resultFlowable = synthesizer.callAsFlowable(text); + + // 处理音频数据 + OutputStream outputStream = response.getOutputStream(); + + resultFlowable.blockingForEach(result -> { + if (result.getAudioFrame() != null) { + try { + // 音频数据是Base64编码的,需要解码 + byte[] audioData = Base64.getDecoder().decode(result.getAudioFrame().getAudio()); + outputStream.write(audioData); + outputStream.flush(); + log.debug("写入音频数据: {} bytes", audioData.length); + } catch (IOException e) { + log.error("写入音频数据失败", e); + } + } + }); + + // 关闭连接和输出流 + synthesizer.getDuplexApi().close(1000, "bye"); + outputStream.close(); + + // 打印首包延迟 + log.info("[Metric] requestId为:{}", synthesizer.getLastRequestId()); + log.info("首包延迟(毫秒)为:{}", synthesizer.getFirstPackageDelay()); + } + + @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public Flux streamAudio( + @RequestParam("text") String text + ) throws NoApiKeyException { + + // 请求参数 + SpeechSynthesisParam param = SpeechSynthesisParam.builder() + .apiKey(System.getenv("DASHSCOPE_API_KEY")) + .model(MODEL) + .voice(VOICE) + .build(); + + SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null); + + // 流式获取音频数据 + Flowable resultFlowable = synthesizer.callAsFlowable(text); + + // 转换为Flux并返回 + return RxJava2Adapter.flowableToFlux(resultFlowable) + .flatMap(result -> { + if (result.getAudioFrame() != null) { + String audioBase64 = result.getAudioFrame().getAudio(); + return Mono.just("data: " + audioBase64 + "\n\n"); + } + return Mono.empty(); + }) + .doOnTerminate(() -> { + // 关闭连接 + synthesizer.getDuplexApi().close(1000, "bye"); + log.info("[Metric] requestId为:{}", synthesizer.getLastRequestId()); + log.info("首包延迟(毫秒)为:{}", synthesizer.getFirstPackageDelay()); + }); + } +} \ No newline at end of file diff --git a/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/pojo/StreamResponse.java b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/pojo/StreamResponse.java new file mode 100644 index 0000000..ed3b507 --- /dev/null +++ b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/pojo/StreamResponse.java @@ -0,0 +1,14 @@ +package com.example.springaialibaba.pojo; + +// 流式响应数据结构 +public class StreamResponse { + public String id; + public int seq; + public String text; + + public StreamResponse(String id, int seq, String text) { + this.id = id; + this.seq = seq; + this.text = text; + } +} \ No newline at end of file diff --git a/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/service/AudioGenerationService.java b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/service/AudioGenerationService.java new file mode 100644 index 0000000..086f7ac --- /dev/null +++ b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/service/AudioGenerationService.java @@ -0,0 +1,107 @@ +package com.example.springaialibaba.service; + +import com.alibaba.dashscope.audio.tts.SpeechSynthesisResult; +import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam; +import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer; +import com.alibaba.dashscope.common.ResultCallback; +import com.alibaba.dashscope.exception.NoApiKeyException; +import com.alibaba.dashscope.utils.Constants; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@Service +public class AudioGenerationService { + + private static final String MODEL = "cosyvoice-v3-flash"; + private static final String VOICE = "longanyang"; + + static { + // 设置WebSocket API地址(北京地域) + Constants.baseWebsocketApiUrl = "wss://dashscope.aliyuncs.com/api-ws/v1/inference"; + } + + /** + * 生成文本的音频数据 + * @param text 要转换为音频的文本 + * @return 音频数据的Flux流 + */ + public Flux generateAudio(String text) { + return Mono.fromCallable(() -> { + try { + SpeechSynthesisParam param = SpeechSynthesisParam.builder() + .apiKey("sk-f7d2253302b547c7a2fe257673cb854b") + .model(MODEL) + .voice(VOICE) + .build(); + + SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null); + + List audioChunks = new ArrayList<>(); + + synthesizer.callAsFlowable(text).blockingForEach(result -> { + if (result.getAudioFrame() != null) { + ByteBuffer audioData = ByteBuffer.wrap(result.getAudioFrame()); + audioChunks.add(audioData); + log.debug("收到音频数据块,大小: {} bytes", result.getAudioFrame().length); + } + }); + + synthesizer.getDuplexApi().close(1000, "bye"); + + log.info("音频生成完成,首包延迟: {} ms", synthesizer.getFirstPackageDelay()); + + return Flux.fromIterable(audioChunks); + + } catch (NoApiKeyException e) { + log.error("API Key错误", e); + return Flux.error(e); + } catch (Exception e) { + log.error("音频生成失败", e); + return Flux.error(e); + } + }).flatMapMany(flux -> flux); + } + + /** + * 生成单个音频数据块(用于实时流式传输) + * @param text 要转换为音频的文本 + * @return 音频数据的Mono + */ + public Mono generateAudioChunk(String text) { + return Mono.fromCallable(() -> { + try { + SpeechSynthesisParam param = SpeechSynthesisParam.builder() + .apiKey("sk-f7d2253302b547c7a2fe257673cb854b") + .model(MODEL) + .voice(VOICE) + .build(); + + SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null); + + ByteBuffer audioData = null; + + synthesizer.callAsFlowable(text).blockingForEach(result -> { + if (result.getAudioFrame() != null) { + audioData = ByteBuffer.wrap(result.getAudioFrame()); + log.debug("生成音频数据块,大小: {} bytes", result.getAudioFrame().length); + } + }); + + synthesizer.getDuplexApi().close(1000, "bye"); + + return audioData; + + } catch (Exception e) { + log.error("音频生成失败", e); + throw new RuntimeException("音频生成失败", e); + } + }); + } +} \ No newline at end of file diff --git a/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/service/SpeechSynthesisService.java b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/service/SpeechSynthesisService.java new file mode 100644 index 0000000..2bd95cd --- /dev/null +++ b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/java/com/example/springaialibaba/service/SpeechSynthesisService.java @@ -0,0 +1,82 @@ +package com.example.springaialibaba.service; + + +import com.alibaba.dashscope.audio.tts.SpeechSynthesisResult; +import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam; +import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer; +import com.alibaba.dashscope.utils.Constants; +import io.reactivex.Flowable; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import reactor.adapter.rxjava.RxJava2Adapter; +import reactor.core.publisher.Flux; + +import java.nio.ByteBuffer; + +@Slf4j +@Service +public class SpeechSynthesisService { + + private static final String MODEL = "cosyvoice-v3-flash"; + private static final String VOICE = "longanyang"; + + public Flux streamSynthesize(String text) { + try { + Constants.baseWebsocketApiUrl = "wss://dashscope.aliyuncs.com/api-ws/v1/inference"; + + SpeechSynthesisParam param = SpeechSynthesisParam.builder() + .apiKey("sk-f7d2253302b547c7a2fe257673cb854b") + .model(MODEL) + .voice(VOICE) + .build(); + + SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null); + Flowable resultFlowable = synthesizer.callAsFlowable(text); + + Flux audioFlux = RxJava2Adapter.flowableToFlux(resultFlowable) + .doOnNext(result -> { + log.info("收到SpeechSynthesisResult, audioFrame: {}, frameSize: {}", + result.getAudioFrame() != null, + result.getAudioFrame() != null ? result.getAudioFrame().remaining() : 0); + }) + .filter(result -> { + boolean hasAudio = result.getAudioFrame() != null; + if (!hasAudio) { + log.info("跳过无音频帧的结果"); + } + return hasAudio; + }) + .map(result -> { + ByteBuffer buffer = result.getAudioFrame(); + byte[] bytes = new byte[buffer.remaining()]; + buffer.get(bytes); + log.info("处理音频数据块,大小: {} 字节", bytes.length); + return bytes; + }) + .doOnComplete(() -> { + log.info("语音合成完成,requestId: {}, 首包延迟: {}ms", + synthesizer.getLastRequestId(), + synthesizer.getFirstPackageDelay()); + try { + synthesizer.getDuplexApi().close(1000, "bye"); + } catch (Exception e) { + log.error("关闭连接失败", e); + } + }) + .doOnError(error -> { + log.error("语音合成错误", error); + try { + synthesizer.getDuplexApi().close(1000, "bye"); + } catch (Exception e) { + log.error("关闭连接失败", e); + } + }); + + return audioFlux; + + } catch (Exception e) { + log.error("语音合成失败", e); + return Flux.error(e); + } + } +} diff --git a/黄永兴学习笔记/智能客服demo/SpringAIAlibaba/src/main/resources/application.yml b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/resources/application.yml similarity index 99% rename from 黄永兴学习笔记/智能客服demo/SpringAIAlibaba/src/main/resources/application.yml rename to 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/resources/application.yml index fecb5d1..d778e3b 100644 --- a/黄永兴学习笔记/智能客服demo/SpringAIAlibaba/src/main/resources/application.yml +++ b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/resources/application.yml @@ -11,3 +11,4 @@ spring: api-key: sk-f7d2253302b547c7a2fe257673cb854b # 业务空间ID workspace-id: llm-fuczq7vkh8vyz716 + diff --git a/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/resources/static/index.html b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/resources/static/index.html new file mode 100644 index 0000000..49aa2f0 --- /dev/null +++ b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/main/resources/static/index.html @@ -0,0 +1,263 @@ + + + + + + 智能客服 - 文本 + 语音 + + + +
+

🤖 智能客服 - 文本 + 语音

+ +
+ + +
+ +
+ + +
+ +
+ 状态:等待提问 +
+ +
+
📝 回答内容
+
+ (回答将在这里显示) +
+
+ + +
+ + + + diff --git a/黄永兴学习笔记/智能客服demo/SpringAIAlibaba/src/test/java/com/example/springaialibaba/SpringAiAlibabaApplicationTests.java b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/test/java/com/example/springaialibaba/SpringAiAlibabaApplicationTests.java similarity index 100% rename from 黄永兴学习笔记/智能客服demo/SpringAIAlibaba/src/test/java/com/example/springaialibaba/SpringAiAlibabaApplicationTests.java rename to 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/src/test/java/com/example/springaialibaba/SpringAiAlibabaApplicationTests.java diff --git a/黄永兴学习笔记/智能客服demo/SpringAIAlibaba/target/classes/application.yml b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/application.yml similarity index 99% rename from 黄永兴学习笔记/智能客服demo/SpringAIAlibaba/target/classes/application.yml rename to 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/application.yml index fecb5d1..d778e3b 100644 --- a/黄永兴学习笔记/智能客服demo/SpringAIAlibaba/target/classes/application.yml +++ b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/application.yml @@ -11,3 +11,4 @@ spring: api-key: sk-f7d2253302b547c7a2fe257673cb854b # 业务空间ID workspace-id: llm-fuczq7vkh8vyz716 + diff --git a/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/SpringAiAlibabaApplication.class b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/SpringAiAlibabaApplication.class new file mode 100644 index 0000000000000000000000000000000000000000..8c0b7bb31e3a2832ea846b406291588d3402257e GIT binary patch literal 788 zcmbVKO;6iE5PcgG970-Xpiuguid)E`z9FO(q!6hmmsU-c9(o#^jah2%M(cIqZ}rrQ z13!Qtg_t#|l0$l_CC_NS-psz4yZf740LOUKLJcbc>TNWzDzJG;KPk*er{SmgQYKDd z^}W){od~RS55@tS0*8soLwQa4G?QU5wMwU?C{r=T6pku;pazfjU^>lILQWaoLJR8w z+HE|+Q-Pkb>8yHUDVJBq{s?1Z++T=!CHJ0#tIrkaL?)qZOjdb&=B&F5RR|nK z|Hp~%my_bR?R1wtWz2E1DR=(BU9Q$eo%hqxBp(pJ5Qy+ z-j`B4mCLazl&3^%f6<+Q&WuJ}>{(ApC)`++ZtY zEm${tzaf5A;Z2r43@&-bvi+EV4z}1@!#18Xh%Y{@z<_2a=>5Ukw|Tw4W$=*&SYNH!2HShpt%F=@X literal 0 HcmV?d00001 diff --git a/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/controller/CustomerServiceController.class b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/controller/CustomerServiceController.class new file mode 100644 index 0000000000000000000000000000000000000000..0162cedd18c2779a990eec6273609ea6cacfb1fd GIT binary patch literal 13054 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 literal 0 HcmV?d00001 diff --git a/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/controller/Main$1.class b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/controller/Main$1.class new file mode 100644 index 0000000000000000000000000000000000000000..6c4c9f98a46dcd3a289ed9f83f854f65ec866863 GIT binary patch literal 2172 zcmbVN-%lJ>6#g#Y4y;plp@mX^)M~M1!FH$?t1O_ffK(TXT}svZa(B3}Q)cIGX6};m z>We%WQ=<>Y#5D2UST#X{#Q5Zc|Ho4M)c?SE?#wJMLT#0VduPs^AKy9WJ7<6YbNd$n zqxjH36T>-MmMw9Mmn*KYf{O2WE8O9(Q{+W%+0s+KbY0Z%-f-6FSF84@Fo=cqA;=Dy4#LrYFBi6olQX5tAX7*cu16LZya zQTPkI=n96;ytKKy$bCn@$HEp>asmb`|DW(?84T%7tqD&t4EKe`2a)sYk|Qmp0;^CF z!Y&ooJyjBc6GXXWGmA-d;HZI4hM~ige}oGY$I!)aWJRcP9cy9eX6IptS`gNu+g4k#o=iDet;w&--`WTLe3GdIyL_Y?olbW5%^(gPdyb`$* zen>usOaHUe)S`kS+RpMy%)9igP$juE&vnO?@F}OH^m0YCXd+`#l8{uj#tCDoH)0>UN?@`(?zDxX1hTiP!sTaHV)t*eVRe zFlM41DZ*KhRo@oVjvlHuJ;3L6ap}3>taw~ieUdLfq*BD3gVQ|n5ama(KRZTvQ&XPp z%7BuKDr#UVUL}vYeN4Qi_eD<-vOFB4Nv`;Uq@gAHQSs9gQY!k)D^Z9biMNqA@D4-o z-*e=6YjRasQK2K!PIFsHe_gYAmf_3B9>&^{!x`=^xgzMzOSxLDWDioiL9)+qVZ9;_ zQNPikUvFW9D0ZQDX~9t zkMF)EjoR&v-HqG#e*S#->pQJjpgPq)-oE$g-P+DawXLlOJ6|!H_{*Lr{G7{!Km-P^ zlfMHMJFEr<-e)-Z@2WJHQNf7dbF@=tWT0rz&=R8+0{Ruu{|S0G=*gm+X-WT2X#JiZ znvkSZf2MtdC+RdJ1-g&W8&v}-($dB^=x(CBdtejk-_Y>`y0`GmHeLWWaYlP<4!yO9 zq0f>{23;5ky>>^Iu~+hemvD}}pAW5A7a=25jHEi|;2z*nveVd7^qmEZ`b_ V(Ys3*ME@<~J$!%@)EMn+@-JxpMa=*J literal 0 HcmV?d00001 diff --git a/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/controller/Main.class b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/controller/Main.class new file mode 100644 index 0000000000000000000000000000000000000000..673fad01a0d53692b183d8bb1d93bd81fe8edc7f GIT binary patch literal 4898 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 literal 0 HcmV?d00001 diff --git a/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/controller/TimeUtils.class b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/controller/TimeUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..0d5a585baa2654725aed07c9abafc3b69ac57b77 GIT binary patch literal 865 zcmb7C+iuf95Ixhhabn!0m_mVa38g?%sWtF~n!*dH>O%rZE`47++pv`{mA&QiS6n1O zJn#X06k>Lr5Red;mAvbjotbmy%zpj$`3r#i=sB1p+>Y}!kgr5~oXDU&E>t!aN+c>0 zkqF{E(?y;nvIzE7DxYbUln&+zOGn~`2ojNvgD26Ej5VQom=~$gS{8)$fxXw96IAZt zk7L-{P3wImJ#lCD{7W{s7<^5-oLPIf^f#e0_ueJKxOjrNgBywUqp!{ z_=7wa$$==8u_w;@j&06G4d*?aLxUUC&s9mdJNRGKSuJlYwNbFtJS@U;cf$MUR$N>` z$H7$=a3+uCHr3z5HLS7TS^ko+I;~+R^-Emelv?+212+lvYKSxW{yf>=5F@x@ep1A8 zR~fyUL!q)QLlGSow#E;VaM7sCe>F7V@W)|n-Qm-$rtf}&_a6RRHs-L*d&?%aIjzOv zZJf0?ycw}4=>eanz{18ytjtpD*12d?yea?}m;vKp6_?m!us0aUEJnWk4*myRf5TP< OURCgafD&%myY6>N0MPsZ literal 0 HcmV?d00001 diff --git a/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/pojo/StreamResponse.class b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/pojo/StreamResponse.class new file mode 100644 index 0000000000000000000000000000000000000000..93cfc5c32c4d99aa9d0ebb5482fa9eca35282a87 GIT binary patch literal 572 zcmb7B$xg#C5PeQULrS{Pma>%tw>AhO&MX%sq)KHGMZG(z)w;??lA`_=hYE=UAHYW; z#sLYTo;cX=&DihFc>MAC_730z2PQNI*N;P2EO?j%!p)LYMiVZ1AU*DJH;HGlJIqtT z!v~Qiag+%Y219+upSc_GXyV>^GvVh9njAAU2EPX+Bd;?CJrhq1tj}QNVnJ6+=Q5J{ zB}2EndcVJ#>WxTx6^}(3I;u9xsF7>8H?qL6X=4o~#hNxutSh!ivc^J=AUtCL7ulaX) zCu%%6q!xAh0-cb0C&pCg1ybJyk`FeZ!KNr6GzeSHD=N;>5_PAuM8i2=qV+;~4Q<-n zkwWvyVUwvIjG6}>PsiCVN6_G#D9`2u7j BcE|t# literal 0 HcmV?d00001 diff --git a/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/service/SpeechSynthesisService.class b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/classes/com/example/springaialibaba/service/SpeechSynthesisService.class new file mode 100644 index 0000000000000000000000000000000000000000..6a4974538f3675ab9b8db09c37dac64d0ee48b2b GIT binary patch literal 7137 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 xId2z + + + + + 智能客服 - 文本 + 语音 + + + +
+

🤖 智能客服 - 文本 + 语音

+ +
+ + +
+ +
+ + +
+ +
+ 状态:等待提问 +
+ +
+
📝 回答内容
+
+ (回答将在这里显示) +
+
+ + +
+ + + + diff --git a/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..e69de29 diff --git a/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..b4d318e --- /dev/null +++ b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,4 @@ +C:\Users\Mayn\IdeaProjects\StudySpringAI\StudySpringAI\SpringAIAlibaba\src\main\java\com\example\springaialibaba\controller\CustomerServiceController.java +C:\Users\Mayn\IdeaProjects\StudySpringAI\StudySpringAI\SpringAIAlibaba\src\main\java\com\example\springaialibaba\controller\Main.java +C:\Users\Mayn\IdeaProjects\StudySpringAI\StudySpringAI\SpringAIAlibaba\src\main\java\com\example\springaialibaba\service\SpeechSynthesisService.java +C:\Users\Mayn\IdeaProjects\StudySpringAI\StudySpringAI\SpringAIAlibaba\src\main\java\com\example\springaialibaba\SpringAiAlibabaApplication.java diff --git a/黄永兴学习笔记/智能客服demo/SpringAIAlibaba/target/test-classes/com/example/springaialibaba/SpringAiAlibabaApplicationTests.class b/黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/test-classes/com/example/springaialibaba/SpringAiAlibabaApplicationTests.class similarity index 100% rename from 黄永兴学习笔记/智能客服demo/SpringAIAlibaba/target/test-classes/com/example/springaialibaba/SpringAiAlibabaApplicationTests.class rename to 黄永兴学习笔记/智能客服案例/SpringAIAlibaba/target/test-classes/com/example/springaialibaba/SpringAiAlibabaApplicationTests.class