package api.service.dify.impl; import api.entity.database.dify.DifyAssistant; import api.entity.input.PageInput; import api.entity.input.dify.*; import api.entity.view.system.UserView; import api.mapper.dify.DifyAssistantMapper; import api.service.dify.IDifyAssistantService; import api.service.BaseServiceImpl; import api.util.helper.HttpHelper; import api.util.helper.StringHelper; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import lombok.var; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Objects; @Transactional @Service public class DifyAssistantServiceImpl extends BaseServiceImpl implements IDifyAssistantService{ public DifyAssistantServiceImpl(){ super(false); } private final Gson gson = new Gson(); //发送对话消息 @Override public SseEmitter chatMessages(DifyChatMessagesInput difyInput, UserView userView, HttpServletResponse response) throws IOException { SseEmitter sseEmitter = new SseEmitter(); // 设置MIME类型为text/event-stream以符合SSE要求 response.setContentType("text/event-stream"); response.setCharacterEncoding("UTF-8"); PrintWriter writer = response.getWriter(); try { var dify=this .getEntity(difyInput.getId()); // 1. 设置URL和API密钥 String apiUrl = dify.getUrl()+"/chat-messages"; String apiKey = dify.getSecretKey(); // 替换为实际API密钥 String files="[]"; if (difyInput.getFiles()!=null&&difyInput.getFiles().size()>0) { StringBuilder builder=new StringBuilder(); builder.append("["); for (DifyFiles item :difyInput.getFiles()) { builder.append("{"); builder.append("\"type\": \"").append(item.getType()).append("\","); builder.append("\"transfer_method\": \"").append(item.getTransfer_method()).append("\","); if(Objects.equals(item.getTransfer_method(), "remote_url")) { builder.append("\"url\": \"").append(item.getUrl()).append("\""); } else { builder.append("\"upload_file_id\": \"").append(item.getUrl()).append("\""); } builder.append("}"); } builder.append("]"); files=builder.toString(); } String jsonString=""; if (difyInput.getInputs()!=null) { ObjectMapper objectMapper = new ObjectMapper(); jsonString= objectMapper.writeValueAsString(difyInput.getInputs()); } // 2. 创建JSON请求体 String jsonBody = "{" + "\"inputs\": "+jsonString+"," + "\"query\": \""+difyInput.getQuery()+"\"," + "\"response_mode\": \"streaming\"," + "\"conversation_id\": \""+difyInput.getConversation_id()+"\"," + "\"user\": \""+userView.getUserName()+"\"," + "\"files\": \""+files+"\"," + "\"auto_generate_name\": \""+difyInput.getAuto_generate_name()+"\"" + "}"; // 3. 创建HTTP连接 URL url = new URL(apiUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setRequestProperty("Authorization", "Bearer " + apiKey); conn.setRequestProperty("Content-Type", "application/json"); conn.setDoOutput(true); // 4. 发送请求体 try (OutputStream os = conn.getOutputStream()) { byte[] input = jsonBody.getBytes(StandardCharsets.UTF_8); os.write(input, 0, input.length); } // 获取响应码 int responseCode = conn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { // 获取响应输入流 InputStream inputStream = conn.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); String line; try { while ((line = reader.readLine()) != null) { if (line.startsWith("data: {\"event\": \"message\"") ||line.startsWith("data: {\"event\": \"message_end\"")) { writer.write(unicodeToString(line)+"\n"); // sseEmitter.send(unicodeToString(line)); // 实时发送单条结果 System.out.println(unicodeToString(line)); writer.flush(); } } } catch (IOException e) { e.printStackTrace(); } } else { System.out.println("POST Request is not successful"); } conn.disconnect(); } catch (Exception e) { e.printStackTrace(); } sseEmitter.complete(); return sseEmitter; } //发送工作流 @Override public SseEmitter workflows(WorkflowsInput difyInput, UserView userView, HttpServletResponse response) throws IOException { SseEmitter sseEmitter = new SseEmitter(); // 设置MIME类型为text/event-stream以符合SSE要求 response.setContentType("text/event-stream"); response.setCharacterEncoding("UTF-8"); PrintWriter writer = response.getWriter(); try { var dify=this .getEntity(difyInput.getId()); // 1. 设置URL和API密钥 String apiUrl = dify.getUrl()+"/workflows/run"; String apiKey = dify.getSecretKey(); // 替换为实际API密钥 String jsonString=""; if (difyInput.getInputs()!=null) { ObjectMapper objectMapper = new ObjectMapper(); jsonString= objectMapper.writeValueAsString(difyInput.getInputs()); } // 2. 创建JSON请求体 String jsonBody = "{" + "\"inputs\": "+jsonString+"," + "\"response_mode\": \"streaming\"," + "\"user\": \""+userView.getUserName()+"\"" + "}"; // 3. 创建HTTP连接 URL url = new URL(apiUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setRequestProperty("Authorization", "Bearer " + apiKey); conn.setRequestProperty("Content-Type", "application/json"); conn.setDoOutput(true); // 4. 发送请求体 try (OutputStream os = conn.getOutputStream()) { byte[] input = jsonBody.getBytes(StandardCharsets.UTF_8); os.write(input, 0, input.length); } // 获取响应码 int responseCode = conn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { // 获取响应输入流 InputStream inputStream = conn.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); String line; try { while ((line = reader.readLine()) != null) { writer.write(unicodeToString(line)+"\n"); // sseEmitter.send(unicodeToString(line)); // 实时发送单条结果 System.out.println(unicodeToString(line)); writer.flush(); } } catch (IOException e) { e.printStackTrace(); } } else { System.out.println("POST Request is not successful"); } conn.disconnect(); } catch (Exception e) { e.printStackTrace(); } sseEmitter.complete(); return sseEmitter; } private static String unicodeToString(String unicode) { StringBuilder sb = new StringBuilder(); int i = -1; int pos = 0; while ((i = unicode.indexOf("\\u", pos)) != -1) { sb.append(unicode.substring(pos, i)); if (i + 5 > unicode.length()) { pos = i + 2; continue; } String hex = unicode.substring(i + 2, i + 6); try { sb.append((char) Integer.parseInt(hex, 16)); pos = i + 6; } catch (NumberFormatException e) { sb.append(unicode.substring(i, i + 2)); pos = i + 2; } } sb.append(unicode.substring(pos)); return sb.toString(); } //消息反馈 @Override public String feedbacks(DifyFeedbacksInput input, UserView userView) throws IOException { var dify=this .getEntity(input.getId()); String apiUrl = dify.getUrl()+"/messages/"+input.getMessage_id()+"/feedbacks"; String apiKey = dify.getSecretKey(); // 替换为实际API密钥 // 2. 创建JSON请求体 String jsonBody = "{\n" + " \"rating\": \""+input.getRating()+"\",\n" + " \"user\": \""+userView.getUserName()+"\",\n" + " \"content\": \""+input.getContent()+"\"\n" + "}"; return HttpHelper.DifyHttpPost(apiUrl,apiKey,jsonBody); } //获取APP的消息点赞和反馈 @Override public String appFeedbacks(PageInput pageInput,long id ) throws Exception { var dify=this .getEntity(id); String apiUrl = dify.getUrl()+"/app/feedbacks?page="+pageInput.getPageNum()+"&limit="+pageInput.getPageSize(); return HttpHelper.DifyHttpGet(apiUrl,dify.getSecretKey()); } @Override public String suggested(long id, String message_id, UserView userView) throws Exception { var dify=this .getEntity(id); String apiUrl = dify.getUrl()+"/messages/"+message_id+"/suggested?user="+userView.getUserName(); return HttpHelper.DifyHttpGet(apiUrl,dify.getSecretKey()); } //获取会话历史消息 @Override public String History(DifyHistoryInput input, UserView userView) throws Exception { var dify=this .getEntity(input.getId()); StringBuilder builder=new StringBuilder(); if (StringHelper.isNotEmpty(input.getFirst_id())) { builder.append("&first_id").append(input.getFirst_id()); } if (input.getLimit()!=null&&input.getLimit()>0) { builder.append("&limit").append(input.getLimit()); } String url=builder.toString(); String apiUrl = dify.getUrl()+"/messages?user="+userView.getUserName()+"&conversation_id="+input.getConversation_id()+url; return HttpHelper.DifyHttpGet(apiUrl,dify.getSecretKey()); } @Override public String conversations(DifyConversationsInput input, UserView userView) throws Exception { var dify=this .getEntity(input.getId()); StringBuilder builder=new StringBuilder(); if (StringHelper.isNotEmpty(input.getLast_id())) { builder.append("&last_id").append(input.getLast_id()); } if (input.getLimit()!=null&&input.getLimit()>0) { builder.append("&limit").append(input.getLimit()); } if (StringHelper.isNotEmpty(input.getSort_by())) { builder.append("&sort_by").append(input.getSort_by()); } String url=builder.toString(); String apiUrl = dify.getUrl()+"/conversations?user="+userView.getUserName()+ url; return HttpHelper.DifyHttpGet(apiUrl,dify.getSecretKey()); } //删除会话 @Override public Boolean DelConversations(long id, String conversation_id, UserView userView) throws Exception { var dify=this .getEntity(id); String apiUrl = dify.getUrl()+"/conversations/"+conversation_id; String requestBody = String.format("{ \"user\": \"%s\" }", userView.getUserName()); return HttpHelper.DifyHttpDelete(apiUrl,dify.getSecretKey(),requestBody); } //会话重命名 @Override public String Rename(DifyRenameInput input, UserView userView) throws Exception { var dify=this .getEntity(input.getId()); String apiUrl = dify.getUrl()+"/conversations/"+input.getConversation_id()+"/name"; String apiKey = dify.getSecretKey(); // 替换为实际API密钥 // 2. 创建JSON请求体 String jsonBody = "{\n" + " \"name\": \""+input.getName()+"\",\n" + " \"auto_generate\": \""+input.getAuto_generate()+"\",\n" + " \"user\": \""+userView.getUserName()+"\"\n" + "}"; return HttpHelper.DifyHttpPost(apiUrl,apiKey,jsonBody); } }