TangCheng
2025-04-17 b611c6cbdd623cd2e2a12d9aebbb35f80fb40590
JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/control/SMTJavaAIControl.java
@@ -1,24 +1,25 @@
package com.smtaiserver.smtaiserver.control;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.io.InputStream;
import java.util.*;
import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import com.smtaiserver.smtaiserver.attach.SMTAIAttachMetricDef;
import com.smtaiserver.smtaiserver.attach.SMTAIAttachTableDef;
import com.smtaiserver.smtaiserver.attach.SMTAIAttachTableDef.SMTAIAttachTableColumn;
import com.smtaiserver.smtaiserver.core.SMTAIServerApp;
import com.smtaiserver.smtaiserver.core.SMTAIServerRequest;
import com.smtaiserver.smtaiserver.core.SMTAIServerRequest.AIAttachFile;
import com.smtaiserver.smtaiserver.database.SMTDatabase;
import com.smtaiserver.smtaiserver.database.SMTDatabase.DBRecord;
import com.smtaiserver.smtaiserver.database.SMTDatabase.DBRecords;
@@ -36,6 +37,47 @@
public class SMTJavaAIControl 
{
   private class SMTCallAgentArgStreamView implements View
   {
      private SMTAIServerRequest    _tranReq;
      public SMTCallAgentArgStreamView(SMTAIServerRequest tranReq)
      {
         _tranReq = tranReq;
         _tranReq.setChunkedMode(true);
      }
      @Override
      public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception
      {
         String agentId = _tranReq.convParamToString("agent_id", true);
         Json jsonArgs = _tranReq.convParamToJson("call_args", true);
         response.setCharacterEncoding("UTF-8");
         response.setContentType("text/plain;charset=UTF-8");
         response.setHeader("smtstream", "chunked");
         try
         {
            SMTQwenAgent agent = SMTAIServerApp.getApp().getQwenAgentManager().getAgentById(agentId);
            if(agent == null)
               throw new Exception("can't find agent : " + agentId);
            SMTLLMConnect llm = SMTAIServerApp.getApp().allocLLMConnect(null);
            if(!jsonArgs.has("question"))
               jsonArgs.set("question", "");
            agent.callAgents("/", jsonArgs, llm, "", _tranReq);
         }
         catch(Exception ex)
         {
            _tranReq.traceLLMDebug("call chat stream excetion : \n" + SMTStatic.toString(ex));
            _tranReq.sendChunkedBlock("error", ex.getMessage());
         }
         _tranReq.sendChunkedBlock("finish", "");
      }
   }
   private class SMTAgentStreamView implements View
   {
      private SMTAIServerRequest    _tranReq;
@@ -76,11 +118,79 @@
   private class SMTChatStreamView implements View
   {
      private SMTAIServerRequest    _tranReq;
      private boolean          _mustRawMode = false;
      
