瀏覽代碼

文心一言api

zhijiezhao 9 月之前
父節點
當前提交
e284d8c49e

+ 22 - 0
pom.xml

@@ -30,6 +30,28 @@
     </dependencyManagement>
     </dependencyManagement>
 
 
     <dependencies>
     <dependencies>
+        <!--百度千帆大模型-->
+        <dependency>
+            <groupId>com.baidubce</groupId>
+            <artifactId>qianfan</artifactId>
+            <version>0.0.9</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+            <version>2.14.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+            <version>20230227</version>
+        </dependency>
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+            <version>3.8.1</version>
+        </dependency>
+
         <dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-actuator</artifactId>
             <artifactId>spring-boot-starter-actuator</artifactId>

+ 50 - 0
src/main/java/com/caimei365/user/controller/ChatLogApi.java

@@ -0,0 +1,50 @@
+package com.caimei365.user.controller;
+
+import com.baidubce.qianfan.model.chat.ChatResponse;
+import com.caimei365.user.model.ResponseJson;
+import com.caimei365.user.model.dto.ChatCompletionResponse;
+import com.caimei365.user.model.dto.ChatDto;
+import com.caimei365.user.model.dto.ChatHistory;
+import com.caimei365.user.model.dto.ChatHistoryMessage;
+import com.caimei365.user.service.ChatLogService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+@Api(tags = "百度ai聊天")
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/user/chat")
+public class ChatLogApi {
+
+    private final ChatLogService chatLogService;
+
+    @ApiOperation("开启新对话")
+    @GetMapping("/new/chat")
+    public ResponseJson<ChatCompletionResponse> getAnswer(Integer userId, String question) {
+        return chatLogService.getAnswer(userId, question);
+    }
+
+    @ApiOperation("对话历史")
+    @GetMapping("/chat/history")
+    public ResponseJson<List<ChatHistory>> getHistory(Integer userId) {
+        return chatLogService.getHistory(userId);
+    }
+
+    @ApiOperation("对话历史详情")
+    @GetMapping("/history/detail")
+    public ResponseJson<List<ChatHistoryMessage>> getHistoryDetail(Integer userId, Integer chatId) {
+        return chatLogService.getHistoryDetail(userId, chatId);
+    }
+
+
+    @ApiOperation("多轮对话")
+    @GetMapping("/second/chat")
+    public ResponseJson<ChatCompletionResponse> getSecondAnswer(Integer chatId, Integer userId, String question) {
+        return chatLogService.getSecondAnswer(chatId, userId, question);
+    }
+}

+ 28 - 0
src/main/java/com/caimei365/user/mapper/ChatMapper.java

@@ -0,0 +1,28 @@
+package com.caimei365.user.mapper;
+
+import com.caimei365.user.model.dto.ChatCompletionResponse;
+import com.caimei365.user.model.dto.ChatHistory;
+import com.caimei365.user.model.dto.ChatHistoryMessage;
+import com.caimei365.user.model.vo.ChatDialogueVo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface ChatMapper {
+
+    void insertChatDialogue(ChatDialogueVo vo);
+
+    void insertUserDetail(String jsonString, Integer id);
+
+    void insertAssistantDetail(String resString, Integer id);
+
+    List<ChatHistory> findHistory(Integer userId);
+
+    List<ChatHistoryMessage> findHistoryMessage(@Param("userId") Integer userId, @Param("id") Integer id);
+
+    void updateChatDialogue(ChatDialogueVo chatDialogueVo);
+
+    List<ChatHistoryMessage> findHistoryQuestion(@Param("chatId") Integer chatId, @Param("userId") Integer userId);
+}

+ 74 - 0
src/main/java/com/caimei365/user/model/dto/ApiRequest.java

