From 096710b3a65f24bd6bf43a2d0c6a239fa31c4937 Mon Sep 17 00:00:00 2001
From: PL <774412461@qq.com>
Date: Fri, 14 Mar 2025 10:09:20 +0800
Subject: [PATCH] =?UTF-8?q?up:DeepSeek=E5=AF=B9=E8=AF=9D=E7=9B=B8=E5=85=B3?=
=?UTF-8?q?=E6=8E=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 7 +-
.../teammodel/ai/deepseek/DeepSeekClient.java | 178 ++++++++++++++++++
src/main/java/cn/teammodel/common/PK.java | 4 +
.../controller/frontend/AiController.java | 5 +-
.../frontend/AiDeepSeekController.java | 129 +++++++++++++
.../model/dto/ai/deepseek/ChatRequestDto.java | 44 +++++
.../dto/ai/deepseek/ChatResponseDto.java | 47 +++++
.../model/dto/ai/deepseek/MessageDto.java | 14 ++
.../model/entity/ai/DeepSeekSession.java | 103 ++++++++++
.../repository/DeepSeekRepository.java | 58 ++++++
.../cn/teammodel/service/DeepSeekService.java | 20 ++
.../service/DeepSeekSessionService.java | 60 ++++++
.../service/impl/DeepSeekServiceImpl.java | 110 +++++++++++
.../impl/DeepSeekSessionServiceImpl.java | 133 +++++++++++++
src/main/resources/DeepSeekConfig.properties | 3 +
15 files changed, 913 insertions(+), 2 deletions(-)
create mode 100644 src/main/java/cn/teammodel/ai/deepseek/DeepSeekClient.java
create mode 100644 src/main/java/cn/teammodel/controller/frontend/AiDeepSeekController.java
create mode 100644 src/main/java/cn/teammodel/model/dto/ai/deepseek/ChatRequestDto.java
create mode 100644 src/main/java/cn/teammodel/model/dto/ai/deepseek/ChatResponseDto.java
create mode 100644 src/main/java/cn/teammodel/model/dto/ai/deepseek/MessageDto.java
create mode 100644 src/main/java/cn/teammodel/model/entity/ai/DeepSeekSession.java
create mode 100644 src/main/java/cn/teammodel/repository/DeepSeekRepository.java
create mode 100644 src/main/java/cn/teammodel/service/DeepSeekService.java
create mode 100644 src/main/java/cn/teammodel/service/DeepSeekSessionService.java
create mode 100644 src/main/java/cn/teammodel/service/impl/DeepSeekServiceImpl.java
create mode 100644 src/main/java/cn/teammodel/service/impl/DeepSeekSessionServiceImpl.java
create mode 100644 src/main/resources/DeepSeekConfig.properties
diff --git a/pom.xml b/pom.xml
index 479a22c..ae5f819 100644
--- a/pom.xml
+++ b/pom.xml
@@ -46,7 +46,12 @@
org.springframework.boot
spring-boot-configuration-processor
-
+
+
+ com.google.code.gson
+ gson
+ 2.8.9
+
com.itextpdf
diff --git a/src/main/java/cn/teammodel/ai/deepseek/DeepSeekClient.java b/src/main/java/cn/teammodel/ai/deepseek/DeepSeekClient.java
new file mode 100644
index 0000000..1a3edd5
--- /dev/null
+++ b/src/main/java/cn/teammodel/ai/deepseek/DeepSeekClient.java
@@ -0,0 +1,178 @@
+package cn.teammodel.ai.deepseek;
+
+import cn.teammodel.common.ErrorCode;
+import cn.teammodel.config.exception.ServiceException;
+import cn.teammodel.model.dto.ai.deepseek.ChatRequestDto;
+import cn.teammodel.model.dto.ai.deepseek.ChatResponseDto;
+import cn.teammodel.model.dto.ai.deepseek.MessageDto;
+import cn.teammodel.utils.JsonUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+import com.google.gson.Gson;
+import okhttp3.*;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import java.util.HashMap;
+import java.util.Map;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+
+public class DeepSeekClient {
+ private static final String API_Key;
+ private static final String API_Url;
+ public static String API_Model;
+ /**
+ * 读取配置文件 读取key 和url
+ */
+ static {
+ Properties props = new Properties();
+ try {
+ InputStream is = DeepSeekClient.class.getResourceAsStream("/DeepSeekConfig.properties");
+ props.load(is);
+ API_Key = props.getProperty("key");
+ API_Url = props.getProperty("url");
+ API_Model = props.getProperty("model");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * 提问题 测试使用
+ * @param mssage
+ */
+ private static Map ask(MessageDto mssage)
+ {
+ Map mapper = new HashMap<>();
+ //创建消息列表
+ List msg = new ArrayList<>();
+ msg.add(mssage);
+
+ //构建请求头
+ ChatRequestDto requestBody = new ChatRequestDto();
+ requestBody.setModel(API_Model);
+ requestBody.setMessages(msg);
+ requestBody.setTemperature(0);
+ requestBody.setMax_tokens(1024);
+
+ long startTime = System.currentTimeMillis();
+ //发起请求
+ ChatResponseDto response = SendRequests(requestBody);
+ //Map response = SendRequest(requestBody);
+ Long endTime = System.currentTimeMillis();
+ //思考耗时 秒
+ long time = (endTime-startTime)/1000;
+ response.setWasteTime(time);
+ return mapper;
+
+ }
+
+ /***
+ * OkHttpClient 方式请求
+ * 返回请求结果 转 实体有问题
+ * @param requestBody
+ * @return
+ */
+ public static ChatResponseDto SendRequests(ChatRequestDto requestBody)
+ {
+ ChatResponseDto chatResponse = new ChatResponseDto();
+ OkHttpClient client = new OkHttpClient().newBuilder().build();
+ MediaType mediaType = MediaType.parse("application/json");
+ //String content = "{\n \"messages\": [\n {\n \"content\": \"You are a helpful assistant\",\n \"role\": \"system\"\n },\n {\n \"content\": \"Hi\",\n \"role\": \"user\"\n }\n ],\n \"model\": \"deepseek-chat\",\n \"frequency_penalty\": 0,\n \"max_tokens\": 2048,\n \"presence_penalty\": 0,\n \"response_format\": {\n \"type\": \"text\"\n },\n \"stop\": null,\n \"stream\": false,\n \"stream_options\": null,\n \"temperature\": 1,\n \"top_p\": 1,\n \"tools\": null,\n \"tool_choice\": \"none\",\n \"logprobs\": false,\n \"top_logprobs\": null\n}";
+ String content = JsonUtil.convertToJson(requestBody);
+
+ RequestBody body = RequestBody.create(mediaType, content);
+ Request request = new Request.Builder()
+ .url(API_Url)
+ .method("POST", body)
+ .addHeader("Content-Type", "application/json")
+ .addHeader("Accept", "application/json")
+ .addHeader("Authorization", "Bearer "+API_Key)
+ .build();
+
+ try(Response response = client.newCall(request).execute()) {
+ if (response.isSuccessful() && response.body() != null) {
+ String responseBody = response.body().string();
+ // 使用 Gson 将 JSON 字符串转换为 MyEntity 对象
+ Gson gson = new Gson();
+ chatResponse = gson.fromJson(responseBody, ChatResponseDto.class);
+ // 确保关闭响应体以释放资源
+ response.body().close();
+ chatResponse.setCode(200);
+ chatResponse.setMsg("成功");
+ } else {
+ chatResponse.setCode( response.code());
+ chatResponse.setMsg(response.body().string());
+ }
+ } catch (IOException e) {
+ if (e.getMessage().equals("Connection timed out") || e.getMessage().equals("timeout"))
+ {
+ chatResponse.setCode(408);
+ chatResponse.setMsg("请求DeepSeek服务器超时");
+ }else {
+ chatResponse.setCode( 500);
+ chatResponse.setMsg(e.getMessage());
+ }
+ }
+ return chatResponse;
+ }
+
+ /***
+ * HttpClient 方式请求
+ * @param requestBody
+ * @return
+ */
+ public static Map SendRequest(ChatRequestDto requestBody) {
+ Map mapper = new HashMap<>();
+ try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+ // 创建HttpPost对象
+ HttpPost httpPost = new HttpPost(API_Url);
+ //添加请求头
+ httpPost.setHeader("Content-Type", "application/json");
+ httpPost.setHeader("Accept", "application/json");
+ httpPost.setHeader("Authorization", "Bearer " +API_Key);
+
+ // 设置请求体
+ String jsonContent = JsonUtil.convertToJson(requestBody);
+ httpPost.setEntity(new StringEntity(jsonContent, ContentType.create("application/json", "UTF-8")));
+
+ // 发送请求
+ try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
+ // 获取响应实体
+ HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ // 解析响应内容
+ String jsonString = EntityUtils.toString(entity);
+ ObjectMapper objectMapper = new ObjectMapper();
+ mapper = objectMapper.readValue(jsonString, TypeFactory.defaultInstance().constructMapType(Map.class, String.class, Object.class));
+ }
+
+ // 检查响应状态码
+ int statusCode = response.getStatusLine().getStatusCode();
+ if (statusCode != 200) throw new RuntimeException("Failed : HTTP error code : " + statusCode);
+ } catch (IOException e) {
+ throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据解析异常");
+ }
+
+ } catch (IOException e) {
+ throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "请求头异常"+e.getMessage());
+ }
+ //TODO 请求接口
+ return mapper;
+ }
+
+
+
+
+}
diff --git a/src/main/java/cn/teammodel/common/PK.java b/src/main/java/cn/teammodel/common/PK.java
index 246227a..9e48736 100644
--- a/src/main/java/cn/teammodel/common/PK.java
+++ b/src/main/java/cn/teammodel/common/PK.java
@@ -25,6 +25,10 @@ public interface PK {
String STUDENT = "Base-%s";
String CLASS = "Class-%s";
String CHAT_SESSION = "ChatSession";
+ /**
+ * DeepSeek问答会话
+ */
+ String DEEPSEEK_SESSION ="DeepSeekSession";
String WEEK_DUTY = "Duty";
String WEEK_DUTY_RECORD = "DutyRecord-%s";
String CHAT_APP = "ChatApp";
diff --git a/src/main/java/cn/teammodel/controller/frontend/AiController.java b/src/main/java/cn/teammodel/controller/frontend/AiController.java
index 84162b4..4306e79 100644
--- a/src/main/java/cn/teammodel/controller/frontend/AiController.java
+++ b/src/main/java/cn/teammodel/controller/frontend/AiController.java
@@ -26,7 +26,7 @@ import java.util.concurrent.CompletableFuture;
@RestController
@RequestMapping("/ai")
-@Api(tags = "AI 能力")
+@Api(tags = "AI 科大讯飞 能力")
public class AiController {
@Resource
private ChatSessionService chatSessionService;
@@ -35,6 +35,7 @@ public class AiController {
@Resource
private ChatAppService chatAppService;
+
@PostMapping("api/chat/completion")
@ApiOperation("与 spark 的流式对话")
public SseEmitter chatCompletionToApi(@RequestBody @Valid ChatCompletionReqDto chatCompletionReqDto) {
@@ -183,4 +184,6 @@ public class AiController {
return chatMessageService.chatTeacherComment(chatTeacherCommentDto,userId, userName);
}
+
+
}
\ No newline at end of file
diff --git a/src/main/java/cn/teammodel/controller/frontend/AiDeepSeekController.java b/src/main/java/cn/teammodel/controller/frontend/AiDeepSeekController.java
new file mode 100644
index 0000000..a966b38
--- /dev/null
+++ b/src/main/java/cn/teammodel/controller/frontend/AiDeepSeekController.java
@@ -0,0 +1,129 @@
+package cn.teammodel.controller.frontend;
+
+import cn.teammodel.common.IdRequest;
+import cn.teammodel.model.dto.ai.UpdateSessionDto;
+import cn.teammodel.model.dto.ai.deepseek.ChatResponseDto;
+import cn.teammodel.model.dto.ai.deepseek.MessageDto;
+import cn.teammodel.model.entity.TmdUserDetail;
+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.common.R;
+import cn.teammodel.service.DeepSeekSessionService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.*;
+
+@RestController
+@RequestMapping("/aiDeepSeek")
+@Api(tags = "AI DeepSeek 能力")
+public class AiDeepSeekController {
+
+ /**
+ * 访问DeepSeek方法
+ */
+ @Resource
+ private DeepSeekService deepSeekChatService;
+
+ /**
+ * 会话管理
+ */
+ @Resource
+ private DeepSeekSessionService deepSeekSessionService;
+
+ /**
+ * 创建默认会话
+ * @return
+ */
+ @PostMapping("session/create/default")
+ @ApiOperation("创建默认会话")
+ public R CreateDefaultSession(){
+ String userId = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().getSubject();
+ String name = (String) ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().get("name");
+ DeepSeekSession session = deepSeekSessionService.CreateDefaultSession(userId,name);
+ return R.success(session);
+ }
+
+ /**
+ * 创建会话 按照结构传输
+ * @param createSession
+ * @return
+ */
+ @PostMapping("session/create")
+ @ApiOperation("创建会话(实体)")
+ public R CreateDefaultSession(@RequestBody @Valid DeepSeekSession createSession){
+ DeepSeekSession session = deepSeekSessionService.CreateSession(createSession);
+ return R.success(session);
+ }
+
+ /**
+ * 删除会话
+ * @param idRequest
+ * @return
+ */
+ @PostMapping("session/del")
+ @ApiOperation("删除会话")
+ public R removeSession(@RequestBody @Valid IdRequest idRequest) {
+ String userId = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().getSubject();
+ deepSeekSessionService.deleteSession(idRequest.getId(), userId);
+ return R.success("删除会话成功");
+ }
+
+ /**
+ * 更新会话
+ * @param upSession
+ * @return
+ */
+ @PostMapping("session/update")
+ @ApiOperation("更新聊天会话")
+ public R updateSession(@RequestBody @Valid DeepSeekSession upSession) {
+ String userId = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().getSubject();
+ DeepSeekSession session = deepSeekSessionService.updateSession(upSession, userId);
+ return R.success(session);
+ }
+
+ /**
+ * 查询我的会话
+ * @return
+ */
+ @PostMapping("session/userid")
+ @ApiOperation("查询自己的会话列表")
+ public R> UserId(){
+ String userId = SecurityUtil.getLoginUser().getId();
+ List sessions = deepSeekSessionService.UserSessionList(userId);
+ return R.success(sessions);
+ }
+
+ /**
+ * 查询某个会话的聊天记录
+ * @param sessionId
+ * @return
+ */
+ @GetMapping("session/history/{sessionId}")
+ @ApiOperation("查询我的聊天记录")
+ public R> getHistory(@PathVariable String sessionId) {
+ String userId = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().getSubject();
+ List history = deepSeekSessionService.listHistory(sessionId, userId);
+ return R.success(history);
+ }
+
+ /**
+ *与deepseek的对话
+ * @param messageDto
+ * @return
+ */
+ @PostMapping("chat")
+ @ApiOperation("与deepseek的对话")
+ public R ChatCompletion(@RequestBody @Valid MessageDto messageDto) {
+ ChatResponseDto chatResponse = deepSeekChatService.ChatAsk(messageDto);
+ return R.success(chatResponse);
+ }
+}
diff --git a/src/main/java/cn/teammodel/model/dto/ai/deepseek/ChatRequestDto.java b/src/main/java/cn/teammodel/model/dto/ai/deepseek/ChatRequestDto.java
new file mode 100644
index 0000000..308c721
--- /dev/null
+++ b/src/main/java/cn/teammodel/model/dto/ai/deepseek/ChatRequestDto.java
@@ -0,0 +1,44 @@
+package cn.teammodel.model.dto.ai.deepseek;
+
+import lombok.Data;
+
+import java.util.List;
+
+/***
+ * 请求体的数据内部结构,用于构建请求 json
+ * {
+ * "messages": [
+ * {
+ * "content": "You are a helpful assistant",
+ * "role": "system"
+ * },
+ * {
+ * "content": "Hi",
+ * "role": "user"
+ * }
+ * ],
+ * "model": "deepseek-chat",
+ * "frequency_penalty": 0,
+ * "max_tokens": 2048,
+ * "presence_penalty": 0,
+ * "response_format": {
+ * "type": "text"
+ * },
+ * "stop": null,
+ * "stream": false,
+ * "stream_options": null,
+ * "temperature": 1,
+ * "top_p": 1,
+ * "tools": null,
+ * "tool_choice": "none",
+ * "logprobs": false,
+ * "top_logprobs": null
+ * }
+ */
+@Data
+public class ChatRequestDto {
+ private String model;
+ private List messages;
+ private int temperature;
+ private int max_tokens;
+}
diff --git a/src/main/java/cn/teammodel/model/dto/ai/deepseek/ChatResponseDto.java b/src/main/java/cn/teammodel/model/dto/ai/deepseek/ChatResponseDto.java
new file mode 100644
index 0000000..a88ee88
--- /dev/null
+++ b/src/main/java/cn/teammodel/model/dto/ai/deepseek/ChatResponseDto.java
@@ -0,0 +1,47 @@
+package cn.teammodel.model.dto.ai.deepseek;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 接着响应的json 格式来设计响应体 用来响应体字符串
+ */
+@Data
+public class ChatResponseDto {
+ private int code;
+ private String msg;
+ private long wasteTime;
+ private String id;
+ private String object;
+ private long created;
+ private String model;
+
+ private Usage usage;
+
+ /**
+ * 返回内容
+ */
+ private List choices;
+ private String system_fingerprint;
+ @Data
+ public static class Choice {
+ private int index;
+ private MessageDto message;
+ private String logprobs;
+ private String finish_reason;
+ }
+ @Data
+ public static class Usage{
+ private int prompt_tokens;
+ private int completion_tokens;
+ private int total_tokens;
+ private Prompt_Tokens_Details prompt_tokens_details;
+ private int prompt_cache_hit_tokens;
+ private int prompt_cache_miss_tokens;
+ }
+ @Data
+ public static class Prompt_Tokens_Details {
+ private int cached_tokens;
+ }
+}
diff --git a/src/main/java/cn/teammodel/model/dto/ai/deepseek/MessageDto.java b/src/main/java/cn/teammodel/model/dto/ai/deepseek/MessageDto.java
new file mode 100644
index 0000000..19af4da
--- /dev/null
+++ b/src/main/java/cn/teammodel/model/dto/ai/deepseek/MessageDto.java
@@ -0,0 +1,14 @@
+package cn.teammodel.model.dto.ai.deepseek;
+
+import lombok.Data;
+
+/**
+ * 内部类定义请求/响应结构
+ */
+@Data
+public class MessageDto {
+ private String role;
+ private String sessionId;
+ private String content;
+
+}
diff --git a/src/main/java/cn/teammodel/model/entity/ai/DeepSeekSession.java b/src/main/java/cn/teammodel/model/entity/ai/DeepSeekSession.java
new file mode 100644
index 0000000..b31f3e0
--- /dev/null
+++ b/src/main/java/cn/teammodel/model/entity/ai/DeepSeekSession.java
@@ -0,0 +1,103 @@
+package cn.teammodel.model.entity.ai;
+
+import cn.hutool.core.lang.UUID;
+import cn.teammodel.model.entity.BaseItem;
+import com.azure.spring.data.cosmos.core.mapping.Container;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.Instant;
+import java.util.List;
+
+/**
+ * deepseek聊天会话
+ * @Date: 2023/6/5
+ */
+@EqualsAndHashCode(callSuper = true)
+@Container(containerName = "Teacher")
+@Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class DeepSeekSession extends BaseItem {
+
+ /**
+ * 用户id
+ */
+ public String userId;
+
+ /**
+ * 会话标题
+ */
+ private String title;
+
+ /**
+ * 生成该 completion 的模型名。
+ */
+ private String model;
+
+ /**
+ * 创建时间
+ */
+ private long createTime;
+
+ /**
+ * 产生对话即更新时间,按更新时间排序
+ */
+ private Long updateTime;
+
+ /**
+ * 会话历史记录
+ */
+ private List history;
+
+ @Data
+ public static class DeepSeekMessage {
+ /**
+ * 该对话的唯一标识符。
+ */
+ private String id;
+
+ /**
+ * 生成这条消息的角色。
+ * 角色 [user, assistant, system]
+ * user:用户。
+ * assistant:模型。
+ * system:模型和用户之间的对话。
+ */
+ private String role;
+
+ /**
+ * 用户的提问文本
+ */
+ private String userText;
+
+ /**
+ * 回答的文本
+ */
+ private String aiText;
+
+ /**
+ * 停止原因 [stop, length, content_filter, tool_calls, insufficient_system_resource] 模型停止生成 token 的原因。
+ * stop:模型自然停止生成,或遇到 stop 序列中列出的字符串。
+ * length :输出长度达到了模型上下文长度限制,或达到了 max_tokens 的限制。
+ * content_filter:输出内容因触发过滤策略而被过滤。
+ * insufficient_system_resource:系统推理资源不足,生成被打断。
+ */
+ private String finish_reason;
+
+ /**
+ * 创建聊天完成时的 Unix 时间戳
+ */
+ private Long createTime;
+
+ public static DeepSeekMessage of(String userText, String aiText){
+ DeepSeekMessage message = new DeepSeekMessage();
+ message.setId(UUID.randomUUID().toString());
+ message.setUserText(userText);
+ message.setAiText(aiText);
+ message.setCreateTime(Instant.now().toEpochMilli());
+ return message;
+ }
+ }
+
+}
diff --git a/src/main/java/cn/teammodel/repository/DeepSeekRepository.java b/src/main/java/cn/teammodel/repository/DeepSeekRepository.java
new file mode 100644
index 0000000..ea94b36
--- /dev/null
+++ b/src/main/java/cn/teammodel/repository/DeepSeekRepository.java
@@ -0,0 +1,58 @@
+package cn.teammodel.repository;
+
+import cn.teammodel.model.entity.ai.ChatSession;
+import cn.teammodel.model.entity.ai.DeepSeekSession;
+import com.azure.spring.data.cosmos.repository.CosmosRepository;
+import com.azure.spring.data.cosmos.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+/**
+ * 数据库操作接口
+ * Created by jiangjingming on 17/6/19.
+ */
+@Repository
+public interface DeepSeekRepository extends CosmosRepository {
+ /**
+ * 根据id和code查询会话信息
+ * @param id
+ * @param code
+ * @return
+ */
+ DeepSeekSession findSessionByIdAndCode(String id, String code);
+
+ /**
+ * 根据会话id查询会话信息
+ * @param sessionId
+ * @return
+ */
+ @Query("select * from c where c.code='DeepSeekSession' and c.sessionId = @sessionId")
+ List findBySessionId(String sessionId);
+
+ /**
+ * 根据用户id查询会话信息
+ * @param userId
+ * @return
+ */
+ @Query("select c.id,c.userId,c.title,c.model,c.createTime,c.updateTime from c where c.code='DeepSeekSession' and c.userId = @userId")
+ List findByUserId(String userId);
+
+ /**
+ * 根据会话id查询会话信息
+ * @param sessionId
+ * @return
+ */
+ @Query("SELECT value ARRAY_SLICE(c.history, -3) FROM c where c.id = @sessionId and c.code = 'DeepSeekSession'")
+ List findLatestMessage(String sessionId);
+
+ /**
+ * 根据用户id查询会话信息
+ * @param userId
+ * @return
+ */
+ @Query("select * from c where c.code = 'DeepSeekSession' and c.id = @userId")
+ List findCommentsById(String userId);
+
+
+
+}
diff --git a/src/main/java/cn/teammodel/service/DeepSeekService.java b/src/main/java/cn/teammodel/service/DeepSeekService.java
new file mode 100644
index 0000000..4184d42
--- /dev/null
+++ b/src/main/java/cn/teammodel/service/DeepSeekService.java
@@ -0,0 +1,20 @@
+package cn.teammodel.service;
+
+import cn.teammodel.model.dto.ai.deepseek.ChatResponseDto;
+import cn.teammodel.model.dto.ai.deepseek.MessageDto;
+import cn.teammodel.model.entity.ai.DeepSeekSession;
+
+import java.util.List;
+
+/**
+ * 访问DeepSeek方法
+ */
+public interface DeepSeekService {
+
+ /**
+ * 获取AI的回答
+ * @param message
+ * @return
+ */
+ ChatResponseDto ChatAsk(MessageDto message);
+}
diff --git a/src/main/java/cn/teammodel/service/DeepSeekSessionService.java b/src/main/java/cn/teammodel/service/DeepSeekSessionService.java
new file mode 100644
index 0000000..90ef875
--- /dev/null
+++ b/src/main/java/cn/teammodel/service/DeepSeekSessionService.java
@@ -0,0 +1,60 @@
+package cn.teammodel.service;
+
+import cn.teammodel.model.dto.ai.deepseek.ChatResponseDto;
+import cn.teammodel.model.entity.ai.DeepSeekSession;
+import cn.teammodel.model.entity.ai.DeepSeekSession.DeepSeekMessage;
+
+import java.util.List;
+
+/**
+ * 会话服务接口
+ * Created by Jiayiwu on 16/5/26.
+ */
+public interface DeepSeekSessionService {
+
+ /**
+ * 创建默认会话
+ * @param userId
+ * @param name
+ * @return
+ */
+ DeepSeekSession CreateDefaultSession(String userId, String name);
+
+ /**
+ * 创建会话
+ * @param session
+ * @return
+ */
+ DeepSeekSession CreateSession(DeepSeekSession session);
+
+ /**
+ * 更新会话
+ * @param upSession
+ * @param userId
+ * @return
+ */
+ DeepSeekSession updateSession(DeepSeekSession upSession, String userId);
+
+ /**
+ * 删除会话
+ * @param id
+ * @param userId
+ */
+ void deleteSession (String id, String userId);
+
+ /**
+ * 获取用户会话列表
+ * @param userId
+ * @return
+ */
+ List UserSessionList(String userId);
+
+ /**
+ * 获取历史消息
+ * @param sessionId
+ * @param userId
+ * @return
+ */
+ List listHistory(String sessionId, String userId);
+
+}
diff --git a/src/main/java/cn/teammodel/service/impl/DeepSeekServiceImpl.java b/src/main/java/cn/teammodel/service/impl/DeepSeekServiceImpl.java
new file mode 100644
index 0000000..8628826
--- /dev/null
+++ b/src/main/java/cn/teammodel/service/impl/DeepSeekServiceImpl.java
@@ -0,0 +1,110 @@
+package cn.teammodel.service.impl;
+
+import cn.teammodel.ai.deepseek.DeepSeekClient;
+import cn.teammodel.common.PK;
+import cn.teammodel.model.dto.ai.deepseek.ChatRequestDto;
+import cn.teammodel.model.dto.ai.deepseek.ChatResponseDto;
+import cn.teammodel.model.dto.ai.deepseek.MessageDto;
+import cn.teammodel.model.entity.ai.DeepSeekSession;
+import cn.teammodel.model.entity.ai.DeepSeekSession.DeepSeekMessage;
+import cn.teammodel.repository.DeepSeekRepository;
+import cn.teammodel.security.utils.SecurityUtil;
+import cn.teammodel.service.DeepSeekService;
+import cn.teammodel.service.DeepSeekSessionService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.time.Instant;
+import java.util.*;
+
+
+/**
+ * 描述:访问DeepSeek方法
+ */
+@Service
+@Slf4j
+public class DeepSeekServiceImpl implements DeepSeekService {
+ @Resource
+ private DeepSeekSessionService deepSeekService;
+
+ @Resource
+ private DeepSeekRepository deepSeekRepository;
+
+ /**
+ * 提问
+ * @param message
+ * @return
+ */
+ @Override
+ public ChatResponseDto ChatAsk(MessageDto message) {
+ //创建消息列表
+ List msg = new ArrayList<>();
+ msg.add(message);
+
+ //构建请求头
+ ChatRequestDto requestBody = new ChatRequestDto();
+ requestBody.setModel(DeepSeekClient.API_Model);
+ requestBody.setMessages(msg);
+ requestBody.setTemperature(0);
+ requestBody.setMax_tokens(1024);
+
+ //开始时间
+ long startTime = System.currentTimeMillis();
+ //发起请求
+ ChatResponseDto 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;
+ }
+
+ //region 辅助方法
+ /**
+ * 新增/更新会话
+ * @param message
+ * @param session
+ * @param savaMessage
+ * @param response
+ */
+ private void UpdateSession(MessageDto message, DeepSeekSession session, DeepSeekMessage savaMessage, ChatResponseDto 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
+
+}
diff --git a/src/main/java/cn/teammodel/service/impl/DeepSeekSessionServiceImpl.java b/src/main/java/cn/teammodel/service/impl/DeepSeekSessionServiceImpl.java
new file mode 100644
index 0000000..dac56eb
--- /dev/null
+++ b/src/main/java/cn/teammodel/service/impl/DeepSeekSessionServiceImpl.java
@@ -0,0 +1,133 @@
+package cn.teammodel.service.impl;
+
+import cn.teammodel.common.ErrorCode;
+import cn.teammodel.common.PK;
+import cn.teammodel.config.exception.ServiceException;
+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.DeepSeekRepository;
+import cn.teammodel.service.DeepSeekSessionService;
+import cn.teammodel.utils.RepositoryUtil;
+import com.azure.cosmos.models.CosmosPatchOperations;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.time.Instant;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+@Service
+@Slf4j
+public class DeepSeekSessionServiceImpl implements DeepSeekSessionService {
+ @Resource // 注入
+ private DeepSeekRepository deepSeekRepository;
+
+ /**
+ * 创建初始会话
+ * @param userId
+ * @param name
+ * @return
+ */
+ @Override
+ public DeepSeekSession CreateDefaultSession(String userId, String name) {
+ //初始化第一条欢迎语
+ DeepSeekMessage message = DeepSeekMessage.of("你好"+name, "我是你的私人 DeepSeek AI 助手小豆,你可以问我任何包括但不仅限于教育的问题,我会尽力为您解答!");
+ List history = Collections.singletonList(message);
+ DeepSeekSession session = new DeepSeekSession();
+ session.setId(UUID.randomUUID().toString());
+ session.setCode(PK.DEEPSEEK_SESSION);
+ session.setTitle("新对话");
+ session.setUserId(userId);
+ session.setCreateTime(Instant.now().toEpochMilli());
+ session.setUpdateTime(Instant.now().toEpochMilli());
+ session.setHistory(history);
+ return deepSeekRepository.save(session);
+ }
+
+ /**
+ * 创建新会话
+ * @param session
+ * @return
+ */
+ @Override
+ public DeepSeekSession CreateSession(DeepSeekSession session) {
+ return deepSeekRepository.save(session);
+ }
+
+ /**
+ * 更新会话
+ * @param upSession
+ * @param userId
+ * @return
+ */
+ @Override
+ public DeepSeekSession updateSession (DeepSeekSession upSession, String userId)
+ {
+ String id = upSession.getId();
+ String title = upSession.getTitle();
+ DeepSeekSession session = RepositoryUtil.findOne(deepSeekRepository.findBySessionId(id), "");
+ if (!session.getUserId().equals(userId)) {
+ throw new ServiceException(ErrorCode.NO_AUTH_ERROR);
+ }
+ CosmosPatchOperations options = CosmosPatchOperations.create()
+ .replace("/title", title);
+
+ deepSeekRepository.save(id, PK.of(PK.CHAT_SESSION), DeepSeekSession.class, options);
+ return session;
+ }
+
+ /**
+ * 删除会话
+ * @param id
+ * @param userId
+ */
+ @Override
+ public void deleteSession (String id, String userId)
+ {
+ DeepSeekSession session = RepositoryUtil.findOne(deepSeekRepository.findBySessionId(id), "");
+ if (!session.getUserId().equals(userId)) {
+ throw new ServiceException(ErrorCode.NO_AUTH_ERROR);
+ }
+ deepSeekRepository.deleteById(id, PK.of(PK.CHAT_SESSION));
+ }
+
+
+ /**
+ * 获取用户会话列表
+ * @param userId
+ * @return
+ */
+ @Override
+ public List UserSessionList(String userId) {
+ List sessions = deepSeekRepository.findByUserId(userId);
+ // 按更新时间排序
+ if (ObjectUtils.isNotEmpty(sessions))
+ {
+ sessions = sessions.stream().sorted(Comparator.comparing(DeepSeekSession::getUpdateTime)).collect(Collectors.toList());
+ }
+ return sessions;
+ }
+
+ /**
+ * 获取历史消息
+ * @param sessionId
+ * @param userId
+ * @return
+ */
+ @Override
+ public List listHistory(String sessionId, String userId) {
+ DeepSeekSession session = deepSeekRepository.findSessionByIdAndCode(sessionId, PK.DEEPSEEK_SESSION);
+ if (!userId.equals(session.getUserId())) {
+ throw new ServiceException(ErrorCode.NO_AUTH_ERROR);
+ }
+ return session.getHistory();
+ }
+
+
+}
diff --git a/src/main/resources/DeepSeekConfig.properties b/src/main/resources/DeepSeekConfig.properties
new file mode 100644
index 0000000..0ca02e2
--- /dev/null
+++ b/src/main/resources/DeepSeekConfig.properties
@@ -0,0 +1,3 @@
+key=sk-83b5b6dd85c745cbae2572ea01c54e44
+url=https://api.deepseek.com/chat/completions
+model=deepseek-chat
\ No newline at end of file