GRPCController.java 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931
  1. package com.slibra.web.controller.business;
  2. import com.alibaba.fastjson2.JSONObject;
  3. import com.alibaba.fastjson2.JSONWriter;
  4. import com.alibaba.fastjson2.JSON;
  5. import com.google.protobuf.ByteString;
  6. import com.slibra.business.domain.*;
  7. import com.slibra.business.mapper.*;
  8. import com.slibra.business.req.*;
  9. import com.slibra.business.res.WorkOrderRes;
  10. import com.slibra.business.service.IFrontService;
  11. import com.slibra.common.DecimalUtils;
  12. import com.slibra.common.config.BigModelConfig;
  13. import com.slibra.common.constant.MyConstants;
  14. import com.slibra.common.core.controller.BaseController;
  15. import com.slibra.common.core.domain.DecisionReq;
  16. import com.slibra.common.core.domain.TXinyiDaily;
  17. import com.slibra.common.enums.BusinessEnum;
  18. import com.slibra.common.exception.ServiceException;
  19. import com.slibra.common.utils.DateUtils;
  20. import com.slibra.common.utils.SecurityUtils;
  21. import com.slibra.common.utils.StringUtils;
  22. import com.slibra.common.utils.format.WaterFormat;
  23. import com.slibra.common.utils.ip.IpUtils;
  24. import com.slibra.common.utils.uuid.IdUtils;
  25. import io.grpc.ManagedChannel;
  26. import io.grpc.ManagedChannelBuilder;
  27. import lombok.extern.slf4j.Slf4j;
  28. import org.pytorch.serve.grpc.inference.InferenceAPIsServiceGrpc;
  29. import org.pytorch.serve.grpc.inference.PredictionResponse;
  30. import org.pytorch.serve.grpc.inference.PredictionsRequest;
  31. import org.springframework.beans.BeanUtils;
  32. import org.springframework.beans.factory.annotation.Autowired;
  33. import org.springframework.util.CollectionUtils;
  34. import org.springframework.web.bind.annotation.*;
  35. import javax.servlet.http.HttpServletResponse;
  36. import java.io.IOException;
  37. import java.io.OutputStream;
  38. import java.math.BigDecimal;
  39. import java.math.RoundingMode;
  40. import java.util.*;
  41. import static com.slibra.common.constant.MyConstants.*;
  42. import static com.slibra.common.enums.BusinessEnum.BigModelBizEnum.DECISION_REPORT;
  43. import static com.slibra.common.enums.BusinessEnum.WarningCategoryEnum.*;
  44. import static com.slibra.common.enums.BusinessEnum.WarningCategoryEnum.CS_ZL;
  45. /**
  46. * 告警相关
  47. */
  48. @RestController
  49. @RequestMapping("/grpc")
  50. @Slf4j
  51. public class GRPCController extends BaseController {
  52. @Autowired
  53. private TXinyiChatRecordMapper chatRecordMapper;
  54. @Autowired
  55. private TXinyiIndustryMapper xinyiIndustryMapper;
  56. @Autowired
  57. private TXinyiDailyMapper xinyiDailyMapper;
  58. @Autowired
  59. private TXinyiChatRecordMapper xinyiChatRecordMapper;
  60. @Autowired
  61. private TXinyiWarningRecordMapper xinyiWarningRecordMapper;
  62. @Autowired
  63. private IFrontService frontService;
  64. @Autowired
  65. private TXinyiNormConfigMapper xinyiNormConfigMapper;
  66. @Autowired
  67. private BigModelConfig bigModelConfig;
  68. /**
  69. *
  70. * get请求测试决策输出
  71. *
  72. * @param response
  73. */
  74. @GetMapping(value = "/test/aaa")
  75. public void decisionStreamTest(HttpServletResponse response)
  76. // public void decisionStream(HttpServletResponse response, ChatReq chatReq)
  77. {
  78. log.info("进入了调⽤大模型决策接口");
  79. ChatReq chatReq = new ChatReq();
  80. HashMap<String, Object> map = new HashMap<>();
  81. map.put("2_2", "正常");
  82. map.put("4_25", "没有");
  83. map.put("2_28", "否");
  84. map.put("6_3", "超标");
  85. chatReq.setFeedback(JSON.toJSONString(map));
  86. chatReq.setCategory("出水氨氮");
  87. chatReq.setWarningId("782");
  88. chatReq.setSimulate("{}");
  89. // 获取输出流
  90. OutputStream outputStream = null;
  91. ManagedChannel channel = null;
  92. //response.setContentType("text/plain");
  93. response.setContentType("text/event-stream");
  94. response.setCharacterEncoding("utf-8");
  95. //2024年5月29日14:15:58 新增逻辑,判断报警状态是否已经结束了,如果结束了就直接模拟一个report返回给前端,不再调用大模型
  96. String warningId = chatReq.getWarningId();
  97. if(StringUtils.isBlank(warningId))
  98. throw new ServiceException("请输入正确的告警id");
  99. TXinyiWarningRecord xinyiWarningRecord = this.xinyiWarningRecordMapper.selectTXinyiWarningRecordById(Long.parseLong(warningId));
  100. if(Objects.isNull(xinyiWarningRecord))
  101. throw new ServiceException("请输入正确的告警id,没有查询到告警信息");
  102. if(1 == xinyiWarningRecord.getStatus() || 2 == xinyiWarningRecord.getStatus()){
  103. //已经关闭的报警,不允许再次点击报警了
  104. String message = this.buildMsg();
  105. try {
  106. outputStream = response.getOutputStream();
  107. outputStream.write(message.getBytes());
  108. outputStream.flush();
  109. return;//输出完提示信息就结束
  110. } catch (IOException e) {
  111. throw new RuntimeException(e);
  112. }
  113. }
  114. StringBuilder sb = new StringBuilder();
  115. //大模型结果 放入一个结合中
  116. List<String> resultData = new ArrayList<>();
  117. //决策和问答不一样 没有历史的概念 所以sessionId都是新的 次数都是1
  118. String sessionId = IdUtils.simpleUUID();
  119. String feedback = chatReq.getFeedback();
  120. String simulate = chatReq.getSimulate();
  121. int type = 3;//仿真预测
  122. if(StringUtils.isBlank(simulate) || "{}".equals(simulate))
  123. type = 1;//决策
  124. //决策请求的业务参数
  125. List<DecisionReq> decisionReqs = getDecisionReqs();
  126. // String rows = JSON.toJSONString(decisionReqs, JSONWriter.Feature.WriteNulls);
  127. boolean needAdd = true;//标识变量是否可以保存
  128. String dataJson = "";
  129. try {
  130. channel = ManagedChannelBuilder.forAddress(bigModelConfig.getIp(), bigModelConfig.getPort())
  131. .usePlaintext()
  132. .build();
  133. InferenceAPIsServiceGrpc.InferenceAPIsServiceBlockingStub stub = InferenceAPIsServiceGrpc.newBlockingStub(channel);
  134. // dataJson = "{\"bot_id\":\"b00001\",\"exp_id\":\"721\",\"norm\":\"" + chatReq.getCategory() + "\",\"feedback\":" + feedback + ",\"simulate\":" + simulate + ",\"session_id\":" + "\"" + sessionId + "\"" + ",\"generate_args\":{\"max_new_tokens\":1024,\"max_length\":4096,\"num_beams\":1,\"do_sample\":true,\"top_p\":0.7,\"temperature\":0.95},\"extra\":{\"rows\":" + rows + "}}";
  135. //2024年6月24日17:59:17 优化,不再拼接JSON字符串
  136. dataJson = buildBigModelReqForDecision(chatReq, feedback, simulate, sessionId, decisionReqs, xinyiWarningRecord, chatReq.getTopP(), chatReq.getTemperature());
  137. // log.info("请求大模型的决策的参数为{}", dataJson);
  138. PredictionsRequest request = PredictionsRequest.newBuilder()
  139. .setModelName("slibra_bot")
  140. .putInput("method", ByteString.copyFrom("decision_stream", "utf-8"))//推理
  141. .putInput("data", ByteString.copyFrom(dataJson, "utf-8"))
  142. .buildPartial();
  143. outputStream = response.getOutputStream();
  144. Iterator<PredictionResponse> predictions = stub.streamPredictions(request);
  145. int i = 0 ;
  146. while (predictions.hasNext()) {
  147. String responseStr = predictions.next().getPrediction().toStringUtf8();
  148. // log.info("决策流式返回的结果是{}", responseStr);
  149. if(StringUtils.isBlank(responseStr)){
  150. log.info("大模型返回的流式决策内容存在空的值,跳过此次输出");
  151. continue;
  152. }
  153. String message = JSON.parseObject(responseStr).getString("message");
  154. //2024年5月25日16:37:16 按照大模型返回的类型解析数据
  155. String biz = JSON.parseObject(responseStr).getString("biz");
  156. // String message = JSON.parseObject(responseStr).getString("message");
  157. if(BusinessEnum.BigModelBizEnum.OK.getCode().equals(biz)){
  158. log.info("结尾语句并且是非JSON,无需处理,返回数据为{}", responseStr);
  159. //结束语句也流式输出,但是并不记录下来 2024年5月24日11:15:23 也不返回前端
  160. }else if(BusinessEnum.BigModelBizEnum.DECISION_DEBUGGER.getCode().equals(biz)){
  161. log.info("中间过程,目前只打印日志,不记录数据,也不返回给前端,返回数据为{}", responseStr);
  162. //结束语句也流式输出,但是并不记录下来 2024年5月24日11:15:23 也不返回前端
  163. //2024年6月23日14:55:19 如果大模型返回error了,不保存记录,并且提示一句错误语
  164. }else if(BusinessEnum.BigModelBizEnum.ERROR.getCode().equalsIgnoreCase(biz)){
  165. log.info("调用大模型的时候,返回的是ERROR,返回数据为{}", responseStr);
  166. needAdd = false;
  167. //返回的是error 给前端返回一句话
  168. try {
  169. String errMsg = this.buildErrMsg();
  170. outputStream.write(errMsg.getBytes());
  171. outputStream.flush();
  172. } catch (IOException ex) {
  173. throw new RuntimeException(ex);
  174. }
  175. } else{//其他 要么alert 要么出的报告
  176. // if(StringUtils.isBlank(message)){
  177. // log.info("×××××××××××××××××××××××××××为空的数据暂时不返回×××××××××××××××××××××××××××");
  178. // }else {
  179. // log.info("返回给前端的数据是{}", responseStr);
  180. resultData.add(responseStr);
  181. responseStr = responseStr + (i++) + "\n";
  182. outputStream.write(responseStr.getBytes());
  183. outputStream.flush();
  184. //2024年7月12日17:47:08 加个打印,处理只要report类型的拼接结果
  185. if(BusinessEnum.BigModelBizEnum.DECISION_REPORT.getCode().equalsIgnoreCase(biz)){
  186. sb.append(message);
  187. }
  188. // }
  189. }
  190. }
  191. } catch (Exception e) {
  192. // throw new RuntimeException(e);
  193. log.error("处理大模型推理异常,异常信息为{}", JSON.toJSONString(e));
  194. //出现异常 给前端返回一句话
  195. try {
  196. outputStream = response.getOutputStream();
  197. String errMsg = this.buildErrMsg();
  198. outputStream.write(errMsg.getBytes());
  199. outputStream.flush();
  200. } catch (IOException ex) {
  201. throw new RuntimeException(ex);
  202. }
  203. } finally {
  204. // log.info("sessionId是{}\n决策最终要保存的数据是{}", sessionId, JSON.toJSONString(resultData));
  205. // log.info("~~~~~~~~~~~~~~~决策最终返回的报告数据是{}", sb.toString());
  206. //保存聊天记录
  207. //将问答更新到数据库中
  208. needAdd = false;
  209. if(needAdd)
  210. addChatRecord(chatReq, sessionId, type, warningId, dataJson, resultData);
  211. // 关闭输出流
  212. try {
  213. outputStream.close();
  214. } catch (IOException e) {
  215. throw new RuntimeException(e);
  216. }finally {
  217. channel.shutdown();
  218. }
  219. }
  220. }
  221. /**
  222. * 调⽤大模型决策接口 + 仿真预测
  223. * @return
  224. */
  225. @PostMapping(value = "/decisionStream")
  226. public void decisionStream(HttpServletResponse response, @RequestBody ChatReq chatReq)
  227. // public void decisionStream(HttpServletResponse response, ChatReq chatReq)
  228. {
  229. log.info("进入了调⽤大模型决策接口");
  230. // 获取输出流
  231. OutputStream outputStream = null;
  232. ManagedChannel channel = null;
  233. //response.setContentType("text/plain");
  234. response.setContentType("text/event-stream");
  235. response.setCharacterEncoding("utf-8");
  236. //2024年5月29日14:15:58 新增逻辑,判断报警状态是否已经结束了,如果结束了就直接模拟一个report返回给前端,不再调用大模型
  237. String warningId = chatReq.getWarningId();
  238. if(StringUtils.isBlank(warningId))
  239. throw new ServiceException("请输入正确的告警id");
  240. TXinyiWarningRecord xinyiWarningRecord = this.xinyiWarningRecordMapper.selectTXinyiWarningRecordById(Long.parseLong(warningId));
  241. if(Objects.isNull(xinyiWarningRecord))
  242. throw new ServiceException("请输入正确的告警id,没有查询到告警信息");
  243. if(1 == xinyiWarningRecord.getStatus() || 2 == xinyiWarningRecord.getStatus()){
  244. //已经关闭的报警,不允许再次点击报警了
  245. String message = this.buildMsg();
  246. try {
  247. outputStream = response.getOutputStream();
  248. outputStream.write(message.getBytes());
  249. outputStream.flush();
  250. return;//输出完提示信息就结束
  251. } catch (IOException e) {
  252. throw new RuntimeException(e);
  253. }
  254. }
  255. // StringBuilder sb = new StringBuilder();
  256. //大模型结果 放入一个结合中
  257. List<String> resultData = new ArrayList<>();
  258. //决策和问答不一样 没有历史的概念 所以sessionId都是新的 次数都是1
  259. String sessionId = IdUtils.simpleUUID();
  260. String feedback = chatReq.getFeedback();
  261. String simulate = chatReq.getSimulate();
  262. int type = 3;//仿真预测
  263. if(StringUtils.isBlank(simulate) || "{}".equals(simulate))
  264. type = 1;//决策
  265. //决策请求的业务参数
  266. List<DecisionReq> decisionReqs = getDecisionReqs();
  267. // String rows = JSON.toJSONString(decisionReqs, JSONWriter.Feature.WriteNulls);
  268. boolean needAdd = true;//标识变量是否可以保存
  269. String dataJson = "";
  270. try {
  271. channel = ManagedChannelBuilder.forAddress(bigModelConfig.getIp(), bigModelConfig.getPort())
  272. .usePlaintext()
  273. .build();
  274. InferenceAPIsServiceGrpc.InferenceAPIsServiceBlockingStub stub = InferenceAPIsServiceGrpc.newBlockingStub(channel);
  275. // dataJson = "{\"bot_id\":\"b00001\",\"exp_id\":\"721\",\"norm\":\"" + chatReq.getCategory() + "\",\"feedback\":" + feedback + ",\"simulate\":" + simulate + ",\"session_id\":" + "\"" + sessionId + "\"" + ",\"generate_args\":{\"max_new_tokens\":1024,\"max_length\":4096,\"num_beams\":1,\"do_sample\":true,\"top_p\":0.7,\"temperature\":0.95},\"extra\":{\"rows\":" + rows + "}}";
  276. //2024年6月24日17:59:17 优化,不再拼接JSON字符串
  277. dataJson = buildBigModelReqForDecision(chatReq, feedback, simulate, sessionId, decisionReqs, xinyiWarningRecord, chatReq.getTopP(), chatReq.getTemperature());
  278. // log.info("请求大模型的决策的参数为{}", dataJson);
  279. PredictionsRequest request = PredictionsRequest.newBuilder()
  280. .setModelName("slibra_bot")
  281. .putInput("method", ByteString.copyFrom("decision_stream", "utf-8"))//推理
  282. .putInput("data", ByteString.copyFrom(dataJson, "utf-8"))
  283. .buildPartial();
  284. outputStream = response.getOutputStream();
  285. Iterator<PredictionResponse> predictions = stub.streamPredictions(request);
  286. while (predictions.hasNext()) {
  287. String responseStr = predictions.next().getPrediction().toStringUtf8();
  288. // log.info("决策流式返回的结果是{}", responseStr);
  289. if(StringUtils.isBlank(responseStr)){
  290. log.info("大模型返回的流式决策内容存在空的值,跳过此次输出");
  291. continue;
  292. }
  293. // String message = JSON.parseObject(responseStr).getString("message");
  294. //2024年5月25日16:37:16 按照大模型返回的类型解析数据
  295. String biz = JSON.parseObject(responseStr).getString("biz");
  296. // String message = JSON.parseObject(responseStr).getString("message");
  297. if(BusinessEnum.BigModelBizEnum.OK.getCode().equals(biz)){
  298. log.info("结尾语句并且是非JSON,无需处理,返回数据为{}", responseStr);
  299. //结束语句也流式输出,但是并不记录下来 2024年5月24日11:15:23 也不返回前端
  300. }else if(BusinessEnum.BigModelBizEnum.DECISION_DEBUGGER.getCode().equals(biz)){
  301. log.info("中间过程,目前只打印日志,不记录数据,也不返回给前端,返回数据为{}", responseStr);
  302. //结束语句也流式输出,但是并不记录下来 2024年5月24日11:15:23 也不返回前端
  303. //2024年6月23日14:55:19 如果大模型返回error了,不保存记录,并且提示一句错误语
  304. }else if(BusinessEnum.BigModelBizEnum.ERROR.getCode().equalsIgnoreCase(biz)){
  305. log.info("调用大模型的时候,返回的是ERROR,返回数据为{}", responseStr);
  306. needAdd = false;
  307. //返回的是error 给前端返回一句话
  308. try {
  309. String errMsg = this.buildErrMsg();
  310. outputStream.write(errMsg.getBytes());
  311. outputStream.flush();
  312. } catch (IOException ex) {
  313. throw new RuntimeException(ex);
  314. }
  315. } else{//其他 要么alert 要么出的报告
  316. // sb.append(responseStr);
  317. //2024年7月13日13:48:48 空的数据也返回,否则样式会有问题(当时加上这个是为了前端正常解析,否则他那里一次接受多个)
  318. /*if(StringUtils.isBlank(message)){
  319. log.info("×××××××××××××××××××××××××××为空的数据暂时不返回×××××××××××××××××××××××××××");
  320. }else {
  321. resultData.add(responseStr);
  322. outputStream.write(responseStr.getBytes());
  323. outputStream.flush();
  324. }*/
  325. resultData.add(responseStr);
  326. outputStream.write(responseStr.getBytes());
  327. outputStream.flush();
  328. }
  329. }
  330. } catch (Exception e) {
  331. // throw new RuntimeException(e);
  332. log.error("处理大模型推理异常,异常信息为{}", JSON.toJSONString(e));
  333. //出现异常 给前端返回一句话
  334. try {
  335. outputStream = response.getOutputStream();
  336. String errMsg = this.buildErrMsg();
  337. outputStream.write(errMsg.getBytes());
  338. outputStream.flush();
  339. } catch (IOException ex) {
  340. throw new RuntimeException(ex);
  341. }
  342. } finally {
  343. // log.info("sessionId是{}\n决策最终要保存的数据是{}", sessionId, JSON.toJSONString(resultData));
  344. //保存聊天记录
  345. //将问答更新到数据库中
  346. if(needAdd)
  347. addChatRecord(chatReq, sessionId, type, warningId, dataJson, resultData);
  348. // 关闭输出流
  349. try {
  350. outputStream.close();
  351. } catch (IOException e) {
  352. throw new RuntimeException(e);
  353. }finally {
  354. channel.shutdown();
  355. }
  356. }
  357. }
  358. private String buildBigModelReqForDecision(ChatReq chatReq, String feedback, String simulate, String sessionId, List<DecisionReq> decisionReqs, TXinyiWarningRecord xinyiWarningRecord, Double topP, Double temperature) {
  359. PolicyReq policyReq = new PolicyReq();
  360. //2024年7月11日17:57:53 因为化验室的改了 但是 调用决策还得用原来的几个值
  361. String category = xinyiWarningRecord.getCategory();
  362. if(ROBOT_XSY_1.getCode().equalsIgnoreCase(category)){
  363. category = CS_ZD.getCode();
  364. } else if (ROBOT_XSY_2.getCode().equalsIgnoreCase(category)) {
  365. category = CS_ZD.getCode();
  366. }else if (ROBOT_ECCZLSY.getCode().equalsIgnoreCase(category)) {
  367. category = CS_ZL.getCode();
  368. }
  369. policyReq.setNorm(category);
  370. // policyReq.setNorm(chatReq.getCategory());//2024年7月12日16:23:24 因为有转义。。。
  371. policyReq.setFeedback(StringUtils.isBlank(feedback) ? null : JSON.parseObject(feedback, Map.class));
  372. policyReq.setSimulate(StringUtils.isBlank(simulate) ? null : JSON.parseObject(simulate, Map.class));
  373. policyReq.setSessionId(sessionId);
  374. //2024年7月5日13:24:10 temperature做区分
  375. GenerateArgs generateArgs = new GenerateArgs();
  376. generateArgs.setTemperature(Objects.isNull(temperature) ? bigModelConfig.getTemperature() : temperature);
  377. generateArgs.setTopP(Objects.isNull(topP) ? bigModelConfig.getTopP() : topP);
  378. policyReq.setGenerateArgs(generateArgs);
  379. HashMap<String, Object> map = new HashMap<>();
  380. map.put("rows", decisionReqs);
  381. //2024年6月25日14:16:05 增加报警是管控值报警还是标准值报警
  382. if(WARNING_LEVEL_ONE.equals(xinyiWarningRecord.getLevel()) || WARNING_LEVEL_TWO.equals(xinyiWarningRecord.getLevel()))
  383. map.put("source", "bzz");
  384. else
  385. map.put("source", "gkz");
  386. policyReq.setExtra(map);
  387. return JSON.toJSONString(policyReq, JSONWriter.Feature.WriteNulls);
  388. }
  389. private void addChatRecord(ChatReq chatReq, String sessionId, int type, String warningId, String question, List<String> resultData) {
  390. chatReq.setSessionId(sessionId);
  391. chatReq.setType(type);//类型(0问答 1决策 2本地 3仿真预测)
  392. chatReq.setModule(3);//0=专家问答,1=智能工单,2=智能体助手,3.告警
  393. // String showVal = this.buildShowValue(tXinyiWarningRecord, tXinyiIndustry, normConfig);
  394. // chatReq.setShowVal(feedback);//前端展示的数据和提问的数据不一致
  395. //如果主动调用决策 showVal应该是最新的那条历史记录对应的数据
  396. List<TXinyiChatRecord> tXinyiChatRecords = this.xinyiChatRecordMapper.selectTXinyiChatRecordList(TXinyiChatRecord.builder().warningId(warningId).build());
  397. if(!CollectionUtils.isEmpty(tXinyiChatRecords))
  398. chatReq.setShowVal(tXinyiChatRecords.get(0).getShowVal());
  399. chatReq.setQuestion(question);
  400. chatReq.setAnswer(JSON.toJSONString(resultData));
  401. chatReq.setWarningId(warningId);
  402. chatReq.setCounts(1);//问答次数
  403. String userId = SecurityUtils.getUserId().toString();
  404. String username = SecurityUtils.getUsername();
  405. chatReq.setUserId(userId);
  406. chatReq.setCreateBy(username);
  407. chatReq.setCreateTime(DateUtils.getNowDate());
  408. this.xinyiChatRecordMapper.insertTXinyiChatRecord(chatReq);
  409. }
  410. private List<DecisionReq> getDecisionReqs() {
  411. //List<HashMap<String, Object>> list = this.xinyiIndustryMapper.selectLast10RecordsForDecision();
  412. //2024年5月21日15:23:07 这里不能用关联查询处理,日报要获取最新的一条而不是今日的数据。
  413. List<DecisionReq> decisionReqs = this.xinyiIndustryMapper.selectLast10RecordsForDecisionOnlyIndustry();
  414. if(!CollectionUtils.isEmpty(decisionReqs)){
  415. //处理日报数据
  416. TXinyiDaily daily = this.xinyiDailyMapper.selectNewestData();
  417. for (DecisionReq decisionReq : decisionReqs) {
  418. if(!Objects.isNull(daily)){
  419. WaterFormat.getWaterDecimationData(decisionReq, daily);
  420. }
  421. }
  422. }
  423. return decisionReqs;
  424. }
  425. private String buildErrMsg() {
  426. JSONObject jsonObject = new JSONObject();
  427. jsonObject.put("biz", DECISION_REPORT.getCode());
  428. jsonObject.put("message", "大模型决策方案生成有点问题,请稍后再试");
  429. return JSON.toJSONString(jsonObject);
  430. }
  431. private String buildMsg() {
  432. JSONObject jsonObject = new JSONObject();
  433. jsonObject.put("biz", DECISION_REPORT.getCode());
  434. jsonObject.put("message", "此报警已经关闭了,无法生成决策方案");
  435. return JSON.toJSONString(jsonObject);
  436. }
  437. /**
  438. * RAG+⼤模型的调⽤参数
  439. * 2024年6月17日09:40:38 工单新增 自定义工单处理
  440. * @return
  441. */
  442. @PostMapping(value = "/inferStreamRag")
  443. public void inferStreamRag(HttpServletResponse response, @RequestBody ChatReq chatReq) {
  444. // public void inferStreamRag(HttpServletResponse response, ChatReq chatReq) {
  445. log.info("进入了调⽤RAG+⼤模型的调⽤参数");
  446. // 获取输出流
  447. OutputStream outputStream = null;
  448. ManagedChannel channel = null;
  449. // response.setContentType("text/plain");
  450. response.setContentType("text/event-stream");
  451. response.setCharacterEncoding("utf-8");
  452. //请求参数
  453. Integer module = chatReq.getModule();//来自那个模块
  454. Date reportDate = chatReq.getReportDate();//如果传过值来了 代表的是工单类型的问答
  455. String timeBegin = chatReq.getTimeBegin();
  456. String timeEnd = chatReq.getTimeEnd();
  457. if((Objects.isNull(reportDate) && StringUtils.isBlank(timeBegin) && StringUtils.isBlank(timeEnd)) && module == 1){//工单 必须要输入日期
  458. //智能工单需要传入一个时间的参数
  459. try {
  460. outputStream = response.getOutputStream();
  461. outputStream.write(CHAT_GONGDAN_1_ERROR_MSG.getBytes());
  462. outputStream.flush();
  463. } catch (IOException e) {
  464. throw new RuntimeException(e);
  465. }
  466. return;
  467. }
  468. StringBuilder sb = new StringBuilder();
  469. String sessionId = chatReq.getSessionId();
  470. int isStrong = Objects.isNull(chatReq.getIsStrong()) ? 0 : chatReq.getIsStrong();
  471. boolean tools = true;//问答因为不确认是否走工具,所以传true; 但是工单一定是不用工具的,传false
  472. boolean useRag = true;//只有问答才传true,其他默认都false
  473. //如果是工单,需要特殊处理一下showVal和question
  474. if(1 == module){
  475. if(StringUtils.isBlank(timeBegin) && StringUtils.isBlank(timeEnd)){//按天生成工单
  476. //获取前一天的日期
  477. Date beforeYesterday = DateUtils.plusDate(-1, reportDate);
  478. //先用日期获取当天和前一天的数据,如果获取不到,则提示错误信息
  479. String date = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, reportDate);
  480. String dateBefore = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, beforeYesterday);
  481. chatReq.setShowVal(GONGDAN_TITLE.replace("#{0}", date));//处理展示的标题
  482. String currentDate = DateUtils.parseDateToStr(DateUtils.YYYYMMDD_TS, reportDate);
  483. String earlyDate = DateUtils.parseDateToStr(DateUtils.YYYYMMDD_TS, beforeYesterday);
  484. List<TXinyiDaily> tXinyiDailiesNow = this.xinyiDailyMapper.selectTXinyiDailyList(TXinyiDaily.builder().testDate(currentDate).build());
  485. List<TXinyiDaily> tXinyiDailiesBefore = this.xinyiDailyMapper.selectTXinyiDailyList(TXinyiDaily.builder().testDate(earlyDate).build());
  486. if(CollectionUtils.isEmpty(tXinyiDailiesNow) || CollectionUtils.isEmpty(tXinyiDailiesBefore)){
  487. //没有查询到数据
  488. try {
  489. outputStream = response.getOutputStream();
  490. outputStream.write(CHAT_GONGDAN_2_ERROR_MSG.getBytes());
  491. outputStream.flush();
  492. } catch (IOException e) {
  493. throw new RuntimeException(e);
  494. }
  495. return;
  496. }
  497. //如果查询到了 拼装数据
  498. //2024年6月25日19:11:49 prompt优化
  499. chatReq.setQuestion(this.buildGDQuestionNew(date, dateBefore, tXinyiDailiesNow.get(0), tXinyiDailiesBefore.get(0)));
  500. }else{//自定义工单
  501. chatReq.setShowVal(GONGDAN_TITLE_CUSTOM.replace("#{0}", timeBegin).replace("#{1}", timeEnd));//处理展示的标题
  502. WorkOrderReq workOrderReq = new WorkOrderReq();
  503. BeanUtils.copyProperties(chatReq, workOrderReq);
  504. //拿到数据
  505. List<WorkOrderRes> workOrderRes = frontService.customWorkOrder(workOrderReq);
  506. //品种prompt
  507. String question = this.buildGDQuestionCustom(workOrderRes, workOrderReq);
  508. //2024年6月23日17:21:58 判断问题的长度,如果长度大于配置的值(5000),提示一句话
  509. if(question.length() > MAX_QUESTION_LENGTH){
  510. log.info("*************自定义工单超长了,组装完的参数为{}", question);
  511. try {
  512. outputStream = response.getOutputStream();
  513. outputStream.write(CHAT_GONGDAN_CUSTOM_ERROR_MSG.getBytes());
  514. outputStream.flush();
  515. } catch (IOException e) {
  516. throw new RuntimeException(e);
  517. }
  518. return;
  519. }
  520. chatReq.setQuestion(question);
  521. //2024年6月20日16:48:08 如果是自定义工单,需要处理图表 放到remark中
  522. chatReq.setRemark(JSON.toJSONString(frontService.customWorkOrderHandleByData(workOrderReq, workOrderRes), JSONWriter.Feature.WriteNulls));
  523. }
  524. isStrong = 1;
  525. tools = false;
  526. useRag = false;
  527. }
  528. String ipAddr = IpUtils.getIpAddr();//获取用户的ip地址 传给大模型
  529. int counts = 1;//默认是第一次
  530. List<String> historyDates = new ArrayList<>();
  531. //查询历史数据,放入集合中
  532. if(StringUtils.isBlank(sessionId))
  533. sessionId= IdUtils.simpleUUID();//第一次
  534. else{
  535. //通过sessionId获取所有的问答记录
  536. List<TXinyiChatRecord> chatRecords = this.chatRecordMapper.selectTXinyiChatRecordList(TXinyiChatRecord.builder().sessionId(sessionId).build());
  537. if(!CollectionUtils.isEmpty(chatRecords)){
  538. for (TXinyiChatRecord chatRecord : chatRecords) {
  539. historyDates.add(chatRecord.getQuestion());
  540. historyDates.add(chatRecord.getAnswer());
  541. }
  542. //问答次数增加
  543. counts = chatRecords.size() + 1;
  544. }
  545. }
  546. //将新的问题放入集合中
  547. historyDates.add(chatReq.getQuestion());
  548. try {
  549. channel = ManagedChannelBuilder.forAddress(bigModelConfig.getIp(), bigModelConfig.getPort())
  550. .usePlaintext()
  551. .build();
  552. InferenceAPIsServiceGrpc.InferenceAPIsServiceBlockingStub stub = InferenceAPIsServiceGrpc.newBlockingStub(channel);
  553. // String dataJson = "{\"bot_id\":\"721\",\"exp_id\":\"721\",\"session_id\":\"" + sessionId + "\",\"use_rag\":\"true\",\"prompt\":\"你是LibraAI水务大模型,由红杉天枰开发的水务垂直大语言模型,能够提供水务行业专家问答、智能决策、报表分析、智能工单管理等一系列功能,作为水务人的AI助手,你会竭尽全力帮助我处理工作问题。\",\"history_dia\":" + JSON.toJSONString(historyDates) + ",\"generate_args\":{\"max_new_tokens\":2048,\"max_length\":4096,\"num_beams\":1,\"do_sample\":true,\"top_p\":0.7,\"temperature\":0.95},\"extra\":{ \"ip_address\": \"" + ipAddr + "\" },\"strengthen\":" + (isStrong == 1) + "}";
  554. //2024年6月25日18:12:23 优化,不再使用拼接JSON字符串
  555. String dataJson = buildBigModelReqForChat(sessionId, historyDates, ipAddr, isStrong, chatReq.getTopP(), chatReq.getTemperature(), tools, useRag);
  556. // log.info("请求大模型的问答参数为{}", dataJson);
  557. PredictionsRequest request = PredictionsRequest.newBuilder()
  558. .setModelName("slibra_bot")
  559. .putInput("method", ByteString.copyFrom("infer_stream", "utf-8"))//推理
  560. .putInput("data", ByteString.copyFrom(dataJson, "utf-8"))
  561. .buildPartial();
  562. outputStream = response.getOutputStream();
  563. Iterator<PredictionResponse> predictions = stub.streamPredictions(request);
  564. //将结果记录到问答表
  565. while (predictions.hasNext()) {
  566. String responseStr = predictions.next().getPrediction().toStringUtf8();
  567. // log.info("大模型问答返回的原始结果为{}", responseStr);
  568. responseStr = JSON.parseObject(responseStr).getString("message");
  569. //2024年7月13日14:30:19 为空字符串的(实际可能是\n这种的)也返回前端,否则样式有问题
  570. if("complete".equals(responseStr) || Objects.isNull(responseStr)){
  571. // System.out.println("结尾语句并且是非JSON,无需处理");
  572. log.info("返回的结果message为{},无需再次处理", responseStr);
  573. //结束语句也流式输出,但是并不记录下来 2024年5月24日11:15:23 也不返回前端
  574. }else{
  575. sb.append(responseStr);
  576. outputStream.write(responseStr.getBytes());
  577. outputStream.flush();
  578. }
  579. }
  580. //将问答更新到数据库中
  581. chatReq.setSessionId(sessionId);
  582. chatReq.setAnswer(sb.toString());
  583. chatReq.setType(0);//0问答 1决策 2本地 3仿真预测
  584. chatReq.setModule(module);//0专家问答 1智能工单 2智能体助手 3告警 4简报
  585. //2024年5月28日10:58:02 由于部分问题 展示的和调用大模型的不一样,所以这个由前端传过来
  586. // chatReq.setShowVal(question);
  587. chatReq.setCounts(counts);//问答次数
  588. String userId = SecurityUtils.getUserId().toString();
  589. String username = SecurityUtils.getUsername();
  590. chatReq.setUserId(userId);
  591. chatReq.setCreateBy(username);
  592. chatReq.setCreateTime(DateUtils.getNowDate());
  593. this.chatRecordMapper.insertTXinyiChatRecord(chatReq);
  594. outputStream.write((DEFAULT_ID_IDENTIFIER + chatReq.getId()).getBytes());
  595. outputStream.flush();
  596. } catch (IOException e) {
  597. throw new RuntimeException(e);
  598. } finally {
  599. // 关闭输出流
  600. try {
  601. outputStream.close();
  602. } catch (IOException e) {
  603. throw new RuntimeException(e);
  604. }finally {
  605. channel.shutdown();
  606. }
  607. }
  608. // return AjaxResult.success("ok");
  609. }
  610. private String buildBigModelReqForChat(String sessionId, List<String> historyDates, String ipAddr, int isStrong, Double topP, Double temperature, boolean tools, boolean useRag) {
  611. ChatRequest chatRequest = new ChatRequest();
  612. chatRequest.setSessionId(sessionId);
  613. chatRequest.setHistoryDia(historyDates);
  614. //2024年7月5日13:24:10 temperature做区分
  615. GenerateArgs generateArgs = new GenerateArgs();
  616. generateArgs.setTemperature(Objects.isNull(temperature) ? bigModelConfig.getTemperature() : temperature);
  617. generateArgs.setTopP(Objects.isNull(topP) ? bigModelConfig.getTopP() : topP);
  618. chatRequest.setGenerateArgs(generateArgs);
  619. Map<String, Object> extra = new HashMap<>();
  620. extra.put("ip_address", ipAddr);
  621. chatRequest.setExtra(extra);
  622. chatRequest.setStrengthen(isStrong == 1);
  623. chatRequest.setTools(String.valueOf(tools));
  624. chatRequest.setUseRag(useRag);
  625. return JSON.toJSONString(chatRequest);
  626. }
  627. private String buildGDQuestionCustom(List<WorkOrderRes> workOrderRes, WorkOrderReq workOrderReq) {
  628. StringBuilder sb = new StringBuilder();
  629. sb.append(GONGDAN_PROMPT_CUSTOM_BEGIN.replace("#{0}", workOrderReq.getTimeBegin()).replace("#{1}", workOrderReq.getTimeEnd()));
  630. if(workOrderReq.getJsSlq() || workOrderReq.getJsSs() || workOrderReq.getJsTp() || workOrderReq.getJsTn() || workOrderReq.getJsCod() || workOrderReq.getJsNh3()){
  631. sb.append("进水:\n");
  632. for (WorkOrderRes workOrderRe : workOrderRes) {
  633. sb.append(workOrderRe.getTime()).append(":");
  634. if(workOrderReq.getJsCod())
  635. sb.append("进水COD:").append(DecimalUtils.getAbsAndScale(workOrderRe.getJsCod(), INT_2)).append("mg/L、");
  636. if(workOrderReq.getJsTn())
  637. sb.append("进水总氮:").append(DecimalUtils.getAbsAndScale(workOrderRe.getJsTn(), INT_2)).append("mg/L、");
  638. if(workOrderReq.getJsTp())
  639. sb.append("进水总磷:").append(DecimalUtils.getAbsAndScale(workOrderRe.getJsTp(), INT_2)).append("mg/L、");
  640. if(workOrderReq.getJsNh3())
  641. sb.append("进水氨氮:").append(DecimalUtils.getAbsAndScale(workOrderRe.getJsNh3(), INT_2)).append("mg/L、");
  642. if(workOrderReq.getJsSs())
  643. sb.append("进水SS:").append(DecimalUtils.getAbsAndScale(workOrderRe.getJsSs(), INT_2)).append("mg/L、");
  644. if(workOrderReq.getJsSlq())
  645. sb.append("进水水量:").append(DecimalUtils.getAbsAndScale(workOrderRe.getJsSlq(), INT_2)).append("m³/d、");
  646. }
  647. }
  648. if(workOrderReq.getCsSlqc() || workOrderReq.getCsSs() || workOrderReq.getCsTp() || workOrderReq.getCsTn() || workOrderReq.getCsCod() || workOrderReq.getCsNh3()){
  649. sb.append("出水:\n");
  650. for (WorkOrderRes workOrderRe : workOrderRes) {
  651. sb.append(workOrderRe.getTime()).append(":");
  652. if(workOrderReq.getCsCod())
  653. sb.append("出水COD:").append(DecimalUtils.getAbsAndScale(workOrderRe.getCsCod(), INT_2)).append("mg/L、");
  654. if(workOrderReq.getCsTn())
  655. sb.append("出水总氮:").append(DecimalUtils.getAbsAndScale(workOrderRe.getCsTn(), INT_2)).append("mg/L、");
  656. if(workOrderReq.getCsTp())
  657. sb.append("出水总磷:").append(DecimalUtils.getAbsAndScale(workOrderRe.getCsTp(), INT_2)).append("mg/L、");
  658. if(workOrderReq.getCsNh3())
  659. sb.append("出水氨氮:").append(DecimalUtils.getAbsAndScale(workOrderRe.getCsNh3(), INT_2)).append("mg/L、");
  660. if(workOrderReq.getCsSs())
  661. sb.append("出水SS:").append(DecimalUtils.getAbsAndScale(workOrderRe.getCsSs(), INT_2)).append("mg/L、");
  662. if(workOrderReq.getCsSlqc())
  663. sb.append("出水水量:").append(DecimalUtils.getAbsAndScale(workOrderRe.getCsSlqc(), INT_2)).append("m³/d、");
  664. }
  665. }
  666. if(workOrderReq.getNo3Hlj1Jqr() || workOrderReq.getNo3Hlj2Jqr() || workOrderReq.getNh31Jqr() || workOrderReq.getNh32Jqr()
  667. || workOrderReq.getNo3Qyc1Jqr() || workOrderReq.getNo3Qyc2Jqr() || workOrderReq.getTpRccJqr()){
  668. sb.append("过程指标:\n");
  669. for (WorkOrderRes workOrderRe : workOrderRes) {
  670. sb.append(workOrderRe.getTime()).append(":");
  671. if(workOrderReq.getNo3Hlj1Jqr())
  672. sb.append("#1好氧池硝酸盐:").append(DecimalUtils.getAbsAndScale(workOrderRe.getNo3Hlj1Jqr(), INT_2)).append("mg/L、");
  673. if(workOrderReq.getNo3Hlj2Jqr())
  674. sb.append("#2好氧池硝酸盐:").append(DecimalUtils.getAbsAndScale(workOrderRe.getNo3Hlj2Jqr(), INT_2)).append("mg/L、");
  675. if(workOrderReq.getNo3Qyc1Jqr())
  676. sb.append("#1缺氧池硝酸盐:").append(DecimalUtils.getAbsAndScale(workOrderRe.getNo3Qyc1Jqr(), INT_2)).append("mg/L、");
  677. if(workOrderReq.getNo3Qyc2Jqr())
  678. sb.append("#2缺氧池硝酸盐:").append(DecimalUtils.getAbsAndScale(workOrderRe.getNo3Qyc2Jqr(), INT_2)).append("mg/L、");
  679. if(workOrderReq.getTpRccJqr())
  680. sb.append("二沉池正磷酸盐:").append(DecimalUtils.getAbsAndScale(workOrderRe.getTpRccJqr(), INT_2)).append("mg/L、");
  681. if(workOrderReq.getNh31Jqr())
  682. sb.append("#1缺氧氨氮:").append(DecimalUtils.getAbsAndScale(workOrderRe.getNh31Jqr(), INT_2)).append("mg/L、");
  683. if(workOrderReq.getNh32Jqr())
  684. sb.append("#2缺氧氨氮:").append(DecimalUtils.getAbsAndScale(workOrderRe.getNh32Jqr(), INT_2)).append("mg/L、");
  685. }
  686. }
  687. sb.append(GONGDAN_PROMPT_CUSTOM_END_1);
  688. if(workOrderReq.getJsCod() || workOrderReq.getCsCod())
  689. sb.append("化学需氧量(COD)、");
  690. if(workOrderReq.getJsTp() || workOrderReq.getCsTp())
  691. sb.append("总磷(TP)、");
  692. if(workOrderReq.getJsTn() || workOrderReq.getCsTn())
  693. sb.append("总氮(TN)、");
  694. if(workOrderReq.getJsSs() || workOrderReq.getCsSs())
  695. sb.append("SS、");
  696. if(workOrderReq.getJsNh3() || workOrderReq.getCsNh3())
  697. sb.append("氨氮、");
  698. sb.append(GONGDAN_PROMPT_CUSTOM_END_2);
  699. return sb.toString();
  700. }
  701. /**
  702. * 通过日期构建工单的请求参数 --new
  703. * @return
  704. */
  705. private String buildGDQuestionNew(String date, String dateBefore, TXinyiDaily tXinyiDaily, TXinyiDaily tXinyiDaily1) {
  706. StringBuilder sb = new StringBuilder(GONGDAN_PROMPT_BEGIN_PRE_1).append(date);
  707. // sb.append(GONGDAN_PROMPT_BEGIN.replace("#{0}", date));
  708. sb.append(GONGDAN_PROMPT_BEGIN_PRE_2).append(date);
  709. sb.append(GONGDAN_PROMPT_BEGIN_PRE_3);
  710. sb.append("进水COD:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getJsCod(), INT_2)).append("mg/L、");
  711. sb.append("进水总氮:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getJsTn(), INT_2)).append("mg/L、");
  712. sb.append("进水总磷:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getJsTp(), INT_2)).append("mg/L、");
  713. sb.append("进水氨氮:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getJsNh3(), INT_2)).append("mg/L、");
  714. sb.append("进水SS:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getJsSs(), INT_2)).append("mg/L、");
  715. sb.append("进水水量:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getJSL(), INT_2)).append("m³/d、");
  716. sb.append(";");
  717. sb.append("出水COD:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getCsCod(), INT_2)).append("mg/L、");
  718. sb.append("出水总氮:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getCsTn(), INT_2)).append("mg/L、");
  719. sb.append("出水总磷:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getCsTp(), INT_2)).append("mg/L、");
  720. sb.append("出水氨氮:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getCsNh3(), INT_2)).append("mg/L、");
  721. sb.append("出水SS:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getCsSs(), INT_2)).append("mg/L、");
  722. sb.append("出水水量:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getCSL(), INT_2)).append("m³/d。");
  723. sb.append("二、生化指标:\n");
  724. //todo 单位确认 下面的应该不是 mg/L
  725. sb.append("#1好氧池pH:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcOnePh(), INT_2)).append("、");
  726. sb.append("#1好氧池SV:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyOneSv(), INT_2)).append("、");
  727. sb.append("#1好氧池SVI:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyOneSvi(), INT_2)).append("、");
  728. sb.append("#1好氧池MLSS:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyOneMlss(), INT_2)).append("、");
  729. sb.append("#1好氧池MLVSS:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyOneMlvss(), INT_2)).append("、");
  730. sb.append("#1好氧池DO:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyOneDo(), INT_2)).append(";");
  731. sb.append("#2好氧池pH:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcTwoPh(), INT_2)).append("、");
  732. sb.append("#2好氧池SV:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyTwoSv(), INT_2)).append("、");
  733. sb.append("#2好氧池SVI:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyTwoSvi(), INT_2)).append("、");
  734. sb.append("#2好氧池MLSS:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyTwoMlss(), INT_2)).append("、");
  735. sb.append("#2好氧池MLVSS:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyTwoMlvss(), INT_2)).append("、");
  736. sb.append("#2好氧池DO:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyTwoDo(), INT_2)).append(";");
  737. sb.append("#1厌氧池DO:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcYyOneDo(), INT_2)).append(";");
  738. sb.append("#2厌氧池DO:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcYyTwoDo(), INT_2)).append("。");
  739. sb.append("最近7天的数据如下:\n");
  740. List<TXinyiDaily> dailyTwoRecords = this.xinyiDailyMapper.selectNRecords(DAILY_REPORT_COUNT_RECORD);
  741. //正常不会有这种问题 因为日报有很多条
  742. if(CollectionUtils.isEmpty(dailyTwoRecords) || dailyTwoRecords.size() < DAILY_REPORT_COUNT_RECORD){
  743. log.error("进入了定时生成每日简报数据 获取最新的{}条数据不足,终止", DAILY_REPORT_COUNT_RECORD);
  744. return sb.toString();
  745. }
  746. //查询配置信息
  747. List<TXinyiNormConfig> tXinyiNormConfigs = this.xinyiNormConfigMapper.selectTXinyiNormConfigList(null);
  748. if(CollectionUtils.isEmpty(tXinyiNormConfigs))
  749. return null;
  750. TXinyiNormConfig normConfig = tXinyiNormConfigs.get(0);
  751. //获取数据
  752. for (TXinyiDaily dailyTwoRecord : dailyTwoRecords) {
  753. sb.append(formateDateStr(dailyTwoRecord.getTestDate())).append("进出水质数据:\n");
  754. sb.append("进水:\n");
  755. sb.append("进水COD").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getJsCod(), 2)).append("mg/L、");
  756. sb.append("进水总氮").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getJsTn(), 2)).append("mg/L、");
  757. sb.append("进水总磷").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getJsTp(), 2)).append("mg/L、");
  758. sb.append("进水氨氮").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getJsNh3(), 2)).append("mg/L、");
  759. sb.append("进水SS").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getJsSs(), 2)).append("mg/L、");
  760. sb.append("进水水量").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getJSL(), 2)).append("m³/d").append(";\n");
  761. sb.append("出水:\n");
  762. sb.append("出水COD").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getCsCod(), 2)).append("mg/L、");
  763. sb.append("出水总氮").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getCsTn(), 2)).append("mg/L、");
  764. sb.append("出水总磷").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getCsTp(), 2)).append("mg/L、");
  765. sb.append("出水氨氮").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getCsNh3(), 2)).append("mg/L、");
  766. sb.append("出水SS").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getCsSs(), 2)).append("mg/L、");
  767. sb.append("出水水量").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getCSL(), 2)).append("m³/d").append("。\n");
  768. }
  769. sb.append(SHORT_REPORT_END);
  770. sb.append("进水COD:").append(DecimalUtils.getAbsAndScale(normConfig.getJscodSjz(), 2)).append("mg/L、");
  771. sb.append("进水总氮:").append(DecimalUtils.getAbsAndScale(normConfig.getJszdSjz(), 2)).append("mg/L、");
  772. sb.append("进水总磷:").append(DecimalUtils.getAbsAndScale(normConfig.getJszlSjz(), 2)).append("mg/L、");
  773. sb.append("进水氨氮:").append(DecimalUtils.getAbsAndScale(normConfig.getJsadSjz(), 2)).append("mg/L、");
  774. sb.append("进水SS:").append(DecimalUtils.getAbsAndScale(normConfig.getJsssSjz(), 2)).append("mg/L、");
  775. sb.append("出水COD:").append(DecimalUtils.getAbsAndScale(normConfig.getCscodBzz(), 2)).append("mg/L、");
  776. sb.append("出水总氮:").append(DecimalUtils.getAbsAndScale(normConfig.getCszzBzz(), 2)).append("mg/L、");
  777. sb.append("出水总磷:").append(DecimalUtils.getAbsAndScale(normConfig.getCszlBzz(), 2)).append("mg/L、");
  778. sb.append("出水氨氮:").append(DecimalUtils.getAbsAndScale(normConfig.getCsadBzz(), 2)).append("mg/L、");
  779. sb.append("出水SS:").append(DecimalUtils.getAbsAndScale(normConfig.getCsssBzz(), 2)).append("mg/L").append("。");
  780. sb.append(GONGDAN_PROMPT_END);
  781. return sb.toString();
  782. }
  783. /**
  784. *
  785. * 2022/01/01 转成2022年01月01日 数据
  786. * @param testDate
  787. * @return
  788. */
  789. private String formateDateStr(String testDate) {
  790. if(StringUtils.isBlank(testDate))
  791. return "";
  792. if(!testDate.contains("/"))
  793. return testDate;
  794. String[] split = testDate.split("/");
  795. return split[0] + "年" + split[1] + "月" + split[2] + "日";
  796. }
  797. /**
  798. * 通过日期构建工单的请求参数
  799. * @return
  800. */
  801. private String buildGDQuestion(String date, String dateBefore, TXinyiDaily xinyiDailyNow, TXinyiDaily xinyiDailyBefore) {
  802. String result = GONGDAN_PROMPT;
  803. result = result.replace("{0}", date);
  804. result = result.replace("{1}", dateBefore);
  805. //替换各种指标
  806. result = result.replace("{2}", String.valueOf(xinyiDailyNow.getJsCod()));
  807. result = result.replace("{3}", String.valueOf(xinyiDailyNow.getJsTn()));
  808. result = result.replace("{4}", String.valueOf(xinyiDailyNow.getJsTp()));
  809. result = result.replace("{5}", String.valueOf(xinyiDailyNow.getJsNh3()));
  810. result = result.replace("{6}", String.valueOf(xinyiDailyNow.getJsSs()));
  811. result = result.replace("{7}", String.valueOf(xinyiDailyNow.getJSL()));
  812. result = result.replace("{8}", String.valueOf(xinyiDailyNow.getCsCod()));
  813. result = result.replace("{9}", String.valueOf(xinyiDailyNow.getCsTn()));
  814. result = result.replace("{10}", String.valueOf(xinyiDailyNow.getCsTp()));
  815. result = result.replace("{11}", String.valueOf(xinyiDailyNow.getCsNh3()));
  816. result = result.replace("{12}", String.valueOf(xinyiDailyNow.getCsSs()));
  817. result = result.replace("{13}", String.valueOf(xinyiDailyNow.getCSL()));
  818. result = result.replace("{14}", String.valueOf(xinyiDailyNow.getShcOnePh()));
  819. result = result.replace("{15}", String.valueOf(xinyiDailyNow.getShcHyOneSv()));
  820. result = result.replace("{16}", String.valueOf(xinyiDailyNow.getShcHyOneSvi()));
  821. result = result.replace("{17}", String.valueOf(xinyiDailyNow.getShcHyOneMlss()));
  822. result = result.replace("{18}", String.valueOf(xinyiDailyNow.getShcHyOneMlvss()));
  823. result = result.replace("{19}", String.valueOf(xinyiDailyNow.getShcHyOneDo()));
  824. result = result.replace("{20}", String.valueOf(xinyiDailyNow.getShcTwoPh()));
  825. result = result.replace("{21}", String.valueOf(xinyiDailyNow.getShcHyTwoSv()));
  826. result = result.replace("{22}", String.valueOf(xinyiDailyNow.getShcHyTwoSvi()));
  827. result = result.replace("{23}", String.valueOf(xinyiDailyNow.getShcHyTwoMlss()));
  828. result = result.replace("{24}", String.valueOf(xinyiDailyNow.getShcHyTwoMlvss()));
  829. result = result.replace("{25}", String.valueOf(xinyiDailyNow.getShcHyTwoDo()));
  830. result = result.replace("{26}", String.valueOf(xinyiDailyNow.getShcYyOneDo()));
  831. result = result.replace("{27}", String.valueOf(xinyiDailyNow.getShcYyTwoDo()));
  832. result = result.replace("{28}", String.valueOf(xinyiDailyBefore.getJsCod()));
  833. result = result.replace("{29}", String.valueOf(xinyiDailyBefore.getJsTn()));
  834. result = result.replace("{30}", String.valueOf(xinyiDailyBefore.getJsTp()));
  835. result = result.replace("{31}", String.valueOf(xinyiDailyBefore.getJsNh3()));
  836. result = result.replace("{32}", String.valueOf(xinyiDailyBefore.getJsSs()));
  837. result = result.replace("{33}", String.valueOf(xinyiDailyBefore.getJSL()));
  838. result = result.replace("{34}", String.valueOf(xinyiDailyBefore.getCsCod()));
  839. result = result.replace("{35}", String.valueOf(xinyiDailyBefore.getCsTn()));
  840. result = result.replace("{36}", String.valueOf(xinyiDailyBefore.getCsTp()));
  841. result = result.replace("{37}", String.valueOf(xinyiDailyBefore.getCsNh3()));
  842. result = result.replace("{38}", String.valueOf(xinyiDailyBefore.getCsSs()));
  843. result = result.replace("{39}", String.valueOf(xinyiDailyBefore.getCSL()));
  844. return result;
  845. }
  846. public static void main(String[] args) {
  847. // String encoded = "\\345\\216\\214\\346\\260\\247\\346\\261\\240\\347\\241\\235\\351\\205\\270\\347\\233\\220\\346\\260\\256\\346\\230\\257\\345\\220\\246\\345\\244\\247\\344\\272";
  848. // String decoded = decodeOctalToUtf8(encoded);
  849. // System.out.println(decoded);
  850. testPredictor();
  851. }
  852. public static void testPredictor(){
  853. // 获取输出流
  854. ManagedChannel channel = null;
  855. try {
  856. channel = ManagedChannelBuilder.forAddress("10.0.0.24", 17070)
  857. .usePlaintext()
  858. .build();
  859. InferenceAPIsServiceGrpc.InferenceAPIsServiceBlockingStub stub = InferenceAPIsServiceGrpc.newBlockingStub(channel);
  860. // String dataJson = "{\"bot_id\":\"b00001\",\"exp_id\":\"721\",\"norm\":\"出水氨氮\",\"session_id\":\" " + IdUtils.simpleUUID() + " \",\"extra\":{}}";
  861. //2024年6月27日13:23:25 优化:改成非拼接JSON字符串
  862. String dataJson = buildBigModelReqForPredictor("出水氨氮");
  863. // log.info("请求大模型的预测的参数为{}", dataJson);
  864. PredictionsRequest request = PredictionsRequest.newBuilder()
  865. .setModelName("slibra_bot")
  866. .putInput("method", ByteString.copyFrom("predictor", "utf-8"))//推理
  867. .putInput("data", ByteString.copyFrom(dataJson, "utf-8"))
  868. .buildPartial();
  869. //2024年6月21日10:35:22 改成非流式输出
  870. /*Iterator<PredictionResponse> predictions = stub.streamPredictions(request);
  871. //将结果记录到问答表
  872. String responseStr = predictions.next().getPrediction().toStringUtf8();
  873. log.info("大模型问答返回的原始结果为{}", responseStr);*/
  874. PredictionResponse predictions = stub.predictions(request);
  875. String responseStr = predictions.getPrediction().toStringUtf8();
  876. // log.info("大模型问答返回的原始结果为{}", responseStr);
  877. } catch (IOException e) {
  878. throw new RuntimeException(e);
  879. } finally {
  880. channel.shutdown();
  881. }
  882. }
  883. private static String buildBigModelReqForPredictor(String type) {
  884. PredictorRequest predictorRequest = new PredictorRequest();
  885. predictorRequest.setNorm(type);
  886. predictorRequest.setSessionId(IdUtils.simpleUUID());
  887. return JSON.toJSONString(predictorRequest);
  888. }
  889. }