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<String, Object> _mapId2Arg = new HashMap<>();
|
public List<Object> _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<Object> _listChildren = new ArrayList<>();
|
|
public SQLXMLNodeQUERY_NAME(Element xmlRoot) throws Exception
|
{
|
_dsId = SMTStatic.getXmlAttr(xmlRoot, "ds_id");
|
|
for (Iterator<Node> 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<String, DBRecord> _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<String, String> 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<String, DBRecord> 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<SMTQueryQualityName> _listQualName = new ArrayList<>();
|
|
public SMTQueryDeviceName(Element xmlDeviceName, Map<String, SMTQueryQualityName> 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<String, List<SMTDeviceNameInfo>> r_mapType2DevInfoList) throws Exception
|
{
|
List<SMTQueryQualityName> 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<SMTDeviceNameInfo> 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<String, DBRecord> 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<SMTQueryDeviceName> _listDevSQL = new ArrayList<>();
|
private Map<String, SMTQueryQualityName> _mapType2QualSQL;
|
|
@Override
|
public void initInstance(DBRecord rec) throws Exception
|
{
|
super.initInstance(rec);
|
|
try
|
{
|
Map<String, String> 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("<ROOT>" + rec.getString("clz_arguments") + "</ROOT>");
|
|
// 加载所有的指标
|
_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<String, List<SMTDeviceNameInfo>> 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<String> setExistQTYPE = new HashSet<>();
|
for(List<SMTDeviceNameInfo> 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<String, List<SMTDeviceNameInfo>> entryDevice : mapType2DevInfoList.entrySet())
|
{
|
|
String deviceType = entryDevice.getKey();
|
List<SMTDeviceNameInfo> 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<String, DBRecord> 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<String, List<SMTDeviceNameInfo>> 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<SMTDeviceNameInfo> 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;
|
}
|
|
}
|