feat(flow): 集成商道智能体平台功能
- 新增 LLM 智能体查询接口,支持文本输入调用 AI 服务 - 实现智能体任务异步执行和取消机制 - 集成 TTS 语音播放功能,支持播放和停止控制 - 添加智能体 API 密钥管理和参数配置 - 实现线程池管理和任务生命周期控制 - 增加异常处理和错误返回机制
This commit is contained in:
parent
6aaed4dacc
commit
9f462e41fc
@ -1,8 +1,12 @@
|
||||
package com.cmvr.web.controller.test;
|
||||
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.cmvr.common.annotation.Anonymous;
|
||||
import com.cmvr.common.core.controller.BaseController;
|
||||
import com.cmvr.common.core.domain.AjaxResult;
|
||||
import com.cmvr.llm.service.LLMAiAgentPlatformService;
|
||||
import com.cmvr.test.flow.context.TaskContextManager;
|
||||
import com.cmvr.test.flow.control.FlowControlService;
|
||||
import com.cmvr.test.flow.runtime.engine.FlowTaskRuntimeService;
|
||||
@ -26,9 +30,15 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
import javax.validation.Valid;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
@Api(tags = "测试--流程服务")
|
||||
@RestController
|
||||
@ -36,6 +46,21 @@ import java.util.List;
|
||||
@RequiredArgsConstructor
|
||||
public class TeFlowController extends BaseController {
|
||||
|
||||
/**
|
||||
* TTS 播放接口,当前按需求固定写死在 Controller 中。
|
||||
*/
|
||||
private static final String TTS_PLAY_URL = "http://localhost:8080/tts/play";
|
||||
|
||||
/**
|
||||
* TTS 停止接口,停止智能体输出时同步调用。
|
||||
*/
|
||||
private static final String TTS_STOP_URL = "http://localhost:8080/tts/stop";
|
||||
|
||||
/**
|
||||
* 商道智能体 AppKey,当前按需求固定写死,不放入配置文件。
|
||||
*/
|
||||
private static final String AI_AGENT_API_KEY = "d9etum54shheenol3apg";
|
||||
|
||||
private final ITeDetectionItemService teDetectionItemService;
|
||||
private final ITeNodeInstService nodeInstService;
|
||||
private final FlowTaskRuntimeService flowTaskRuntimeService;
|
||||
@ -43,14 +68,29 @@ public class TeFlowController extends BaseController {
|
||||
private final FlowControlService flowControlService;
|
||||
private final FlowActionExecutorService flowActionExecutorService;
|
||||
private final TiTouchOperateService tiTouchOperateService;
|
||||
private final LLMAiAgentPlatformService llmAiAgentPlatformService;
|
||||
private final List<String> taskInstIdList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 智能体调用是阻塞式 query,这里用单线程保存当前任务句柄,便于 stop 接口中断当前请求。
|
||||
*/
|
||||
private final ExecutorService aiAgentExecutor = Executors.newSingleThreadExecutor(runnable -> {
|
||||
Thread thread = new Thread(runnable, "flow-ai-agent-query");
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
});
|
||||
|
||||
/**
|
||||
* 当前正在执行的智能体任务。当前接口按“同一时间只保留一个前端智能体调用”处理。
|
||||
*/
|
||||
private volatile Future<JSONObject> currentAiAgentFuture;
|
||||
|
||||
@ApiOperation("流程发布")
|
||||
@PostMapping("/publish")
|
||||
public AjaxResult publish(@RequestBody TeDetectionItem detectionItem) {
|
||||
return toAjax(teDetectionItemService.publish(detectionItem.getId()));
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation("演示任务执行入口")
|
||||
@PostMapping("/demo")
|
||||
@Anonymous
|
||||
@ -59,7 +99,7 @@ public class TeFlowController extends BaseController {
|
||||
try {
|
||||
taskInstIdList.forEach(flowControlService::stop);
|
||||
} catch (Exception e) {
|
||||
// 忽略
|
||||
// 演示入口清理旧任务失败时继续启动新任务,避免影响手动调试。
|
||||
}
|
||||
taskInstIdList.clear();
|
||||
}
|
||||
@ -121,10 +161,110 @@ public class TeFlowController extends BaseController {
|
||||
return AjaxResult.ok(flowActionExecutorService.actionExecute(flowActionRequestVO));
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用商道智能体平台。
|
||||
*
|
||||
* <p>前端只需要传入 text。后端固定 action、apiKey 和 TTS 参数。
|
||||
* 调用会放入可取消任务中,前端可以通过 /flow/llm/stop 停止当前调用并停止 TTS。</p>
|
||||
*/
|
||||
@GetMapping("/llm/query")
|
||||
@ApiOperation("调用商道智能体")
|
||||
public AjaxResult queryAiAgent(String text) {
|
||||
if (text == null || text.trim().isEmpty()) {
|
||||
return AjaxResult.error("text不能为空");
|
||||
}
|
||||
|
||||
stopCurrentAiAgentFuture(true);
|
||||
|
||||
JSONObject params = new JSONObject();
|
||||
params.put("url", TTS_PLAY_URL);
|
||||
params.put("voice", "x4_yezi");
|
||||
params.put("speed", 45);
|
||||
params.put("volume", 100);
|
||||
|
||||
Future<JSONObject> future = aiAgentExecutor.submit(() -> llmAiAgentPlatformService.query(
|
||||
null,
|
||||
text.trim(),
|
||||
AI_AGENT_API_KEY,
|
||||
true,
|
||||
params
|
||||
));
|
||||
currentAiAgentFuture = future;
|
||||
|
||||
try {
|
||||
return AjaxResult.ok(future.get());
|
||||
} catch (CancellationException e) {
|
||||
return AjaxResult.error("智能体调用已停止");
|
||||
} catch (InterruptedException e) {
|
||||
future.cancel(true);
|
||||
Thread.currentThread().interrupt();
|
||||
return AjaxResult.error("智能体调用被中断");
|
||||
} catch (ExecutionException e) {
|
||||
Throwable cause = e.getCause() == null ? e : e.getCause();
|
||||
return AjaxResult.error("智能体调用失败:" + cause.getMessage());
|
||||
} finally {
|
||||
if (currentAiAgentFuture == future) {
|
||||
currentAiAgentFuture = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止当前智能体调用,并通知 TTS 服务停止播放。
|
||||
*
|
||||
* <p>停止分两步:先取消当前 query 任务,触发底层 SSE 等待线程中断;
|
||||
* 再调用本地 TTS stop 接口,停止已经进入播放队列的音频。</p>
|
||||
*/
|
||||
@PostMapping("/llm/stop")
|
||||
@ApiOperation("停止商道智能体和TTS")
|
||||
public AjaxResult stopAiAgent() {
|
||||
stopCurrentAiAgentFuture(false);
|
||||
// String ttsStopResult = stopTts();
|
||||
return AjaxResult.ok("ok");
|
||||
}
|
||||
|
||||
@GetMapping("/testrun")
|
||||
@ApiOperation("测试接口")
|
||||
public AjaxResult testrun(@RequestParam("imageUrl") String imageUrl,
|
||||
@RequestParam("iconUrl") String iconUrl) {
|
||||
return AjaxResult.ok(tiTouchOperateService.test(imageUrl, iconUrl));
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消当前智能体任务。
|
||||
*
|
||||
* @param stopTts 是否同时停止 TTS 播放
|
||||
*/
|
||||
private void stopCurrentAiAgentFuture(boolean stopTts) {
|
||||
Future<JSONObject> future = currentAiAgentFuture;
|
||||
if (future != null && !future.isDone()) {
|
||||
future.cancel(true);
|
||||
}
|
||||
currentAiAgentFuture = null;
|
||||
if (stopTts) {
|
||||
stopTts();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用本地 TTS 停止接口。
|
||||
*/
|
||||
private String stopTts() {
|
||||
try (HttpResponse response = HttpRequest.post(TTS_STOP_URL)
|
||||
.timeout(3000)
|
||||
.execute()) {
|
||||
return response.body();
|
||||
} catch (Exception e) {
|
||||
return "调用TTS停止接口失败:" + e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Spring 容器关闭时释放智能体执行线程。
|
||||
*/
|
||||
@PreDestroy
|
||||
public void destroy() {
|
||||
stopCurrentAiAgentFuture(true);
|
||||
aiAgentExecutor.shutdownNow();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user