      public SMTChatStreamView(SMTAIServerRequest tranReq)
      public SMTChatStreamView(SMTAIServerRequest tranReq, MultipartFile[] files) throws Exception
      {
         // 如果文件存在,则将文件保存
         if(files != null && files.length > 0)
         {
            try(SMTDatabase db = SMTAIServerApp.getApp().allocDatabase())
            {
               db.beginTran();
               try
               {
                  for(MultipartFile file : files)
                  {
                     String fileText="";
                     String fileSuffix = (String) SMTAIServerApp.getApp().getGlobalConfig("file_suffix", false);
                     String fileName = new File(file.getOriginalFilename()).getName();
                     byte[] fileData = readAttachFile(file);
                     if (fileSuffix.contains(fileName.substring(fileName.lastIndexOf(".") + 1))) {
                        fileText = SMTAIServerApp.fileTranslTxt(file);
                     }
                     String fileId = SMTStatic.newUUID();
                     db.executeSQL(
                          " INSERT INTO chat_history_attach(attach_id, attach_type, attach_title, attach_bytes)"
                        + " VALUES(?,?,?,?)", new Object[] {
                           fileId,
                           "FILE",
                           fileName,
                           fileData
                        });
                     tranReq.addAttachFile(new AIAttachFile(fileId, fileName, fileText));
                  }
                  db.commitTran();
               }
               catch(Exception ex)
               {
                  db.rollbackDB(ex);
               }
            }
            _mustRawMode = true;
         }
         Json jsonTables = tranReq.convParamToJson("tables", false);
         if(jsonTables != null)
         {
            tranReq.setAttachTables(jsonTables);
            _mustRawMode = true;
         }
         Json jsonMetrics = tranReq.convParamToJson("metrics", false);
         if(jsonMetrics != null)
         {
            tranReq.setJsonAttachMetrics(jsonMetrics);
            _mustRawMode = true;
         }
         _tranReq = tranReq;
         _tranReq.setChunkedMode(true);
      }
      private byte[] readAttachFile(MultipartFile file) throws Exception
      {
         InputStream is = file.getInputStream();
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         byte[] data = new byte[1024 * 1024];
         while(true)
         {
            int size = is.read(data);
            if(size <= 0)
               return bos.toByteArray();
            bos.write(data, 0, size);
         }
      }
      
      
@@ -116,7 +226,7 @@
         
         try
         {
            Json jsonResult = chatQuestionToJson(_tranReq, true);
            Json jsonResult = chatQuestionToJson(_tranReq, true, _mustRawMode);
            if(!jsonResult.safeGetBoolean("json_ok", false))
               _tranReq.sendChunkedBlock("error", jsonResult.safeGetStr("json_msg", "内部错误"));
         }
@@ -178,164 +288,9 @@
      }
   }
   
   private class SMTAttachFileChatStreamView implements View
   {
      private SMTAIServerRequest    _tranReq;
      private List<MultipartFile> _files;
      public SMTAttachFileChatStreamView(SMTAIServerRequest tranReq, List<MultipartFile> files)
      {
         _tranReq = tranReq;
         _files = files;
         _tranReq.setChunkedMode(true);
      }
      @Override
      public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception
      {
         response.setCharacterEncoding("UTF-8");
         //response.setHeader("Transfer-Encoding", "chunked");
         response.setContentType("text/plain;charset=UTF-8");
         //response.setContentType("application/json;charset=UTF-8");
         response.setHeader("smtstream", "chunked");
         String userId = _tranReq.getLoginUserId();
         {
            SMTSSEBroadcastChat chat = SMTAIServerApp.getApp().getBroadcastChat(userId);
            if(chat != null)
            {
               SMTJsonWriter jsonWr = new SMTJsonWriter(false);
               String from = (String) _tranReq.getSessionAttribute("login_from");
               if(SMTStatic.isNullOrEmpty(from))
                  from = "手机";
               jsonWr.addKeyValue("type", "chat_start");
               jsonWr.addKeyValue("from", from);
               jsonWr.addKeyValue("sender", _tranReq.getSessionId());
               jsonWr.addKeyValue("question", _tranReq.convParamToString("question", true));
               jsonWr.addKeyValue("history_group_id", _tranReq.convParamToString("history_group_id", true));
               chat.sendChatNotify(_tranReq.getSessionId(), jsonWr.getFullJson());
            }
         }
         try
         {
            attachFileChatQuestionToJson(_tranReq, true);
            //Json jsonResult = chatQuestionToJson(_tranReq, true);
            //if(!jsonResult.safeGetBoolean("json_ok", false))
            //   _tranReq.sendChunkedBlock("error", jsonResult.safeGetStr("json_msg", "内部错误"));
         }
         catch(Exception ex)
         {
            _tranReq.traceLLMDebug("call chat stream excetion : \n" + SMTStatic.toString(ex));
            _tranReq.sendChunkedBlock("error", ex.getMessage());
         }
         _tranReq.sendChunkedBlock("finish", "");
         // 广播通知所有同用户对话
         SMTDatabase db = SMTAIServerApp.getApp().allocDatabase();
         try
         {
            String sql = " SELECT history_id, D.group_id, D.create_time FROM chat_history_detail D INNER JOIN chat_history_group G"
                  + " ON D.group_id=G.group_id AND user_id=? AND D.create_time >= ?::timestamp + '-1 hours'"
                  + " ORDER BY D.create_time";
            Date time = new Date();
            DBRecords recs = db.querySQL(sql, new Object[] {
               _tranReq.getLoginUserId(),
               time
               });
            SMTSSEBroadcastChat chat = SMTAIServerApp.getApp().getBroadcastChat(userId);
            if(chat != null)
            {
               if(recs.getRowCount() > 0)
               {
                  SMTJsonWriter jsonWr = new SMTJsonWriter(false);
                  String from = (String) _tranReq.getSessionAttribute("login_from");
                  if(SMTStatic.isNullOrEmpty(from))
                     from = "手机";
                  jsonWr.addKeyValue("type", "chat_history_id");
                  jsonWr.addKeyValue("from", from);
                  jsonWr.addKeyValue("sender", _tranReq.getSessionId());
                  jsonWr.beginArray("id_list");
                  for(DBRecord rec : recs.getRecords())
                  {
                     jsonWr.beginMap(null);
                     {
                        jsonWr.addKeyValue("history_id", rec.getString("history_id"));
                        jsonWr.addKeyValue("group_id", rec.getString("group_id"));
                        jsonWr.addKeyValue("time", rec.getString("create_time"));
                     }
                     jsonWr.endMap();
                  }
                  jsonWr.endArray();
                  chat.sendChatNotify(_tranReq.getSessionId(), jsonWr.getFullJson());
               }
            }
         }
         finally
         {
            db.close();
         }
      }
   }
   ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
   
