package com.rj.service.biz.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.rj.controller.biz.dto.ConsultingScenarioRequest; import com.rj.entity.bz.ConsultingScenario; import com.rj.mapper.biz.ConsultingScenarioMapper; import com.rj.service.biz.IConsultingScenarioService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.Iterator; import java.util.ArrayList; import java.util.List; import java.time.LocalDateTime; /** * Author: 李中华 wx: spllzh email(qq): 28668817@qq.com * Date: 2025/9/2 19:56 **/ @Service @Slf4j public class ConsultingScenarioServiceImpl extends ServiceImpl implements IConsultingScenarioService { // Dify API 配置 @Value("${dify.api.base-url}") private String difyApiUrlBase; @Value("${dify.api.workflow-endpoint-consultingScenar}") private String difyApiUrlEndPoint; @Value("${dify.api.apikey-consultingScenar}") //【AI】DCC用户问题分类提取 private String difyApiKey; private final ObjectMapper objectMapper = new ObjectMapper(); @Override public Object processConsultingScenario(ConsultingScenarioRequest request) { log.info("开始处理咨询场景请求: chat={}, businessType={}, sourceCorpusId={}, sourceCorpusTime={}", request.getChat(), request.getBusinessType(), request.getSourceCorpusId(), request.getSourceCorpusTime()); try { // 构造调用Dify工作流的请求 Map requestBody = new HashMap<>(); requestBody.put("inputs", Map.of( "chat", request.getChat(), // Dify 要求在 inputs 中提供 businessType "businessType", request.getBusinessType(), "sourceCorpusId", request.getSourceCorpusId(), "sourceCorpusTime", request.getSourceCorpusTime() )); requestBody.put("response_mode", "blocking"); requestBody.put("user", "api_user"); // 发起HTTP请求调用Dify工作流 RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.set("Authorization", "Bearer " + difyApiKey); HttpEntity> entity = new HttpEntity<>(requestBody, headers); String difyApiUrl = difyApiUrlBase + difyApiUrlEndPoint; log.info("调用Dify工作流: url={}, requestBody={}", difyApiUrl, requestBody); ResponseEntity response = restTemplate.postForEntity(difyApiUrl, entity, String.class); // 解析响应并打印到控制台 JsonNode jsonResponse = objectMapper.readTree(response.getBody()); log.info("Dify工作流响应结果: {}", jsonResponse.toPrettyString()); // 从响应中提取 outputs.text JsonNode outputsNode = jsonResponse.path("data").path("outputs"); String textBlock = outputsNode.path("text").asText(null); if (textBlock == null || textBlock.isEmpty()) { log.warn("未在响应中找到 outputs.text,返回原始响应"); return jsonResponse; } // 提取代码块中的 JSON(优先 ```json ... ```,否则回退到最外层花括号) String extractedJson = extractJsonString(textBlock); if (extractedJson == null) { log.warn("未能从文本中提取 JSON,返回原始响应"); return jsonResponse; } JsonNode parsedNode = objectMapper.readTree(extractedJson); // 映射到实体并保存 com.rj.entity.bz.ConsultingScenario entityToSave = mapToEntity(parsedNode); // 主键与时间戳 if (entityToSave.getId() == null || entityToSave.getId().isEmpty()) { entityToSave.setId(UUID.randomUUID().toString()); } entityToSave.setCreatedAt(LocalDateTime.now()); entityToSave.setUpdatedAt(LocalDateTime.now()); boolean saved = this.save(entityToSave); log.info("ConsultingScenario 保存结果: {}", saved); Map result = new HashMap<>(); result.put("saved", saved); result.put("entity", entityToSave); result.put("difyResponse", jsonResponse); return result; } catch (Exception e) { log.error("调用Dify工作流时发生错误", e); throw new RuntimeException("调用Dify工作流失败: " + e.getMessage(), e); } } /** * 从包含思考与代码块的文本中提取 JSON 字符串 */ private String extractJsonString(String text) { try { String startFlag = "```json"; String fence = "```"; int start = text.indexOf(startFlag); if (start >= 0) { int jsonStart = start + startFlag.length(); int end = text.indexOf(fence, jsonStart); if (end > jsonStart) { return text.substring(jsonStart, end).trim(); } } // 回退方案:提取第一个 '{' 到最后一个 '}' int firstBrace = text.indexOf('{'); int lastBrace = text.lastIndexOf('}'); if (firstBrace >= 0 && lastBrace > firstBrace) { return text.substring(firstBrace, lastBrace + 1); } return null; } catch (Exception e) { log.warn("提取 JSON 文本失败", e); return null; } } /** * 将解析后的 JSON 映射为 ConsultingScenario 实体 */ private com.rj.entity.bz.ConsultingScenario mapToEntity(JsonNode root) { com.rj.entity.bz.ConsultingScenario entity = new com.rj.entity.bz.ConsultingScenario(); // consultingScenario 主体 JsonNode cs = root.path("consultingScenario"); if (cs.isObject()) { entity.setMainCategory(cs.path("mainCategory").asText(null)); entity.setSubCategory(cs.path("subCategory").asText(null)); entity.setConfidence(cs.path("confidence").asText(null)); } entity.setUserDemand(root.path("userDemand").asText(null)); entity.setConsultingContent(joinArray(root.path("consultingContent"))); entity.setInvolvedVehicleModels(joinArray(root.path("involvedVehicleModels"))); entity.setKnowledgeGap(joinArray(root.path("knowledgeGap"))); entity.setPriority(root.path("priority").asText(null)); entity.setRemarks(root.path("remarks").asText(null)); return entity; } private String joinArray(JsonNode node) { if (node == null || !node.isArray()) { return null; } List list = new ArrayList<>(); Iterator it = node.elements(); while (it.hasNext()) { JsonNode n = it.next(); if (n.isTextual()) { list.add(n.asText()); } else { list.add(n.toString()); } } return String.join("\n", list); } }