|
|
@@ -2,6 +2,7 @@ package com.inspur.device.service.impl;
|
|
|
|
|
|
import cn.hutool.http.HttpRequest;
|
|
|
import cn.hutool.http.HttpResponse;
|
|
|
+import cn.hutool.json.JSONArray;
|
|
|
import cn.hutool.json.JSONUtil;
|
|
|
import com.alibaba.fastjson2.JSON;
|
|
|
import com.alibaba.fastjson2.JSONObject;
|
|
|
@@ -9,12 +10,19 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.inspur.device.domain.SmsbDifyDatasets;
|
|
|
+import com.inspur.device.domain.SmsbDifyDatasetsFile;
|
|
|
import com.inspur.device.domain.bo.SmsbDifyDatasetsBo;
|
|
|
import com.inspur.device.domain.vo.DifyDatasetsRspData;
|
|
|
+import com.inspur.device.domain.vo.SmsbDifyDatasetsFileVo;
|
|
|
+import com.inspur.device.domain.vo.SmsbDifyDatasetsProductVo;
|
|
|
import com.inspur.device.domain.vo.SmsbDifyDatasetsVo;
|
|
|
+import com.inspur.device.mapper.SmsbDifyDatasetsFileMapper;
|
|
|
import com.inspur.device.mapper.SmsbDifyDatasetsMapper;
|
|
|
+import com.inspur.device.mapper.SmsbDifyDatasetsProductMapper;
|
|
|
+import com.inspur.device.service.ISmsbDifyDatasetsFileService;
|
|
|
import com.inspur.device.service.ISmsbDifyDatasetsService;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
+import org.dromara.common.core.exception.ServiceException;
|
|
|
import org.dromara.common.core.utils.MapstructUtils;
|
|
|
import org.dromara.common.core.utils.StringUtils;
|
|
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
|
|
@@ -25,11 +33,16 @@ import org.springframework.beans.factory.annotation.Value;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.util.CollectionUtils;
|
|
|
|
|
|
+import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.net.URL;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.Collection;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Map;
|
|
|
+import java.nio.file.Files;
|
|
|
+import java.nio.file.Path;
|
|
|
+import java.nio.file.Paths;
|
|
|
+import java.nio.file.StandardCopyOption;
|
|
|
+import java.util.*;
|
|
|
|
|
|
/**
|
|
|
* 知识库管理Service业务层处理
|
|
|
@@ -43,15 +56,16 @@ public class SmsbDifyDatasetsServiceImpl implements ISmsbDifyDatasetsService {
|
|
|
|
|
|
@Value("${dify.url}")
|
|
|
private String difyUrl;
|
|
|
-
|
|
|
@Value("${dify.datasets.apiKey}")
|
|
|
private String datasetsApiKey;
|
|
|
-
|
|
|
+ @Value("${server.tempDir}")
|
|
|
+ private String tempDir;
|
|
|
/** 知识库API */
|
|
|
private final static String API_DATASETS_COMMON = "/v1/datasets";
|
|
|
-
|
|
|
-
|
|
|
private final SmsbDifyDatasetsMapper baseMapper;
|
|
|
+ private final SmsbDifyDatasetsProductMapper smsbDifyDatasetsProductMapper;
|
|
|
+ private final SmsbDifyDatasetsFileMapper smsbDifyDatasetsFileMapper;
|
|
|
+ private final ISmsbDifyDatasetsFileService smsbDifyDatasetsFileService;
|
|
|
|
|
|
|
|
|
/**
|
|
|
@@ -109,6 +123,123 @@ public class SmsbDifyDatasetsServiceImpl implements ISmsbDifyDatasetsService {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public boolean pushProduct(SmsbDifyDatasetsBo bo) throws IOException {
|
|
|
+ Long datasetsId = bo.getId();
|
|
|
+ SmsbDifyDatasetsVo datasetsVo = baseMapper.selectVoById(datasetsId);
|
|
|
+ List<String> productIds = bo.getEntryIds();
|
|
|
+ if (CollectionUtils.isEmpty(productIds)) {
|
|
|
+ throw new ServiceException("产品条目ID不能为空!");
|
|
|
+ }
|
|
|
+ List<SmsbDifyDatasetsProductVo> productVoList = smsbDifyDatasetsProductMapper.selectVoListByIds(productIds);
|
|
|
+ // 1 生成新的内容
|
|
|
+ StringBuffer sb = new StringBuffer();
|
|
|
+ for (SmsbDifyDatasetsProductVo productVo : productVoList) {
|
|
|
+ sb.append("###");
|
|
|
+ sb.append("产品名称:" + productVo.getName()).append("\n");
|
|
|
+ sb.append("产品简介:" + productVo.getNote()).append("\n");
|
|
|
+ sb.append("产品图片:" + productVo.getImgUrl()).append("\n");
|
|
|
+ }
|
|
|
+ // 2 查询当前产品库关联的文件
|
|
|
+ SmsbDifyDatasetsFileVo difyDatasetsFileVo = smsbDifyDatasetsFileMapper.selectVoOne(new LambdaQueryWrapper<SmsbDifyDatasetsFile>()
|
|
|
+ .eq(SmsbDifyDatasetsFile::getDatasetsId,datasetsId).last("limit 1"));
|
|
|
+ // 3 根据记录先删除dify平台的文件
|
|
|
+ if (null != difyDatasetsFileVo) {
|
|
|
+ List<Long> ids = new ArrayList<>();
|
|
|
+ ids.add(difyDatasetsFileVo.getId());
|
|
|
+ smsbDifyDatasetsFileService.deleteWithValidByIds(ids,false);
|
|
|
+ }
|
|
|
+ // 4 生成新的文件上传至dify平台
|
|
|
+ String filePath = createTempFile(sb.toString());
|
|
|
+ boolean uploadResult = upload2Dify(datasetsVo,filePath);
|
|
|
+
|
|
|
+ return uploadResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean upload2Dify(SmsbDifyDatasetsVo datasetsVo,String filePath) {
|
|
|
+ // 根据
|
|
|
+ // 2、 调用dify接口,将文件上传至dify
|
|
|
+ String requestUrl = difyUrl + API_DATASETS_COMMON + "/" + datasetsVo.getDifyId() + "/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;
|
|
|
+ }
|
|
|
+ // 3、 获取接口返回文件ID
|
|
|
+ cn.hutool.json.JSONObject document = JSONUtil.parseObj(response.body()).get("document", cn.hutool.json.JSONObject.class);
|
|
|
+ String difyId = document.getStr("id");
|
|
|
+ // 4、 保存至数据库
|
|
|
+ SmsbDifyDatasetsFile add = new SmsbDifyDatasetsFile();
|
|
|
+ add.setDatasetsDifyId(datasetsVo.getDifyId());
|
|
|
+ add.setDifyId(difyId);
|
|
|
+ // 获取知识库信息
|
|
|
+ add.setDatasetsId(datasetsVo.getId());
|
|
|
+ add.setDatasetsName(datasetsVo.getName());
|
|
|
+ add.setName(filePath);
|
|
|
+ add.setIndexingStatus(document.getStr("indexing_status"));
|
|
|
+ add.setPosition(document.getInt("position"));
|
|
|
+ add.setTokens(document.getInt("tokens"));
|
|
|
+ add.setWordCount(document.getInt("word_count"));
|
|
|
+ add.setFilePath(filePath);
|
|
|
+ smsbDifyDatasetsFileMapper.insert(add);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String createAddFileRequestBody() {
|
|
|
+ // 构建 JSON 格式的 data 参数
|
|
|
+ cn.hutool.json.JSONObject dataJson = new cn.hutool.json.JSONObject();
|
|
|
+ // 1-索引方式
|
|
|
+ dataJson.put("indexing_technique", "high_quality");
|
|
|
+
|
|
|
+ // 2-处理规则
|
|
|
+ cn.hutool.json.JSONObject processRule = new cn.hutool.json.JSONObject();
|
|
|
+ // 2-1 清洗、分段模式
|
|
|
+ processRule.put("mode", "custom");
|
|
|
+ // 2-2 自定义规则
|
|
|
+ cn.hutool.json.JSONObject rules = new cn.hutool.json.JSONObject();
|
|
|
+ // 2-2-1 预处理规则
|
|
|
+ JSONArray preProcessingRules = new JSONArray();
|
|
|
+ cn.hutool.json.JSONObject rule1 = new cn.hutool.json.JSONObject();
|
|
|
+ rule1.put("id", "remove_extra_spaces");
|
|
|
+ rule1.put("enabled", true);
|
|
|
+ preProcessingRules.add(rule1);
|
|
|
+ cn.hutool.json.JSONObject rule2 = new cn.hutool.json.JSONObject();
|
|
|
+ rule2.put("id", "remove_urls_emails");
|
|
|
+ rule2.put("enabled", false);
|
|
|
+ preProcessingRules.add(rule2);
|
|
|
+ // 2-2-1 分段规则
|
|
|
+ cn.hutool.json.JSONObject segmentation = new cn.hutool.json.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 String createTempFile(String entryContent) throws IOException {
|
|
|
+ // 创建一个临时路径
|
|
|
+ String localPath = tempDir + "/" + System.currentTimeMillis();
|
|
|
+ Path path = Paths.get(localPath);
|
|
|
+ Files.createDirectories(path);
|
|
|
+ // 将entryContent保存到临时路径
|
|
|
+ String filePath = localPath + "/" + System.currentTimeMillis() + ".txt";
|
|
|
+ Path filePathObj = Paths.get(filePath);
|
|
|
+ byte[] contentBytes = entryContent.getBytes(StandardCharsets.UTF_8);
|
|
|
+ Files.write(filePathObj, contentBytes);
|
|
|
+ return filePath;
|
|
|
+ }
|
|
|
+
|
|
|
private SmsbDifyDatasets buildDatasetByDifyData(DifyDatasetsRspData dataset) {
|
|
|
SmsbDifyDatasets smsbDifyDatasets = new SmsbDifyDatasets();
|
|
|
BeanUtils.copyProperties(dataset, smsbDifyDatasets);
|