|
|
|
@ -17,8 +17,11 @@ 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;
|
|
|
|
@ -28,12 +31,15 @@ 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;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -136,6 +142,7 @@ public class DeepSeekServiceImpl implements DeepSeekService {
|
|
|
|
|
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());
|
|
|
|
@ -150,13 +157,13 @@ public class DeepSeekServiceImpl implements DeepSeekService {
|
|
|
|
|
question.put("content", chatCompletionReqDto.getText());
|
|
|
|
|
|
|
|
|
|
Map<String, Object> requestMap = new HashMap<>();
|
|
|
|
|
requestMap.put("model", DeepSeekClient.API_Model);
|
|
|
|
|
requestMap.put("model", chatCompletionReqDto.getModel());
|
|
|
|
|
requestMap.put("messages", Collections.singletonList(question));
|
|
|
|
|
requestMap.put("stream", true);
|
|
|
|
|
requestMap.put("max_tokens", 1024);
|
|
|
|
|
|
|
|
|
|
String requestBody = objectMapper.writeValueAsString(requestMap);
|
|
|
|
|
httpPost.setEntity(new StringEntity(requestBody, StandardCharsets.UTF_8));
|
|
|
|
|
StringBuilder responseBody = new StringBuilder();
|
|
|
|
|
try (CloseableHttpResponse response = client.execute(httpPost);
|
|
|
|
|
BufferedReader reader = new BufferedReader(
|
|
|
|
|
new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8))) {
|
|
|
|
@ -167,7 +174,7 @@ public class DeepSeekServiceImpl implements DeepSeekService {
|
|
|
|
|
if ("[DONE]".equals(jsonData)) {
|
|
|
|
|
sseEmitter.send("[DONE]");
|
|
|
|
|
// 会话完成,更新历史会话记录
|
|
|
|
|
ChatSession.Message message = ChatSession.Message.of(chatCompletionReqDto.getText(), strContent.toString(),chatCompletionReqDto.getModel());
|
|
|
|
|
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())
|
|
|
|
@ -181,11 +188,20 @@ public class DeepSeekServiceImpl implements DeepSeekService {
|
|
|
|
|
.path("delta")
|
|
|
|
|
.path("content")
|
|
|
|
|
.asText("");
|
|
|
|
|
//推理过程
|
|
|
|
|
String reasoning_content = node.path("choices")
|
|
|
|
|
.path(0)
|
|
|
|
|
.path("delta")
|
|
|
|
|
.path("reasoning_content")
|
|
|
|
|
.asText("");
|
|
|
|
|
if (!content.isEmpty()) {
|
|
|
|
|
responseBody.append(content);
|
|
|
|
|
strContent.append(content);
|
|
|
|
|
sseEmitter.send(content);
|
|
|
|
|
}
|
|
|
|
|
if (!reasoning_content.isEmpty()) {
|
|
|
|
|
strReasoning.append(reasoning_content);
|
|
|
|
|
sseEmitter.send("reasoning:"+ reasoning_content);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
log.info("流式回答结束,{}",question);
|
|
|
|
@ -204,6 +220,98 @@ public class DeepSeekServiceImpl implements DeepSeekService {
|
|
|
|
|
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<String, Object> question = new HashMap<>();
|
|
|
|
|
question.put("role", "user");
|
|
|
|
|
question.put("content", chatCompletionReqDto.getText());
|
|
|
|
|
|
|
|
|
|
Map<String, Object> 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 辅助方法
|
|
|
|
|
/**
|
|
|
|
|
* 新增/更新会话
|
|
|
|
|