Agent 业务逻辑完善

This commit is contained in:
2026-01-17 16:44:56 +08:00
parent 914c69c2de
commit 8d0c1efd66
7 changed files with 181 additions and 93 deletions

View File

@@ -29,8 +29,8 @@ public class MyWebSocketClient {
try { try {
// 发送消息到服务端 // 发送消息到服务端
Map<String,String> map = new HashMap<>(); Map<String,String> map = new HashMap<>();
map.put("type", "contextual_update"); map.put("type", "transcript");
map.put("user_id", session.getId()); map.put("role", "user");
map.put("text", "你好,只回复一句话"); map.put("text", "你好,只回复一句话");
String s = JSONUtil.toJsonStr(map); String s = JSONUtil.toJsonStr(map);
session.getBasicRemote().sendText(s); session.getBasicRemote().sendText(s);
@@ -44,8 +44,8 @@ public class MyWebSocketClient {
Thread.sleep(2000); Thread.sleep(2000);
// 发送消息到服务端 // 发送消息到服务端
Map<String,String> map = new HashMap<>(); Map<String,String> map = new HashMap<>();
map.put("type", "contextual_update"); map.put("type", "transcript");
map.put("user_id", session.getId()); map.put("role", "user");
map.put("text", "你能回答我其他的嘛"); map.put("text", "你能回答我其他的嘛");
String s = JSONUtil.toJsonStr(map); String s = JSONUtil.toJsonStr(map);
session.getBasicRemote().sendText(s); session.getBasicRemote().sendText(s);
@@ -78,7 +78,7 @@ public class MyWebSocketClient {
// WebSocket服务端地址示例 // WebSocket服务端地址示例
String serverUri = "ws://vetti.hotake.cn/prod-api/voice-websocket/elevenLabsAgent/104"; String serverUri = "ws://vetti.hotake.cn/prod-api/voice-websocket/elevenLabsAgent/104";
try { try {
// 获取WebSocket容器 // 获取WebSocket容器c
WebSocketContainer container = ContainerProvider.getWebSocketContainer(); WebSocketContainer container = ContainerProvider.getWebSocketContainer();
// 连接服务端传入客户端端点实例和服务端URI // 连接服务端传入客户端端点实例和服务端URI
container.connectToServer(new MyWebSocketClient(), new URI(serverUri)); container.connectToServer(new MyWebSocketClient(), new URI(serverUri));

View File

@@ -0,0 +1,42 @@
package com.vetti.web.controller.ai;
import com.vetti.common.core.controller.BaseController;
import com.vetti.common.core.domain.R;
import com.vetti.hotake.domain.dto.HotakeJobDescriptionGeneratorDto;
import com.vetti.hotake.domain.vo.HotakeJobDescriptionGeneratorVo;
import com.vetti.hotake.service.IHotakeAiCommonToolsService;
import com.vetti.web.entity.dto.ConvAiTokenDto;
import com.vetti.web.service.IElevenLabsConvAiTokenClientService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* AI ElevemLabs Agent 信息Controller
*
* @author wangxiangshun
* @date 2025-12-14
*/
@Api(tags ="AI ElevemLabs Agent")
@RestController
@RequestMapping("/hotake/elevenLabsConvAi")
public class HotakeElevenLabsConvAiTokenClientController extends BaseController {
@Autowired
private IElevenLabsConvAiTokenClientService convAiTokenClientService;
/**
* 获取ElevemLabs Agent令牌
*/
@ApiOperation("获取ElevemLabs Agent令牌")
@PostMapping(value = "/getToken")
public R<ConvAiTokenDto> handleElevemLabsAgentToken()
{
return R.ok(convAiTokenClientService.getConvAiToken());
}
}

View File

@@ -0,0 +1,26 @@
package com.vetti.web.entity.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 获取ElevenLabs Agent token 信息对象
*
* @author wangxiangshun
* @date 2025-11-02
*/
@Data
@Accessors(chain = true)
public class ConvAiTokenDto {
@ApiModelProperty("核心对话Token")
private String token;
@ApiModelProperty("会话ID")
private String conversation_id;
@ApiModelProperty("Token过期时间时间戳")
private long expires_at;
}

View File

@@ -0,0 +1,25 @@
package com.vetti.web.entity.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 获取ElevenLabs Agent token 请求体 信息对象
*
* @author wangxiangshun
* @date 2025-11-02
*/
@Data
@Accessors(chain = true)
public class ConvAiTokenRequestVo {
@ApiModelProperty("Agent ID必填")
private String agent_id;
@ApiModelProperty("会话ID可选")
private String conversation_id;
@ApiModelProperty("用户ID可选")
private String user_id;
}

View File

@@ -1,4 +0,0 @@
package com.vetti.web.service;
public interface ElevenLabsConvAiTokenClientService {
}

View File

@@ -0,0 +1,17 @@
package com.vetti.web.service;
import com.vetti.web.entity.dto.ConvAiTokenDto;
/**
* ElevenLabs Agent 信息 服务类
*
* @author WangXiangShun
* @since 2025-08-27
*/
public interface IElevenLabsConvAiTokenClientService {
/**
* 获取ConvAI对话Token
* @return
*/
public ConvAiTokenDto getConvAiToken();
}

View File

@@ -1,111 +1,93 @@
package com.vetti.web.service.impl; package com.vetti.web.service.impl;
import com.google.gson.Gson; import cn.hutool.json.JSONUtil;
import com.vetti.common.exception.ServiceException;
import com.vetti.common.utils.SecurityUtils;
import com.vetti.web.entity.dto.ConvAiTokenDto;
import com.vetti.web.entity.vo.ConvAiTokenRequestVo;
import com.vetti.web.service.IElevenLabsConvAiTokenClientService;
import lombok.extern.slf4j.Slf4j;
import okhttp3.MediaType; import okhttp3.MediaType;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.RequestBody; import okhttp3.RequestBody;
import okhttp3.Response; import okhttp3.Response;
import org.springframework.stereotype.Service;
import java.io.IOException; import java.io.IOException;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class ElevenLabsConvAiTokenClientServiceImpl { /**
* ElevenLabs Agent 信息 服务实现类
*
* @author WangXiangShun
* @since 2025-08-27
*/
@Slf4j
@Service
public class ElevenLabsConvAiTokenClientServiceImpl implements IElevenLabsConvAiTokenClientService {
// ========== 配置项(替换为你的实际值) ========== // ========== 配置项(替换为你的实际值) ==========
private static final String XI_API_KEY = "sk_dfe2b45e19bf8ad93a71d3a0faa61619a91e817df549d116"; // 从ElevenLabs控制台获取 // 从ElevenLabs控制台获取
private static final String AGENT_ID = "agent_9401kd09yfjnes2vddz1n29wev2t"; // 如agent_9401kd09yfjnes2vddz1n29wev2t private static final String XI_API_KEY = "sk_dfe2b45e19bf8ad93a71d3a0faa61619a91e817df549d116";
private static final String TOKEN_API_URL = "https://api.elevenlabs.io/v1/convai/conversation/token"; // 如agent_9401kd09yfjnes2vddz1n29wev2t
private static final String AGENT_ID = "agent_9401kd09yfjnes2vddz1n29wev2t";
//请求地址
private static final String TOKEN_API_URL = "https://api.elevenlabs.io/v1/convai/conversation/token?agent_id=agent_9401kd09yfjnes2vddz1n29wev2t";
// JSON媒体类型 // JSON媒体类型
private static final MediaType JSON_MEDIA_TYPE = MediaType.get("application/json; charset=utf-8"); private static final MediaType JSON_MEDIA_TYPE = MediaType.get("application/json; charset=utf-8");
private final OkHttpClient client;
private final Gson gson;
// 构造方法:初始化客户端
public ElevenLabsConvAiTokenClientServiceImpl() {
// 初始化OkHttp客户端设置超时
this.client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.build();
this.gson = new Gson();
}
// ===================== 核心获取ConvAI Token ===================== // ===================== 核心获取ConvAI Token =====================
/** /**
* 获取ConvAI对话Token * 获取ConvAI对话Token
* @param conversationId 会话ID可选不传则自动生成
* @param userId 用户ID可选用于区分用户
* @return Token响应对象 * @return Token响应对象
* @throws IOException 网络/接口异常 * @throws IOException 网络/接口异常
*/ */
public ConvAiTokenResponse getConvAiToken(String conversationId, String userId) throws IOException { public ConvAiTokenDto getConvAiToken() {
// 1. 构造请求体 try {
ConvAiTokenRequest requestBody = new ConvAiTokenRequest(); // 用户ID可选用于区分用户
requestBody.setAgent_id(AGENT_ID); Long userId = SecurityUtils.getUserId();
// 会话ID不传则生成随机ID // 1. 构造请求体
requestBody.setConversation_id(conversationId == null ? UUID.randomUUID().toString() : conversationId); ConvAiTokenRequestVo requestBody = new ConvAiTokenRequestVo();
requestBody.setUser_id(userId); // 用户ID可选 requestBody.setAgent_id(AGENT_ID);
// 会话ID不传则生成随机ID
// 2. 构建HTTP请求 requestBody.setConversation_id(UUID.randomUUID().toString());
Request request = new Request.Builder() // 用户ID可选
.url(TOKEN_API_URL) requestBody.setUser_id(userId.toString());
// 核心鉴权添加XI-API-KEY头 // 2. 构建HTTP请求
.addHeader("xi-api-key", XI_API_KEY) Request request = new Request.Builder()
.addHeader("Content-Type", "application/json") .url(TOKEN_API_URL)
// 发送JSON请求体 // 核心鉴权添加XI-API-KEY头
.post(RequestBody.create(gson.toJson(requestBody), JSON_MEDIA_TYPE)) .addHeader("xi-api-key", XI_API_KEY)
.build(); .addHeader("Content-Type", "application/json")
.build();
// 3. 执行请求并解析响应 // 初始化OkHttp客户端设置超时
try (Response response = client.newCall(request).execute()) { OkHttpClient client = new OkHttpClient.Builder()
// 检查响应状态 .connectTimeout(10, TimeUnit.SECONDS)
if (!response.isSuccessful()) { .readTimeout(10, TimeUnit.SECONDS)
String errorBody = response.body() != null ? response.body().string() : "无错误信息"; .writeTimeout(10, TimeUnit.SECONDS)
throw new IOException("获取Token失败HTTP码=" + response.code() + ",错误信息=" + errorBody); .build();
// 3. 执行请求并解析响应
try (Response response = client.newCall(request).execute()) {
log.info("1-错误信息为:{}",JSONUtil.toJsonStr(response));
// 检查响应状态
if (!response.isSuccessful()) {
String errorBody = response.body() != null ? response.body().string() : "无错误信息";
log.info("2-错误信息为:{}",errorBody);
throw new IOException("Failed to obtain Token");
}
// 解析JSON响应为实体类
String responseBody = response.body().string();
log.info("3-获取令牌数据:{}", responseBody);
return JSONUtil.toBean(responseBody, ConvAiTokenDto.class);
} }
} catch (Exception e) {
// 解析JSON响应为实体类 e.printStackTrace();
String responseBody = response.body().string(); throw new ServiceException("Failed to obtain Token");
return gson.fromJson(responseBody, ConvAiTokenResponse.class);
} }
} }
// ===================== 数据模型(匹配接口格式) =====================
/**
* Token请求体对应接口入参
*/
static class ConvAiTokenRequest {
private String agent_id; // Agent ID必填
private String conversation_id; // 会话ID可选
private String user_id; // 用户ID可选
// Getter & Setter
public String getAgent_id() { return agent_id; }
public void setAgent_id(String agent_id) { this.agent_id = agent_id; }
public String getConversation_id() { return conversation_id; }
public void setConversation_id(String conversation_id) { this.conversation_id = conversation_id; }
public String getUser_id() { return user_id; }
public void setUser_id(String user_id) { this.user_id = user_id; }
}
/**
* Token响应体对应接口返回
*/
static class ConvAiTokenResponse {
private String token; // 核心对话Token
private String conversation_id; // 会话ID
private long expires_at; // Token过期时间时间戳
// Getter & Setter
public String getToken() { return token; }
public void setToken(String token) { this.token = token; }
public String getConversation_id() { return conversation_id; }
public void setConversation_id(String conversation_id) { this.conversation_id = conversation_id; }
public long getExpires_at() { return expires_at; }
public void setExpires_at(long expires_at) { this.expires_at = expires_at; }
}
// ===================== 测试主方法 ===================== // ===================== 测试主方法 =====================
// public static void main(String[] args) { // public static void main(String[] args) {
@@ -120,10 +102,10 @@ public class ElevenLabsConvAiTokenClientServiceImpl {
// System.out.println("会话ID" + response.getConversation_id()); // System.out.println("会话ID" + response.getConversation_id());
// System.out.println("过期时间(时间戳):" + response.getExpires_at()); // System.out.println("过期时间(时间戳):" + response.getExpires_at());
// //
//
// // 后续使用拼接WebSocket地址 // // 后续使用拼接WebSocket地址
// String wsUrl = "wss://api.elevenlabs.io/v1/convai/ws?token=" + response.getToken(); // String wsUrl = "wss://api.elevenlabs.io/v1/convai/ws?token=" + response.getToken();
// System.out.println("WebSocket连接地址" + wsUrl); // System.out.println("WebSocket连接地址" + wsUrl);
//
// } catch (IOException e) { // } catch (IOException e) {
// System.err.println("❌ 获取Token失败" + e.getMessage()); // System.err.println("❌ 获取Token失败" + e.getMessage());
// e.printStackTrace(); // e.printStackTrace();