package com.slibra.web.controller.business; import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONWriter; import com.alibaba.fastjson2.JSON; import com.google.protobuf.ByteString; import com.slibra.business.domain.*; import com.slibra.business.mapper.*; import com.slibra.business.req.*; import com.slibra.business.res.WorkOrderRes; import com.slibra.business.service.IFrontService; import com.slibra.common.DecimalUtils; import com.slibra.common.config.BigModelConfig; import com.slibra.common.core.controller.BaseController; import com.slibra.common.core.domain.DecisionReq; import com.slibra.common.core.domain.TXinyiDaily; import com.slibra.common.enums.BusinessEnum; import com.slibra.common.exception.ServiceException; import com.slibra.common.utils.DateUtils; import com.slibra.common.utils.SecurityUtils; import com.slibra.common.utils.StringUtils; import com.slibra.common.utils.format.WaterFormat; import com.slibra.common.utils.ip.IpUtils; import com.slibra.common.utils.uuid.IdUtils; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; import lombok.extern.slf4j.Slf4j; import org.pytorch.serve.grpc.inference.InferenceAPIsServiceGrpc; import org.pytorch.serve.grpc.inference.PredictionResponse; import org.pytorch.serve.grpc.inference.PredictionsRequest; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.OutputStream; import java.util.*; import static com.slibra.common.constant.MyConstants.*; import static com.slibra.common.enums.BusinessEnum.BigModelBizEnum.DECISION_REPORT; import static com.slibra.common.enums.BusinessEnum.WarningCategoryEnum.*; import static com.slibra.common.enums.BusinessEnum.WarningCategoryEnum.CS_ZL; /** * 告警相关 */ @RestController @RequestMapping("/grpc") @Slf4j public class GRPCController extends BaseController { @Autowired private TXinyiChatRecordMapper chatRecordMapper; @Autowired private TXinyiIndustryMapper xinyiIndustryMapper; @Autowired private TXinyiDailyMapper xinyiDailyMapper; @Autowired private TXinyiChatRecordMapper xinyiChatRecordMapper; @Autowired private TXinyiWarningRecordMapper xinyiWarningRecordMapper; @Autowired private IFrontService frontService; @Autowired private TXinyiNormConfigMapper xinyiNormConfigMapper; @Autowired private BigModelConfig bigModelConfig; // 用户自定义的端口 @Value("${token.port}") private String port; /** * * get请求测试决策输出 * * @param response */ @GetMapping(value = "/test/aaa") public void decisionStreamTest(HttpServletRequest httpServletRequest, HttpServletResponse response) // public void decisionStream(HttpServletResponse response, ChatReq chatReq) { log.info("进入了调⽤大模型决策接口"); ChatReq chatReq = new ChatReq(); HashMap map = new HashMap<>(); map.put("2_2", "正常"); map.put("4_25", "没有"); map.put("2_28", "否"); map.put("6_3", "超标"); chatReq.setFeedback(JSON.toJSONString(map)); chatReq.setCategory("出水氨氮"); chatReq.setWarningId("782"); chatReq.setSimulate("{}"); // 获取输出流 OutputStream outputStream = null; ManagedChannel channel = null; //response.setContentType("text/plain"); response.setContentType("text/event-stream"); response.setCharacterEncoding("utf-8"); //2024年5月29日14:15:58 新增逻辑,判断报警状态是否已经结束了,如果结束了就直接模拟一个report返回给前端,不再调用大模型 String warningId = chatReq.getWarningId(); if(StringUtils.isBlank(warningId)) throw new ServiceException("请输入正确的告警id"); TXinyiWarningRecord xinyiWarningRecord = this.xinyiWarningRecordMapper.selectTXinyiWarningRecordById(Long.parseLong(warningId)); if(Objects.isNull(xinyiWarningRecord)) throw new ServiceException("请输入正确的告警id,没有查询到告警信息"); if(1 == xinyiWarningRecord.getStatus() || 2 == xinyiWarningRecord.getStatus()){ //已经关闭的报警,不允许再次点击报警了 String message = this.buildMsg(); try { outputStream = response.getOutputStream(); outputStream.write(message.getBytes()); outputStream.flush(); return;//输出完提示信息就结束 } catch (IOException e) { throw new RuntimeException(e); } } StringBuilder sb = new StringBuilder(); //大模型结果 放入一个结合中 List resultData = new ArrayList<>(); //决策和问答不一样 没有历史的概念 所以sessionId都是新的 次数都是1 String sessionId = IdUtils.simpleUUID(); String feedback = chatReq.getFeedback(); String simulate = chatReq.getSimulate(); int type = 3;//仿真预测 if(StringUtils.isBlank(simulate) || "{}".equals(simulate)) type = 1;//决策 //决策请求的业务参数 List decisionReqs = getDecisionReqs(); // String rows = JSON.toJSONString(decisionReqs, JSONWriter.Feature.WriteNulls); boolean needAdd = true;//标识变量是否可以保存 String dataJson = ""; String headerPort = httpServletRequest.getHeader(port); try { channel = ManagedChannelBuilder.forAddress(bigModelConfig.getIp(), StringUtils.isBlank(headerPort) ? bigModelConfig.getPort() : Integer.parseInt(headerPort)) .usePlaintext() .build(); InferenceAPIsServiceGrpc.InferenceAPIsServiceBlockingStub stub = InferenceAPIsServiceGrpc.newBlockingStub(channel); // 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 + "}}"; //2024年6月24日17:59:17 优化,不再拼接JSON字符串 dataJson = buildBigModelReqForDecision(chatReq, feedback, simulate, sessionId, decisionReqs, xinyiWarningRecord, chatReq.getTopP(), chatReq.getTemperature()); // log.info("请求大模型的决策的参数为{}", dataJson); PredictionsRequest request = PredictionsRequest.newBuilder() .setModelName("slibra_bot") .putInput("method", ByteString.copyFrom("decision_stream", "utf-8"))//推理 .putInput("data", ByteString.copyFrom(dataJson, "utf-8")) .buildPartial(); outputStream = response.getOutputStream(); Iterator predictions = stub.streamPredictions(request); int i = 0 ; while (predictions.hasNext()) { String responseStr = predictions.next().getPrediction().toStringUtf8(); // log.info("决策流式返回的结果是{}", responseStr); if(StringUtils.isBlank(responseStr)){ log.info("大模型返回的流式决策内容存在空的值,跳过此次输出"); continue; } String message = JSON.parseObject(responseStr).getString("message"); //2024年5月25日16:37:16 按照大模型返回的类型解析数据 String biz = JSON.parseObject(responseStr).getString("biz"); // String message = JSON.parseObject(responseStr).getString("message"); if(BusinessEnum.BigModelBizEnum.OK.getCode().equals(biz)){ log.info("结尾语句并且是非JSON,无需处理,返回数据为{}", responseStr); //结束语句也流式输出,但是并不记录下来 2024年5月24日11:15:23 也不返回前端 }else if(BusinessEnum.BigModelBizEnum.DECISION_DEBUGGER.getCode().equals(biz)){ log.info("中间过程,目前只打印日志,不记录数据,也不返回给前端,返回数据为{}", responseStr); //结束语句也流式输出,但是并不记录下来 2024年5月24日11:15:23 也不返回前端 //2024年6月23日14:55:19 如果大模型返回error了,不保存记录,并且提示一句错误语 }else if(BusinessEnum.BigModelBizEnum.ERROR.getCode().equalsIgnoreCase(biz)){ log.info("调用大模型的时候,返回的是ERROR,返回数据为{}", responseStr); needAdd = false; //返回的是error 给前端返回一句话 try { String errMsg = this.buildErrMsg(); outputStream.write(errMsg.getBytes()); outputStream.flush(); } catch (IOException ex) { throw new RuntimeException(ex); } } else{//其他 要么alert 要么出的报告 // if(StringUtils.isBlank(message)){ // log.info("×××××××××××××××××××××××××××为空的数据暂时不返回×××××××××××××××××××××××××××"); // }else { // log.info("返回给前端的数据是{}", responseStr); resultData.add(responseStr); responseStr = responseStr + (i++) + "\n"; outputStream.write(responseStr.getBytes()); outputStream.flush(); //2024年7月12日17:47:08 加个打印,处理只要report类型的拼接结果 if(BusinessEnum.BigModelBizEnum.DECISION_REPORT.getCode().equalsIgnoreCase(biz)){ sb.append(message); } // } } } } catch (Exception e) { // throw new RuntimeException(e); log.error("处理大模型推理异常,异常信息为{}", JSON.toJSONString(e)); //出现异常 给前端返回一句话 try { outputStream = response.getOutputStream(); String errMsg = this.buildErrMsg(); outputStream.write(errMsg.getBytes()); outputStream.flush(); } catch (IOException ex) { throw new RuntimeException(ex); } } finally { // log.info("sessionId是{}\n决策最终要保存的数据是{}", sessionId, JSON.toJSONString(resultData)); // log.info("~~~~~~~~~~~~~~~决策最终返回的报告数据是{}", sb.toString()); //保存聊天记录 //将问答更新到数据库中 needAdd = false; if(needAdd) addChatRecord(chatReq, sessionId, type, warningId, dataJson, resultData); // 关闭输出流 try { outputStream.close(); } catch (IOException e) { throw new RuntimeException(e); }finally { channel.shutdown(); } } } /** * 调⽤大模型决策接口 + 仿真预测 * @return */ @PostMapping(value = "/decisionStream") public void decisionStream(HttpServletRequest httpServletRequest, HttpServletResponse response, @RequestBody ChatReq chatReq) // public void decisionStream(HttpServletResponse response, ChatReq chatReq) { log.info("进入了调⽤大模型决策接口"); // 获取输出流 OutputStream outputStream = null; ManagedChannel channel = null; //response.setContentType("text/plain"); response.setContentType("text/event-stream"); response.setCharacterEncoding("utf-8"); //2024年5月29日14:15:58 新增逻辑,判断报警状态是否已经结束了,如果结束了就直接模拟一个report返回给前端,不再调用大模型 String warningId = chatReq.getWarningId(); if(StringUtils.isBlank(warningId)) throw new ServiceException("请输入正确的告警id"); TXinyiWarningRecord xinyiWarningRecord = this.xinyiWarningRecordMapper.selectTXinyiWarningRecordById(Long.parseLong(warningId)); if(Objects.isNull(xinyiWarningRecord)) throw new ServiceException("请输入正确的告警id,没有查询到告警信息"); if(1 == xinyiWarningRecord.getStatus() || 2 == xinyiWarningRecord.getStatus()){ //已经关闭的报警,不允许再次点击报警了 String message = this.buildMsg(); try { outputStream = response.getOutputStream(); outputStream.write(message.getBytes()); outputStream.flush(); return;//输出完提示信息就结束 } catch (IOException e) { throw new RuntimeException(e); } } // StringBuilder sb = new StringBuilder(); //大模型结果 放入一个结合中 List resultData = new ArrayList<>(); //决策和问答不一样 没有历史的概念 所以sessionId都是新的 次数都是1 String sessionId = IdUtils.simpleUUID(); String feedback = chatReq.getFeedback(); String simulate = chatReq.getSimulate(); int type = 3;//仿真预测 if(StringUtils.isBlank(simulate) || "{}".equals(simulate)) type = 1;//决策 //决策请求的业务参数 List decisionReqs = getDecisionReqs(); // String rows = JSON.toJSONString(decisionReqs, JSONWriter.Feature.WriteNulls); boolean needAdd = true;//标识变量是否可以保存 String dataJson = ""; String headerPort = httpServletRequest.getHeader(port); try { channel = ManagedChannelBuilder.forAddress(bigModelConfig.getIp(), StringUtils.isBlank(headerPort) ? bigModelConfig.getPort() : Integer.parseInt(headerPort)) .usePlaintext() .build(); InferenceAPIsServiceGrpc.InferenceAPIsServiceBlockingStub stub = InferenceAPIsServiceGrpc.newBlockingStub(channel); // 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 + "}}"; //2024年6月24日17:59:17 优化,不再拼接JSON字符串 dataJson = buildBigModelReqForDecision(chatReq, feedback, simulate, sessionId, decisionReqs, xinyiWarningRecord, chatReq.getTopP(), chatReq.getTemperature()); // log.info("请求大模型的决策的参数为{}", dataJson); PredictionsRequest request = PredictionsRequest.newBuilder() .setModelName("slibra_bot") .putInput("method", ByteString.copyFrom("decision_stream", "utf-8"))//推理 .putInput("data", ByteString.copyFrom(dataJson, "utf-8")) .buildPartial(); outputStream = response.getOutputStream(); Iterator predictions = stub.streamPredictions(request); while (predictions.hasNext()) { String responseStr = predictions.next().getPrediction().toStringUtf8(); // log.info("决策流式返回的结果是{}", responseStr); if(StringUtils.isBlank(responseStr)){ log.info("大模型返回的流式决策内容存在空的值,跳过此次输出"); continue; } // String message = JSON.parseObject(responseStr).getString("message"); //2024年5月25日16:37:16 按照大模型返回的类型解析数据 String biz = JSON.parseObject(responseStr).getString("biz"); // String message = JSON.parseObject(responseStr).getString("message"); if(BusinessEnum.BigModelBizEnum.OK.getCode().equals(biz)){ log.info("结尾语句并且是非JSON,无需处理,返回数据为{}", responseStr); //结束语句也流式输出,但是并不记录下来 2024年5月24日11:15:23 也不返回前端 }else if(BusinessEnum.BigModelBizEnum.DECISION_DEBUGGER.getCode().equals(biz)){ log.info("中间过程,目前只打印日志,不记录数据,也不返回给前端,返回数据为{}", responseStr); //结束语句也流式输出,但是并不记录下来 2024年5月24日11:15:23 也不返回前端 //2024年6月23日14:55:19 如果大模型返回error了,不保存记录,并且提示一句错误语 }else if(BusinessEnum.BigModelBizEnum.ERROR.getCode().equalsIgnoreCase(biz)){ log.info("调用大模型的时候,返回的是ERROR,返回数据为{}", responseStr); needAdd = false; //返回的是error 给前端返回一句话 try { String errMsg = this.buildErrMsg(); outputStream.write(errMsg.getBytes()); outputStream.flush(); } catch (IOException ex) { throw new RuntimeException(ex); } } else{//其他 要么alert 要么出的报告 // sb.append(responseStr); //2024年7月13日13:48:48 空的数据也返回,否则样式会有问题(当时加上这个是为了前端正常解析,否则他那里一次接受多个) /*if(StringUtils.isBlank(message)){ log.info("×××××××××××××××××××××××××××为空的数据暂时不返回×××××××××××××××××××××××××××"); }else { resultData.add(responseStr); outputStream.write(responseStr.getBytes()); outputStream.flush(); }*/ resultData.add(responseStr); outputStream.write(responseStr.getBytes()); outputStream.flush(); } } } catch (Exception e) { needAdd = false; // throw new RuntimeException(e); log.error("处理大模型推理异常,异常信息为{}", JSON.toJSONString(e)); //出现异常 给前端返回一句话 try { outputStream = response.getOutputStream(); String errMsg = this.buildErrMsg(); outputStream.write(errMsg.getBytes()); outputStream.flush(); } catch (IOException ex) { // throw new RuntimeException(ex); log.error("输出异常信义的时候又被中断了,异常信息为{}", JSON.toJSONString(ex)); } } finally { // log.info("sessionId是{}\n决策最终要保存的数据是{}", sessionId, JSON.toJSONString(resultData)); //保存聊天记录 //将问答更新到数据库中 if(needAdd) addChatRecord(chatReq, sessionId, type, warningId, dataJson, resultData); // 关闭输出流 try { outputStream.close(); } catch (IOException e) { throw new RuntimeException(e); }finally { channel.shutdown(); } } } private String buildBigModelReqForDecision(ChatReq chatReq, String feedback, String simulate, String sessionId, List decisionReqs, TXinyiWarningRecord xinyiWarningRecord, Double topP, Double temperature) { PolicyReq policyReq = new PolicyReq(); //2024年7月11日17:57:53 因为化验室的改了 但是 调用决策还得用原来的几个值 String category = xinyiWarningRecord.getCategory(); /*if(ROBOT_XSY_1.getCode().equalsIgnoreCase(category) || ROBOT_XSY_2.getCode().equalsIgnoreCase(category)){ category = CS_ZD.getCode(); } else if (ROBOT_ANDAN_1.getCode().equalsIgnoreCase(category) || ROBOT_ANDAN_2.getCode().equalsIgnoreCase(category)) { category = CS_AD.getCode(); }else if (ROBOT_ECCZLSY.getCode().equalsIgnoreCase(category)) { category = CS_ZL.getCode(); }*/ //2024年08月25日15:40:31 处理数据映射,改成字母,但是显示的还是中文 category = this.parseCategory(category); policyReq.setNorm(category); // policyReq.setNorm(chatReq.getCategory());//2024年7月12日16:23:24 因为有转义。。。 policyReq.setFeedback(StringUtils.isBlank(feedback) ? null : JSON.parseObject(feedback, Map.class)); policyReq.setSimulate(StringUtils.isBlank(simulate) ? null : JSON.parseObject(simulate, Map.class)); policyReq.setSessionId(sessionId); //2024年7月5日13:24:10 temperature做区分 GenerateArgs generateArgs = new GenerateArgs(); generateArgs.setTemperature(Objects.isNull(temperature) ? bigModelConfig.getTemperature() : temperature); generateArgs.setTopP(Objects.isNull(topP) ? bigModelConfig.getTopP() : topP); policyReq.setGenerateArgs(generateArgs); HashMap map = new HashMap<>(); map.put("rows", decisionReqs); //2024年6月25日14:16:05 增加报警是管控值报警还是标准值报警 if(WARNING_LEVEL_ONE.equals(xinyiWarningRecord.getLevel()) || WARNING_LEVEL_TWO.equals(xinyiWarningRecord.getLevel())) map.put("source", "bzz"); else map.put("source", "gkz"); policyReq.setExtra(map); return JSON.toJSONString(policyReq, JSONWriter.Feature.WriteNulls); } private String parseCategory(String category) { switch (category) { case "进水COD" : return "js_cod"; case "进水总磷" : return "js_tp"; case "进水总氮" : return "js_tn"; case "进水氨氮" : return "js_andan"; case "进水SS" : return "js_ss"; case "出水COD" : return "cs_cod"; case "出水总磷" : return "cs_tp"; case "出水总氮" : return "cs_tn"; case "出水氨氮" : return "cs_andan"; case "出水SS" : return "cs_ss"; case "#1好氧硝酸盐" : return "cs_tn_lxjc1"; case "#2好氧硝酸盐" : return "cs_tn_lxjc2"; case "出水氨氮连续检测" : return "cs_andan_lxjc1"; case "二沉池正磷酸盐" : return "cs_tp_lxjc"; default: throw new ServiceException("暂时不支持的类型"); } } private void addChatRecord(ChatReq chatReq, String sessionId, int type, String warningId, String question, List resultData) { chatReq.setSessionId(sessionId); chatReq.setType(type);//类型(0问答 1决策 2本地 3仿真预测) chatReq.setModule(3);//0=专家问答,1=智能工单,2=智能体助手,3.告警 // String showVal = this.buildShowValue(tXinyiWarningRecord, tXinyiIndustry, normConfig); // chatReq.setShowVal(feedback);//前端展示的数据和提问的数据不一致 //如果主动调用决策 showVal应该是最新的那条历史记录对应的数据 List tXinyiChatRecords = this.xinyiChatRecordMapper.selectTXinyiChatRecordList(TXinyiChatRecord.builder().warningId(warningId).build()); if(!CollectionUtils.isEmpty(tXinyiChatRecords)) chatReq.setShowVal(tXinyiChatRecords.get(0).getShowVal()); chatReq.setQuestion(question); chatReq.setAnswer(JSON.toJSONString(resultData)); chatReq.setWarningId(warningId); chatReq.setCounts(1);//问答次数 String userId = SecurityUtils.getUserId().toString(); String username = SecurityUtils.getUsername(); chatReq.setUserId(userId); chatReq.setCreateBy(username); chatReq.setCreateTime(DateUtils.getNowDate()); this.xinyiChatRecordMapper.insertTXinyiChatRecord(chatReq); } private List getDecisionReqs() { //List> list = this.xinyiIndustryMapper.selectLast10RecordsForDecision(); //2024年5月21日15:23:07 这里不能用关联查询处理,日报要获取最新的一条而不是今日的数据。 List decisionReqs = this.xinyiIndustryMapper.selectLast10RecordsForDecisionOnlyIndustry(); if(!CollectionUtils.isEmpty(decisionReqs)){ //处理日报数据 TXinyiDaily daily = this.xinyiDailyMapper.selectNewestData(); for (DecisionReq decisionReq : decisionReqs) { if(!Objects.isNull(daily)){ WaterFormat.getWaterDecimationData(decisionReq, daily); } } } return decisionReqs; } private String buildErrMsg() { JSONObject jsonObject = new JSONObject(); jsonObject.put("biz", DECISION_REPORT.getCode()); jsonObject.put("message", "大模型决策方案生成有点问题,请稍后再试"); return JSON.toJSONString(jsonObject); } private String buildMsg() { JSONObject jsonObject = new JSONObject(); jsonObject.put("biz", DECISION_REPORT.getCode()); jsonObject.put("message", "此报警已经关闭了,无法生成决策方案"); return JSON.toJSONString(jsonObject); } /** * RAG+⼤模型的调⽤参数 * 2024年6月17日09:40:38 工单新增 自定义工单处理 * @return */ @PostMapping(value = "/inferStreamRag") public void inferStreamRag(HttpServletRequest httpServletRequest, HttpServletResponse response, @RequestBody ChatReq chatReq) { // public void inferStreamRag(HttpServletResponse response, ChatReq chatReq) { log.info("进入了调⽤RAG+⼤模型的调⽤参数"); // 获取输出流 OutputStream outputStream = null; ManagedChannel channel = null; // response.setContentType("text/plain"); response.setContentType("text/event-stream"); response.setCharacterEncoding("utf-8"); //请求参数 Integer module = chatReq.getModule();//来自那个模块 Date reportDate = chatReq.getReportDate();//如果传过值来了 代表的是工单类型的问答 String timeBegin = chatReq.getTimeBegin(); String timeEnd = chatReq.getTimeEnd(); if((Objects.isNull(reportDate) && StringUtils.isBlank(timeBegin) && StringUtils.isBlank(timeEnd)) && module == 1){//工单 必须要输入日期 //智能工单需要传入一个时间的参数 try { outputStream = response.getOutputStream(); outputStream.write(CHAT_GONGDAN_1_ERROR_MSG.getBytes()); outputStream.flush(); } catch (IOException e) { throw new RuntimeException(e); } return; } StringBuilder sb = new StringBuilder(); String sessionId = chatReq.getSessionId(); int isStrong = Objects.isNull(chatReq.getIsStrong()) ? 0 : chatReq.getIsStrong(); String tools = STR_FALSE;//问答因为不确认是否走工具,所以传true; 但是工单一定是走工具的,传工具名称 2024年08月11日15:51:33 只有工具才是具体名称 boolean useRag = true;//只有问答才传true,其他默认都false String extraStr = ""; //如果是工单,需要特殊处理一下showVal和question if(1 == module){ if(StringUtils.isBlank(timeBegin) && StringUtils.isBlank(timeEnd)){//按天生成工单 //获取前一天的日期 Date beforeYesterday = DateUtils.plusDate(-1, reportDate); //先用日期获取当天和前一天的数据,如果获取不到,则提示错误信息 String date = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, reportDate); chatReq.setShowVal(GONGDAN_TITLE.replace("#{0}", date));//处理展示的标题 /*String dateBefore = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, beforeYesterday); String currentDate = DateUtils.parseDateToStr(DateUtils.YYYYMMDD_TS, reportDate); String earlyDate = DateUtils.parseDateToStr(DateUtils.YYYYMMDD_TS, beforeYesterday); List tXinyiDailiesNow = this.xinyiDailyMapper.selectTXinyiDailyList(TXinyiDaily.builder().testDate(currentDate).build()); List tXinyiDailiesBefore = this.xinyiDailyMapper.selectTXinyiDailyList(TXinyiDaily.builder().testDate(earlyDate).build()); if(CollectionUtils.isEmpty(tXinyiDailiesNow) || CollectionUtils.isEmpty(tXinyiDailiesBefore)){ //没有查询到数据 try { outputStream = response.getOutputStream(); outputStream.write(CHAT_GONGDAN_2_ERROR_MSG.getBytes()); outputStream.flush(); } catch (IOException e) { throw new RuntimeException(e); } return; } //如果查询到了 拼装数据 //2024年6月25日19:11:49 prompt优化 chatReq.setQuestion(this.buildGDQuestionNew(date, dateBefore, tXinyiDailiesNow.get(0), tXinyiDailiesBefore.get(0)));*/ //2024年7月29日11:38:53 工单改版,由大模型处理数据 // chatReq.setQuestion(this.buildGDNormalQuestion(DateUtils.parseDateToStr(DateUtils.YYYYMMDD_TS, reportDate))); chatReq.setQuestion(MODULE_CONTENT_NORMAL); extraStr = this.buildGDNormalQuestion(DateUtils.parseDateToStr(DateUtils.YYYYMMDD_TS, reportDate)); }else{//自定义工单 chatReq.setShowVal(GONGDAN_TITLE_CUSTOM.replace("#{0}", timeBegin).replace("#{1}", timeEnd));//处理展示的标题 WorkOrderReq workOrderReq = new WorkOrderReq(); BeanUtils.copyProperties(chatReq, workOrderReq); //拿到数据 List workOrderRes = frontService.customWorkOrder(workOrderReq); //拼接prompt /*String question = this.buildGDQuestionCustom(workOrderRes, workOrderReq); //2024年6月23日17:21:58 判断问题的长度,如果长度大于配置的值(5000),提示一句话 if(question.length() > MAX_QUESTION_LENGTH){ log.info("*************自定义工单超长了,组装完的参数为{}", question); try { outputStream = response.getOutputStream(); outputStream.write(CHAT_GONGDAN_CUSTOM_ERROR_MSG.getBytes()); outputStream.flush(); } catch (IOException e) { throw new RuntimeException(e); } return; }*/ //2024年7月29日11:47:05 调整:图表以及大模型的数据都由大模型处理,这里拼接他需要的格式 // chatReq.setQuestion(this.buildGDCustomQuestion(timeBegin, timeEnd, chatReq.getWhichWay())); chatReq.setQuestion(MODULE_CONTENT_CUSTOM); extraStr = buildGDCustomQuestion(timeBegin, timeEnd, chatReq); //2024年6月20日16:48:08 如果是自定义工单,需要处理图表 放到remark中 chatReq.setRemark(JSON.toJSONString(frontService.customWorkOrderHandleByData(workOrderReq, workOrderRes), JSONWriter.Feature.WriteNulls)); } isStrong = 0;//2024年7月29日14:15:47 工单不走文心一言了 useRag = false; tools = TOOLS_WORK_ORDER; } String ipAddr = IpUtils.getIpAddr();//获取用户的ip地址 传给大模型 int counts = 1;//默认是第一次 List historyDates = new ArrayList<>(); //查询历史数据,放入集合中 if(StringUtils.isBlank(sessionId)) sessionId= IdUtils.simpleUUID();//第一次 else{ //通过sessionId获取所有的问答记录 List chatRecords = this.chatRecordMapper.selectTXinyiChatRecordList(TXinyiChatRecord.builder().sessionId(sessionId).build()); if(!CollectionUtils.isEmpty(chatRecords)){ for (TXinyiChatRecord chatRecord : chatRecords) { historyDates.add(chatRecord.getQuestion()); historyDates.add(chatRecord.getAnswer()); } //问答次数增加 counts = chatRecords.size() + 1; } } //将新的问题放入集合中 historyDates.add(chatReq.getQuestion()); String headerPort = httpServletRequest.getHeader(port); try { channel = ManagedChannelBuilder.forAddress(bigModelConfig.getIp(), StringUtils.isBlank(headerPort) ? bigModelConfig.getPort() : Integer.parseInt(headerPort)) .usePlaintext() .build(); InferenceAPIsServiceGrpc.InferenceAPIsServiceBlockingStub stub = InferenceAPIsServiceGrpc.newBlockingStub(channel); // 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) + "}"; //2024年6月25日18:12:23 优化,不再使用拼接JSON字符串 //2024年7月27日18:13:47 前端传过来tools String toolsReq = chatReq.getTools(); //2024年7月29日14:20:22 先判断是不是走本地工具,再判断前端工具 //2024年08月11日15:54:52 问答默认都是false了,只有前端指定工具才是具体的工具名称 // if(StringUtils.isBlank(tools) || STR_TRUE.equals(tools)){ if(StringUtils.isNotBlank(toolsReq)){ useRag = false;//2024年7月27日18:20:23 走本地工具,不需要文本增强 isStrong = 0; tools = toolsReq; } //2024年08月21日11:49:25 如果是智慧办公,useRag也是false if(2 == module){//智慧办公 useRag = false; } // else // tools = tools; // } String dataJson = buildBigModelReqForChat(sessionId, historyDates, ipAddr, isStrong, chatReq.getTopP(), chatReq.getTemperature(), tools, useRag, extraStr, chatReq.getPrompt()); log.info("******请求大模型的问答参数为{}", dataJson); PredictionsRequest request = PredictionsRequest.newBuilder() .setModelName("slibra_bot") .putInput("method", ByteString.copyFrom("infer_stream", "utf-8"))//推理 .putInput("data", ByteString.copyFrom(dataJson, "utf-8")) .buildPartial(); outputStream = response.getOutputStream(); Iterator predictions = stub.streamPredictions(request); //将结果记录到问答表 while (predictions.hasNext()) { String responseStr = predictions.next().getPrediction().toStringUtf8(); // log.info("大模型问答返回的原始结果为{}", responseStr); if(StringUtils.isBlank(responseStr)){ log.error("大模型返回的是空,无法解析"); continue; } responseStr = JSON.parseObject(responseStr).getString("message"); //2024年7月13日14:30:19 为空字符串的(实际可能是\n这种的)也返回前端,否则样式有问题 if("complete".equals(responseStr) || Objects.isNull(responseStr)){ // System.out.println("结尾语句并且是非JSON,无需处理"); log.info("返回的结果message为{},无需再次处理", responseStr); //结束语句也流式输出,但是并不记录下来 2024年5月24日11:15:23 也不返回前端 }else{ sb.append(responseStr); outputStream.write(responseStr.getBytes()); outputStream.flush(); } } //将问答更新到数据库中 chatReq.setSessionId(sessionId); chatReq.setAnswer(sb.toString()); chatReq.setType(0);//0问答 1决策 2本地 3仿真预测 chatReq.setModule(module);//0专家问答 1智能工单 2智能体助手 3告警 4简报 //2024年5月28日10:58:02 由于部分问题 展示的和调用大模型的不一样,所以这个由前端传过来 // chatReq.setShowVal(question); chatReq.setCounts(counts);//问答次数 String userId = SecurityUtils.getUserId().toString(); String username = SecurityUtils.getUsername(); chatReq.setUserId(userId); chatReq.setCreateBy(username); chatReq.setCreateTime(DateUtils.getNowDate()); this.chatRecordMapper.insertTXinyiChatRecord(chatReq); outputStream.write((DEFAULT_ID_IDENTIFIER + chatReq.getId()).getBytes()); outputStream.flush(); } catch (IOException e) { throw new RuntimeException(e); } finally { // 关闭输出流 try { outputStream.close(); } catch (IOException e) { throw new RuntimeException(e); }finally { channel.shutdown(); } } // return AjaxResult.success("ok"); } private String buildGDCustomQuestion(String timeBegin, String timeEnd, ChatReq chatReq) { //存放的JSON HashMap map = new HashMap<>(); map.put(TIMEBEGIN, timeBegin); map.put(TIMEEND, timeEnd); map.put(MODULE, MODULE_CONTENT_CUSTOM); map.put(TYPE, CUSTOM_WORK_ORDER); //拼装的SQL HashMap sqlMap = new HashMap<>(); StringBuilder sb = new StringBuilder(); if(chatReq.getWhichWay() == 0){//日报 // sqlMap.put(REPORT, sb.append(TOOLS_WORK_ORDER_SQL_DAILY).append(TOOLS_WORK_ORDER_SQL_DIAN_BEGIN).append(TIMEBEGIN).append(TOOLS_WORK_ORDER_SQL_DIAN_END).append(TOOLS_WORK_ORDER_SQL_AND).append(TOOLS_WORK_ORDER_SQL_DIAN_BEGIN).append(TIMEEND).append(TOOLS_WORK_ORDER_SQL_DIAN_END).append(TOOLS_WORK_ORDER_SQL_END).toString()); //2024年7月31日10:32:14 要根据前端用户选择的不同指标来拼接不同的SQL //只要出现一个就可以拼接了 if (chatReq.getJsSlq() || chatReq.getJsCod() || chatReq.getJsTn() || chatReq.getJsTp() || chatReq.getJsNh3() || chatReq.getJsSs() || chatReq.getCsSlqc() || chatReq.getCsCod() || chatReq.getCsTn() || chatReq.getCsTp() || chatReq.getCsNh3() || chatReq.getCsSs()){ //拼接 sb.append(TOOLS_WORK_ORDER_SQL_DAILY_BEGIN); if(chatReq.getJsSlq()) sb.append(",AVG(JSL) 进水量"); if(chatReq.getJsCod()) sb.append(",AVG(JS_COD) 进水COD"); if(chatReq.getJsTn()) sb.append(",AVG(JS_TN) 进水总氮"); if(chatReq.getJsTp()) sb.append(",AVG(JS_TP) 进水总磷"); if(chatReq.getJsNh3()) sb.append(",AVG(JS_NH3) 进水氨氮"); if(chatReq.getJsSs()) sb.append(",AVG(JS_SS) 进水SS"); if(chatReq.getCsSlqc()) sb.append(",AVG(CSL) 出水量"); if(chatReq.getCsCod()) sb.append(",AVG(CS_COD) 出水COD"); if(chatReq.getCsTn()) sb.append(",AVG(CS_TN) 出水总氮"); if(chatReq.getCsTp()) sb.append(",AVG(CS_TP) 出水总磷"); if(chatReq.getCsNh3()) sb.append(",AVG(CS_NH3) 出水氨氮"); if(chatReq.getCsSs()) sb.append(",AVG(CS_SS) 出水SS"); sb.append(TOOLS_WORK_ORDER_SQL_DAILY_END).append(TOOLS_WORK_ORDER_SQL_DIAN_BEGIN).append(TIMEBEGIN).append(TOOLS_WORK_ORDER_SQL_DIAN_END).append(TOOLS_WORK_ORDER_SQL_AND).append(TOOLS_WORK_ORDER_SQL_DIAN_BEGIN).append(TIMEEND).append(TOOLS_WORK_ORDER_SQL_DIAN_END).append(TOOLS_WORK_ORDER_SQL_END); sqlMap.put(REPORT, sb.toString()); //清空 sb = new StringBuilder(); } }else{//工业库 // sqlMap.put(ONLINE, sb.append(TOOLS_WORK_ORDER_SQL_INDUSTRY).append(TOOLS_WORK_ORDER_SQL_DIAN_BEGIN).append(TIMEBEGIN).append(TOOLS_WORK_ORDER_SQL_DIAN_END).append(TOOLS_WORK_ORDER_SQL_AND).append(TOOLS_WORK_ORDER_SQL_DIAN_BEGIN).append(TIMEEND).append(TOOLS_WORK_ORDER_SQL_DIAN_END).append(TOOLS_WORK_ORDER_SQL_END).toString()); //2024年7月31日10:32:14 要根据前端用户选择的不同指标来拼接不同的SQL //只要出现一个就可以拼接了 if (chatReq.getJsSlq() || chatReq.getJsCod() || chatReq.getJsTn() || chatReq.getJsTp() || chatReq.getJsNh3() || chatReq.getJsSs() || chatReq.getCsSlqc() || chatReq.getCsCod() || chatReq.getCsTn() || chatReq.getCsTp() || chatReq.getCsNh3() || chatReq.getCsSs()){ //拼接 sb.append(TOOLS_WORK_ORDER_SQL_INDUSTRY_BEGIN); if(chatReq.getJsSlq()) sb.append(", AVG(JS_SLQ) 进水量"); if(chatReq.getJsCod()) sb.append(",AVG(JS_COD) 进水COD"); if(chatReq.getJsTn()) sb.append(",AVG(JS_TN) 进水总氮"); if(chatReq.getJsTp()) sb.append(",AVG(JS_TP) 进水总磷"); if(chatReq.getJsNh3()) sb.append(",AVG(JS_NH3) 进水氨氮"); if(chatReq.getJsSs()) sb.append(",AVG(JS_SS) 进水SS"); if(chatReq.getCsSlqc()) sb.append(",AVG(CS_SLQC) 出水量"); if(chatReq.getCsCod()) sb.append(",AVG(CS_COD) 出水COD"); if(chatReq.getCsTn()) sb.append(",AVG(CS_TN) 出水总氮"); if(chatReq.getCsTp()) sb.append(",AVG(CS_TP) 出水总磷"); if(chatReq.getCsNh3()) sb.append(",AVG(CS_NH3) 出水氨氮"); if(chatReq.getCsSs()) sb.append(",AVG(CS_SS) 出水SS"); sb.append(TOOLS_WORK_ORDER_SQL_INDUSTRY_END).append(TOOLS_WORK_ORDER_SQL_DIAN_BEGIN).append(TIMEBEGIN).append(TOOLS_WORK_ORDER_SQL_DIAN_END).append(TOOLS_WORK_ORDER_SQL_AND).append(TOOLS_WORK_ORDER_SQL_DIAN_BEGIN).append(TIMEEND).append(TOOLS_WORK_ORDER_SQL_DIAN_END).append(TOOLS_WORK_ORDER_SQL_END); sqlMap.put(ONLINE, sb.toString()); //清空 sb = new StringBuilder(); } } // sqlMap.put(ROBOT, sb.append(TOOLS_WORK_ORDER_SQL_ROBOT).append(TOOLS_WORK_ORDER_SQL_DIAN_BEGIN).append(TIMEBEGIN).append(TOOLS_WORK_ORDER_SQL_DIAN_END).append(TOOLS_WORK_ORDER_SQL_AND).append(TOOLS_WORK_ORDER_SQL_DIAN_BEGIN).append(TIMEEND).append(TOOLS_WORK_ORDER_SQL_DIAN_END).append(TOOLS_WORK_ORDER_SQL_END).toString()); //2024年7月31日10:32:14 要根据前端用户选择的不同指标来拼接不同的SQL //只要出现一个就可以拼接了 if(chatReq.getNo3Hlj1Jqr() || chatReq.getNo3Hlj2Jqr() || chatReq.getNh31Jqr() || chatReq.getNh32Jqr() || chatReq.getNo3Qyc1Jqr() || chatReq.getNo3Qyc2Jqr() || chatReq.getTpRccJqr()){ //拼接 sb.append(TOOLS_WORK_ORDER_SQL_ROBOT_BEGIN); if(chatReq.getNo3Hlj1Jqr()){ sb.append(", AVG(NO3_HLJ1_JQR) '#1好氧池硝酸盐'"); } if(chatReq.getNo3Hlj2Jqr()){ sb.append(",AVG(NO3_HLJ2_JQR) '#2好氧池硝酸盐'"); } if(chatReq.getNh31Jqr()){ sb.append(",AVG(NH3_1_JQR) '#1缺氧氨氮'"); } if(chatReq.getNh32Jqr()){ sb.append(",AVG(NH3_2_JQR) '#2缺氧氨氮'"); } if(chatReq.getNo3Qyc1Jqr()){ sb.append(",AVG(NO3_QYC_1_JQR) '#1缺氧池硝酸盐'"); } if(chatReq.getNo3Qyc2Jqr()){ sb.append(",AVG(NO3_QYC_2_JQR) '#2缺氧池硝酸盐'"); } if(chatReq.getTpRccJqr()){ sb.append(",AVG(TP_RCC_JQR) '二沉池正磷酸盐'"); } sb.append(TOOLS_WORK_ORDER_SQL_ROBOT_END).append(TOOLS_WORK_ORDER_SQL_DIAN_BEGIN).append(TIMEBEGIN).append(TOOLS_WORK_ORDER_SQL_DIAN_END).append(TOOLS_WORK_ORDER_SQL_AND).append(TOOLS_WORK_ORDER_SQL_DIAN_BEGIN).append(TIMEEND).append(TOOLS_WORK_ORDER_SQL_DIAN_END).append(TOOLS_WORK_ORDER_SQL_END); sqlMap.put(ROBOT, sb.toString()); } map.put(DATA, sqlMap); return JSON.toJSONString(map); } private String buildGDNormalQuestion(String date) { //存放的JSON HashMap map = new HashMap<>(); map.put(TIMEBEGIN, date); map.put(TIMEEND, date); map.put(MODULE, MODULE_CONTENT_NORMAL); map.put(TYPE, NORMAL_WORK_ORDER); return JSON.toJSONString(map); } private String buildBigModelReqForChat(String sessionId, List historyDates, String ipAddr, int isStrong, Double topP, Double temperature, String tools, boolean useRag, String extraStr, String prompt) { ChatRequest chatRequest = new ChatRequest(); chatRequest.setSessionId(sessionId); chatRequest.setHistoryDia(historyDates); //2024年7月5日13:24:10 temperature做区分 GenerateArgs generateArgs = new GenerateArgs(); generateArgs.setTemperature(Objects.isNull(temperature) ? bigModelConfig.getTemperature() : temperature); generateArgs.setTopP(Objects.isNull(topP) ? bigModelConfig.getTopP() : topP); chatRequest.setGenerateArgs(generateArgs); Map extra = new HashMap<>(); extra.put("ip_address", ipAddr); if(StringUtils.isNotBlank(extraStr)) extra.put(TOOLS_WORK_ORDER, extraStr); chatRequest.setExtra(extra); chatRequest.setStrengthen(isStrong == 1); chatRequest.setTools(tools); chatRequest.setUseRag(useRag); //2024年08月11日16:04:21 允许用户自定义prompt chatRequest.setPrompt(StringUtils.isBlank(prompt) ? DEFAULT_PROMPT : prompt); return JSON.toJSONString(chatRequest); } private String buildGDQuestionCustom(List workOrderRes, WorkOrderReq workOrderReq) { StringBuilder sb = new StringBuilder(); sb.append(GONGDAN_PROMPT_CUSTOM_BEGIN.replace("#{0}", workOrderReq.getTimeBegin()).replace("#{1}", workOrderReq.getTimeEnd())); if(workOrderReq.getJsSlq() || workOrderReq.getJsSs() || workOrderReq.getJsTp() || workOrderReq.getJsTn() || workOrderReq.getJsCod() || workOrderReq.getJsNh3()){ sb.append("进水:\n"); for (WorkOrderRes workOrderRe : workOrderRes) { sb.append(workOrderRe.getTime()).append(":"); if(workOrderReq.getJsCod()) sb.append("进水COD:").append(DecimalUtils.getAbsAndScale(workOrderRe.getJsCod(), INT_2)).append("mg/L、"); if(workOrderReq.getJsTn()) sb.append("进水总氮:").append(DecimalUtils.getAbsAndScale(workOrderRe.getJsTn(), INT_2)).append("mg/L、"); if(workOrderReq.getJsTp()) sb.append("进水总磷:").append(DecimalUtils.getAbsAndScale(workOrderRe.getJsTp(), INT_2)).append("mg/L、"); if(workOrderReq.getJsNh3()) sb.append("进水氨氮:").append(DecimalUtils.getAbsAndScale(workOrderRe.getJsNh3(), INT_2)).append("mg/L、"); if(workOrderReq.getJsSs()) sb.append("进水SS:").append(DecimalUtils.getAbsAndScale(workOrderRe.getJsSs(), INT_2)).append("mg/L、"); if(workOrderReq.getJsSlq()) sb.append("进水水量:").append(DecimalUtils.getAbsAndScale(workOrderRe.getJsSlq(), INT_2)).append("m³/d、"); } } if(workOrderReq.getCsSlqc() || workOrderReq.getCsSs() || workOrderReq.getCsTp() || workOrderReq.getCsTn() || workOrderReq.getCsCod() || workOrderReq.getCsNh3()){ sb.append("出水:\n"); for (WorkOrderRes workOrderRe : workOrderRes) { sb.append(workOrderRe.getTime()).append(":"); if(workOrderReq.getCsCod()) sb.append("出水COD:").append(DecimalUtils.getAbsAndScale(workOrderRe.getCsCod(), INT_2)).append("mg/L、"); if(workOrderReq.getCsTn()) sb.append("出水总氮:").append(DecimalUtils.getAbsAndScale(workOrderRe.getCsTn(), INT_2)).append("mg/L、"); if(workOrderReq.getCsTp()) sb.append("出水总磷:").append(DecimalUtils.getAbsAndScale(workOrderRe.getCsTp(), INT_2)).append("mg/L、"); if(workOrderReq.getCsNh3()) sb.append("出水氨氮:").append(DecimalUtils.getAbsAndScale(workOrderRe.getCsNh3(), INT_2)).append("mg/L、"); if(workOrderReq.getCsSs()) sb.append("出水SS:").append(DecimalUtils.getAbsAndScale(workOrderRe.getCsSs(), INT_2)).append("mg/L、"); if(workOrderReq.getCsSlqc()) sb.append("出水水量:").append(DecimalUtils.getAbsAndScale(workOrderRe.getCsSlqc(), INT_2)).append("m³/d、"); } } if(workOrderReq.getNo3Hlj1Jqr() || workOrderReq.getNo3Hlj2Jqr() || workOrderReq.getNh31Jqr() || workOrderReq.getNh32Jqr() || workOrderReq.getNo3Qyc1Jqr() || workOrderReq.getNo3Qyc2Jqr() || workOrderReq.getTpRccJqr()){ sb.append("过程指标:\n"); for (WorkOrderRes workOrderRe : workOrderRes) { sb.append(workOrderRe.getTime()).append(":"); if(workOrderReq.getNo3Hlj1Jqr()) sb.append("#1好氧池硝酸盐:").append(DecimalUtils.getAbsAndScale(workOrderRe.getNo3Hlj1Jqr(), INT_2)).append("mg/L、"); if(workOrderReq.getNo3Hlj2Jqr()) sb.append("#2好氧池硝酸盐:").append(DecimalUtils.getAbsAndScale(workOrderRe.getNo3Hlj2Jqr(), INT_2)).append("mg/L、"); if(workOrderReq.getNo3Qyc1Jqr()) sb.append("#1缺氧池硝酸盐:").append(DecimalUtils.getAbsAndScale(workOrderRe.getNo3Qyc1Jqr(), INT_2)).append("mg/L、"); if(workOrderReq.getNo3Qyc2Jqr()) sb.append("#2缺氧池硝酸盐:").append(DecimalUtils.getAbsAndScale(workOrderRe.getNo3Qyc2Jqr(), INT_2)).append("mg/L、"); if(workOrderReq.getTpRccJqr()) sb.append("二沉池正磷酸盐:").append(DecimalUtils.getAbsAndScale(workOrderRe.getTpRccJqr(), INT_2)).append("mg/L、"); if(workOrderReq.getNh31Jqr()) sb.append("#1缺氧氨氮:").append(DecimalUtils.getAbsAndScale(workOrderRe.getNh31Jqr(), INT_2)).append("mg/L、"); if(workOrderReq.getNh32Jqr()) sb.append("#2缺氧氨氮:").append(DecimalUtils.getAbsAndScale(workOrderRe.getNh32Jqr(), INT_2)).append("mg/L、"); } } sb.append(GONGDAN_PROMPT_CUSTOM_END_1); if(workOrderReq.getJsCod() || workOrderReq.getCsCod()) sb.append("化学需氧量(COD)、"); if(workOrderReq.getJsTp() || workOrderReq.getCsTp()) sb.append("总磷(TP)、"); if(workOrderReq.getJsTn() || workOrderReq.getCsTn()) sb.append("总氮(TN)、"); if(workOrderReq.getJsSs() || workOrderReq.getCsSs()) sb.append("SS、"); if(workOrderReq.getJsNh3() || workOrderReq.getCsNh3()) sb.append("氨氮、"); sb.append(GONGDAN_PROMPT_CUSTOM_END_2); return sb.toString(); } /** * 通过日期构建工单的请求参数 --new * @return */ private String buildGDQuestionNew(String date, String dateBefore, TXinyiDaily tXinyiDaily, TXinyiDaily tXinyiDaily1) { StringBuilder sb = new StringBuilder(GONGDAN_PROMPT_BEGIN_PRE_1).append(date); // sb.append(GONGDAN_PROMPT_BEGIN.replace("#{0}", date)); sb.append(GONGDAN_PROMPT_BEGIN_PRE_2).append(date); sb.append(GONGDAN_PROMPT_BEGIN_PRE_3); sb.append("进水COD:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getJsCod(), INT_2)).append("mg/L、"); sb.append("进水总氮:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getJsTn(), INT_2)).append("mg/L、"); sb.append("进水总磷:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getJsTp(), INT_2)).append("mg/L、"); sb.append("进水氨氮:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getJsNh3(), INT_2)).append("mg/L、"); sb.append("进水SS:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getJsSs(), INT_2)).append("mg/L、"); sb.append("进水水量:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getJSL(), INT_2)).append("m³/d、"); sb.append(";"); sb.append("出水COD:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getCsCod(), INT_2)).append("mg/L、"); sb.append("出水总氮:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getCsTn(), INT_2)).append("mg/L、"); sb.append("出水总磷:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getCsTp(), INT_2)).append("mg/L、"); sb.append("出水氨氮:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getCsNh3(), INT_2)).append("mg/L、"); sb.append("出水SS:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getCsSs(), INT_2)).append("mg/L、"); sb.append("出水水量:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getCSL(), INT_2)).append("m³/d。"); sb.append("二、生化指标:\n"); //todo 单位确认 下面的应该不是 mg/L sb.append("#1好氧池pH:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcOnePh(), INT_2)).append("、"); sb.append("#1好氧池SV:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyOneSv(), INT_2)).append("、"); sb.append("#1好氧池SVI:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyOneSvi(), INT_2)).append("、"); sb.append("#1好氧池MLSS:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyOneMlss(), INT_2)).append("、"); sb.append("#1好氧池MLVSS:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyOneMlvss(), INT_2)).append("、"); sb.append("#1好氧池DO:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyOneDo(), INT_2)).append(";"); sb.append("#2好氧池pH:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcTwoPh(), INT_2)).append("、"); sb.append("#2好氧池SV:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyTwoSv(), INT_2)).append("、"); sb.append("#2好氧池SVI:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyTwoSvi(), INT_2)).append("、"); sb.append("#2好氧池MLSS:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyTwoMlss(), INT_2)).append("、"); sb.append("#2好氧池MLVSS:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyTwoMlvss(), INT_2)).append("、"); sb.append("#2好氧池DO:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcHyTwoDo(), INT_2)).append(";"); sb.append("#1厌氧池DO:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcYyOneDo(), INT_2)).append(";"); sb.append("#2厌氧池DO:").append(DecimalUtils.getAbsAndScale(tXinyiDaily.getShcYyTwoDo(), INT_2)).append("。"); sb.append("最近7天的数据如下:\n"); List dailyTwoRecords = this.xinyiDailyMapper.selectNRecords(DAILY_REPORT_COUNT_RECORD); //正常不会有这种问题 因为日报有很多条 if(CollectionUtils.isEmpty(dailyTwoRecords) || dailyTwoRecords.size() < DAILY_REPORT_COUNT_RECORD){ log.error("进入了定时生成每日简报数据 获取最新的{}条数据不足,终止", DAILY_REPORT_COUNT_RECORD); return sb.toString(); } //查询配置信息 List tXinyiNormConfigs = this.xinyiNormConfigMapper.selectTXinyiNormConfigList(null); if(CollectionUtils.isEmpty(tXinyiNormConfigs)) return null; TXinyiNormConfig normConfig = tXinyiNormConfigs.get(0); //获取数据 for (TXinyiDaily dailyTwoRecord : dailyTwoRecords) { sb.append(formateDateStr(dailyTwoRecord.getTestDate())).append("进出水质数据:\n"); sb.append("进水:\n"); sb.append("进水COD").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getJsCod(), 2)).append("mg/L、"); sb.append("进水总氮").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getJsTn(), 2)).append("mg/L、"); sb.append("进水总磷").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getJsTp(), 2)).append("mg/L、"); sb.append("进水氨氮").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getJsNh3(), 2)).append("mg/L、"); sb.append("进水SS").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getJsSs(), 2)).append("mg/L、"); sb.append("进水水量").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getJSL(), 2)).append("m³/d").append(";\n"); sb.append("出水:\n"); sb.append("出水COD").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getCsCod(), 2)).append("mg/L、"); sb.append("出水总氮").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getCsTn(), 2)).append("mg/L、"); sb.append("出水总磷").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getCsTp(), 2)).append("mg/L、"); sb.append("出水氨氮").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getCsNh3(), 2)).append("mg/L、"); sb.append("出水SS").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getCsSs(), 2)).append("mg/L、"); sb.append("出水水量").append(DecimalUtils.getAbsAndScale(dailyTwoRecord.getCSL(), 2)).append("m³/d").append("。\n"); } sb.append(SHORT_REPORT_END); sb.append("进水COD:").append(DecimalUtils.getAbsAndScale(normConfig.getJscodSjz(), 2)).append("mg/L、"); sb.append("进水总氮:").append(DecimalUtils.getAbsAndScale(normConfig.getJszdSjz(), 2)).append("mg/L、"); sb.append("进水总磷:").append(DecimalUtils.getAbsAndScale(normConfig.getJszlSjz(), 2)).append("mg/L、"); sb.append("进水氨氮:").append(DecimalUtils.getAbsAndScale(normConfig.getJsadSjz(), 2)).append("mg/L、"); sb.append("进水SS:").append(DecimalUtils.getAbsAndScale(normConfig.getJsssSjz(), 2)).append("mg/L、"); sb.append("出水COD:").append(DecimalUtils.getAbsAndScale(normConfig.getCscodBzz(), 2)).append("mg/L、"); sb.append("出水总氮:").append(DecimalUtils.getAbsAndScale(normConfig.getCszzBzz(), 2)).append("mg/L、"); sb.append("出水总磷:").append(DecimalUtils.getAbsAndScale(normConfig.getCszlBzz(), 2)).append("mg/L、"); sb.append("出水氨氮:").append(DecimalUtils.getAbsAndScale(normConfig.getCsadBzz(), 2)).append("mg/L、"); sb.append("出水SS:").append(DecimalUtils.getAbsAndScale(normConfig.getCsssBzz(), 2)).append("mg/L").append("。"); sb.append(GONGDAN_PROMPT_END); return sb.toString(); } /** * * 2022/01/01 转成2022年01月01日 数据 * @param testDate * @return */ private String formateDateStr(String testDate) { if(StringUtils.isBlank(testDate)) return ""; if(!testDate.contains("/")) return testDate; String[] split = testDate.split("/"); return split[0] + "年" + split[1] + "月" + split[2] + "日"; } /** * 通过日期构建工单的请求参数 * @return */ private String buildGDQuestion(String date, String dateBefore, TXinyiDaily xinyiDailyNow, TXinyiDaily xinyiDailyBefore) { String result = GONGDAN_PROMPT; result = result.replace("{0}", date); result = result.replace("{1}", dateBefore); //替换各种指标 result = result.replace("{2}", String.valueOf(xinyiDailyNow.getJsCod())); result = result.replace("{3}", String.valueOf(xinyiDailyNow.getJsTn())); result = result.replace("{4}", String.valueOf(xinyiDailyNow.getJsTp())); result = result.replace("{5}", String.valueOf(xinyiDailyNow.getJsNh3())); result = result.replace("{6}", String.valueOf(xinyiDailyNow.getJsSs())); result = result.replace("{7}", String.valueOf(xinyiDailyNow.getJSL())); result = result.replace("{8}", String.valueOf(xinyiDailyNow.getCsCod())); result = result.replace("{9}", String.valueOf(xinyiDailyNow.getCsTn())); result = result.replace("{10}", String.valueOf(xinyiDailyNow.getCsTp())); result = result.replace("{11}", String.valueOf(xinyiDailyNow.getCsNh3())); result = result.replace("{12}", String.valueOf(xinyiDailyNow.getCsSs())); result = result.replace("{13}", String.valueOf(xinyiDailyNow.getCSL())); result = result.replace("{14}", String.valueOf(xinyiDailyNow.getShcOnePh())); result = result.replace("{15}", String.valueOf(xinyiDailyNow.getShcHyOneSv())); result = result.replace("{16}", String.valueOf(xinyiDailyNow.getShcHyOneSvi())); result = result.replace("{17}", String.valueOf(xinyiDailyNow.getShcHyOneMlss())); result = result.replace("{18}", String.valueOf(xinyiDailyNow.getShcHyOneMlvss())); result = result.replace("{19}", String.valueOf(xinyiDailyNow.getShcHyOneDo())); result = result.replace("{20}", String.valueOf(xinyiDailyNow.getShcTwoPh())); result = result.replace("{21}", String.valueOf(xinyiDailyNow.getShcHyTwoSv())); result = result.replace("{22}", String.valueOf(xinyiDailyNow.getShcHyTwoSvi())); result = result.replace("{23}", String.valueOf(xinyiDailyNow.getShcHyTwoMlss())); result = result.replace("{24}", String.valueOf(xinyiDailyNow.getShcHyTwoMlvss())); result = result.replace("{25}", String.valueOf(xinyiDailyNow.getShcHyTwoDo())); result = result.replace("{26}", String.valueOf(xinyiDailyNow.getShcYyOneDo())); result = result.replace("{27}", String.valueOf(xinyiDailyNow.getShcYyTwoDo())); result = result.replace("{28}", String.valueOf(xinyiDailyBefore.getJsCod())); result = result.replace("{29}", String.valueOf(xinyiDailyBefore.getJsTn())); result = result.replace("{30}", String.valueOf(xinyiDailyBefore.getJsTp())); result = result.replace("{31}", String.valueOf(xinyiDailyBefore.getJsNh3())); result = result.replace("{32}", String.valueOf(xinyiDailyBefore.getJsSs())); result = result.replace("{33}", String.valueOf(xinyiDailyBefore.getJSL())); result = result.replace("{34}", String.valueOf(xinyiDailyBefore.getCsCod())); result = result.replace("{35}", String.valueOf(xinyiDailyBefore.getCsTn())); result = result.replace("{36}", String.valueOf(xinyiDailyBefore.getCsTp())); result = result.replace("{37}", String.valueOf(xinyiDailyBefore.getCsNh3())); result = result.replace("{38}", String.valueOf(xinyiDailyBefore.getCsSs())); result = result.replace("{39}", String.valueOf(xinyiDailyBefore.getCSL())); return result; } public static void main(String[] args) { // 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"; // String decoded = decodeOctalToUtf8(encoded); // System.out.println(decoded); testPredictor(); } public static void testPredictor(){ // 获取输出流 ManagedChannel channel = null; try { channel = ManagedChannelBuilder.forAddress("10.0.0.24", 27070) .usePlaintext() .build(); InferenceAPIsServiceGrpc.InferenceAPIsServiceBlockingStub stub = InferenceAPIsServiceGrpc.newBlockingStub(channel); // String dataJson = "{\"bot_id\":\"b00001\",\"exp_id\":\"721\",\"norm\":\"出水氨氮\",\"session_id\":\" " + IdUtils.simpleUUID() + " \",\"extra\":{}}"; //2024年6月27日13:23:25 优化:改成非拼接JSON字符串 String dataJson = buildBigModelReqForPredictor("缺氧出水氨氮1"); // String dataJson = buildBigModelReqForPredictor("qyxsy1"); // log.info("请求大模型的预测的参数为{}", dataJson); PredictionsRequest request = PredictionsRequest.newBuilder() .setModelName("slibra_bot") .putInput("method", ByteString.copyFrom("predictor", "utf-8"))//推理 .putInput("data", ByteString.copyFrom(dataJson, "utf-8")) .buildPartial(); //2024年6月21日10:35:22 改成非流式输出 /*Iterator predictions = stub.streamPredictions(request); //将结果记录到问答表 String responseStr = predictions.next().getPrediction().toStringUtf8(); log.info("大模型问答返回的原始结果为{}", responseStr);*/ PredictionResponse predictions = stub.predictions(request); String responseStr = predictions.getPrediction().toStringUtf8(); log.info("大模型问答返回的原始结果为{}", responseStr); } catch (IOException e) { throw new RuntimeException(e); } finally { channel.shutdown(); } } private static String buildBigModelReqForPredictor(String type) { PredictorRequest predictorRequest = new PredictorRequest(); predictorRequest.setNorm(type); predictorRequest.setSessionId(IdUtils.simpleUUID()); return JSON.toJSONString(predictorRequest); } }