@@ -0,0 +1,74 @@
+package com.caimei365.user.model.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.List;
+
+@Data
+@Accessors(fluent = true)
+public class ApiRequest {
+
+    /**
+     * 百度千帆大模型ERNIE-3.5-8K
+     * https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Olvlzrruq
+     */
+
+    @JsonProperty("messages")
+    private List<Message> messages;
+
+    /**
+     * 是否强制关闭实时搜索功能,默认false,表示不关闭
+     */
+    @JsonProperty("disable_search")
+    private boolean disableSearch;
+
+    /**
+     * 是否以流式接口的形式返回数据,默认false
+     */
+    @JsonProperty("stream")
+    private boolean stream;
+
+    /**
+     * 温度 0.6
+     * 说明:
+     * (1)影响输出文本的多样性,取值越大,生成文本的多样性越强
+     * (2)默认0.8,取值范围 [0, 1.0]
+     */
+    @JsonProperty("top_p")
+    private Double top_p;
+
+    /**
+     * 重复惩罚值 1.5
+     * 通过对已生成的token增加惩罚,减少重复生成的现象。说明:
+     * (1)值越大表示惩罚越大
+     * (2)默认1.0,取值范围:[1.0, 2.0]
+     */
+    @JsonProperty("penalty_score")
+    private Double penaltyScore;
+
+    /**
+     * 搜索溯源
+     */
+    @JsonProperty("enable_citation")
+    private boolean enableCitation;
+
+
+    /**
+     * 搜索溯源
+     */
+    @JsonProperty("enable_trace")
+    private boolean enableTrace;
+
+    @Data
+    @Accessors(fluent = true)
+    public static class Message {
+        @JsonProperty("role")
+        private String role;
+
+        @JsonProperty("content")
+        private String content;
+
+    }
+}

+ 87 - 0
src/main/java/com/caimei365/user/model/dto/ChatCompletionResponse.java

@@ -0,0 +1,87 @@
+package com.caimei365.user.model.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ChatCompletionResponse {
+
+
+    private Integer chatId;
+
+    @JsonProperty("id")
+    private String id;
+
+    @JsonProperty("object")
+    private String oct;
+
+    @JsonProperty("created")
+    private long created;
+
+    @JsonProperty("result")
+    private String result;
+
+    @JsonProperty("is_truncated")
+    private boolean isTruncated;
+
+    @JsonProperty("need_clear_history")
+    private boolean needClearHistory;
+
+    @JsonProperty("sentence_id")
+    private Integer sentenceId;
+
+    @JsonProperty("is_end")
+    private boolean isEnd;
+
+    @JsonProperty("search_info")
+    private SearchInfo searchInfo;
+
+    @JsonProperty("finish_reason")
+    private String finishReason;
+
+    @JsonProperty("usage")
+    private Usage usage;
+
+    // Getters and setters or Lombok annotations
+
+    @Data
+    public static class SearchInfo {
+        @JsonProperty("search_results")
+        private List<SearchResult> searchResults;
+
+        // Getters and setters or Lombok annotations
+    }
+
+    @Data
+    public static class SearchResult {
+        @JsonProperty("index")
+        private int index;
+
+        @JsonProperty("url")
+        private String url;
+
+        @JsonProperty("title")
+        private String title;
+
+        @JsonProperty("datasource_id")
+        private String datasourceId;
+
+        // Getters and setters or Lombok annotations
+    }
+
+    @Data
+    public static class Usage {
+        @JsonProperty("prompt_tokens")
+        private int promptTokens;
+
+        @JsonProperty("completion_tokens")
+        private int completionTokens;
+
+        @JsonProperty("total_tokens")
+        private int totalTokens;
+
+        // Getters and setters or Lombok annotations
+    }
+}

+ 13 - 0
src/main/java/com/caimei365/user/model/dto/ChatDto.java

@@ -0,0 +1,13 @@
+package com.caimei365.user.model.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+@Data
+@Accessors(fluent = true)
+public class ChatDto {
+
+    private Integer userId;
+    private Integer chatId;
+    private String question;
+}

+ 14 - 0
src/main/java/com/caimei365/user/model/dto/ChatHistory.java

@@ -0,0 +1,14 @@
+package com.caimei365.user.model.dto;
+
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.List;
+
+@Data
+public class ChatHistory {
+    private Integer id;
+    private String firstQuestion;
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private String addTime;
+}

