|
@@ -1,20 +1,25 @@
|
|
|
package com.etotem.cfc.service;
|
|
package com.etotem.cfc.service;
|
|
|
|
|
|
|
|
import com.etotem.cfc.entity.DanKnowledgeBase;
|
|
import com.etotem.cfc.entity.DanKnowledgeBase;
|
|
|
|
|
+import com.etotem.cfc.entity.ProductDimensionConfig;
|
|
|
|
|
+import com.etotem.cfc.mapper.ProductDimensionConfigMapper;
|
|
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
|
|
+import org.springframework.http.HttpEntity;
|
|
|
|
|
+import org.springframework.http.HttpHeaders;
|
|
|
|
|
+import org.springframework.http.HttpMethod;
|
|
|
|
|
+import org.springframework.http.MediaType;
|
|
|
import org.springframework.scheduling.annotation.Async;
|
|
import org.springframework.scheduling.annotation.Async;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
+import org.springframework.web.client.RestTemplate;
|
|
|
|
|
|
|
|
|
|
+import javax.annotation.Resource;
|
|
|
|
|
+import java.util.HashMap;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
|
|
|
-/**
|
|
|
|
|
- * Dify 知识库同步服务
|
|
|
|
|
- *
|
|
|
|
|
- * 在知识点新增/编辑/删除时异步推送到 Dify Dataset。
|
|
|
|
|
- * Dify 调用失败不影响主流程,仅记录 error log。
|
|
|
|
|
- */
|
|
|
|
|
@Service
|
|
@Service
|
|
|
public class DifySyncService {
|
|
public class DifySyncService {
|
|
|
|
|
|
|
@@ -26,41 +31,50 @@ public class DifySyncService {
|
|
|
@Value("${dify.api-key}")
|
|
@Value("${dify.api-key}")
|
|
|
private String difyApiKey;
|
|
private String difyApiKey;
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 推送知识点到 Dify(异步,不阻塞主流程)
|
|
|
|
|
- *
|
|
|
|
|
- * @param knowledge 知识点
|
|
|
|
|
- * @param dimensionCodes 关联维度代码列表(每个维度对应一个 Dify dataset)
|
|
|
|
|
- */
|
|
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private ProductDimensionConfigMapper productDimensionConfigMapper;
|
|
|
|
|
+
|
|
|
|
|
+ private final RestTemplate restTemplate = new RestTemplate();
|
|
|
|
|
+
|
|
|
@Async
|
|
@Async
|
|
|
public void syncToDify(DanKnowledgeBase knowledge, List<String> dimensionCodes) {
|
|
public void syncToDify(DanKnowledgeBase knowledge, List<String> dimensionCodes) {
|
|
|
- if (dimensionCodes == null || dimensionCodes.isEmpty()) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (dimensionCodes == null || dimensionCodes.isEmpty()) return;
|
|
|
for (String code : dimensionCodes) {
|
|
for (String code : dimensionCodes) {
|
|
|
try {
|
|
try {
|
|
|
- // TODO: 根据 dimensionCode 查找 product_dimension_config 中的 dify_dataset_id
|
|
|
|
|
- // 如果 dify_dataset_id 为空则跳过
|
|
|
|
|
- // 调用 Dify API: POST /v1/datasets/{dataset_id}/documents
|
|
|
|
|
- // 文档标题: knowledge.title, 内容: knowledge.content
|
|
|
|
|
- log.info("准备同步知识点[{}]到维度[{}]的 Dify dataset", knowledge.getTitle(), code);
|
|
|
|
|
|
|
+ ProductDimensionConfig config = productDimensionConfigMapper.selectOne(
|
|
|
|
|
+ new LambdaQueryWrapper<ProductDimensionConfig>().eq(ProductDimensionConfig::getDimensionCode, code));
|
|
|
|
|
+ if (config == null || config.getDifyDatasetId() == null || config.getDifyDatasetId().isEmpty()) {
|
|
|
|
|
+ log.warn("维度[{}]未配置 Dify Dataset,跳过同步", code);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ String url = difyBaseUrl + "/v1/datasets/" + config.getDifyDatasetId() + "/documents";
|
|
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
|
|
+ headers.setContentType(MediaType.APPLICATION_JSON);
|
|
|
|
|
+ headers.set("Authorization", "Bearer " + difyApiKey);
|
|
|
|
|
+ Map<String, Object> body = new HashMap<>();
|
|
|
|
|
+ body.put("name", knowledge.getTitle());
|
|
|
|
|
+ Map<String, Object> textContent = new HashMap<>();
|
|
|
|
|
+ textContent.put("content", knowledge.getContent());
|
|
|
|
|
+ body.put("text", textContent);
|
|
|
|
|
+ HttpEntity<Map<String, Object>> entity = new HttpEntity<>(body, headers);
|
|
|
|
|
+ restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
|
|
|
|
|
+ log.info("同步知识点[{}]到维度[{}]的 Dify dataset 成功", knowledge.getTitle(), code);
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.error("同步知识点[{}]到维度[{}]的 Dify dataset 失败", knowledge.getTitle(), code, e);
|
|
log.error("同步知识点[{}]到维度[{}]的 Dify dataset 失败", knowledge.getTitle(), code, e);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 从 Dify 删除知识点文档(异步)
|
|
|
|
|
- *
|
|
|
|
|
- * @param knowledgeId 知识点ID
|
|
|
|
|
- * @param difyDatasetId Dify Dataset ID
|
|
|
|
|
- */
|
|
|
|
|
@Async
|
|
@Async
|
|
|
public void removeFromDify(Long knowledgeId, String difyDatasetId) {
|
|
public void removeFromDify(Long knowledgeId, String difyDatasetId) {
|
|
|
try {
|
|
try {
|
|
|
- // TODO: 调用 Dify API: DELETE /v1/datasets/{dataset_id}/documents/{doc_id}
|
|
|
|
|
- log.info("准备从 Dify dataset[{}]删除知识点[{}]", difyDatasetId, knowledgeId);
|
|
|
|
|
|
|
+ if (difyDatasetId == null || difyDatasetId.isEmpty()) return;
|
|
|
|
|
+ String url = difyBaseUrl + "/v1/datasets/" + difyDatasetId + "/documents/" + knowledgeId;
|
|
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
|
|
+ headers.set("Authorization", "Bearer " + difyApiKey);
|
|
|
|
|
+ HttpEntity<String> entity = new HttpEntity<>(headers);
|
|
|
|
|
+ restTemplate.exchange(url, HttpMethod.DELETE, entity, String.class);
|
|
|
|
|
+ log.info("从 Dify dataset[{}]删除知识点[{}]成功", difyDatasetId, knowledgeId);
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.error("从 Dify 删除知识点[{}]失败", knowledgeId, e);
|
|
log.error("从 Dify 删除知识点[{}]失败", knowledgeId, e);
|
|
|
}
|
|
}
|