package cn.teammodel.service.impl; import cn.teammodel.ai.cache.HistoryCache; import cn.teammodel.ai.deepseek.DeepSeekClient; import cn.teammodel.common.PK; import cn.teammodel.model.dto.ai.ChatCompletionReqDto; import cn.teammodel.model.dto.ai.deepseek.DeepSeekChatRequestDto; import cn.teammodel.model.dto.ai.deepseek.DeepSeekChatResponse; import cn.teammodel.model.dto.ai.deepseek.ChatReqDto; import cn.teammodel.model.entity.ai.ChatSession; import cn.teammodel.model.entity.ai.DeepSeekSession; import cn.teammodel.model.entity.ai.DeepSeekSession.DeepSeekMessage; import cn.teammodel.repository.ChatSessionRepository; import cn.teammodel.repository.DeepSeekRepository; import cn.teammodel.security.utils.SecurityUtil; import cn.teammodel.service.DeepSeekService; import cn.teammodel.service.DeepSeekSessionService; import cn.teammodel.utils.RepositoryUtil; import com.azure.cosmos.models.CosmosPatchOperations; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import lombok.extern.slf4j.Slf4j; import okhttp3.*; import okio.BufferedSource; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.springframework.stereotype.Service; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import javax.annotation.Resource; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import com.fasterxml.jackson.databind.ObjectMapper; /** * 描述:访问DeepSeek方法 */ @Service @Slf4j public class DeepSeekServiceImpl implements DeepSeekService { @Resource private DeepSeekSessionService deepSeekService; @Resource private DeepSeekRepository deepSeekRepository; @Resource private ChatSessionRepository chatSessionRepository; private final ExecutorService executorService = Executors.newCachedThreadPool(); private final ObjectMapper objectMapper = new ObjectMapper(); /** * 提问 * @param message * @return */ @Override public DeepSeekChatResponse ChatAsk(ChatReqDto message) { //创建消息列表 List msg = new ArrayList<>(); msg.add(message); //构建请求头 DeepSeekChatRequestDto requestBody = new DeepSeekChatRequestDto(); requestBody.setModel(DeepSeekClient.API_Model); requestBody.setMessages(msg); requestBody.setTemperature(0); requestBody.setMax_tokens(1024); //开始时间 long startTime = System.currentTimeMillis(); //发起请求 DeepSeekChatResponse response = DeepSeekClient.SendRequests(requestBody); //Map response = DeepSeekClient.SendRequests(requestBody); //Map response = SendRequest(requestBody); //结束时间 long endTime = System.currentTimeMillis(); //思考耗时 秒 response.setWasteTime((endTime-startTime)/1000); if (response.getCode() == 200){ DeepSeekMessage savaMessage = new DeepSeekMessage(); savaMessage.setId(response.getId()); savaMessage.setUserText(message.getContent()); savaMessage.setAiText(response.getChoices().get(0).getMessage().getContent()); savaMessage.setRole(response.getChoices().get(0).getMessage().getRole()); savaMessage.setCreateTime(response.getCreated()); savaMessage.setFinish_reason(response.getChoices().get(0).getFinish_reason()); DeepSeekSession session = new DeepSeekSession(); if (message.getSessionId() != null){ session = deepSeekRepository.findSessionByIdAndCode(message.getSessionId(), PK.CHAT_SESSION); UpdateSession(message, session, savaMessage, response); }else { UpdateSession(message, session, savaMessage, response); } } return response; } @Override public SseEmitter OKHttpChatSeeEmitterAsk(ChatReqDto message) { SseEmitter se = new SseEmitter(-1L); //创建消息列表 List msg = new ArrayList<>(); msg.add(message); //构建请求头 DeepSeekChatRequestDto requestBody = new DeepSeekChatRequestDto(); requestBody.setModel(DeepSeekClient.API_Model); requestBody.setMessages(msg); requestBody.setTemperature(0); requestBody.setMax_tokens(1024); requestBody.setStream(true); if (requestBody.getStream()){ se = DeepSeekClient.SendRequestsEmitter(requestBody); }else { DeepSeekChatResponse response = DeepSeekClient.SendRequests(requestBody); } return se; } /** * 提问 流式回答 * @param chatCompletionReqDto * @return */ @Override public SseEmitter ChatSeeEmitterAsk(ChatCompletionReqDto chatCompletionReqDto) { SseEmitter sseEmitter = new SseEmitter(-1L); StringBuilder strContent = new StringBuilder(); StringBuilder strReasoning = new StringBuilder(); //executorService.execute(()-> { try { log.info("流式回答开始,问题:{}", chatCompletionReqDto.getText()); try (CloseableHttpClient client = HttpClients.createDefault()) { HttpPost httpPost = new HttpPost(DeepSeekClient.API_Url); httpPost.setHeader("Content-Type", "application/json"); httpPost.setHeader("Accept", "application/json"); httpPost.setHeader("Authorization", "Bearer " + DeepSeekClient.API_Key); List> messages = new ArrayList<>(); //助手的角色 Map systemMessage = new HashMap<>(); systemMessage.put("role", "system"); systemMessage.put("content", "你是一个教师助手"); messages.add(systemMessage); //用户的消息 Map userMessage = new HashMap<>(); userMessage.put("role", "user"); userMessage.put("content", chatCompletionReqDto.getText()); messages.add(userMessage); //向DeepSeek发送请求 Map requestMap = new HashMap<>(); requestMap.put("model", chatCompletionReqDto.getModel()); requestMap.put("messages", messages); requestMap.put("stream", true); requestMap.put("max_tokens", 1024); String requestBody = objectMapper.writeValueAsString(requestMap); httpPost.setEntity(new StringEntity(requestBody, StandardCharsets.UTF_8)); try (CloseableHttpResponse response = client.execute(httpPost); BufferedReader reader = new BufferedReader( new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8))) { String line; while ((line = reader.readLine()) != null) { if (line.startsWith("data: ")) { String jsonData = line.substring(6); if ("[DONE]".equals(jsonData)) { sseEmitter.send("[DONE]"); //断开连接 sseEmitter.complete(); // 会话完成,更新历史会话记录 if (chatCompletionReqDto.isSave()){ ChatSession.Message message = ChatSession.Message.of(chatCompletionReqDto.getText(), strContent.toString(),chatCompletionReqDto.getModel(),strReasoning.toString()); HistoryCache.updateContext(chatCompletionReqDto.getSessionId(), message); CosmosPatchOperations options = CosmosPatchOperations.create() .replace("/updateTime", Instant.now().toEpochMilli()) .add("/history/-", message); chatSessionRepository.save(chatCompletionReqDto.getSessionId(), PK.of(PK.CHAT_SESSION), ChatSession.class, options); } break; } JsonNode node = objectMapper.readTree(jsonData); String content = node.path("choices") .path(0) .path("delta") .path("content") .asText(""); //推理过程 String reasoning_content = node.path("choices") .path(0) .path("delta") .path("reasoning_content") .asText(""); if (!content.isEmpty()) { strContent.append(content); sseEmitter.send(content); } if (!reasoning_content.isEmpty()) { strReasoning.append(reasoning_content); sseEmitter.send("reasoning:"+ reasoning_content); } } } log.info("流式回答结束,{}",messages); //sseEmitter.complete(); } } catch (Exception e) { log.error("处理 Deepseek 请求时发生错误", e); sseEmitter.completeWithError(e); } } catch (Exception e) { log.error("处理 Deepseek 请求时发生错误", e); sseEmitter.completeWithError(e); } //}); return sseEmitter; } /** * 深度思考 * @param chatCompletionReqDto * @return */ @Override public SseEmitter ReasonerChatCompletion(ChatCompletionReqDto chatCompletionReqDto) { SseEmitter sseEmitter = new SseEmitter(-1L); OkHttpClient client = new OkHttpClient.Builder() .readTimeout(30, TimeUnit.SECONDS) .build(); MediaType JSON = MediaType.parse("application/json; charset=utf-8"); // 构建请求体 // String requestBody = "{" // + "\"model\": \"deepseek-chat\"," // + "\"messages\": [{\"role\": \"user\", \"content\": \"请介绍一下成都\"}]," // + "\"stream\": true," // + "\"temperature\": 0.7" // + "}"; Map question = new HashMap<>(); question.put("role", "user"); question.put("content", chatCompletionReqDto.getText()); Map requestMap = new HashMap<>(); requestMap.put("model", chatCompletionReqDto.getModel()); requestMap.put("messages", Collections.singletonList(question)); requestMap.put("stream", true); String requestBody = null; try { requestBody = objectMapper.writeValueAsString(requestMap); } catch (JsonProcessingException e) { log.error("处理用户转换问题出错", e); sseEmitter.completeWithError(e); } Request request = new Request.Builder() .url(DeepSeekClient.API_Url) .post(RequestBody.create(JSON, requestBody)) .addHeader("Authorization", "Bearer " + DeepSeekClient.API_Key) .addHeader("Accept", "text/event-stream") .build(); try(Response response = client.newCall(request).execute()){ if (response.isSuccessful() && response.body() != null) { try (ResponseBody body = response.body()) { if (body != null) { BufferedSource source = body.source(); while (!source.exhausted()) { String line = source.readUtf8Line(); if (line != null && line.startsWith("data: ")) { String json = line.substring(6).trim(); if (json.equals("[DONE]")) { sseEmitter.send("[DONE]"); break; } JsonNode node = objectMapper.readTree(json); String content = node.path("choices") .path(0) .path("delta") .path("content") .asText(""); String reasoning_content = node.path("choices") .path(0) .path("delta") .path("reasoning_content") .asText(""); if (!content.isEmpty()) { sseEmitter.send(content); } if (!reasoning_content.isEmpty()) { sseEmitter.send("reasoning:"+reasoning_content); } } } log.info("流式回答结束,{}",requestBody); sseEmitter.complete(); } } catch (IOException e) { log.error("处理 Deepseek 请求时发生错误", e); sseEmitter.completeWithError(e); } } }catch (IOException e) { log.error("处理 Deepseek 请求时发生错误", e); sseEmitter.completeWithError(e); } return sseEmitter; } //region 辅助方法 /** * 新增/更新会话 * @param message * @param session * @param savaMessage * @param response */ private void UpdateSession(ChatReqDto message, DeepSeekSession session, DeepSeekMessage savaMessage, DeepSeekChatResponse response) { if (session.getId() == null){ List history = Collections.singletonList(savaMessage); String userId = SecurityUtil.getLoginUser().getId(); session.setId(UUID.randomUUID().toString()); session.setCode(PK.DEEPSEEK_SESSION); session.setTitle("新对话"); session.setUserId(userId); session.setModel(response.getModel()); session.setCreateTime(Instant.now().toEpochMilli()); session.setUpdateTime(Instant.now().toEpochMilli()); session.setHistory(history); session = deepSeekRepository.save(session); }else { session.getHistory().add(savaMessage); deepSeekService.updateSession(session, message.getSessionId()); } } //endregion }