    protected Json attachFileChatQuestionToJson(SMTAIServerRequest tranReq, boolean isStreamMode) throws Exception
    {
       try
       {
          tranReq.clearChatStreamReplyValue();
          String sampleId = tranReq.convParamToString("sample_id", false);
          String llmId = tranReq.convParamToString("llm_id", false);
          String historyGroupId = tranReq.convParamToString("history_group_id", true);
          String question = tranReq.convParamToString("question", true);
          String processId = tranReq.convParamToString("process_id", false);
          Boolean rawMode = tranReq.convParamToBoolean("raw_mode", false);
          String prevQuestion = tranReq.convParamToString("prev_question", false);
          String groupType = tranReq.convParamToString("group_type", false);
          double[] curPos = tranReq.convParamToDoubleArray("cur_pos", false);
          if(SMTStatic.isNullOrEmpty(groupType))
             groupType = "业务场景";
          tranReq.setCurQuestionPos(curPos);
          tranReq.setCurGroupType(groupType);
          question = SMTAIServerApp.getApp().getQueryAIQuestionReplace().replaceQuestion(groupType, question);
          if(rawMode == null)
             rawMode = false;
            tranReq.setAsynProcessId(processId);
            Json jsonResult = null;
            Exception exResult = null;
          long ticket = System.currentTimeMillis();
          tranReq.setAsynProcessText("开始分析");
          tranReq.setAIQuestion(question);
           //jsonResult = SMTJavaAIChat.questionChat("aliyun", tranReq.getAgentGroupSet(), groupType, question, prevQuestion, rawMode, tranReq);
          Json jsonOutput = afterCallChat(isStreamMode, ticket, groupType, historyGroupId, jsonResult, sampleId, llmId, tranReq, exResult);
          return jsonOutput;
       }
      finally
      {
         tranReq.closeQuestionResource();
      }
    }
   public ModelAndView systemPing(SMTAIServerRequest tranReq) throws Exception
    public ModelAndView systemPing(SMTAIServerRequest tranReq) throws Exception
   {
      SMTJsonWriter jsonWr = tranReq.newReturnJsonWriter(true, null, null);
      jsonWr.addKeyValue("is_login", tranReq.getLoginUserId() != null);
@@ -427,11 +382,11 @@
   
    public ModelAndView chatQuestion(SMTAIServerRequest tranReq) throws Exception 
    {
       Json jsonOutput = chatQuestionToJson(tranReq, false);
       Json jsonOutput = chatQuestionToJson(tranReq, false, false);
       return tranReq.returnJson(jsonOutput);
    }
    
    protected Json chatQuestionToJson(SMTAIServerRequest tranReq, boolean isStreamMode) throws Exception
    protected Json chatQuestionToJson(SMTAIServerRequest tranReq, boolean isStreamMode, boolean mustRawMode) throws Exception
    {
       try
       {
@@ -442,7 +397,7 @@
          String historyGroupId = tranReq.convParamToString("history_group_id", true);
          String question = tranReq.convParamToString("question", true);
          String processId = tranReq.convParamToString("process_id", false);
          Boolean rawMode = tranReq.convParamToBoolean("raw_mode", false);
          String sRawMode = tranReq.convParamToString("raw_mode", false);
          String prevQuestion = tranReq.convParamToString("prev_question", false);
          String groupType = tranReq.convParamToString("group_type", false);
          double[] curPos = tranReq.convParamToDoubleArray("cur_pos", false);
@@ -455,9 +410,21 @@
          
          question = SMTAIServerApp.getApp().getQueryAIQuestionReplace().replaceQuestion(groupType, question);
          
          boolean rawMode = false;
          
          if(rawMode == null)
             rawMode = false;
          if(sRawMode != null)
          {
             if("AI".equals(sRawMode))
             {
                rawMode = false;
             }
             else
             {
                rawMode = "true".equals(sRawMode);
                 if(mustRawMode)
                    rawMode = true;
             }
          }
          
            tranReq.setAsynProcessId(processId);
            Json jsonResult = null;
@@ -481,53 +448,62 @@
   {
      tranReq.sendChunkedBlock("begin", "分析[" + jsonSummary.safeGetStr("title", "") + "]的数据");
      
      StringBuilder sbQuestion = new StringBuilder();
      sbQuestion.append("以下是[" + jsonSummary.safeGetStr("title", "") + "]的数据,请对其进行分析,并提炼出最精简的结果。\n");
      
      boolean isFirst = true;
      int maxCol = 0;
      for(Json jsonCol : jsonSummary.getJson("cols").asJsonList())
      boolean set = tranReq.setSendStarStream(true);
      try
      {
         if(isFirst)
            isFirst = false;
         else
            sbQuestion.append(",");
         sbQuestion.append(jsonCol.safeGetStr("title", "值"));
         maxCol ++;
      }
      sbQuestion.append("\n");
      for(Json jsonRow : jsonSummary.getJson("values").asJsonList())
      {
         List<Json> listJsonRow = jsonRow.asJsonList();
         for(int i = 0; i < maxCol; i ++)
         StringBuilder sbQuestion = new StringBuilder();
         sbQuestion.append("以下是[" + jsonSummary.safeGetStr("title", "") + "]的数据,请对其进行分析,并提炼出最精简的结果。\n");
         boolean isFirst = true;
         int maxCol = 0;
         for(Json jsonCol : jsonSummary.getJson("cols").asJsonList())
         {
            if(i > 0)
               sbQuestion.append(",");
            Json jsonValue = listJsonRow.get(i);
            if(jsonValue.isNull())
            {
               sbQuestion.append("");
            }
            if(isFirst)
               isFirst = false;
            else
            {
               sbQuestion.append(listJsonRow.get(i).asString());
            }
               sbQuestion.append(",");
            sbQuestion.append(jsonCol.safeGetStr("title", "值"));
            maxCol ++;
         }
         sbQuestion.append("\n");
         
         if(sbQuestion.length() > 4096)
            break;
         for(Json jsonRow : jsonSummary.getJson("values").asJsonList())
         {
            List<Json> listJsonRow = jsonRow.asJsonList();
            for(int i = 0; i < maxCol; i ++)
            {
               if(i > 0)
                  sbQuestion.append(",");
               Json jsonValue = listJsonRow.get(i);
               if(jsonValue.isNull())
               {
                  sbQuestion.append("");
               }
               else
               {
                  sbQuestion.append(listJsonRow.get(i).asString());
               }
            }
            sbQuestion.append("\n");
            if(sbQuestion.length() > 4096)
               break;
         }
         String answer = llm.callWithMessage(null, sbQuestion.toString(), tranReq).replace("\r", "");
         jsonWrConclusion.beginMap(null);
         {
            jsonWrConclusion.addKeyValue("agent_key", agentKey);
            jsonWrConclusion.addKeyValue("report", answer);
         }
         jsonWrConclusion.endMap();
      }
      String answer = llm.callWithMessage(null, sbQuestion.toString(), tranReq).replace("\r", "");
      jsonWrConclusion.beginMap(null);
      finally
      {
         jsonWrConclusion.addKeyValue("agent_key", agentKey);
         jsonWrConclusion.addKeyValue("report", answer);
         tranReq.setSendStarStream(set);
      }
      jsonWrConclusion.endMap();
      
      return null;
   }
@@ -560,11 +536,11 @@
            Json jsonSqlParams = null;
            if(jsonResult != null)
            {
               jsonResult.set("question", tranReq.getAIQuestion());
               jsonResult.set("history_id", historyId);
               tranReq.addAttachMessageToJson(jsonResult);
               jsonSqlParams = tranReq.getParamJson();
               
               Json jsonExtCallList = tranReq.getExtCallJsonWriter();
@@ -1032,9 +1008,9 @@
    }
    
    public ModelAndView chatQuestionStream(SMTAIServerRequest tranReq) throws Exception
    public ModelAndView chatQuestionStream(SMTAIServerRequest tranReq, @RequestParam(value="files", required=false) MultipartFile[] files) throws Exception
    {
       return new ModelAndView(new SMTChatStreamView(tranReq));
       return new ModelAndView(new SMTChatStreamView(tranReq, files));
    }
    
    public ModelAndView chatAgentStream(SMTAIServerRequest tranReq) throws Exception 
@@ -1276,9 +1252,213 @@
       
       return tranReq.returnJson(jsonWr);
    }
    public ModelAndView testUpload(SMTAIServerRequest tranReq, @RequestPart(value = "files", required=false) List<MultipartFile> files) throws Exception
    public ModelAndView getAttachTableList(SMTAIServerRequest tranReq) throws Exception
    {
       return new ModelAndView(new SMTAttachFileChatStreamView(tranReq, files));
       SMTJsonWriter jsonWr = tranReq.newReturnJsonWriter(true, null, null);
       jsonWr.beginArray("tables");
       for(SMTAIAttachTableDef attachTableDef : SMTAIServerApp.getApp().getAttachTableDefMap().values())
       {
          jsonWr.beginMap(null);
          {
             jsonWr.addKeyValue("id", attachTableDef.getId());
             jsonWr.addKeyValue("title", attachTableDef.getTitle());
             jsonWr.addKeyValue("group", attachTableDef.getGroup());
             jsonWr.addKeyValue("is_chart", attachTableDef.isChartTable());
             jsonWr.beginArray("columns");
             for(SMTAIAttachTableColumn columnDef : attachTableDef.getColumnList())
             {
                jsonWr.beginMap(null);
                {
                   jsonWr.addKeyValue("name", columnDef.getName());
                   jsonWr.addKeyValue("title", columnDef.getTitle());
                   jsonWr.addKeyValue("filter", columnDef.getFilter());
                   jsonWr.addKeyValue("chart_type", columnDef.getChartType());
                }
                jsonWr.endMap();
             }
             jsonWr.endArray();
          }
          jsonWr.endMap();
       }
       jsonWr.endArray();
       return tranReq.returnJson(jsonWr);
    }
    public ModelAndView queryAttachTableRecords(SMTAIServerRequest tranReq) throws Exception
    {
       String attachTableId = tranReq.convParamToString("id", true);
       Json jsonFilters = tranReq.convParamToJson("filter", false);
       Json jsonOrders = tranReq.convParamToJson("order", false);
       Integer limit = tranReq.convParamToInteger("limit", false);
       SMTAIAttachTableDef attachTableDef = (SMTAIAttachTableDef) SMTAIServerApp.getApp().getAttachTableDef(attachTableId);
       if (limit==null)
         limit=100;
       SMTJsonWriter jsonWr = tranReq.newReturnJsonWriter(true, null, null);
       attachTableDef.queryRecordsToJson(jsonFilters, jsonOrders, jsonWr,limit);
       return tranReq.returnJson(jsonWr);
    }
    public ModelAndView getAttachMetricList(SMTAIServerRequest tranReq) throws Exception
    {
       SMTJsonWriter jsonWr = tranReq.newReturnJsonWriter(true, null, null);
       jsonWr.beginArray("metrics");
       for(SMTAIAttachMetricDef attachMetricDef : SMTAIServerApp.getApp().getAttachMetricDefMap().values())
       {
          jsonWr.beginMap(null);
          {
             jsonWr.addKeyValue("id", attachMetricDef.getId());
             jsonWr.addKeyValue("title", attachMetricDef.getTitle());
             jsonWr.addKeyValue("group", attachMetricDef.getGroup());
          }
          jsonWr.endMap();
       }
       jsonWr.endArray();
       return tranReq.returnJson(jsonWr);
    }
    public ModelAndView queryAttachMetricNames(SMTAIServerRequest tranReq) throws Exception
    {
       String attachMetricId = tranReq.convParamToString("id", true);
       String queryName = tranReq.convParamToString("name", true);
       SMTAIAttachMetricDef attachMetricDef = SMTAIServerApp.getApp().getAttachMetricDef(attachMetricId);
       SMTJsonWriter jsonWr = tranReq.newReturnJsonWriter(true, null, null);
       jsonWr.beginArray("values");
       attachMetricDef.queryNameToJson(queryName, jsonWr);
       jsonWr.endArray();
       return tranReq.returnJson(jsonWr);
    }
    public ModelAndView queryAttachMetricValues(SMTAIServerRequest tranReq) throws Exception
    {
       String attachMetricId = tranReq.convParamToString("id", true);
       Date startTime = tranReq.convParamToDate("start_time", true);
          Date endTime = tranReq.convParamToDate("end_time", true);
       Json jsonQuotaKeys = tranReq.convParamToJson("quota_keys", true);
       Integer limit = tranReq.convParamToInteger("limit", false);
      if (limit==null)
         limit=100;
       SMTAIAttachMetricDef attachMetricDef = SMTAIServerApp.getApp().getAttachMetricDef(attachMetricId);
       SMTJsonWriter jsonWr = tranReq.newReturnJsonWriter(true, null, null);
       attachMetricDef.queryValueToJson(startTime, endTime, jsonQuotaKeys, jsonWr,limit);
       return tranReq.returnJson(jsonWr);
    }
    public ModelAndView callLLM(SMTAIServerRequest tranReq) throws Exception
    {
       String llmId = tranReq.convParamToString("llm_id", false);
       Json jsonSystems = tranReq.convParamToJson("system_json", false);
       String question = tranReq.convParamToString("question", true);
       boolean answerIsJson = tranReq.convParamToBoolean("answer_is_json", true);
       SMTJsonWriter jsonWr = tranReq.newReturnJsonWriter(true, null, null);
       SMTLLMConnect conn = SMTAIServerApp.getApp().allocLLMConnect(llmId);
       List<String> listSystem = new ArrayList<>();
       if(jsonSystems != null)
       {
          for(Json jsonSystem : jsonSystems.asJsonList())
          {
             listSystem.add(jsonSystem.asString());
          }
       }
       String answer = conn.callWithMessage(listSystem, question, tranReq);
       if(answerIsJson)
       {
          jsonWr.addKeyRaw("answer", SMTStatic.convLLMAnswerToJson(answer, false));
       }
       else
       {
          jsonWr.addKeyValue("answer", answer);
       }
      return tranReq.returnJson(jsonWr);
    }
   public ModelAndView downloadFileByFileId(SMTAIServerRequest tranReq, HttpServletResponse response) throws Exception {
      String fileId = tranReq.convParamToString("file_id", true);  // 获取请求中的file_id
      SMTDatabase db = SMTAIServerApp.getApp().allocDatabase();
      try {
         // 查询指定file_id的文件记录
         DBRecords dbRecords = db.querySQL("SELECT * FROM ai_times.chat_history_attach WHERE attach_id=?", new Object[]{fileId});
         if (dbRecords.getRecords().isEmpty()) {
            throw new Exception("文件不存在");
         }
         // 获取文件信息
         DBRecord fileRecord = dbRecords.getRecords().get(0);
         String attachTitle = fileRecord.getString("attach_title");  // 获取文件标题
         String extension = attachTitle.substring(attachTitle.lastIndexOf(".") + 1);
         // 扩展名和 MIME 类型映射
         Object fileTypeMapping = SMTAIServerApp.getApp().getGlobalConfig("file_type_mapping", false);
         Json json = Json.read(fileTypeMapping.toString());
         Map<String, Object> mimeTypes = json.asMap();
         String mimeType = (String) mimeTypes.getOrDefault(extension.toLowerCase(), "application/octet-stream");
         // 获取文件的字节数据,假设返回的是字节数组
         byte[] bytes = (byte[]) fileRecord.getValue("attach_bytes");  // 获取字节数据
         return tranReq.returnDownloadByteArray(bytes, attachTitle, mimeType);
//         // 设置响应头和文件名
//         String fileName = attachTitle != null ? attachTitle : "downloaded_file";
//         response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
//         response.setContentType("application/octet-stream");
//         response.getOutputStream().write(bytes);  // 写入字节数据
//         response.getOutputStream().flush();
      } catch (Exception e) {
         throw new Exception("Error processing file download: " + e.getMessage());
      }
   }
   public ModelAndView chatCallAgent(SMTAIServerRequest tranReq) throws Exception
   {
      String agentId = tranReq.convParamToString("agent_id", true);
      Json jsonArgs = tranReq.convParamToJson("args", false);
      SMTQwenAgent agent = SMTAIServerApp.getApp().getQwenAgentManager().getAgentById(agentId);
      if(agent == null)
         throw new Exception("can't find agent : " + agentId);
      SMTLLMConnect llm = SMTAIServerApp.getApp().allocLLMConnect(null);
      if(jsonArgs == null)
         jsonArgs = Json.object("question", "");
      if(!jsonArgs.has("question"))
         jsonArgs.set("question", "");
      agent.callAgents("/", jsonArgs, llm, "", tranReq);
      List<SMTJsonWriter> listResult = tranReq.getResultJsonWrList();
      SMTJsonWriter jsonWr = tranReq.newReturnJsonWriter(true, null, null);
      jsonWr.beginArray("results");
      if(listResult != null && listResult.size() > 0)
      {
         for(SMTJsonWriter jsonWrResult : listResult)
         {
            jsonWr.addKeyRaw(null, jsonWrResult.getRootJson());
         }
      }
      jsonWr.endArray();
      return tranReq.returnJson(jsonWr);
   }
   public ModelAndView callAgentArgStream(SMTAIServerRequest tranReq) throws Exception
   {
       return new ModelAndView(new SMTCallAgentArgStreamView(tranReq));
   }
}