调用dify,解决时间问题,源语料为空的问题

This commit is contained in:
spllzh
2025-09-08 00:00:08 +08:00
parent a25d80ae28
commit 206275317f
9 changed files with 1552 additions and 0 deletions

View File

@@ -0,0 +1,308 @@
package com.rj.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.rj.entity.bz.DifyWorkflowAnalysis;
import com.rj.service.biz.IDifyWorkflowAnalysisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
/**
* Dify工作流服务类
* 用于调用Dify平台的工作流API
*
* @author 李中华
* @date 2025/1/3
*/
@Slf4j
@Service
public class DifyWorkflowService {
@Value("${dify.api.base-url}")
private String difyBaseUrl;
@Value("${dify.api.workflow-endpoint-consultingScenar}")
private String workflowEndpoint;
@Value("${dify.api.summary-qiwei-token}")// 企微(一句话+分类别) app-WPuiaYg0iVLc2ws0iOfsAUC6
private String summaryQiweiToken;
@Value("${dify.api.summary-ddc-token}")// DDC一句话+分类别) app-rgaQbIir7vrVb1473Z3Puz6w
private String summaryddcToken;
@Value("${dify.api.summary-nameplate-token}")// 铭牌(一句话+分类别) //app-cv5glaYrY4zgjq0XIidSoJea
private String summaryNameplateToken;
private final RestTemplate restTemplate;
@Autowired
private IDifyWorkflowAnalysisService difyWorkflowAnalysisService;
public DifyWorkflowService() {
this.restTemplate = new RestTemplate();
}
/**
* 调用企微对话分析工作流
*
* @param request 工作流请求参数
* @return 工作流响应结果
*/
public DifyWorkflowResponse callConsultingScenarioWorkflow(DifyWorkflowRequest request) {
try {
String url = difyBaseUrl + workflowEndpoint;
// 构建请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + summaryQiweiToken);
// 构建请求体
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("inputs", request.getInputs());
requestBody.put("response_mode", "blocking");
requestBody.put("user", request.getUserId());
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);
log.info("调用Dify工作流API: {}", url);
log.info("请求参数: {}", JSON.toJSONString(requestBody));
ResponseEntity<String> response = restTemplate.exchange(
url,
HttpMethod.POST,
entity,
String.class
);
log.info("Dify工作流响应状态: {}", response.getStatusCode());
log.info("Dify工作流响应内容: {}", response.getBody());
if (response.getStatusCode() == HttpStatus.OK) {
JSONObject responseJson = JSON.parseObject(response.getBody());
return parseWorkflowResponse(responseJson, request);
} else {
throw new RuntimeException("Dify工作流调用失败状态码: " + response.getStatusCode());
}
} catch (Exception e) {
log.error("调用Dify工作流异常", e);
throw new RuntimeException("调用Dify工作流异常: " + e.getMessage(), e);
}
}
/**
* 解析工作流响应并保存数据
*/
private DifyWorkflowResponse parseWorkflowResponse(JSONObject responseJson, DifyWorkflowRequest request) {
DifyWorkflowResponse response = new DifyWorkflowResponse();
if (responseJson.containsKey("data")) {
JSONObject data = responseJson.getJSONObject("data");
response.setWorkflowRunId(data.getString("workflow_run_id"));
response.setTaskId(data.getString("task_id"));
response.setData(data);
// 解析并保存分析结果到数据库
if (data.containsKey("outputs")) {
JSONObject outputs = data.getJSONObject("outputs");
log.info("Dify工作流响应数据 outputs : {}", outputs);
// 保存分析结果到数据库
saveAnalysisResultToDatabase(outputs, request);
}
}
if (responseJson.containsKey("metadata")) {
response.setMetadata(responseJson.getJSONObject("metadata"));
}
return response;
}
/**
* 保存分析结果到数据库
*/
private void saveAnalysisResultToDatabase(JSONObject outputs, DifyWorkflowRequest request) {
try {
DifyWorkflowAnalysis analysis = new DifyWorkflowAnalysis();
// 从outputs中提取数据
if (outputs.containsKey("data")) {
JSONObject analysisData = outputs.getJSONObject("data");
// 提取分析结果摘要
if (analysisData.containsKey("analysisResult")) {
analysis.setAnalysisResult(analysisData.getString("analysisResult"));
}
// 解析详细分析结果
if (analysisData.containsKey("analysisDetail")) {
JSONObject analysisDetail = analysisData.getJSONObject("analysisDetail");
// 解析客户需求
if (analysisDetail.containsKey("customerNeeds")) {
JSONObject customerNeeds = analysisDetail.getJSONObject("customerNeeds");
analysis.setCustomerSource(customerNeeds.getString("customerSource"));
analysis.setCustomerOccupation(customerNeeds.getString("customerOccupation"));
analysis.setCustomerHobbies(customerNeeds.getString("customerHobbies"));
analysis.setHomeAddress(customerNeeds.getString("homeAddress"));
analysis.setCarPurchaseNeed(customerNeeds.getString("carPurchase"));
analysis.setPurchaseType(customerNeeds.getString("purchaseType"));
analysis.setPurchaseBuyer(customerNeeds.getString("purchaseBuyer"));
analysis.setCarUser(customerNeeds.getString("carUser"));
analysis.setIntendedCarModel(customerNeeds.getString("intendedCarModel"));
analysis.setCarQualifications(customerNeeds.getString("carQualifications"));
analysis.setCarBudget(customerNeeds.getString("carBudget"));
analysis.setFinancialInstallment(customerNeeds.getString("financialInstallment"));
analysis.setPurchaseCycle(customerNeeds.getString("purchaseCycle"));
analysis.setFocusPoints(customerNeeds.getString("focus"));
analysis.setConcerns(customerNeeds.getString("concerns"));
analysis.setCarContrast(customerNeeds.getString("carContrast"));
}
// 解析顾问服务
if (analysisDetail.containsKey("customerService")) {
JSONObject customerService = analysisDetail.getJSONObject("customerService");
analysis.setProductDescription(customerService.getString("productDesc"));
analysis.setSolution(customerService.getString("solution"));
analysis.setQuotation(customerService.getString("quotation"));
}
// 解析后续行动和未解决问题
analysis.setAgreedFollowUpActions(analysisDetail.getString("agreedFollowUpActions"));
analysis.setUnresolvedIssues(analysisDetail.getString("unresolvedIssues"));
}
}
// 从outputs中提取其他字段
if (outputs.containsKey("unionId")) {
analysis.setUnionId(outputs.getString("unionId"));
}
if (outputs.containsKey("consultantId")) {
analysis.setConsultantId(outputs.getString("consultantId"));
}
if (outputs.containsKey("communicateDate")) {
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
analysis.setCommunicateDate(LocalDateTime.parse(outputs.getString("communicateDate"), formatter));
} catch (Exception e) {
log.warn("解析沟通时间失败: {}", outputs.getString("communicateDate"), e);
analysis.setCommunicateDate(LocalDateTime.now());
}
}
if (outputs.containsKey("analysisScene")) {
analysis.setAnalysisScene(outputs.getString("analysisScene"));
}
if (outputs.containsKey("analysisRecordId")) {
analysis.setAnalysisRecordId(outputs.getString("analysisRecordId"));
}
if (outputs.containsKey("version")) {
analysis.setVersion(outputs.getInteger("version"));
}
// 从request的inputs中提取原始对话内容
if (request.getInputs() != null && request.getInputs().containsKey("chat")) {
analysis.setOriginalCorpus((String) request.getInputs().get("chat"));
}
// 设置创建时间和更新时间
LocalDateTime now = LocalDateTime.now();
analysis.setCreatedAt(now);
analysis.setUpdatedAt(now);
// 保存到数据库
boolean saveResult = difyWorkflowAnalysisService.save(analysis);
if (saveResult) {
log.info("分析结果保存成功ID: {}", analysis.getId());
} else {
log.error("分析结果保存失败");
}
} catch (Exception e) {
log.error("保存分析结果到数据库失败", e);
}
}
/**
* Dify工作流请求参数
*/
public static class DifyWorkflowRequest {
private Map<String, Object> inputs;
private String userId;
public DifyWorkflowRequest() {}
public DifyWorkflowRequest(Map<String, Object> inputs, String userId) {
this.inputs = inputs;
this.userId = userId;
}
public Map<String, Object> getInputs() {
return inputs;
}
public void setInputs(Map<String, Object> inputs) {
this.inputs = inputs;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
}
/**
* Dify工作流响应结果
*/
public static class DifyWorkflowResponse {
private String workflowRunId;
private String taskId;
private JSONObject data;
private JSONObject metadata;
public String getWorkflowRunId() {
return workflowRunId;
}
public void setWorkflowRunId(String workflowRunId) {
this.workflowRunId = workflowRunId;
}
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public JSONObject getData() {
return data;
}
public void setData(JSONObject data) {
this.data = data;
}
public JSONObject getMetadata() {
return metadata;
}
public void setMetadata(JSONObject metadata) {
this.metadata = metadata;
}
}
}