+ 12 - 0
src/main/java/com/caimei365/user/model/dto/ChatHistoryMessage.java

@@ -0,0 +1,12 @@
+package com.caimei365.user.model.dto;
+
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+@Data
+public class ChatHistoryMessage {
+    private Integer identity;
+    private String message;
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private String addTime;
+}

+ 12 - 0
src/main/java/com/caimei365/user/model/vo/ChatDialogueVo.java

@@ -0,0 +1,12 @@
+package com.caimei365.user.model.vo;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+@Data
+@Accessors(fluent = true)
+public class ChatDialogueVo {
+    private Integer id;
+    private String chatText;
+    private Integer userId;
+}

+ 20 - 0
src/main/java/com/caimei365/user/service/ChatLogService.java

@@ -0,0 +1,20 @@
+package com.caimei365.user.service;
+
+import com.caimei365.user.model.ResponseJson;
+import com.caimei365.user.model.dto.ChatCompletionResponse;
+import com.caimei365.user.model.dto.ChatDto;
+import com.caimei365.user.model.dto.ChatHistory;
+import com.caimei365.user.model.dto.ChatHistoryMessage;
+
+import java.util.List;
+import java.util.Map;
+
+public interface ChatLogService {
+    ResponseJson<ChatCompletionResponse> getAnswer(Integer userId, String question);
+
+    ResponseJson<List<ChatHistory>> getHistory(Integer userId);
+
+    ResponseJson<List<ChatHistoryMessage>> getHistoryDetail(Integer userId, Integer chatId);
+
+    ResponseJson<ChatCompletionResponse> getSecondAnswer(Integer chatId,Integer userId, String question);
+}

+ 150 - 0
src/main/java/com/caimei365/user/service/impl/ChatLogServiceImpl.java

