|
|
@@ -10,6 +10,7 @@ import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.github.therapi.runtimejavadoc.repack.com.eclipsesource.json.JsonObject;
|
|
|
+import com.inspur.device.domain.vo.DifyDatasetsFileRspData;
|
|
|
import com.inspur.device.domain.vo.SmsbDeviceGroupRelVo;
|
|
|
import com.inspur.device.mapper.SmsbDeviceGroupRelMapper;
|
|
|
import com.inspur.digital.domain.SmsbAppointmentInfo;
|
|
|
@@ -38,10 +39,17 @@ import org.springframework.beans.factory.annotation.Value;
|
|
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
+import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.nio.file.Files;
|
|
|
+import java.nio.file.Path;
|
|
|
+import java.nio.file.Paths;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Collection;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
* 预约信息Service业务层处理
|
|
|
@@ -73,6 +81,16 @@ public class SmsbAppointmentInfoServiceImpl implements ISmsbAppointmentInfoServi
|
|
|
private String difyBaseUrl;
|
|
|
@Value("${dify.sc_agent.apiKey}")
|
|
|
private String difyScAgentApiKey;
|
|
|
+ @Value("${dify.sc_dataset.report}")
|
|
|
+ private String difyScDatasetReportId;
|
|
|
+ @Value("${server.tempDir}")
|
|
|
+ private String tempDir;
|
|
|
+ @Value("${dify.datasets.apiKey}")
|
|
|
+ private String datasetsApiKey;
|
|
|
+ /**
|
|
|
+ * 知识库API
|
|
|
+ */
|
|
|
+ private final static String API_DATASETS_COMMON = "/v1/datasets";
|
|
|
/**
|
|
|
* 默认场景序号 诊断评估
|
|
|
*/
|
|
|
@@ -224,59 +242,68 @@ public class SmsbAppointmentInfoServiceImpl implements ISmsbAppointmentInfoServi
|
|
|
JSONObject reportContent = reportMapJson.getJSONObject("reportContent");
|
|
|
// 2-1 评分标准:
|
|
|
JSONArray standards = reportContent.getJSONArray("standards");
|
|
|
- StringBuilder standardResult = new StringBuilder();
|
|
|
- standardResult.append("评分标准:\n");
|
|
|
- for (int i = 0; i < standards.size(); i++) {
|
|
|
-
|
|
|
- standardResult.append("等级名称:").append(standards.getJSONObject(i).getStr("levelName")).append("\n");
|
|
|
- standardResult.append("等级描述:").append(standards.getJSONObject(i).get("levelDesc")).append("\n");
|
|
|
- standardResult.append("最小分值:").append(standards.getJSONObject(i).get("minScore")).append("\n");
|
|
|
- standardResult.append("最大分值:").append(standards.getJSONObject(i).get("maxScore")).append("\n");
|
|
|
+ if (null != standards && standards.size() > 0) {
|
|
|
+ StringBuilder standardResult = new StringBuilder();
|
|
|
+ standardResult.append("评分标准:\n");
|
|
|
+ for (int i = 0; i < standards.size(); i++) {
|
|
|
+
|
|
|
+ standardResult.append("等级名称:").append(standards.getJSONObject(i).getStr("levelName")).append("\n");
|
|
|
+ standardResult.append("等级描述:").append(standards.getJSONObject(i).get("levelDesc")).append("\n");
|
|
|
+ standardResult.append("最小分值:").append(standards.getJSONObject(i).get("minScore")).append("\n");
|
|
|
+ standardResult.append("最大分值:").append(standards.getJSONObject(i).get("maxScore")).append("\n");
|
|
|
+ }
|
|
|
+ result.add(standardResult.toString());
|
|
|
}
|
|
|
- result.add(standardResult.toString());
|
|
|
// 2-2 当前分值
|
|
|
result.add("当前分值:" + reportContent.get("score"));
|
|
|
// 2-3 对标情况
|
|
|
JSONObject benchmarking = reportContent.getJSONObject("benchmarking");
|
|
|
// 2-3-1 等级情况
|
|
|
JSONArray rate = benchmarking.getJSONArray("rate");
|
|
|
- StringBuilder rateResult = new StringBuilder();
|
|
|
- for (int i = 0; i < rate.size(); i++) {
|
|
|
- rateResult.append("等级情况:\n");
|
|
|
- rateResult.append("等级名称:").append(rate.getJSONObject(i).getStr("rate")).append("\n");
|
|
|
- rateResult.append("等级数量:").append(rate.getJSONObject(i).get("quantity")).append("\n");
|
|
|
- rateResult.append("平均分值:").append(rate.getJSONObject(i).get("avg")).append("\n");
|
|
|
+ if (null != rate && rate.size() > 0) {
|
|
|
+ StringBuilder rateResult = new StringBuilder();
|
|
|
+ for (int i = 0; i < rate.size(); i++) {
|
|
|
+ rateResult.append("等级情况:\n");
|
|
|
+ rateResult.append("等级名称:").append(rate.getJSONObject(i).getStr("rate")).append("\n");
|
|
|
+ rateResult.append("等级数量:").append(rate.getJSONObject(i).get("quantity")).append("\n");
|
|
|
+ rateResult.append("平均分值:").append(rate.getJSONObject(i).get("avg")).append("\n");
|
|
|
+ }
|
|
|
+ result.add(rateResult.toString());
|
|
|
}
|
|
|
- result.add(rateResult.toString());
|
|
|
// 2-3-2 得分情况
|
|
|
JSONObject location = benchmarking.getJSONObject("location");
|
|
|
- StringBuilder locationResult = new StringBuilder();
|
|
|
- locationResult.append("得分情况:\n");
|
|
|
- locationResult.append("自评高于贵公司的数量:").append(location.get("current")).append("\n");
|
|
|
- locationResult.append("自评等于贵公司的数量:").append(location.get("equalCount")).append("\n");
|
|
|
- locationResult.append("总数量:").append(location.get("count")).append("\n");
|
|
|
- result.add(locationResult.toString());
|
|
|
+ if (null != location) {
|
|
|
+ StringBuilder locationResult = new StringBuilder();
|
|
|
+ locationResult.append("得分情况:\n");
|
|
|
+ locationResult.append("自评高于贵公司的数量:").append(location.get("current")).append("\n");
|
|
|
+ locationResult.append("自评等于贵公司的数量:").append(location.get("equalCount")).append("\n");
|
|
|
+ locationResult.append("总数量:").append(location.get("count")).append("\n");
|
|
|
+ result.add(locationResult.toString());
|
|
|
+ }
|
|
|
// 2-4 分析建议
|
|
|
JSONObject suggestion = reportContent.getJSONObject("suggestion");
|
|
|
// 2-4-1 劣势列表
|
|
|
JSONArray disadvantage = suggestion.getJSONArray("disadvantage");
|
|
|
+ if (null != disadvantage && disadvantage.size() > 0){
|
|
|
StringBuilder disadvantageResult = new StringBuilder();
|
|
|
for (int i = 0; i < disadvantage.size(); i++) {
|
|
|
disadvantageResult.append("劣势列表:\n");
|
|
|
disadvantageResult.append(disadvantage.get(i)).append("\n");
|
|
|
}
|
|
|
result.add(disadvantageResult.toString());
|
|
|
+ }
|
|
|
// 2-4-2 优势列表
|
|
|
JSONArray advantage = suggestion.getJSONArray("advantage");
|
|
|
- StringBuilder advantageResult = new StringBuilder();
|
|
|
- for (int i = 0; i < advantage.size(); i++) {
|
|
|
- advantageResult.append("优势列表:\n");
|
|
|
- advantageResult.append(advantage.get(i)).append("\n");
|
|
|
+ if (null != advantage && advantage.size() > 0) {
|
|
|
+ StringBuilder advantageResult = new StringBuilder();
|
|
|
+ for (int i = 0; i < advantage.size(); i++) {
|
|
|
+ advantageResult.append("优势列表:\n");
|
|
|
+ advantageResult.append(advantage.get(i)).append("\n");
|
|
|
+ }
|
|
|
+ result.add(advantageResult.toString());
|
|
|
}
|
|
|
- result.add(advantageResult.toString());
|
|
|
// 2-4-3 相关建议列表
|
|
|
JSONObject content = suggestion.getJSONObject("content");
|
|
|
-
|
|
|
result.add("相关建议:" + content.toString()
|
|
|
.replaceAll("\\{", "").replaceAll("}", "")
|
|
|
.replaceAll("\\[", "").replaceAll("]", "").trim());
|
|
|
@@ -393,6 +420,8 @@ public class SmsbAppointmentInfoServiceImpl implements ISmsbAppointmentInfoServi
|
|
|
return R.ok(result);
|
|
|
}
|
|
|
List<SmsbScDeviceStartInfoVo> deviceStartInfoList = new ArrayList<>();
|
|
|
+ // 针对评估所有内容集合
|
|
|
+ List<String> reportContentList = new ArrayList<>();
|
|
|
for (SmsbDeviceGroupRelVo deviceGroupRel : deviceGroupRelList) {
|
|
|
SmsbScDeviceStartInfoVo deviceStartInfo = new SmsbScDeviceStartInfoVo();
|
|
|
deviceStartInfo.setIdentifier(deviceGroupRel.getDeviceIdentifier());
|
|
|
@@ -404,6 +433,12 @@ public class SmsbAppointmentInfoServiceImpl implements ISmsbAppointmentInfoServi
|
|
|
.eq(SmsbDeviceChatScReport::getType, 1)
|
|
|
.orderByDesc(SmsbDeviceChatScReport::getAppointmentId).last("limit 1"));
|
|
|
deviceStartInfo.setHelloWorld(report.getContent());
|
|
|
+ List<SmsbDeviceChatScReportVo> reportVoList = smsbDeviceChatScReportMapper.selectVoList(new LambdaQueryWrapper<SmsbDeviceChatScReport>()
|
|
|
+ .eq(SmsbDeviceChatScReport::getAppointmentId, appointmentInfo.getId())
|
|
|
+ .eq(SmsbDeviceChatScReport::getType, 2));
|
|
|
+ if (CollectionUtils.isNotEmpty(reportVoList)) {
|
|
|
+ reportContentList = reportVoList.stream().map(SmsbDeviceChatScReportVo::getContent).collect(Collectors.toList());
|
|
|
+ }
|
|
|
} else if (deviceGroupRel.getSceneSort().equals(DEFAULT_SCENE_SORT_2)) {
|
|
|
|
|
|
} else if (deviceGroupRel.getSceneSort().equals(DEFAULT_SCENE_SORT_3)) {
|
|
|
@@ -415,6 +450,142 @@ public class SmsbAppointmentInfoServiceImpl implements ISmsbAppointmentInfoServi
|
|
|
}
|
|
|
result.setDeviceStartInfoList(deviceStartInfoList);
|
|
|
// TODO 异步现场启动 更新知识库
|
|
|
+ // 线程1 更新评估报告知识库
|
|
|
+ syncDatasets(reportContentList, difyScDatasetReportId);
|
|
|
+
|
|
|
return R.ok(result);
|
|
|
}
|
|
|
+
|
|
|
+ private void syncDatasets(List<String> contentList, String datasetsId) {
|
|
|
+ Runnable transTask = () -> {
|
|
|
+ try {
|
|
|
+ log.info("syncDatasets thread begin contentList.size(): " + contentList.size() + ",datasetsId : " + datasetsId);
|
|
|
+ // 组装条目
|
|
|
+ StringBuilder allContentStr = new StringBuilder();
|
|
|
+ for (String content : contentList) {
|
|
|
+ allContentStr.append("###").append("\n");
|
|
|
+ allContentStr.append(content).append("\n");
|
|
|
+ }
|
|
|
+ String filePath = createTempFile(allContentStr.toString());
|
|
|
+ log.info("syncDatasets thread createTempFile success tempFilePath = " + filePath);
|
|
|
+ boolean uploadResult = uploadDatasetsToDify(datasetsId,filePath);
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ log.info("createReport thread end !");
|
|
|
+ };
|
|
|
+ // 提交Runnable任务到线程池
|
|
|
+ threadPoolTaskExecutor.submit(transTask);
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean uploadDatasetsToDify(String datasetsId, String filePath) {
|
|
|
+ // 1、 根据知识库ID 获取文件列表
|
|
|
+ List<DifyDatasetsFileRspData> datasetsFiles = getDatasetsFiles(datasetsId);
|
|
|
+ // 2、如果知识库文件不为空,删除知识库内文件
|
|
|
+ if (!CollectionUtils.isEmpty(datasetsFiles)) {
|
|
|
+ for (DifyDatasetsFileRspData datasetsFile : datasetsFiles) {
|
|
|
+ deleteDatasetsFiles(datasetsId,datasetsFile.getId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 3、上传文件
|
|
|
+ boolean uploadResult = uploadDatasetsFiles(datasetsId,filePath);
|
|
|
+ log.info("uploadDatasetsToDify datasetsId is " + datasetsId + ",result = " + uploadResult);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean uploadDatasetsFiles(String datasetsId, String filePath) {
|
|
|
+ // 调用dify接口,将文件上传至dify
|
|
|
+ String requestUrl = difyBaseUrl + API_DATASETS_COMMON + "/" + datasetsId + "/document/create-by-file";
|
|
|
+ String requestBody = createAddFileRequestBody();
|
|
|
+
|
|
|
+ // 发送请求
|
|
|
+ HttpResponse response = HttpRequest.post(requestUrl)
|
|
|
+ .header("Authorization", "Bearer " + datasetsApiKey)
|
|
|
+ .header("User-Agent","PostmanRuntime/7.26.8")
|
|
|
+ .form("data", requestBody)
|
|
|
+ .form("file", new File(filePath))
|
|
|
+ .execute();
|
|
|
+ // 处理响应
|
|
|
+ if (!response.isOk()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ private String createAddFileRequestBody() {
|
|
|
+ // 构建 JSON 格式的 data 参数
|
|
|
+ JSONObject dataJson = new JSONObject();
|
|
|
+ // 1-索引方式
|
|
|
+ dataJson.put("indexing_technique", "high_quality");
|
|
|
+
|
|
|
+ // 2-处理规则
|
|
|
+ JSONObject processRule = new JSONObject();
|
|
|
+ // 2-1 清洗、分段模式
|
|
|
+ processRule.put("mode", "custom");
|
|
|
+ // 2-2 自定义规则
|
|
|
+ JSONObject rules = new JSONObject();
|
|
|
+ // 2-2-1 预处理规则
|
|
|
+ JSONArray preProcessingRules = new JSONArray();
|
|
|
+ JSONObject rule1 = new JSONObject();
|
|
|
+ rule1.put("id", "remove_extra_spaces");
|
|
|
+ rule1.put("enabled", true);
|
|
|
+ preProcessingRules.add(rule1);
|
|
|
+ JSONObject rule2 = new JSONObject();
|
|
|
+ rule2.put("id", "remove_urls_emails");
|
|
|
+ rule2.put("enabled", true);
|
|
|
+ preProcessingRules.add(rule2);
|
|
|
+ // 2-2-1 分段规则
|
|
|
+ JSONObject segmentation = new JSONObject();
|
|
|
+ segmentation.put("separator", "###");
|
|
|
+ segmentation.put("max_tokens", 800);
|
|
|
+ rules.put("pre_processing_rules", preProcessingRules);
|
|
|
+ rules.put("segmentation", segmentation);
|
|
|
+ processRule.put("rules", rules);
|
|
|
+
|
|
|
+ dataJson.put("process_rule", processRule);
|
|
|
+ return dataJson.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void deleteDatasetsFiles(String datasetsId,String datasetsFileId) {
|
|
|
+ String requestUrl = difyBaseUrl + API_DATASETS_COMMON + "/" + datasetsId + "/documents/" + datasetsFileId;
|
|
|
+ HttpRequest request = HttpRequest.delete(requestUrl)
|
|
|
+ .header("Authorization", "Bearer " + datasetsApiKey)
|
|
|
+ .header("User-Agent","PostmanRuntime/7.26.8");
|
|
|
+ HttpResponse response = request.execute();
|
|
|
+ log.info("delete datasetsId's datasetsFileId is " + response.isOk());
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<DifyDatasetsFileRspData> getDatasetsFiles(String datasetsId) {
|
|
|
+ String requestUrl = difyBaseUrl + API_DATASETS_COMMON + "/" + datasetsId + "/documents?page=1&limit=100";
|
|
|
+ HttpRequest request = HttpRequest.get(requestUrl)
|
|
|
+ .header("Authorization", "Bearer " + datasetsApiKey)
|
|
|
+ .header("User-Agent","PostmanRuntime/7.26.8");
|
|
|
+ HttpResponse response = request.execute();
|
|
|
+ if (!response.isOk()) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ String responseBody = response.body();
|
|
|
+ JSONObject jsonObject = JSONUtil.parseObj(responseBody);
|
|
|
+ // 1 如果结果为0 直接返回
|
|
|
+ Integer total = jsonObject.getInt("total");
|
|
|
+ if (total == 0) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ // data中取出知识库列表
|
|
|
+ List<DifyDatasetsFileRspData> datasetsFiles = jsonObject.getJSONArray("data").toList(DifyDatasetsFileRspData.class);
|
|
|
+ log.info("getDatasetsFiles datasetsId is " + datasetsId + ",total = " + total + ",datasetsFiles size: " + datasetsFiles.size());
|
|
|
+ return datasetsFiles;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String createTempFile(String datasetsContent) throws IOException {
|
|
|
+ // 创建一个临时路径
|
|
|
+ String localPath = tempDir + "/" + System.currentTimeMillis();
|
|
|
+ Path path = Paths.get(localPath);
|
|
|
+ Files.createDirectories(path);
|
|
|
+ // 将datasetsContent保存到临时路径
|
|
|
+ String filePath = localPath + "/" + System.currentTimeMillis() + ".txt";
|
|
|
+ Path filePathObj = Paths.get(filePath);
|
|
|
+ byte[] contentBytes = datasetsContent.getBytes(StandardCharsets.UTF_8);
|
|
|
+ Files.write(filePathObj, contentBytes);
|
|
|
+ return filePath;
|
|
|
+ }
|
|
|
}
|