View File

@@ -0,0 +1,52 @@
package com.rj.service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.Map;
/**
* 文件上传服务接口
*
* @author 李中华 ,spllzh
* @since 2025-08-07
*/
public interface IFileUploadService {
/**
* 上传音频文件
* @param file 音频文件
* @param audioId 录音ID
* @return 上传结果
*/
Map<String, Object> uploadAudioFile(MultipartFile file, String audioId) throws IOException;
/**
* 上传音频文件并更新录音记录
* @param file 音频文件
* @param audioId 录音ID
* @return 上传结果
*/
Map<String, Object> uploadAudioFileAndUpdateRecord(MultipartFile file, String audioId) throws IOException;
/**
* 获取音频文件访问URL
* @param audioId 录音ID
* @return 音频文件访问URL
*/
String getAudioFileUrl(String audioId);
/**
* 删除音频文件
* @param audioId 录音ID
* @return 删除结果
*/
boolean deleteAudioFile(String audioId);
/**
* 检查音频文件是否存在
* @param audioId 录音ID
* @return 是否存在
*/
boolean audioFileExists(String audioId);
}

View File

@@ -0,0 +1,302 @@
package com.rj.service.impl;
import com.rj.entity.AudioManagement;
import com.rj.service.IFileUploadService;
import com.rj.service.IAudioManagementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* 文件上传服务实现类
*
* @author 李中华 ,spllzh
* @since 2025-08-07
*/
@Slf4j
@Service
public class FileUploadServiceImpl implements IFileUploadService {
@Autowired
private IAudioManagementService audioManagementService;
@Value("${app.audio.upload.path:uploads/audio}")
private String uploadPath;
@Value("${app.audio.access.url:/api/audio/}")
private String accessUrl;
@Value("${app.audio.max.size:100MB}")
private String maxFileSize;
// 支持的音频格式
private static final String[] SUPPORTED_AUDIO_FORMATS = {
"mp3", "wav", "m4a", "aac", "ogg", "flac", "wma"
};
@Override
public Map<String, Object> uploadAudioFile(MultipartFile file, String audioId) throws IOException {
Map<String, Object> result = new HashMap<>();
try {
// 验证文件
if (file == null || file.isEmpty()) {
result.put("success", false);
result.put("message", "文件不能为空");
return result;
}
// 验证文件大小
long maxSize = parseFileSize(maxFileSize);
if (file.getSize() > maxSize) {
result.put("success", false);
result.put("message", "文件大小超过限制,最大允许 " + maxFileSize);
return result;
}
// 验证文件格式
String originalFilename = file.getOriginalFilename();
if (!isValidAudioFormat(originalFilename)) {
result.put("success", false);
result.put("message", "不支持的音频格式,支持的格式:" + String.join(", ", SUPPORTED_AUDIO_FORMATS));
return result;
}
// 创建上传目录
Path uploadDir = Paths.get(uploadPath);
if (!Files.exists(uploadDir)) {
Files.createDirectories(uploadDir);
}
// 生成文件名
String fileExtension = getFileExtension(originalFilename);
String fileName = audioId+"_"+UUID.randomUUID() + "." + fileExtension;
Path filePath = uploadDir.resolve(fileName);
// 保存文件
Files.copy(file.getInputStream(), filePath);
// 生成访问URL
String fileUrl = accessUrl + fileName;
result.put("success", true);
result.put("message", "文件上传成功");
result.put("fileName", fileName);
result.put("fileUrl", fileUrl);
result.put("fileSize", file.getSize());
result.put("originalName", originalFilename);
log.info("音频文件上传成功audioId={}, fileName={}, size={}", audioId, fileName, file.getSize());
} catch (Exception e) {
log.error("音频文件上传失败audioId={}, error={}", audioId, e.getMessage(), e);
result.put("success", false);
result.put("message", "文件上传失败:" + e.getMessage());
}
return result;
}
@Override
public Map<String, Object> uploadAudioFileAndUpdateRecord(MultipartFile file, String audioId) throws IOException {
Map<String, Object> result = new HashMap<>();
try {
// 先上传文件
Map<String, Object> uploadResult = uploadAudioFile(file, audioId);
if (!(Boolean) uploadResult.get("success")) {
return uploadResult;
}
// 获取录音记录
AudioManagement audio = audioManagementService.getById(audioId);
if (audio == null) {
result.put("success", false);
result.put("message", "录音记录不存在");
return result;
}
// 更新录音记录的文件信息
String fileName = (String) uploadResult.get("fileName");
String fileUrl = (String) uploadResult.get("fileUrl");
Long fileSize = (Long) uploadResult.get("fileSize");
String originalName = (String) uploadResult.get("originalName");
String fileExtension = getFileExtension(originalName);
audio.setAudioFilePath(uploadPath + "/" + fileName);
audio.setAudioFileUrl(fileUrl);
audio.setAudioFileSize(fileSize);
audio.setAudioFileOriginalName(originalName);
audio.setAudioFileExtension(fileExtension);
audio.setUploadTime(java.time.LocalDateTime.now());
audio.setUpdateTime(java.time.LocalDateTime.now());
// 保存更新
boolean updated = audioManagementService.updateById(audio);
if (updated) {
result.put("success", true);
result.put("message", "音频文件上传成功并更新录音记录");
result.put("data", uploadResult);
result.put("audioRecord", audio);
log.info("音频文件上传并更新录音记录成功audioId={}, fileName={}", audioId, fileName);
} else {
result.put("success", false);
result.put("message", "文件上传成功但更新录音记录失败");
result.put("data", uploadResult);
}
} catch (Exception e) {
log.error("音频文件上传并更新录音记录失败audioId={}, error={}", audioId, e.getMessage(), e);
result.put("success", false);
result.put("message", "文件上传并更新录音记录失败:" + e.getMessage());
}
return result;
}
@Override
public String getAudioFileUrl(String audioId) {
if (StringUtils.isEmpty(audioId)) {
return null;
}
Path uploadDir = Paths.get(uploadPath);
File dir = uploadDir.toFile();
if (!dir.exists() || !dir.isDirectory()) {
return null;
}
// 查找对应的音频文件
File[] files = dir.listFiles((d, name) -> name.startsWith(audioId + "."));
if (files != null && files.length > 0) {
String fileName = files[0].getName();
return accessUrl + fileName;
}
return null;
}
@Override
public boolean deleteAudioFile(String audioId) {
if (StringUtils.isEmpty(audioId)) {
return false;
}
try {
Path uploadDir = Paths.get(uploadPath);
File dir = uploadDir.toFile();
if (!dir.exists() || !dir.isDirectory()) {
return false;
}
// 查找对应的音频文件
File[] files = dir.listFiles((d, name) -> name.startsWith(audioId + "."));
if (files != null && files.length > 0) {
boolean deleted = files[0].delete();
if (deleted) {
log.info("音频文件删除成功audioId={}, fileName={}", audioId, files[0].getName());
}
return deleted;
}
return false;
} catch (Exception e) {
log.error("音频文件删除失败audioId={}, error={}", audioId, e.getMessage(), e);
return false;
}
}
@Override
public boolean audioFileExists(String audioId) {
if (StringUtils.isEmpty(audioId)) {
return false;
}
Path uploadDir = Paths.get(uploadPath);
File dir = uploadDir.toFile();
if (!dir.exists() || !dir.isDirectory()) {
return false;
}
File[] files = dir.listFiles((d, name) -> name.startsWith(audioId + "."));
return files != null && files.length > 0;
}
/**
* 验证音频文件格式
*/
private boolean isValidAudioFormat(String filename) {
if (StringUtils.isEmpty(filename)) {
return false;
}
String extension = getFileExtension(filename).toLowerCase();
for (String format : SUPPORTED_AUDIO_FORMATS) {
if (format.equals(extension)) {
return true;
}
}
return false;
}
/**
* 获取文件扩展名
*/
private String getFileExtension(String filename) {
if (StringUtils.isEmpty(filename)) {
return "";
}
int lastDotIndex = filename.lastIndexOf('.');
if (lastDotIndex > 0 && lastDotIndex < filename.length() - 1) {
return filename.substring(lastDotIndex + 1);
}
return "";
}
/**
* 解析文件大小字符串
*/
private long parseFileSize(String sizeStr) {
if (StringUtils.isEmpty(sizeStr)) {
return 100 * 1024 * 1024; // 默认100MB
}
sizeStr = sizeStr.trim().toUpperCase();
long multiplier = 1;
if (sizeStr.endsWith("KB")) {
multiplier = 1024;
sizeStr = sizeStr.substring(0, sizeStr.length() - 2);
} else if (sizeStr.endsWith("MB")) {
multiplier = 1024 * 1024;
sizeStr = sizeStr.substring(0, sizeStr.length() - 2);
} else if (sizeStr.endsWith("GB")) {
multiplier = 1024 * 1024 * 1024;
sizeStr = sizeStr.substring(0, sizeStr.length() - 2);
}
try {
return Long.parseLong(sizeStr) * multiplier;
} catch (NumberFormatException e) {
return 100 * 1024 * 1024; // 默认100MB
}
}
}