@@ -0,0 +1,150 @@
+package com.caimei365.user.service.impl;
+
+import com.caimei365.user.mapper.ChatMapper;
+import com.caimei365.user.model.ResponseJson;
+import com.caimei365.user.model.dto.*;
+import com.caimei365.user.model.vo.ChatDialogueVo;
+import com.caimei365.user.service.ChatLogService;
+import com.caimei365.user.utils.QianFanUtils;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.pagehelper.PageHelper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+
+@Slf4j
+@Service
+public class ChatLogServiceImpl implements ChatLogService {
+
+    @Resource
+    private ChatMapper chatMapper;
+
+    @Override
+    public ResponseJson<ChatCompletionResponse> getAnswer(Integer userId, String question) {
+        log.info("dto------------->" + question);
+        ApiRequest chatRequest = new ApiRequest();
+        ApiRequest.Message message = new ApiRequest.Message();
+        question = question + ",内容不超过350字";
+        message.role("user").content(question);
+        ArrayList<ApiRequest.Message> messages = new ArrayList<>();
+        messages.add(message);
+        chatRequest.penaltyScore(1.0).top_p(0.6).enableTrace(true).enableCitation(false).messages(messages);
+        ObjectMapper objectMapper = new ObjectMapper();
+        String jsonString = "";
+        String resString = "";
+        try {
+            jsonString = objectMapper.writeValueAsString(chatRequest);
+            log.info("request------------------------->" + jsonString);
+            ChatCompletionResponse chatCompletionResponse = QianFanUtils.firstChat(jsonString);
+            resString = objectMapper.writeValueAsString(chatCompletionResponse);
+            ChatDialogueVo chatDialogueVo = new ChatDialogueVo();
+            chatDialogueVo.chatText(jsonString).userId(userId);
+            chatMapper.insertChatDialogue(chatDialogueVo);
+            chatMapper.insertUserDetail(jsonString, chatDialogueVo.id());
+            chatMapper.insertAssistantDetail(resString, chatDialogueVo.id());
+            chatCompletionResponse.setChatId(chatDialogueVo.id());
+            return ResponseJson.success(chatCompletionResponse);
+        } catch (JsonProcessingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public ResponseJson<List<ChatHistory>> getHistory(Integer userId) {
+        List<ChatHistory> chats = chatMapper.findHistory(userId);
+        try {
+            ObjectMapper objectMapper = new ObjectMapper();
+            for (ChatHistory chat : chats) {
+                String firstQuestion = chat.getFirstQuestion();
+                ApiRequest apiRequest = objectMapper.readValue(firstQuestion, ApiRequest.class);
+                ApiRequest.Message message = apiRequest.messages().get(0);
+                chat.setFirstQuestion(message.content());
+            }
+        } catch (JsonProcessingException e) {
+            throw new RuntimeException(e);
+        }
+        return ResponseJson.success(chats);
+    }
+
+    @Override
+    public ResponseJson<List<ChatHistoryMessage>> getHistoryDetail(Integer userId, Integer chatId) {
+        List<ChatHistoryMessage> messages = chatMapper.findHistoryMessage(userId, chatId);
+        ObjectMapper objectMapper = new ObjectMapper();
+        try {
+//            for (ChatHistoryMessage chm : messages) {
+//                if (0 == chm.getIdentity()) {
+//                    ApiRequest question = objectMapper.readValue(chm.getMessage(), ApiRequest.class);
+//                    chm.setMessage(question.messages().get(0).content());
+//                } else {
+//                    ChatCompletionResponse answer = objectMapper.readValue(chm.getMessage(), ChatCompletionResponse.class);
+//                    chm.setMessage(answer.getResult());
+//                }
+//            }
+
+
+            for (int i = 0; i < messages.size(); i++) {
+                if (0 == messages.get(i).getIdentity()) {
+                    ApiRequest question = objectMapper.readValue(messages.get(i).getMessage(), ApiRequest.class);
+                    messages.get(i).setMessage(question.messages().get(i).content());
+                } else {
+                    ChatCompletionResponse answer = objectMapper.readValue(messages.get(i).getMessage(), ChatCompletionResponse.class);
+                    messages.get(i).setMessage(answer.getResult());
+                }
+            }
+
+
+        } catch (JsonProcessingException e) {
+            throw new RuntimeException(e);
+        }
+        return ResponseJson.success(messages);
+    }
+
+    @Override
+    public ResponseJson<ChatCompletionResponse> getSecondAnswer(Integer chatId, Integer userId, String question) {
+        List<ChatHistoryMessage> historyMessage = chatMapper.findHistoryQuestion(chatId, userId);
+        if(historyMessage.size()<1){
+            return ResponseJson.error("无历史记录");
+        }
+        ObjectMapper objectMapper = new ObjectMapper();
+        try {
+            ChatHistoryMessage questions = historyMessage.get(0);
+            ChatHistoryMessage answer = historyMessage.get(1);
+            /**
+             * 取最近回复的answer和question,填充assistant及content,再加入新一轮的question,发起提问
+             */
+            ApiRequest his = objectMapper.readValue(questions.getMessage(), ApiRequest.class);
+            List<ApiRequest.Message> messages = his.messages();
+            ChatCompletionResponse chatResp = objectMapper.readValue(answer.getMessage(), ChatCompletionResponse.class);
+            ApiRequest.Message resMes = new ApiRequest.Message();
+            resMes.role("assistant").content(chatResp.getResult());
+            messages.add(resMes);
+            /**
+             * 正常轮次提问
+             */
+            ApiRequest chatRequest = new ApiRequest();
+            ApiRequest.Message message = new ApiRequest.Message();
+            question = question + ",内容不超过350字";
+            message.role("user").content(question);
+            messages.add(message);
+            chatRequest.penaltyScore(1.0).top_p(0.6).enableTrace(true).enableCitation(false).messages(messages);
+            String jsonString = "";
+            String resString = "";
+            jsonString = objectMapper.writeValueAsString(chatRequest);
+            log.info("request------------------------->" + jsonString);
+            ChatCompletionResponse chatCompletionResponse = QianFanUtils.firstChat(jsonString);
+            resString = objectMapper.writeValueAsString(chatCompletionResponse);
+            ChatDialogueVo chatDialogueVo = new ChatDialogueVo();
+            chatDialogueVo.chatText(jsonString).userId(userId).id(chatId);
+            chatMapper.updateChatDialogue(chatDialogueVo);
+            chatMapper.insertUserDetail(jsonString, chatDialogueVo.id());
+            chatMapper.insertAssistantDetail(resString, chatDialogueVo.id());
+            return ResponseJson.success(chatCompletionResponse);
+        } catch (JsonProcessingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}

+ 129 - 0
src/main/java/com/caimei365/user/utils/QianFanUtils.java

@@ -0,0 +1,129 @@
+package com.caimei365.user.utils;
+
+import com.baidubce.qianfan.model.chat.ChatRequest;
+import com.caimei365.user.model.dto.ApiRequest;
+import com.caimei365.user.model.dto.ChatCompletionResponse;
+import com.caimei365.user.model.dto.ChatDto;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+public class QianFanUtils {
+    public static final String API_KEY = "LmSYMsGCHfkco5HcMj5AfVHg";
+    public static final String SECRET_KEY = "YKs5P1RXIBHA502f9lGBQXyHBr1WtyYi";
+    // 你可以根据需要调整这些值
+
+    // 连接超时时间,单位毫秒
+    private static final long CONNECT_TIMEOUT_MILLIS = 80000L;
+    // 读取超时时间,单位毫秒
+    private static final long READ_TIMEOUT_MILLIS = 80000L;
+    // 写入超时时间,单位毫秒
+    private static final long WRITE_TIMEOUT_MILLIS = 80000L;
+    static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder()
+            // 设置连接超时时间
+            .connectTimeout(CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+            // 设置读取超时时间
+            .readTimeout(READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+            // 设置写入超时时间
+            .writeTimeout(WRITE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+            .build();
+
+//    public static void main(String[] args) {
+//        String jsonString = "{\"messages\":[{\"role\":\"user\",\"content\":\"黄金微针品牌推荐\"}],\"disable_search\":false,\"enable_citation\":false,\"enable_trace\":false}";
+//
+//        try {
+//            ObjectMapper objectMapper = new ObjectMapper();
+//            ApiRequest apiRequest = objectMapper.readValue(jsonString, ApiRequest.class);
+//
+//            List<ApiRequest.Message> messages = apiRequest.getMessages();
+//            ApiRequest.Message message1 = new ApiRequest.Message();
+//            message1.setContent("我推你的老师");
+//            message1.setRole("assistant");
+//            messages.add(message1);
+//            System.out.println("req--------->" + apiRequest.toString());
+//            // 打印或进一步处理apiRequest对象
+//            String s = objectMapper.writeValueAsString(apiRequest);
+//            System.out.println("resp---------->" + s);
+//
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//        }
+//    }
+
+
+    public static ChatCompletionResponse firstChat(String jsonString){
+        try {
+            ObjectMapper objectMapper = new ObjectMapper();
+            MediaType mediaType = MediaType.parse("application/json");
+            RequestBody body = RequestBody.create(mediaType, jsonString);
+            Request request = new Request.Builder()
+                    .url("https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token=" + getAccessToken())
+                    .method("POST", body)
+                    .addHeader("Content-Type", "application/json")
+                    .build();
+            Response response = HTTP_CLIENT.newCall(request).execute();
+            log.info("response------------->" + response.body());
+            ChatCompletionResponse chatCompletionResponse = objectMapper.readValue(response.body().string(), ChatCompletionResponse.class);
+            return chatCompletionResponse;
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+
+    /**
+     * 从用户的AK,SK生成鉴权签名(Access Token)
+     *
+     * @return 鉴权签名(Access Token)
+     * @throws IOException IO异常
+     */
+    static String getAccessToken() throws IOException {
+        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
+        RequestBody body = RequestBody.create(mediaType, "grant_type=client_credentials&client_id=" + API_KEY
+                + "&client_secret=" + SECRET_KEY);
+        Request request = new Request.Builder()
+                .url("https://aip.baidubce.com/oauth/2.0/token")
+                .method("POST", body)
+                .addHeader("Content-Type", "application/x-www-form-urlencoded")
+                .build();
+        Response response = HTTP_CLIENT.newCall(request).execute();
+        return new JSONObject(response.body().string()).getString("access_token");
+    }
+
+//
+//    public static void main(String[] args) {
+//
+//        ChatResponse response = new Qianfan("TtNscff25p7t2aKuQ1vFJg7g","7vUKsmllQeBgFxq3xVCKYJdnS7fWEdS1").chatCompletion()
+//                // 使用model指定预置模型
+//                .model("ERNIE-Bot-4")
+//                // .endpoint("completions_pro")
+//                // 也可以使用endpoint指定任意模型 (二选一)
+//                // 添加用户消息 (此方法可以调用多次,以实现多轮对话的消息传递)
+//                .addMessage("user", "你好")
+//                // 自定义超参数
+//                .temperature(0.7)
+//                // 发起请求
+//                .execute();
+//        System.out.println(response.getResult());
+//    }
+//
+//    public static void aaa(String[] args) throws IllegalAccessException {
+//
+//        // 使用安全认证AK/SK鉴权,替换下列示例中参数,安全认证Access Key替换your_iam_ak,Secret Key替换your_iam_sk
+//        Qianfan qianfan = new Qianfan("your_iam_ak", "your_iam_sk");
+//
+//        // 调用大模型
+//        Image2TextResponse response = qianfan.image2Text().model("Fuyu-8B")
+//                .image("/9j/4AAQSkZJRgABAQAAAQABAAD/xxxxxx")
+//                .prompt("introduce the picture")
+//                .execute();
+//        System.out.println(response.getResult());
+//    }
+}

+ 53 - 0
src/main/resources/mapper/ChatMapper.xml

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.caimei365.user.mapper.ChatMapper">
+
+    <insert id="insertChatDialogue" parameterType="ChatDialogueVo" useGeneratedKeys="true" keyProperty="id">
+        insert into cm_chat_dialogue (chatText, userId, addTime)
+            value (#{chatText}, #{userId}, now())
+    </insert>
+
+    <insert id="insertUserDetail">
+        insert into cm_chat_details (chatId, text, identity, addTime)
+            value (#{id}, #{jsonString}, 0, now())
+    </insert>
+
+    <insert id="insertAssistantDetail">
+        insert into cm_chat_details (chatId, text, identity, addTime)
+            value (#{id}, #{resString}, 1, now())
+    </insert>
+
+    <select id="findHistory" resultType="com.caimei365.user.model.dto.ChatHistory">
+        select id, REPLACE(chatText, ',内容不超过350字', '') as firstQuestion, addTime
+        from cm_chat_dialogue
+        where userId = #{userId}
+          and delFlag = 0
+        ORDER BY ADDTIME DESC
+        limit 10
+    </select>
+
+    <select id="findHistoryMessage" resultType="com.caimei365.user.model.dto.ChatHistoryMessage">
+        select REPLACE(ccd.text, ',内容不超过350字', '') as message, ccd.identity, ccd.addTime
+        from cm_chat_details ccd
+        left join cm_chat_dialogue ccdd on ccdd.id = ccd.chatId
+        where ccdd.userId = #{userId}
+          and ccd.chatId = #{id}
+        ORDER BY ADDTIME ASC,identity ASC
+    </select>
+
+    <update id="updateChatDialogue">
+        update cm_chat_dialogue
+        set chatText = #{chatText}
+        where id = #{id}
+    </update>
+
+    <select id="findHistoryQuestion" resultType="com.caimei365.user.model.dto.ChatHistoryMessage">
+        select ccd.text as message, ccd.identity, ccd.addTime
+        from cm_chat_details ccd
+        left join cm_chat_dialogue ccdd on ccdd.id = ccd.chatId
+        where ccdd.userId = #{userId}
+          and ccd.chatId = #{chatId}
+        ORDER BY ADDTIME DESC, identity ASC
+        limit 2
+    </select>
+</mapper>