TangCheng
2025-03-05 35c3d6fb4284eccae884b9f17a0712e9c54343c6
Merge branch 'weixin' of http://47.103.154.90:83/r/WI/Service.V1.0 into weixin

# Conflicts:
# JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/control/SMTAIWeixinControl.java
已删除3个文件
已修改2个文件
482 ■■■■■ 文件已修改
JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/control/SMTAIWeixinControl.java 330 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/vo/Item.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/vo/MediaVo.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/vo/WechatMessageVO.java 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JAVA/SMTAIServer/src/main/resources/requestmap/weixin.json 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/control/SMTAIWeixinControl.java
@@ -7,8 +7,6 @@
import com.smtaiserver.smtaiserver.database.SMTDatabase.DBRecords;
import com.smtaiserver.smtaiserver.javaai.ast.ASTDBMap;
import com.smtaiserver.smtaiserver.javaai.llm.core.SMTLLMConnect;
import com.smtaiserver.smtaiserver.vo.MediaVo;
import com.smtaiserver.smtaiserver.vo.WechatMessageVO;
import com.smtservlet.core.SMTRequest;
import com.smtservlet.util.Json;
import com.smtservlet.util.SMTJsonWriter;
@@ -20,18 +18,14 @@
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.boot.configurationprocessor.json.JSONException;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.servlet.ModelAndView;
import javax.annotation.Resource;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.crypto.Data;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
@@ -42,7 +36,6 @@
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import static java.util.Arrays.sort;
@@ -52,11 +45,10 @@
  private static final String TO_USER_NAME = "ToUserName";
  private static final String CONTENT = "Content";
  private static Logger _logger = LogManager.getLogger(SMTAIServerControl.class);
  private Object        _lockToken = new Object();
  private String        _tokenValue = null;
  private long            _tokenTicket = 0;
  private Object _lockToken = new Object();
  private String _tokenValue = null;
  private long _tokenTicket = 0;
  /** å¾®ä¿¡éªŒè¯ */
  public ModelAndView weChatNotify(SMTAIServerRequest tranReq) throws Exception {
@@ -72,39 +64,53 @@
    if (requestMap.isEmpty()) {
      return null;
    }
    //    wechatMessage.setFromUserName(requestMap.get(TO_USER_NAME));
    //    wechatMessage.setToUserName(requestMap.get(FROM_USER_NAME));
    //    wechatMessage.setCreateTime(System.currentTimeMillis() / 1000);
    String xmltemp =
        "<xml>\n"
            + "  <ToUserName><![CDATA[{{{toUser}}}]]></ToUserName>\n"
            + "  <FromUserName><![CDATA[{{{fromUser}}}]]></FromUserName>\n"
            + "  <CreateTime>{{{CreateTime}}}</CreateTime>\n"
            + "  <MsgType><![CDATA[text]]></MsgType>\n"
            + "  <Content><![CDATA[我正在思考哦~请稍等……]]></Content>\n"
            + "</xml>";
    long l = System.currentTimeMillis() / 1000;
    String createTimeStr = String.valueOf(l); // å°† long è½¬æ¢ä¸º String
    // æ›¿æ¢å ä½ç¬¦
    String result =
        xmltemp
            .replace("{{{toUser}}}", requestMap.get(TO_USER_NAME))
            .replace("{{{fromUser}}}", requestMap.get(FROM_USER_NAME))
            .replace("{{{CreateTime}}}", createTimeStr);
    String reqContent = requestMap.get(CONTENT);
    WechatMessageVO wechatMessage = new WechatMessageVO();
    wechatMessage.setFromUserName(requestMap.get(TO_USER_NAME));
    wechatMessage.setToUserName(requestMap.get(FROM_USER_NAME));
    // è®¾ç½®æ¶ˆæ¯ç±»åž‹
    switch (reqContent) {
      case "文字":
        wechatMessage.setMsgType("text");
        break;
      case "图片":
        wechatMessage.setMsgType("image");
        break;
      case "语音":
        wechatMessage.setMsgType("voice");
        break;
      case "视频":
        wechatMessage.setMsgType("video");
        break;
      case "音乐":
        wechatMessage.setMsgType("music");
        break;
      case "图文":
        wechatMessage.setMsgType("news");
        break;
      default:
        wechatMessage.setMsgType("text");
        break;
    }
    //    switch (reqContent) {
    //      case "文字":
    //        wechatMessage.setMsgType("text");
    //        break;
    //      case "图片":
    //        wechatMessage.setMsgType("image");
    //        break;
    //      case "语音":
    //        wechatMessage.setMsgType("voice");
    //        break;
    //      case "视频":
    //        wechatMessage.setMsgType("video");
    //        break;
    //      case "音乐":
    //        wechatMessage.setMsgType("music");
    //        break;
    //      case "图文":
    //        wechatMessage.setMsgType("news");
    //        break;
    //      default:
    //        wechatMessage.setMsgType("text");
    //        break;
    //    }
    wechatMessage.setCreateTime(System.currentTimeMillis() / 1000);
    MediaVo media = new MediaVo();
    wechatMessage.setContent("我正在思考哦~请稍等……");
    //    MediaVo media = new MediaVo();
    //    wechatMessage.setContent("我正在思考哦~请稍等……");
    // å¼‚步调用 aiReplyToTheUserASecondTime
    CompletableFuture.runAsync(
        () -> {
@@ -158,102 +164,112 @@
    try {
      // å°† WechatMessageVO å¯¹è±¡è½¬æ¢ä¸º XML
      JAXBContext jaxbContext = JAXBContext.newInstance(WechatMessageVO.class);
      Marshaller marshaller = jaxbContext.createMarshaller();
      marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
      StringWriter sw = new StringWriter();
      marshaller.marshal(wechatMessage, sw);
      _logger.info("微信消息返参:" + sw);
      //      JAXBContext jaxbContext = JAXBContext.newInstance(WechatMessageVO.class);
      //      Marshaller marshaller = jaxbContext.createMarshaller();
      //      marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
      //      StringWriter sw = new StringWriter();
      //      marshaller.marshal(wechatMessage, sw);
      _logger.info("微信消息返参:" + xmltemp);
      // è¿”回 XML å­—符串
      return tranReq.returnText(sw.toString());
    } catch (JAXBException e) {
      return tranReq.returnText(xmltemp.toString());
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
  /** ai回复
 * @throws Exception */
  private String callAIForAnswerQuestion(String question, SMTAIServerRequest tranReq) throws Exception
  {
      String callFunc =
              "query_water_fee:\n"
              + "    åŠŸèƒ½ï¼š\n"
              + "          æŸ¥è¯¢ç”¨æˆ·ç”¨æ°´é‡å’Œæ°´è´¹ä¿¡æ¯\n"
              + "    å‚æ•°:\n"
              + "          question:用户问题\n"
              + "          user_name:用户名\n"
              + "          value_title:'用水量'或'æ°´è´¹'\n"
              + "          value_name:用水量:volume, æ°´è´¹:amount\n"
              + "          start_time:查询起始日期,格式:年-月-日\n"
              + "          end_time:查询结束时间,格式:年-月-日\n"
              ;
      String prompt = ((String) SMTAIServerApp.getApp().getGlobalConfig("prompt.agent_tools"))
             .replace("{{{AGENT_TOOL_DEFINE_LIST}}}", callFunc);
      SMTLLMConnect llm = SMTAIServerApp.getApp().allocLLMConnect(null);
      String answer = llm.callWithMessage(new String[] {prompt}, question, tranReq);
      tranReq.traceLLMDebug(answer);
      Json oASTList = SMTStatic.convLLMAnswerToJson(answer, true);
      if(oASTList != null && oASTList.isArray())
      {
          List<Json> jsonASTList = oASTList.asJsonList();
          if(jsonASTList.size() > 0)
          {
              Json jsonAST = jsonASTList.get(0);
              if("query_water_fee".equals(jsonAST.safeGetStr("call", null)))
              {
                  jsonAST = jsonAST.getJson("args");
                  try(ASTDBMap dbMap = new ASTDBMap())
                  {
                      SMTDatabase db = dbMap.getDatabase("DS_74_CHENGTOU");
                      DBRecords recs = db.querySQL(
                          " SELECT ROUND(SUM(" + jsonAST.getJson("value_name").asString() + ")::NUMERIC(10, 2), 2) AS TOTAL"
                        + " FROM chengtou_data.bill_data WHERE billing_date BETWEEN ? AND ?"
                        , new Object[] {
                        SMTStatic.toDate(jsonAST.getJson("start_time").asString()),
                        SMTStatic.toDate(jsonAST.getJson("end_time").asString())
                        });
                      if(recs.getRowCount() == 0)
                          return "从" + jsonAST.getJson("start_time").asString() + "到" + jsonAST.getJson("end_time").asString() + "的" + jsonAST.getJson("value_title").asString() + "未查到任何数据";
                      return "从" + jsonAST.getJson("start_time").asString() + "到" + jsonAST.getJson("end_time").asString() + "的" + jsonAST.getJson("value_title").asString()
                          + "总计" + recs.getRecord(0).getString(0);
                  }
              }
          }
      }
      answer = llm.callWithMessage(null, question, tranReq);
      return answer;
  /**
   * ai回复
   *
   * @throws Exception
   */
  private String callAIForAnswerQuestion(String question, SMTAIServerRequest tranReq)
      throws Exception {
    String callFunc =
        "query_water_fee:\n"
            + "    åŠŸèƒ½ï¼š\n"
            + "          æŸ¥è¯¢ç”¨æˆ·ç”¨æ°´é‡å’Œæ°´è´¹ä¿¡æ¯\n"
            + "    å‚æ•°:\n"
            + "          question:用户问题\n"
            + "          user_name:用户名\n"
            + "          value_title:'用水量'或'æ°´è´¹'\n"
            + "          value_name:用水量:volume, æ°´è´¹:amount\n"
            + "          start_time:查询起始日期,格式:年-月-日\n"
            + "          end_time:查询结束时间,格式:年-月-日\n";
    String prompt =
        ((String) SMTAIServerApp.getApp().getGlobalConfig("prompt.agent_tools"))
            .replace("{{{AGENT_TOOL_DEFINE_LIST}}}", callFunc);
    SMTLLMConnect llm = SMTAIServerApp.getApp().allocLLMConnect(null);
    String answer = llm.callWithMessage(new String[] {prompt}, question, tranReq);
    tranReq.traceLLMDebug(answer);
    List<Json> jsonASTList = SMTStatic.convLLMAnswerToJson(answer, true).asJsonList();
    if (jsonASTList.size() > 0) {
      Json jsonAST = jsonASTList.get(0);
      if ("query_water_fee".equals(jsonAST.safeGetStr("call", null))) {
        jsonAST = jsonAST.getJson("args");
        try (ASTDBMap dbMap = new ASTDBMap()) {
          SMTDatabase db = dbMap.getDatabase("DS_74_CHENGTOU");
          DBRecords recs =
              db.querySQL(
                  " SELECT ROUND(SUM("
                      + jsonAST.getJson("value_name").asString()
                      + ")::NUMERIC(10, 2), 2) AS TOTAL"
                      + " FROM chengtou_data.bill_data WHERE billing_date BETWEEN ? AND ?",
                  new Object[] {
                    SMTStatic.toDate(jsonAST.getJson("start_time").asString()),
                    SMTStatic.toDate(jsonAST.getJson("end_time").asString())
                  });
          if (recs.getRowCount() == 0)
            return "从"
                + jsonAST.getJson("start_time").asString()
                + "到"
                + jsonAST.getJson("end_time").asString()
                + "的"
                + jsonAST.getJson("value_title").asString()
                + "未查到任何数据";
          return "从"
              + jsonAST.getJson("start_time").asString()
              + "到"
              + jsonAST.getJson("end_time").asString()
              + "的"
              + jsonAST.getJson("value_title").asString()
              + "总计"
              + recs.getRecord(0).getString(0);
        }
      }
    }
    answer = llm.callWithMessage(null, question, tranReq);
    return answer;
  }
  /** äºŒæ¬¡å›žå¤ */
  public ModelAndView aiReplyToTheUserASecondTime(String answer, String fromUserName)
      throws Exception {
    String accessToken = getAccessToken();
    SMTJsonWriter jsonWr = new SMTJsonWriter(false);
    jsonWr.addKeyValue("touser", fromUserName);
    jsonWr.addKeyValue("msgtype", "text");
    jsonWr.beginMap("text");
    {
        jsonWr.addKeyValue("content", answer);
      jsonWr.addKeyValue("content", answer);
    }
    jsonWr.endMap();
//    JSONObject jsonObject = new JSONObject();
//    jsonObject.put("touser", fromUserName);
//    jsonObject.put("msgtype", "text");
//    JSONObject jsonObject1 = new JSONObject();
//    jsonObject1.put("content", answer);
//    jsonObject.put("text", jsonObject1);
//    _logger.info("jsonObject: {}", jsonObject);
    //    JSONObject jsonObject = new JSONObject();
    //    jsonObject.put("touser", fromUserName);
    //    jsonObject.put("msgtype", "text");
    //    JSONObject jsonObject1 = new JSONObject();
    //    jsonObject1.put("content", answer);
    //    jsonObject.put("text", jsonObject1);
    //    _logger.info("jsonObject: {}", jsonObject);
    String url =
        String.format(
            "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%s", accessToken);
    //Map<String, Object> stringObjectMap = jsonObjectToMap(jsonWr.getRootJson());
    // Map<String, Object> stringObjectMap = jsonObjectToMap(jsonWr.getRootJson());
    String s = sendPost(url, jsonWr.getRootJson());
    _logger.info("上传结果: {}", s);
    return null;
@@ -279,63 +295,31 @@
    return tranReq.returnText("");
  }
  public String getAccessToken() throws Exception
  {
      synchronized(this._lockToken)
      {
          if(_tokenValue == null || (System.currentTimeMillis() - _tokenTicket) > 3600 * 1000)
          {
              HashMap<String, String> weixinParam = getWeixinParam();
              String url =
                  "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
                      + weixinParam.get("appId")
                      + "&secret="
                      + weixinParam.get("secret");
              String response = HttpUtil.get(url);
              JSONObject jsonObject = new JSONObject(response);
              if (jsonObject.has("access_token")) {
                String accessToken = jsonObject.getString("access_token");
                _tokenValue = accessToken;
              }
              else
              {
                  throw new Exception("can't get weixin token");
              }
              _tokenTicket = System.currentTimeMillis();
          }
          return _tokenValue;
      }
  public String getAccessToken() throws Exception {
    synchronized (this._lockToken) {
      if (_tokenValue == null || (System.currentTimeMillis() - _tokenTicket) > 3600 * 1000) {
        HashMap<String, String> weixinParam = getWeixinParam();
        String url =
            "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
                + weixinParam.get("appId")
                + "&secret="
                + weixinParam.get("secret");
        String response = HttpUtil.get(url);
        JSONObject jsonObject = new JSONObject(response);
        if (jsonObject.has("access_token")) {
          String accessToken = jsonObject.getString("access_token");
          _tokenValue = accessToken;
        } else {
          throw new Exception("can't get weixin token");
        }
        _tokenTicket = System.currentTimeMillis();
      }
      return _tokenValue;
    }
  }
//  public static Map<String, Object> jsonObjectToMap(JSONObject jsonObject) throws JSONException {
//    Map<String, Object> map = new HashMap<>();
//    Iterator<String> keys = jsonObject.keys();
//
//    while (keys.hasNext()) {
//      String key = keys.next();
//      Object value = jsonObject.get(key);
//
//      // å¦‚果值是 JSONObject,递归转换为 Map
//      if (value instanceof JSONObject) {
//        value = jsonObjectToMap((JSONObject) value);
//      }
//
//      map.put(key, value);
//    }
//
//    return map;
//  }
  /**
   * éªŒè¯ç­¾åutil
   *
   * @param signature
   * @param timestamp
   * @param nonce
   * @return
   */
  /** éªŒè¯ç­¾åutil */
  public static boolean checkSignature(String signature, String timestamp, String nonce)
      throws Exception {
    HashMap<String, String> weixinParam = getWeixinParam();
@@ -425,7 +409,7 @@
  public static String sendPost(String urlString, Json jsonParam) throws Exception {
    // å°†å‚数转换为 JSON æ ¼å¼å­—符串
   // JSONObject jsonParams = new JSONObject(params);
    // JSONObject jsonParams = new JSONObject(params);
    String payload = jsonParam.toString();
    // åˆ›å»ºè¿žæŽ¥
    URL url = new URL(urlString);
JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/vo/Item.java
ÎļþÒÑɾ³ý
JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/vo/MediaVo.java
ÎļþÒÑɾ³ý
JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/vo/WechatMessageVO.java
ÎļþÒÑɾ³ý
JAVA/SMTAIServer/src/main/resources/requestmap/weixin.json
@@ -15,5 +15,22 @@
        ]
      }
    ]
  },
  "weixin/test_control": {
    "map": {
      "class": "#SMTAIWeixinControl",
      "method": ""
    },
    "no_shrio": true,
    "swaggers": [
      {
        "tags": [
          "微信公众号主测试接口"
        ],
        "title": "测试接口",
        "parameters": [
        ]
      }
    ]
  }
}