LocalWavFile.java 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. package com.telerobot.fs.robot.impl;
  2. import com.alibaba.fastjson.JSONArray;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.telerobot.fs.entity.dto.LlmAiphoneRes;
  5. import com.telerobot.fs.entity.dto.llm.CozeAccount;
  6. import com.telerobot.fs.entity.dto.llm.LlmAccount;
  7. import com.telerobot.fs.entity.pojo.LlmToolRequest;
  8. import com.telerobot.fs.robot.AbstractChatRobot;
  9. import com.telerobot.fs.utils.CommonUtils;
  10. import okhttp3.MediaType;
  11. import okhttp3.Request;
  12. import okhttp3.RequestBody;
  13. import okhttp3.Response;
  14. import org.apache.commons.lang.StringUtils;
  15. import org.apache.http.HttpStatus;
  16. import java.io.IOException;
  17. import java.util.List;
  18. public class LocalWavFile extends AbstractChatRobot {
  19. @Override
  20. public LlmAiphoneRes talkWithAiAgent(String question, Boolean... withKbResponse) {
  21. LlmAiphoneRes aiphoneRes = new LlmAiphoneRes();
  22. aiphoneRes.setStatus_code(1);
  23. aiphoneRes.setClose_phone(0);
  24. aiphoneRes.setIfcan_interrupt(0);
  25. // 获取随路数据
  26. JSONObject bizJson = new JSONObject();
  27. if (null != callDetail.getOutboundPhoneInfo()) {
  28. if (null != callDetail.getOutboundPhoneInfo().getBizJson()) {
  29. bizJson = JSONObject.parseObject(callDetail.getOutboundPhoneInfo().getBizJson());
  30. }
  31. }
  32. logger.info("随路数据:{}", bizJson);
  33. logger.info("模型接口地址:{}", getAccount().serverUrl);
  34. if (firstRound) {
  35. firstRound = false;
  36. String llmTips = ((LlmAccount) getAccount()).getLlmTips();
  37. String faqContent = ((LlmAccount) getAccount()).getFaqContext();
  38. String tips = llmTips;
  39. if (StringUtils.isNotBlank(faqContent)
  40. && !"-".equals(faqContent)) {
  41. tips = tips + "\r\n\r\n" + faqContent;
  42. }
  43. addDialogue(ROLE_SYSTEM, tips);
  44. String openingRemarks = replaceParams(llmAccountInfo.openingRemarks, bizJson);
  45. addDialogue(ROLE_ASSISTANT, openingRemarks);
  46. ttsTextCache.add(openingRemarks);
  47. if (StringUtils.isNotBlank(llmAccountInfo.openingRemarksWav)) {
  48. aiphoneRes.setTtsFilePathList(llmAccountInfo.openingRemarksWav);
  49. }
  50. if (StringUtils.isNotBlank(llmAccountInfo.transferToAgentTipsWav)) {
  51. llmAccountInfo.transferToAgentTips = llmAccountInfo.transferToAgentTipsWav;
  52. }
  53. if (StringUtils.isNotBlank(llmAccountInfo.hangupTipsWav)) {
  54. llmAccountInfo.hangupTips = llmAccountInfo.hangupTipsWav;
  55. }
  56. logger.info("{},openingRemarksWav:{}", this.uuid, aiphoneRes.getTtsFilePathList());
  57. aiphoneRes.setBody(openingRemarks);
  58. return aiphoneRes;
  59. } else {
  60. if (!StringUtils.isEmpty(question)) {
  61. addDialogue(ROLE_USER, question);
  62. } else {
  63. addDialogue(ROLE_USER, "NO_VOICE");
  64. String noVoiceTips = llmAccountInfo.customerNoVoiceTips;
  65. addDialogue(ROLE_ASSISTANT, noVoiceTips);
  66. ttsTextCache.add(noVoiceTips);
  67. if (StringUtils.isNotBlank(llmAccountInfo.customerNoVoiceTipsWav)) {
  68. aiphoneRes.setTtsFilePathList(llmAccountInfo.customerNoVoiceTipsWav);
  69. }
  70. logger.info("{},customerNoVoiceTipsWav:{}", this.uuid, aiphoneRes.getTtsFilePathList());
  71. aiphoneRes.setBody(noVoiceTips);
  72. return aiphoneRes;
  73. }
  74. try {
  75. JSONObject response = sendNoneStreamingRequest(aiphoneRes, llmRoundMessages, bizJson, question);
  76. if (null != response) {
  77. llmRoundMessages.add(response);
  78. } else {
  79. aiphoneRes.setStatus_code(0);
  80. }
  81. } catch (Throwable throwable) {
  82. aiphoneRes.setStatus_code(0);
  83. logger.error("{} talkWithAiAgent error: {} \n {}", uuid, throwable.toString(), CommonUtils.getStackTraceString(throwable.getStackTrace()));
  84. }
  85. return aiphoneRes;
  86. }
  87. }
  88. private JSONObject sendNoneStreamingRequest(LlmAiphoneRes aiphoneRes, List<JSONObject> messages, JSONObject bizJson, String question) throws IOException {
  89. JSONObject requestBody = new JSONObject();
  90. // 模型名称
  91. requestBody.put("model", ((LlmAccount)getAccount()).getModelName());
  92. // 流式响应
  93. requestBody.put("stream", false);
  94. JSONArray messagesArray = new JSONArray();
  95. messagesArray.addAll(messages);
  96. // 对话上下文(包括客户最近说的一句话)
  97. requestBody.put("messages", messagesArray);
  98. // 随路数据(即客户信息)
  99. requestBody.put("custInfo", bizJson);
  100. // 客户刚刚说的话
  101. requestBody.put("question", question);
  102. // 本通电话的唯一标识
  103. requestBody.put("uuid", uuid);
  104. logger.info("请求参数:{}", requestBody.toJSONString());
  105. RequestBody body = RequestBody.create(
  106. MediaType.parse("application/json"),
  107. requestBody.toJSONString()
  108. );
  109. Request request = new Request.Builder()
  110. .url(getAccount().serverUrl)
  111. .post(body)
  112. .addHeader("Content-Type", "application/json")
  113. .addHeader("Accept", "*/*")
  114. .addHeader("Connection", "keep-alive")
  115. .addHeader("Authorization", "Bearer " + ((LlmAccount)getAccount()).getApiKey())
  116. .build();
  117. try (Response response = CLIENT.newCall(request).execute()) {
  118. if (!response.isSuccessful()) {
  119. logger.error("Model api error: http-code={}, msg={}, url={}",
  120. response.code(),
  121. response.message(),
  122. getAccount().serverUrl
  123. );
  124. }
  125. String chatContent = "";
  126. // {"code":200, "data":{"choices":[{"delta":{"content":"xxxxxxx", "wavFilePath":"/home/Records/251224101457010001/20260113161253001914.wav"}}]}}
  127. JSONObject result = JSONObject.parseObject(response.body().string());
  128. logger.info("{} recv local response:{}", uuid, result);
  129. String wavFiles = "";
  130. if (result.getInteger("code") == 200 && null != result.getJSONObject("data")) {
  131. JSONArray choices = result.getJSONObject("data").getJSONArray("choices");
  132. if (null != choices && choices.size() > 0) {
  133. JSONObject delta = choices.getJSONObject(0).getJSONObject("delta");
  134. chatContent = delta.getString("content");
  135. wavFiles = delta.getString("wavFilePath");
  136. if (chatContent.contains(LlmToolRequest.TRANSFER_TO_AGENT)) {
  137. aiphoneRes.setTransferToAgent(1);
  138. logger.info("{} `TRANSFER_TO_AGENT` command detected. ", getTraceId());
  139. }
  140. if (chatContent.contains(LlmToolRequest.HANGUP)) {
  141. aiphoneRes.setClose_phone(1);
  142. logger.info("{} `HANGUP` command detected. ", getTraceId());
  143. }
  144. if (!StringUtils.isEmpty(chatContent)) {
  145. chatContent = chatContent.replace(LlmToolRequest.TRANSFER_TO_AGENT,"")
  146. .replace(LlmToolRequest.HANGUP,"")
  147. .replace("`","");
  148. ttsTextCache.add(chatContent);
  149. ttsTextLength += chatContent.length();
  150. }
  151. }
  152. }
  153. logger.info("{} recv llm response end flag. answer={}, wavFiles={}", this.uuid, chatContent, wavFiles);
  154. aiphoneRes.setTtsFilePathList(wavFiles);
  155. JSONObject finalResponse = new JSONObject();
  156. finalResponse.put("role", "assistant");
  157. finalResponse.put("content", chatContent);
  158. aiphoneRes.setBody(chatContent);
  159. return finalResponse;
  160. }
  161. }
  162. }