package com.smtaiserver.smtaiserver.javaai.qwen.agent; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.commons.text.similarity.JaccardSimilarity; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.tree.DefaultText; import com.smtaiserver.smtaiserver.core.SMTAIServerApp; import com.smtaiserver.smtaiserver.core.SMTAIServerRequest; import com.smtaiserver.smtaiserver.database.SMTDatabase; import com.smtaiserver.smtaiserver.database.SMTDatabase.DBRecord; import com.smtaiserver.smtaiserver.database.SMTDatabase.DBRecords; import com.smtaiserver.smtaiserver.javaai.SMTJavaAIError; import com.smtaiserver.smtaiserver.javaai.ast.ASTDBMap; import com.smtaiserver.smtaiserver.javaai.llm.core.SMTLLMConnect; import com.smtservlet.util.Json; import com.smtservlet.util.SMTJsonWriter; import com.smtservlet.util.SMTStatic; public class SMTQwenAgentDuckLastValue extends SMTQwenAgent { private static class SQLXMLExecArg { public Map _mapId2Arg = new HashMap<>(); public List _sqlParams = new ArrayList<>(); public StringBuilder _sbSQLText = new StringBuilder(); public Object getArgValue(String key) throws Exception { Object value = _mapId2Arg.get(key); if(value == null) throw new Exception("can't find value"); return value; } } /////////////////////////////////////////////////////////////////////////////////////// private static abstract class SQLXMLNode { public abstract SMTJavaAIError execute(SQLXMLExecArg execArg) throws Exception; } /////////////////////////////////////////////////////////////////////////////////////// private static class SQLXMLNodePARAM extends SQLXMLNode { protected String _key; public SQLXMLNodePARAM(Element xmlRoot) throws Exception { _key = SMTStatic.getXmlAttr(xmlRoot, "key"); } @Override public SMTJavaAIError execute(SQLXMLExecArg execArg) throws Exception { Object value = execArg.getArgValue(_key); execArg._sqlParams.add(value); execArg._sbSQLText.append("?"); return null; } } /////////////////////////////////////////////////////////////////////////////////////// private static class SQLXMLNodeQUERY_NAME extends SQLXMLNode { private String _dsId; private List _listChildren = new ArrayList<>(); public SQLXMLNodeQUERY_NAME(Element xmlRoot) throws Exception { _dsId = SMTStatic.getXmlAttr(xmlRoot, "ds_id"); for (Iterator iterInner = xmlRoot.nodeIterator(); iterInner.hasNext();) { Node nodeInner = iterInner.next(); if(nodeInner.getNodeType() == Node.TEXT_NODE) { String text = ((DefaultText)nodeInner).getText(); int lastPos = _listChildren.size() - 1; if(lastPos >= 0 && _listChildren.get(lastPos) instanceof String) { _listChildren.set(lastPos, (String)_listChildren.get(lastPos) + text); } else { _listChildren.add(text); } } else { _listChildren.add(createSQLXMLNode((Element)nodeInner)); } } } @Override public SMTJavaAIError execute(SQLXMLExecArg execArg) throws Exception { for(Object oxmlNode : _listChildren) { if(oxmlNode instanceof String) { execArg._sbSQLText.append(oxmlNode); } else if(oxmlNode instanceof SQLXMLNode) { SMTJavaAIError error = ((SQLXMLNode)oxmlNode).execute(execArg); if(error != null) return error; } } return null; } } //////////////////////////////////////////////////////////////////////////////// private static SQLXMLNode createSQLXMLNode(Element xmlRoot) throws Exception { String name = xmlRoot.getName().toUpperCase(); if("QUERY_NAME".equals(name)) return new SQLXMLNodeQUERY_NAME(xmlRoot); if("PARAM".equals(name)) return new SQLXMLNodePARAM(xmlRoot); else throw new Exception("unknow SQLXML : " + name); } //////////////////////////////////////////////////////////////////////////////// private static class SMTDeviceNameInfo { public DBRecord _recDev; public Map _mapType2QualRec = new LinkedHashMap<>(); public SMTDeviceNameInfo(DBRecord recDev) { _recDev = recDev; } } //////////////////////////////////////////////////////////////////////////////// private static class SMTQueryQualityName { public String _otype; public String[] _listAlias; public String[] _refKeys; public String _queryDetailId; public String _unitName; public SQLXMLNodeQUERY_NAME _sqlxmlQueryQual; public SMTQueryQualityName(Element xmlDeviceName, Map mapMetric2Unit) throws Exception { _otype = SMTStatic.getXmlAttr(xmlDeviceName, "otype"); _listAlias = SMTStatic.getXmlAttr(xmlDeviceName, "alias", "").split(","); _refKeys = SMTStatic.getXmlAttr(xmlDeviceName, "ref_keys").split(","); _queryDetailId = SMTStatic.getXmlAttr(xmlDeviceName, "query_detail_id", ""); String metricId = SMTStatic.getXmlAttr(xmlDeviceName, "metric_id", ""); _unitName = mapMetric2Unit.get(metricId); Element xmlQueryName = (Element)xmlDeviceName.selectSingleNode("QUERY_NAME"); _sqlxmlQueryQual = (SQLXMLNodeQUERY_NAME)SMTQwenAgentDuckLastValue.createSQLXMLNode(xmlQueryName); } public boolean isMatchQTYPE(String[] askQTYPEList, JaccardSimilarity jaccardSimilarity) { if(askQTYPEList == null) return true; for(String askPTYPE : askQTYPEList) { if(_listAlias != null) { for(String alias : _listAlias) { if(jaccardSimilarity.apply(askPTYPE, alias) >= 0.3) return true; } } } return false; } public SMTJavaAIError queryQualityValueMap(ASTDBMap dbMap, SMTAIServerRequest tranReq, Map r_mapQualKey2Rec) throws Exception { SQLXMLExecArg execArg = new SQLXMLExecArg(); SMTJavaAIError error = _sqlxmlQueryQual.execute(execArg); if(error != null) return error; SMTDatabase db = dbMap.getDatabase(_sqlxmlQueryQual._dsId); tranReq.traceLLMDebug(execArg._sbSQLText.toString()); DBRecords recs = db.querySQL(execArg._sbSQLText.toString(), execArg._sqlParams.toArray(new Object[execArg._sqlParams.size()])); StringBuilder sbKey = new StringBuilder(); for(DBRecord rec : recs.getRecords()) { sbKey.setLength(0); for(String key : _refKeys) { sbKey.append(rec.getString(key) + "\b"); } r_mapQualKey2Rec.put(sbKey.toString(), rec); } return null; } } //////////////////////////////////////////////////////////////////////////////// private static class SMTQueryDeviceName { public String _otype; public String[] _listAlias; public SQLXMLNodeQUERY_NAME _sqlxmlQueryDev; public List _listQualName = new ArrayList<>(); public SMTQueryDeviceName(Element xmlDeviceName, Map mapType2QualSQL) throws Exception { _otype = SMTStatic.getXmlAttr(xmlDeviceName, "otype"); _listAlias = SMTStatic.getXmlAttr(xmlDeviceName, "alias").split(","); _sqlxmlQueryDev = (SQLXMLNodeQUERY_NAME)SMTQwenAgentDuckLastValue.createSQLXMLNode((Element)xmlDeviceName.selectSingleNode("QUERY_NAME")); for(Node nodeQualName : xmlDeviceName.selectNodes("QUALITY_LIST/QUALITY")) { String QTYPE = SMTStatic.getXmlAttr((Element)nodeQualName, "otype"); SMTQueryQualityName qualNameDef = mapType2QualSQL.get(QTYPE); if(qualNameDef == null) throw new Exception("can't find quality name : " + _otype + "." + QTYPE); _listQualName.add(qualNameDef); } } public SMTJavaAIError queryQualityNames(ASTDBMap dbMap, String[] askQTYPEList, JaccardSimilarity jaccardSimilarity, SMTAIServerRequest tranReq, Map> r_mapType2DevInfoList) throws Exception { List listQualInfo = new ArrayList<>(); // 遍历所有需要查询的指标,筛选出匹配的指标列表 for(SMTQueryQualityName qualInfo : _listQualName) { if(!qualInfo.isMatchQTYPE(askQTYPEList, jaccardSimilarity)) continue; listQualInfo.add(qualInfo); } tranReq.sendChunkedBlock("begin", "查询设备[" + this._otype + "]基本信息"); // 生成设备查询SQL SQLXMLExecArg execArg = new SQLXMLExecArg(); SMTJavaAIError error = _sqlxmlQueryDev.execute(execArg); if(error != null) return error; // 查询所有设备 SMTDatabase db = dbMap.getDatabase(_sqlxmlQueryDev._dsId); tranReq.traceLLMDebug(execArg._sbSQLText.toString()); DBRecords recs = db.querySQL(execArg._sbSQLText.toString(), execArg._sqlParams.toArray(new Object[execArg._sqlParams.size()])); // 将设备加入列表 List listDeviceInfo = new ArrayList<>(); r_mapType2DevInfoList.put(_otype, listDeviceInfo); for(DBRecord rec : recs.getRecords()) { SMTDeviceNameInfo deviceInfo = new SMTDeviceNameInfo(rec); listDeviceInfo.add(deviceInfo); } tranReq.sendChunkedBlock("begin", "查询设备[" + this._otype + "]指标信息"); // 查询指标信息 StringBuilder sbKey = new StringBuilder(); for(SMTQueryQualityName qualInfo : listQualInfo) { Map mapQualKey2Rec = new HashMap<>(); // 查询当前指标下所有最新值 if((error = qualInfo.queryQualityValueMap(dbMap, tranReq, mapQualKey2Rec)) != null) return error; // 遍历设备名称,把指标挂接上去 for(SMTDeviceNameInfo deviceInfo : listDeviceInfo) { sbKey.setLength(0); for(String key : qualInfo._refKeys) { sbKey.append(deviceInfo._recDev.getString(key) + "\b"); } DBRecord recQual = mapQualKey2Rec.get(sbKey.toString()); if(recQual == null) continue; deviceInfo._mapType2QualRec.put(qualInfo._otype, recQual); } } r_mapType2DevInfoList.put(this._otype, listDeviceInfo); return null; } public boolean isMatchPTYPE(String[] askPTYPEList, JaccardSimilarity jaccardSimilarity) { if(askPTYPEList == null) return true; for(String askPTYPE : askPTYPEList) { if(jaccardSimilarity.apply(askPTYPE, _otype) >= 0.3) return true; if(_listAlias != null) { for(String alias : _listAlias) { if(jaccardSimilarity.apply(askPTYPE, alias) >= 0.3) return true; } } } return false; } } //////////////////////////////////////////////////////////////////////////////// private List _listDevSQL = new ArrayList<>(); private Map _mapType2QualSQL; @Override public void initInstance(DBRecord rec) throws Exception { super.initInstance(rec); try { Map mapMetric2Unit = new HashMap<>(); // 获取所有的指标单位 SMTDatabase db = SMTAIServerApp.getApp().allocDatabase(); try { DBRecords recs = db.querySQL("SELECT metrics_id, metrics_unit FROM ai_metrics_def WHERE metrics_unit IS NOT NULL", null); for(DBRecord recUnit : recs.getRecords()) { mapMetric2Unit.put(recUnit.getString("metrics_id"), recUnit.getString("metrics_unit")); } } finally { db.close(); } Document doc = SMTStatic.convStrToXmlDoc("" + rec.getString("clz_arguments") + ""); // 加载所有的指标 _mapType2QualSQL = new HashMap<>(); for(Node nodeDeviceSQL : doc.selectNodes("ROOT/QUALITY_LIST/QUALITY_SQL")) { SMTQueryQualityName sqlxmlNode = new SMTQueryQualityName((Element)nodeDeviceSQL, mapMetric2Unit); _mapType2QualSQL.put(sqlxmlNode._otype, sqlxmlNode); } // 加载所有的设备 for(Node nodeDeviceSQL : doc.selectNodes("ROOT/DEVICE_LIST/DEVICE_SQL")) { SMTQueryDeviceName sqlxmlNode = new SMTQueryDeviceName((Element)nodeDeviceSQL, _mapType2QualSQL); _listDevSQL.add(sqlxmlNode); } } catch(Exception ex) { throw new Exception("init mertic agent error : " + this._agentId, ex); } } private void outputToJson(Map> mapType2DevInfoList, SMTJsonWriter jsonWr) throws Exception { jsonWr.addKeyValue("answer_type", "summary"); jsonWr.beginArray("summary"); jsonWr.beginMap(null); { jsonWr.addKeyValue("type", "device_last_value"); jsonWr.addKeyValue("title", "监测设备的最新数据"); // 扫描所有存在的指标 Set setExistQTYPE = new HashSet<>(); for(List deviceInfoList : mapType2DevInfoList.values()) { for(SMTDeviceNameInfo deviceInfo : deviceInfoList) { for(String QTYPE : deviceInfo._mapType2QualRec.keySet()) { setExistQTYPE.add(QTYPE); } } } // 加入指标名 jsonWr.beginArray("rows"); for(String QTYPE : setExistQTYPE) { SMTQueryQualityName qualInfo = _mapType2QualSQL.get(QTYPE); jsonWr.beginMap(null); { jsonWr.addKeyValue("id", QTYPE); jsonWr.addKeyValue("title", qualInfo._listAlias[0]); jsonWr.addKeyValue("query_detail_id", qualInfo._queryDetailId); jsonWr.addKeyValue("unit", qualInfo._unitName); } jsonWr.endMap(); } jsonWr.endArray(); jsonWr.beginArray("values"); for(Entry> entryDevice : mapType2DevInfoList.entrySet()) { String deviceType = entryDevice.getKey(); List deviceInfoList = entryDevice.getValue(); for(SMTDeviceNameInfo deviceInfo : deviceInfoList) { jsonWr.beginMap(null); { jsonWr.addKeyValue("OTYPE", deviceType); jsonWr.addKeyValue("ONAME", deviceInfo._recDev.getString("PNAME")); jsonWr.addKeyValue("OTITLE", deviceInfo._recDev.getString("PTITLE")); for(Entry entryQual : deviceInfo._mapType2QualRec.entrySet()) { jsonWr.addKeyValue("OTIME", entryQual.getValue().getString("OTIME")); jsonWr.beginMap(entryQual.getKey()); { jsonWr.addKeyValue("ONAME", entryQual.getValue().getString("ONAME")); jsonWr.addKeyValue("OVALUE", entryQual.getValue().getString("OVALUE")); } jsonWr.endMap(); } } jsonWr.endMap(); } } jsonWr.endArray(); } jsonWr.endMap(); jsonWr.endArray(); } @Override public SMTJavaAIError callAgents(String jsonPath, Json jsonArgs, SMTLLMConnect llm, String question, SMTAIServerRequest tranReq) throws Exception { JaccardSimilarity jaccardSimilarity = new JaccardSimilarity(); // 获取用户参数 String sPTYPEList = jsonArgs.safeGetStr("ptype", ""); String sVPROPList = jsonArgs.safeGetStr("vprop", ""); String[] askPTYPEList = SMTStatic.isNullOrEmpty(sPTYPEList) ? null : sPTYPEList.split(","); String[] askQTYPEList = SMTStatic.isNullOrEmpty(sVPROPList) ? null : sVPROPList.split(","); // 匹配PTYPE Map> mapType2DevInfoList = new LinkedHashMap<>(); ASTDBMap dbMap = new ASTDBMap(); try { // 查询设备及对应的指标信息 for(SMTQueryDeviceName sqlxmlDevSQL : _listDevSQL) { // 如果问题中的设备类型和sqlxml对象不匹配,则忽略 if(!sqlxmlDevSQL.isMatchPTYPE(askPTYPEList, jaccardSimilarity)) continue; // 查询当前设备基本信息 sqlxmlDevSQL.queryQualityNames(dbMap, askQTYPEList, jaccardSimilarity, tranReq, mapType2DevInfoList); } // 将无指标的设备全部清除 tranReq.sendChunkedBlock("begin", "清除无指标的设备"); for(List listDevInfo : mapType2DevInfoList.values()) { for(int i = listDevInfo.size() - 1; i >= 0; i --) { if(listDevInfo.get(i)._mapType2QualRec.size() == 0) listDevInfo.remove(i); } } // 输出结果 SMTJsonWriter jsonWr = tranReq.getResultJsonWr(); outputToJson(mapType2DevInfoList, jsonWr); tranReq.sendChunkedResultBlock(); } finally { dbMap.close(); } return null; } }