package com.xly.web; import cn.hutool.core.util.ObjectUtil; import com.xly.runner.AppStartupRunner; import com.xly.service.UserSceneSessionService; import com.xly.tool.DynamicToolProvider; import com.xly.tts.bean.*; import com.xly.tts.service.LocalAudioCache; import com.xly.tts.service.PythonTtsProxyService; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.core.io.InputStreamResource; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.io.InputStream; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @Slf4j @RestController @RequestMapping("/api/tts") @RequiredArgsConstructor public class TTSStreamController { private final PythonTtsProxyService pythonTtsProxyService; private final DynamicToolProvider dynamicToolProvider; private final UserSceneSessionService userSceneSessionService; private final AppStartupRunner appStartupRunner; /*** * @Author 钱豹 * @Date 14:32 2026/2/10 * @Param [request] * @return org.springframework.http.ResponseEntity * @Description 初始化AI所有变量 热启动 **/ @PostMapping("/initTool") public ResponseEntity initTool(@RequestBody TTSRequestDTO request) { appStartupRunner.cleanAllInit(); userSceneSessionService.cleanAllSession(); dynamicToolProvider.cleanAllToolProvider(); //方法重新初始化 dynamicToolProvider.init(); return pythonTtsProxyService.initTool(request); } /** * 提取报修结构化信息 */ @PostMapping(value="/init", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.ALL_VALUE}) public ResponseEntity init(@RequestBody TTSRequestDTO request) { return pythonTtsProxyService.init(request); } @PostConstruct public void init() { log.info("TTS Stream Controller initialized"); log.info("Python TTS Service URL: http://localhost:8000"); } @PreDestroy public void cleanup() { log.info("TTS Stream Controller shutting down"); pythonTtsProxyService.shutdown(); } /** * 流式合成语音(代理到Python服务) */ @PostMapping(value = "/stream/query", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.ALL_VALUE}) public ResponseEntity stream(@RequestBody TTSRequestDTO request) { return pythonTtsProxyService.synthesizeStreamAi(request); } /** * 流式合成语音(代理到Python服务) */ @PostMapping(value = "/stream/queryFlux", consumes = {MediaType.APPLICATION_JSON_VALUE}, produces = {MediaType.APPLICATION_OCTET_STREAM_VALUE, MediaType.APPLICATION_JSON_VALUE}) public Flux streamFlux(@Valid @RequestBody Mono requestMono) { return requestMono.flatMapMany(request -> { log.info("处理请求: requestId={}, text长度={}", request.getUserid(), request.getText().length()); return pythonTtsProxyService.synthesizeStreamAiStream(request); }) .doOnSubscribe(sub -> log.debug("流式订阅开始")) .doOnCancel(() -> log.debug("流式请求被取消")) .doOnComplete(() -> log.debug("流式响应完成")) .doOnError(e -> log.error("流式处理错误", e)); } @GetMapping("/audio/piece") public ResponseEntity> getPiece( @RequestParam String cacheKey, @RequestParam int index) { return ResponseEntity.ok(LocalAudioCache.getPiece(cacheKey, index)); } /** * 流式合成语音(代理到Python服务) */ @PostMapping("/cleanMemory") public ResponseEntity cleanMemory(@RequestBody TTSRequestDTO request) { return pythonTtsProxyService.cleanMemory(request); } /** * 流式合成语音(异步) */ @PostMapping("/async-stream") public CompletableFuture> asyncStreamSynthesize( @RequestBody TTSRequestDTO request) { log.info("收到异步流式合成请求"); return pythonTtsProxyService.synthesizeStreamAsync(request); } /** * 直接调用Python服务合成 */ @PostMapping("/direct-stream") public ResponseEntity directStreamSynthesize(@RequestBody TTSRequestDTO request) { log.info("收到直接合成请求"); return pythonTtsProxyService.synthesizeDirect(request); } /** * 简化的流式接口 */ @PostMapping("/quick-stream") public ResponseEntity quickStream( @RequestParam String text, @RequestParam(defaultValue = "zh-CN-XiaoxiaoNeural") String voice) { log.info("收到快速合成请求: voice={}, text={}", voice, text.length() > 50 ? text.substring(0, 50) + "..." : text); return pythonTtsProxyService.quickSynthesize(text, voice); } /** * GET方式的快速合成接口 */ @GetMapping("/quick-stream") public ResponseEntity quickStreamGet( @RequestParam String text, @RequestParam(defaultValue = "zh-CN-XiaoxiaoNeural") String voice) { return quickStream(text, voice); } /** * 获取所有可用语音 */ @GetMapping("/voices") public ResponseEntity> getVoices() { log.info("收到获取语音列表请求"); List voices = pythonTtsProxyService.getAvailableVoices(); return ResponseEntity.ok(voices); } /** * 获取特定语音详情 */ @GetMapping("/voices/{name}") public ResponseEntity getVoiceDetail(@PathVariable String name) { log.info("收到获取语音详情请求: {}", name); VoiceInfoDTO voice = pythonTtsProxyService.getVoiceDetail(name); if (voice != null) { return ResponseEntity.ok(voice); } else { return ResponseEntity.notFound().build(); } } /** * 健康检查(同时检查Java服务和Python服务) */ @GetMapping("/health") public ResponseEntity healthCheck() { boolean pythonServiceHealthy = pythonTtsProxyService.healthCheck(); HealthStatus healthStatus = new HealthStatus(); healthStatus.setJavaService("healthy"); healthStatus.setPythonService(pythonServiceHealthy ? "healthy" : "unhealthy"); healthStatus.setTimestamp(System.currentTimeMillis()); healthStatus.setMessage(pythonServiceHealthy ? "所有服务运行正常" : "Python TTS服务不可用"); if (pythonServiceHealthy) { return ResponseEntity.ok(healthStatus); } else { return ResponseEntity.status(503).body(healthStatus); } } /** * 简单健康检查(仅返回状态) */ @GetMapping("/health/simple") public ResponseEntity healthCheckSimple() { boolean pythonServiceHealthy = pythonTtsProxyService.healthCheck(); if (pythonServiceHealthy) { return ResponseEntity.ok("TTS服务运行正常"); } else { return ResponseEntity.status(503).body("Python TTS服务不可用"); } } /** * 批处理合成 */ @PostMapping("/batch") public ResponseEntity>> batchSynthesize( @RequestBody List requests) { log.info("收到批量合成请求,数量: {}", requests.size()); List> results = pythonTtsProxyService.batchSynthesize(requests); return ResponseEntity.ok(results); } /** * 测试接口 */ @GetMapping("/test") public ResponseEntity testSynthesis() { log.info("收到测试请求"); TTSRequestDTO request = new TTSRequestDTO(); request.setText("这是一个测试语音,用于验证Edge-TTS服务是否正常工作。"); request.setVoice("zh-CN-XiaoxiaoNeural"); return pythonTtsProxyService.synthesizeStream(request); } /** * 状态接口 */ @GetMapping("/status") public ResponseEntity getStatus() { ServiceStatus status = new ServiceStatus(); status.setJavaService(true); status.setPythonService(pythonTtsProxyService.healthCheck()); status.setServiceUrl("http://localhost:8000"); status.setJavaApiUrl("/api/tts"); status.setTimestamp(new java.util.Date()); return ResponseEntity.ok(status); } }