Browse Source

车队形式

chenbiao 2 năm trước cách đây
mục cha
commit
a2fb95a0b6

+ 5 - 1
netflix-dao/src/main/java/com/cyksj/model/entity/ChatgptSession.java

@@ -41,6 +41,9 @@ public class ChatgptSession extends BaseEntity {
     @TableField("accountId")
     private Long accountId;
 
+    @TableField("isCar")
+    private Boolean isCar;
+
     /**
      * 车id
      */
@@ -50,7 +53,7 @@ public class ChatgptSession extends BaseEntity {
     /**
      * 车名称
      */
-    private String cardName;
+    private String carName;
 
     /**
      * 官方session
@@ -63,4 +66,5 @@ public class ChatgptSession extends BaseEntity {
      */
     private String remark;
 
+
 }

+ 1 - 1
netflix-dao/src/main/java/com/cyksj/model/entity/ChatgptUser.java

@@ -64,7 +64,7 @@ public class ChatgptUser extends BaseEntity {
     /**
      * 限制次数
      */
-    private Integer limit;
+    private Integer limitNum;
 
     /**
      * 限制时间

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/ChatgptUserConversation.java

@@ -38,5 +38,10 @@ public class ChatgptUserConversation extends BaseEntity {
      */
     private String title;
 
+    /**
+     * 消息id
+     */
+    private String messageId;
+
 
 }

+ 15 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GoodsDonSku.java

@@ -163,6 +163,21 @@ public class GoodsDonSku extends BaseEntity {
      */
     private Boolean isMirror;
 
+    /**
+     * 是否是车队形式
+     */
+    private Boolean isCar;
+
+    /**
+     * 限制次数
+     */
+    private Integer gptLimitNum;
+
+    /**
+     * 限制时间
+     */
+    private Long gptLimitTime;
+
     /**
      * 特定价格
      */

+ 1 - 3
netflix-dao/src/main/java/com/cyksj/model/request/gpt/ConversationRequest.java

@@ -1,11 +1,9 @@
 package com.cyksj.model.request.gpt;
 
 import lombok.Data;
-import org.checkerframework.checker.units.qual.A;
 
 import java.util.List;
 import java.util.Map;
-import java.util.Random;
 
 /**
  * @author chan
@@ -68,7 +66,7 @@ public class ConversationRequest {
     private boolean force_rate_limit;
     private String websocket_request_id;
 
-    private String cardId;
+    private String carId;
 
     // Inner class for Message
     @Data

+ 23 - 0
netflix-dao/src/main/java/com/cyksj/model/response/ConversationLimitResponse.java

@@ -0,0 +1,23 @@
+package com.cyksj.model.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author chan
+ * @date 2024/4/9 17:41
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ConversationLimitResponse {
+
+    /**
+     * 是否限制
+     */
+    private boolean limited;
+
+    private Long nextAvailableTime; // 以毫秒为单位
+
+}

+ 53 - 0
netflix-dao/src/main/java/com/cyksj/model/views/ChatGptUserConversationRecordHistoryView.java

@@ -0,0 +1,53 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @author chan
+ * @date 2024/4/10 11:37
+ */
+@Data
+@SearchBean(tables = "(SELECT MAX(id) id from chatgpt_user_conversation_record as r\n" +
+        "GROUP BY r.conversation_id) t left join chatgpt_user_conversation_record as r on t.id = r.id , chatgpt_user_conversation as c"
+        ,where = "r.conversation_id = c.conversationId"
+        ,orderBy = "r.created_time desc"
+)
+public class ChatGptUserConversationRecordHistoryView {
+
+    @DbField("r.user_token")
+    private String userToken;
+    /**
+     * 对话标题
+     */
+    @DbField("c.title")
+    private String title;
+
+    /**
+     * 对话id
+     */
+    @DbField("r.conversation_id")
+    private String conversationId;
+
+    /**
+     * 对话时间
+     */
+    @DbField("r.created_time")
+    private Date conversationTime;
+
+    /**
+     * 车队id
+     */
+    @DbField("c.car_id")
+    private String carId;
+
+    /**
+     * 车队名称
+     */
+    @DbField("c.car_name")
+    private String carName;
+
+}

+ 40 - 0
netflix-dao/src/main/java/com/cyksj/model/views/ChatGptUserView.java

@@ -0,0 +1,40 @@
+package com.cyksj.model.views;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @author chan
+ * @date 2024/4/10 11:21
+ */
+@Data
+@Builder
+public class ChatGptUserView {
+
+    /**
+     * 规格名称
+     */
+    private String skuName;
+
+    /**
+     * 过期时间
+     */
+    private Date expireTime;
+
+    /**
+     * 限制时间
+     */
+    private Long limitTime;
+
+    /**
+     * 限制次数
+     */
+    private Integer limitNum;
+
+    /**
+     * 使用次数
+     */
+    private Long use;
+}

+ 62 - 0
netflix-dao/src/main/java/com/cyksj/model/views/ChatgptCarInfoView.java

@@ -0,0 +1,62 @@
+package com.cyksj.model.views;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @author chan
+ * @date 2024/4/8 17:02
+ */
+@Data
+public class ChatgptCarInfoView {
+
+    /**
+     * 车次id
+     */
+    private String carId;
+
+    /**
+     * 车次名称
+     */
+    private String carName;
+
+    /**
+     * 车次状态 繁忙 空闲 停运
+     */
+
+    private String status;
+
+
+    /**
+     * 得分
+     */
+    private Double score;
+
+    /**
+     * 可用时间
+     */
+    private Date expTime;
+
+    /**
+     * 车次类型 team plus 3.5
+     */
+
+    private String type;
+
+    /**
+     * 限制次数
+     */
+    private Integer gptLimit;
+
+    /**
+     * 使用次数
+     */
+
+    private Integer use;
+
+    /**
+     * 是否为历史车次
+     */
+    private Boolean isHistory;
+}

+ 110 - 0
netflix-service/src/main/java/com/cyksj/redis/RedisService.java

@@ -5,6 +5,7 @@ import lombok.AllArgsConstructor;
 import lombok.Getter;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ZSetOperations;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.PostConstruct;
@@ -607,6 +608,37 @@ public class RedisService {
         }
     }
 
+    // 增加ZSet元素的分数
+    public Double zIncrementScore(String key, String value, double delta) {
+        try {
+            return redisTemplate.opsForZSet().incrementScore(key, value, delta);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+
+    // 封装获取ZSet分数操作
+    public Double zScore(String key, Object value) {
+        try {
+            return redisTemplate.opsForZSet().score(key, value);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    // 封装ZSet添加或更新分数操作
+    public Boolean zAddOrUpdateScore(String key, Object value, double score) {
+        try {
+            return redisTemplate.opsForZSet().add(key, value, score);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
     /**
      * 获取ZSet的大小
      */
@@ -618,7 +650,28 @@ public class RedisService {
             return null;
         }
     }
+    /**
+     * 获取ZSet的大小
+     */
+    public Long zCount(String key, long start, long end) {
+        try {
+            return redisTemplate.opsForZSet().count(key, start, end);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
 
+    // 封装获取ZSet范围内成员的方法
+    public Set<Object> zRange(String key, long start, long end) {
+        try {
+            ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
+            return zSetOperations.range(key, start, end);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
     /**
      * 删除ZSet中分数范围内的元素
      */
@@ -631,6 +684,60 @@ public class RedisService {
         }
     }
 
+    /**
+     * 返回有序集 key 中,所有分数介于 min 和 max 之间(包括等于 min 或 max)的成员。
+     * 有序集成员按分数值递增(从小到大)次序排列。
+     * 此方法还支持限制返回的元素数量。
+     *
+     * @param key 有序集合的key
+     * @param min 分数范围的最小值
+     * @param max 分数范围的最大值
+     * @param offset 开始返回的索引位置
+     * @param count 返回的最大元素数量
+     * @return 介于最小值和最大值之间的成员的集合
+     */
+    public Set<Object> zRangeByScore(String key, double min, double max, long offset, long count) {
+        return redisTemplate.opsForZSet().rangeByScore(key, min, max, offset, count);
+    }
+
+    /**
+     * 从ZSet获取所有成员及其分数
+     * @param key ZSet的键
+     * @return ZSet中所有成员及其分数的集合
+     */
+    public Set<ZSetOperations.TypedTuple<Object>> zRangeWithScores(String key, long start, long end){
+        return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
+    }
+
+    /**
+     * 检查指定值是否存在于有序集合中
+     * @param key
+     * @param value
+     * @return
+     */
+    public boolean checkValueExistsInZSet(String key, String value) {
+        // 检查指定值是否存在于有序集合中
+        return redisTemplate.opsForZSet().score(key, value) != null;
+    }
+
+    /**
+     * 从ZSet中删除指定的成员
+     *
+     * @param key ZSet的键
+     * @param value 要删除的成员值
+     * @return 被成功移除的成员数量
+     */
+    public Long zRemove(String key, Object value) {
+        try {
+            return redisTemplate.opsForZSet().remove(key, value);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0L;
+        }
+    }
+
+
+
 
     public Set<String> keys(String name) {
         return redisTemplate.keys(name);
@@ -712,6 +819,9 @@ public class RedisService {
         CHATGPT_CONVERSATION_LIMIT("chatgpt:conversation:limit:", "chatGpt 对话限制", 3 * 60 * 60L),
 
         CHATGPT_CAR_CONVERSATION_LIMIT("chatgpt:conversation:car:", "chatGpt 车队对话数量", 3 * 60 * 60L),
+        CHATGPT_CAR_SCORES("chatgpt:car:scores","chatGpt 车队分数", 48 * 60 * 60L),
+        CHATGPT_CAR_HIGH_CHAT("chatgpt:car:high:chat:%s","chatGpt gpt4 对话次数", 48 * 60 * 60L),
+        CHATGPT_CAR_LOW_CHAT("chatgpt:car:low:chat:%s","chatGpt 3.5 对话次数", 48 * 60 * 60L),
         ;
 
         private String name;

+ 28 - 1
netflix-service/src/main/java/com/cyksj/service/chatgpt/ChatGptAccountService.java

@@ -1,10 +1,15 @@
 package com.cyksj.service.chatgpt;
 
 import com.cyksj.model.entity.Account;
+import com.cyksj.model.entity.ChatgptSession;
 import com.cyksj.model.entity.ChatgptUser;
 import com.cyksj.model.request.gpt.ConversationRequest;
+import com.cyksj.model.response.ConversationLimitResponse;
+import com.cyksj.model.views.ChatGptUserView;
+import com.cyksj.model.views.ChatgptCarInfoView;
 
 import java.time.LocalDateTime;
+import java.util.Set;
 
 /**
  * @author chan
@@ -17,6 +22,8 @@ public interface ChatGptAccountService {
 
     String getLoginUrl(Long userId, Long relationId);
 
+    String getCarLoginUrl(Long userId, Long relationId, String carId);
+
     ChatgptUser findByUserTokenAndExpireTimeAfter(String userToken, LocalDateTime now);
 
     /**
@@ -25,7 +32,27 @@ public interface ChatGptAccountService {
      * @param model 对话模型
      * @return 是否限制
      */
-    boolean conversationLimit(String userToken, String model);
+    ConversationLimitResponse conversationLimit(String userToken, String model, String carId);
 
     void saveConversationRecord(String userToken, ConversationRequest conversationRequest);
+
+    /**
+     * 获取对话次数
+     * @param userToken 用户token
+     * @param limitTime 限制时间
+     * @return
+     */
+    Long getConversationCount(String userToken, Long limitTime);
+
+    ChatgptSession checkSession(String carId);
+
+    Boolean checkCarAccount(long userId, Long relationId);
+
+    ChatgptUser getCarChatGptUser(long userId, Long relationId);
+
+    Set<ChatgptCarInfoView> getCarInfoList(String userToken);
+
+    ChatGptUserView getUserInfo(long userId, Long relationId);
+
+    void genTitleSync(String messageId, String carid, String userToken);
 }

+ 370 - 40
netflix-service/src/main/java/com/cyksj/service/chatgpt/impl/ChatGptAccountServiceImpl.java

@@ -1,5 +1,6 @@
 package com.cyksj.service.chatgpt.impl;
 
+import cn.hutool.core.date.DateTime;
 import cn.hutool.core.lang.UUID;
 import cn.hutool.http.HttpRequest;
 import cn.hutool.http.HttpResponse;
@@ -7,21 +8,31 @@ import cn.hutool.http.HttpUtil;
 import cn.hutool.http.Method;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
 import com.cyksj.common.util.StringUtil;
 import com.cyksj.mapper.*;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.request.gpt.ConversationRequest;
+import com.cyksj.model.response.ConversationLimitResponse;
+import com.cyksj.model.views.ChatGptUserConversationRecordHistoryView;
+import com.cyksj.model.views.ChatGptUserView;
+import com.cyksj.model.views.ChatgptCarInfoView;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.chatgpt.ChatGptAccountService;
 import com.cyksj.service.user.UserBindRelationService;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.util.MapUtils;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.ZSetOperations;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.PostConstruct;
 import javax.imageio.stream.FileImageOutputStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -29,6 +40,8 @@ import java.time.LocalDateTime;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * @author chan
@@ -42,12 +55,17 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
     @Value("${chatgpt.domain}")
     private String GPT_DOMAIN;
 
+    @Value("${chatgpt.car.domain}")
+    private String CAR_GPT_DOMAIN;
+
     private static final String GPT_PROXY = "https://chat-chan-87jztgkf257d.xyhelper.net";
 
     private static final int MAX_REQUESTS = 40; // 3小时内最大请求次数
 
     private static final long WINDOW_SIZE = 3 * 60 * 60; // 3小时窗口的秒数
 
+    private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance();
+
     private final RedisService redisService;
 
     private final ChatgptUserMapper chatgptUserMapper;
@@ -66,6 +84,12 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
 
     private final ChatgptUserConversationRecordMapper chatgptUserConversationRecordMapper;
 
+    private final ChatgptUserConversationMapper chatgptUserConversationMapper;
+
+    private final AccountMapper accountMapper;
+
+    private final BeanSearcher beanSearcher;
+
     @Override
     public String addAccount(Account account) {
         if (isAccountExists(account)) {
@@ -169,13 +193,33 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
         GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId());
 
         if (goodsDonSku != null && goodsDonSku.getIsMirror()) {
-            ChatgptUser chatgptUser = getChatgptUser(userId, relationId, groupsRelation, groupsTrips);
+            ChatgptUser chatgptUser = getChatgptUser(userId, relationId, groupsRelation, groupsTrips, goodsDonSku);
             return GPT_DOMAIN + "/login_token?access_token=" + chatgptUser.getUserToken();
         } else {
             throw BusinessRuntimeException.getInstance("服务器出了点问题");
         }
     }
 
+    /**
+     * 获取车队登录url
+     *
+     * @param userId
+     * @param carId
+     * @return
+     */
+    @Override
+    public String getCarLoginUrl(Long userId, Long relationId, String carId) {
+        GroupsRelation groupsRelation = getGroupsRelation(userId, relationId);
+        GroupsTrips groupsTrips = getGroupsTrips(groupsRelation);
+        GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId());
+        if (goodsDonSku != null && goodsDonSku.getIsMirror() && goodsDonSku.getIsCar()) {
+            ChatgptUser chatgptUser = getChatgptCarUser(userId, relationId, groupsRelation, goodsDonSku);
+            return GPT_DOMAIN + "/auth//auth/logintoken?carid=" + carId + "&usertoken=" + chatgptUser.getUserToken();
+        } else {
+            throw BusinessRuntimeException.getInstance("服务器出了点问题");
+        }
+    }
+
     /**
      * 获取车位信息
      *
@@ -206,11 +250,22 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
         return groupsTrips;
     }
 
-    private ChatgptUser getChatgptUser(Long userId, Long relationId, GroupsRelation groupsRelation, GroupsTrips groupsTrips) {
+    private ChatgptUser getChatgptUser(Long userId, Long relationId, GroupsRelation groupsRelation, GroupsTrips groupsTrips, GoodsDonSku goodsDonSku) {
         ChatgptUser chatgptUser = chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getRelationId, relationId));
         User user = userMapper.selectById(userId);
         if (chatgptUser == null) {
-            chatgptUser = createChatgptUser(groupsRelation, groupsTrips, user);
+            chatgptUser = createChatgptUser(groupsRelation, groupsTrips, user, goodsDonSku);
+        } else {
+            updateChatgptUser(groupsRelation, user, chatgptUser);
+        }
+        return chatgptUser;
+    }
+
+    private ChatgptUser getChatgptCarUser(Long userId, Long relationId, GroupsRelation groupsRelation, GoodsDonSku goodsDonSku) {
+        ChatgptUser chatgptUser = chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getRelationId, relationId));
+        User user = userMapper.selectById(userId);
+        if (chatgptUser == null) {
+            chatgptUser = createChatgptUser(groupsRelation, null, user, goodsDonSku);
         } else {
             updateChatgptUser(groupsRelation, user, chatgptUser);
         }
@@ -220,12 +275,37 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
     /**
      * 创建chatgptUser
      */
-    private ChatgptUser createChatgptUser(GroupsRelation groupsRelation, GroupsTrips groupsTrips, User user) {
-        ChatgptSession chatgptSession = chatgptSessionMapper.selectOne(Wrappers.lambdaQuery(ChatgptSession.class).eq(ChatgptSession::getAccountId, groupsTrips.getAccountId()));
+    private ChatgptUser createChatgptUser(GroupsRelation groupsRelation, GroupsTrips groupsTrips, User user, GoodsDonSku goodsDonSku) {
         ChatgptUser chatgptUser = new ChatgptUser();
+        if (!goodsDonSku.getIsCar()) {
+            ChatgptSession chatgptSession = chatgptSessionMapper.selectOne(Wrappers.lambdaQuery(ChatgptSession.class).eq(ChatgptSession::getAccountId, groupsTrips.getAccountId()));
+            if (chatgptSession == null) {
+
+                Account account = accountMapper.selectById(groupsTrips.getAccountId());
+                String officialSession = "";
+                try {
+                    JSONObject loginResult = getLoginResult(account);
+                    if (StringUtils.isBlank(loginResult.getStr("accessToken"))) {
+                        throw BusinessRuntimeException.getInstance(loginResult.getStr("detail"));
+                    }
+                    officialSession = loginResult.toString();
+                } catch (Exception e) {
+                    throw BusinessRuntimeException.getInstance("配置账号错误 msg: " + e.getMessage());
+                }
+
+                createChatgptSession(account, officialSession);
+                chatgptSession = chatgptSessionMapper.selectOne(Wrappers.lambdaQuery(ChatgptSession.class).eq(ChatgptSession::getAccountId, groupsTrips.getAccountId()));
+
+            }
+            chatgptUser.setSessionId(chatgptSession.getId());
+        }
+        if (goodsDonSku.getIsCar()) {
+            chatgptUser.setIsCar(true);
+            chatgptUser.setLimitNum(goodsDonSku.getGptLimitNum());
+            chatgptUser.setLimitTime(goodsDonSku.getGptLimitTime());
+        }
         chatgptUser.setExpireTime(groupsRelation.getExpiryTime());
         chatgptUser.setIsPlus(1);
-        chatgptUser.setSessionId(chatgptSession.getId());
         chatgptUser.setName(user.getNickname());
         chatgptUser.setImg(getWxImg(user.getHeadimgurl(), user));
         chatgptUser.setRelationId(groupsRelation.getId());
@@ -270,79 +350,90 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
         return chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getUserToken, userToken).gt(ChatgptUser::getExpireTime, now));
     }
 
-    @Override
-    public boolean conversationLimit(String userToken, String model) {
-        boolean limit = true;
-        if("gpt-4".equals(model)){
-            ChatgptUser chatgptUser = chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getUserToken, userToken));
-            if (chatgptUser == null) {
-                return false;
-            }
-            //如果不为车队 直接返回
-            if(!chatgptUser.getIsCar()){
-                return true;
-            }
-            limit = isConversationAllowed(userToken, chatgptUser.getLimit(), chatgptUser.getLimitTime());
-            //车队次数记录
-
-        }
-        return limit;
-    }
-
     @Override
     public void saveConversationRecord(String userToken, ConversationRequest conversationRequest) {
-        ChatgptSession chatgptSession = chatgptSessionMapper.selectOne(Wrappers.lambdaQuery(ChatgptSession.class).eq(ChatgptSession::getCarId, conversationRequest.getCardId()));
+        ChatgptSession chatgptSession = chatgptSessionMapper.selectOne(Wrappers.lambdaQuery(ChatgptSession.class).eq(ChatgptSession::getCarId, conversationRequest.getCarId()));
         ChatgptUserConversationRecord chatgptUserConversationRecord = new ChatgptUserConversationRecord();
         chatgptUserConversationRecord.setUserToken(userToken);
         chatgptUserConversationRecord.setCarId(chatgptSession.getCarId());
-        chatgptUserConversationRecord.setCarName(chatgptSession.getCardName());
-        if(StringUtils.isBlank(conversationRequest.getConversation_id())){
+        chatgptUserConversationRecord.setCarName(chatgptSession.getCarName());
+        if (StringUtils.isBlank(conversationRequest.getConversation_id())) {
             chatgptUserConversationRecord.setMessageId(conversationRequest.getMessages().get(0).getId());
-        }else {
+        } else {
             chatgptUserConversationRecord.setConversationId(conversationRequest.getConversation_id());
         }
 
         chatgptUserConversationRecord.setModel(conversationRequest.getModel());
         chatgptUserConversationRecordMapper.insert(chatgptUserConversationRecord);
+
+        updateExperienceAndScore(conversationRequest.getCarId(), !"text-davinci-002-render-sha".equals(conversationRequest.getModel()), System.currentTimeMillis());
+    }
+
+
+    @Override
+    public ConversationLimitResponse conversationLimit(String userToken, String model, String carId) {
+        ConversationLimitResponse conversationLimitResponse = new ConversationLimitResponse();
+        conversationLimitResponse.setLimited(false);
+        if ("gpt-4".equals(model)) {
+            ChatgptUser chatgptUser = chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getUserToken, userToken));
+            if (chatgptUser == null) {
+                conversationLimitResponse.setLimited(true);
+            }
+            //如果不为车队 直接返回
+            if (!chatgptUser.getIsCar()) {
+                return conversationLimitResponse;
+            }
+            conversationLimitResponse = isConversationAllowed(userToken, chatgptUser.getLimitNum(), chatgptUser.getLimitTime());
+            //车队次数记录
+            cardConversationRecord(carId);
+        }
+
+        return conversationLimitResponse;
     }
 
+
     /**
      * 检查是否允许进行进行提问
      *
      * @param userToken 用户token
      * @return true 如果允许请求,false 如果请求被限制
      */
-    public boolean isConversationAllowed(String userToken, int limit, Long limitTime) {
+    public ConversationLimitResponse isConversationAllowed(String userToken, int limit, Long limitTime) {
         String key = RedisService.key.CHATGPT_CONVERSATION_LIMIT.getName() + ":" + userToken;
         long currentTimeMillis = System.currentTimeMillis();
         long windowStartMillis = currentTimeMillis - (limitTime * 60 * 60) * 1000;
-
+        ConversationLimitResponse conversationLimitResponse = new ConversationLimitResponse();
         // 清除时间窗口之前的请求记录
         redisService.zRemoveRangeByScore(key, 0, windowStartMillis);
 
         Long currentSize = redisService.zCard(key);
         if (currentSize != null && currentSize >= limit) {
             // 如果当前请求次数超过限制,则拒绝请求
-            return false;
+            Set<Object> times = redisService.zRangeByScore(key, 0, currentTimeMillis, 0, 1);
+            Long oldestTime = (Long) times.stream().findFirst().orElse(null);
+            if (oldestTime != null) {
+                // 下一次可用时间是最早请求时间之后的3小时
+                long nextAvailableTime = oldestTime + (limitTime * 60 * 60 * 1000);
+                conversationLimitResponse.setNextAvailableTime(nextAvailableTime);
+            }
+            conversationLimitResponse.setLimited(true);
+            return conversationLimitResponse;
         } else {
             // 如果未超过限制,记录当前请求的时间戳
             redisService.zAdd(key, currentTimeMillis, currentTimeMillis);
             // 设置ZSet的过期时间,窗口大小加上一段冗余时间
             redisService.expire(key, (limitTime * 60 * 60) + 20);
-            return true;
+            conversationLimitResponse.setLimited(false);
+            return conversationLimitResponse;
         }
     }
 
 
     /**
      * 记录车队的提问次数
-     * @param userToken
-     * @param limit
-     * @param limitTime
-     * @return
      */
-    public boolean cardConversationRecord(String cardid) {
-        String key = RedisService.key.CHATGPT_CAR_CONVERSATION_LIMIT.getName() + ":" + cardid;
+    public boolean cardConversationRecord(String carid) {
+        String key = RedisService.key.CHATGPT_CAR_CONVERSATION_LIMIT.getName() + ":" + carid;
         long currentTimeMillis = System.currentTimeMillis();
         long windowStartMillis = currentTimeMillis - (WINDOW_SIZE) * 1000;
 
@@ -368,10 +459,30 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
      * @param userToken 用户token
      * @return 滑动窗口内的请求次数
      */
+    @Override
     public Long getConversationCount(String userToken, Long limitTime) {
         String key = RedisService.key.CHATGPT_CONVERSATION_LIMIT.getName() + ":" + userToken;
         long currentTimeMillis = System.currentTimeMillis();
-        long windowStartMillis = currentTimeMillis -  (limitTime * 60 * 60) * 1000;
+        long windowStartMillis = currentTimeMillis - (limitTime * 60 * 60) * 1000;
+
+        // 清除时间窗口之前的请求记录(可选,根据需要决定是否在此处清理过期记录)
+        redisService.zRemoveRangeByScore(key, 0, windowStartMillis);
+
+        // 获取当前窗口内的请求次数
+        Long currentSize = redisService.zCard(key);
+        return currentSize != null ? currentSize : 0L;
+    }
+
+    /**
+     * 获取指定车队ID在滑动窗口内的提问次数
+     *
+     * @param carId 车队ID
+     * @return 滑动窗口内的请求次数
+     */
+    private Long getCarConversationCount(String carId, Long limitTime) {
+        String key = RedisService.key.CHATGPT_CAR_CONVERSATION_LIMIT.getName() + ":" + carId;
+        long currentTimeMillis = System.currentTimeMillis();
+        long windowStartMillis = currentTimeMillis - (limitTime * 60 * 60) * 1000;
 
         // 清除时间窗口之前的请求记录(可选,根据需要决定是否在此处清理过期记录)
         redisService.zRemoveRangeByScore(key, 0, windowStartMillis);
@@ -381,5 +492,224 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
         return currentSize != null ? currentSize : 0L;
     }
 
+    @Override
+    public ChatgptSession checkSession(String carId) {
+        ChatgptSession chatgptSession = chatgptSessionMapper.selectOne(Wrappers.lambdaQuery(ChatgptSession.class).eq(ChatgptSession::getCarId, carId).eq(ChatgptSession::getIsCar, true).last(" limit 1"));
+        if (chatgptSession == null) {
+            throw BusinessRuntimeException.getInstance("车队不存在");
+        }
+        return chatgptSession;
+    }
+
+
+    private Long carOaiLimit(String carId) {
+        if (redisService.hasKey("clears_in:" + carId)) {
+            return redisService.getExpire("clears_in:" + carId);
+        }
+        return 0L;
+    }
+
+
+    @Override
+    public Boolean checkCarAccount(long userId, Long relationId) {
+        GroupsRelation groupsRelation = getGroupsRelation(userId, relationId);
+        GroupsTrips groupsTrips = getGroupsTrips(groupsRelation);
+        GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId());
+
+        if (goodsDonSku != null && goodsDonSku.getIsMirror() && goodsDonSku.getIsCar()) {
+            ChatgptUser chatgptUser = getChatgptCarUser(userId, relationId, groupsRelation, goodsDonSku);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public ChatgptUser getCarChatGptUser(long userId, Long relationId) {
+        GroupsRelation groupsRelation = getGroupsRelation(userId, relationId);
+        GroupsTrips groupsTrips = getGroupsTrips(groupsRelation);
+        GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId());
+
+        if (goodsDonSku != null && goodsDonSku.getIsMirror() && goodsDonSku.getIsCar()) {
+            ChatgptUser chatgptUser = getChatgptCarUser(userId, relationId, groupsRelation, goodsDonSku);
+            return chatgptUser;
+        }
+        return null;
+    }
+
+    /**
+     * 获取车队信息
+     */
+    @Override
+    public Set<ChatgptCarInfoView> getCarInfoList(String userToken) {
+        List<ChatGptUserConversationRecordHistoryView> search = beanSearcher.searchAll(ChatGptUserConversationRecordHistoryView.class, MapUtils.builder().field("userToken", userToken).limit(0, 2).build());
+        Set<ChatgptCarInfoView> res = search.stream()
+                .map((historyView) -> {
+                    ChatgptCarInfoView chatgptCarInfoView = buildChatgptCarInfoView(historyView.getCarId(), redisService.zScore(RedisService.key.CHATGPT_CAR_SCORES.getName(), historyView.getCarId()));
+                    chatgptCarInfoView.setIsHistory(true);
+                    return chatgptCarInfoView;
+                }).collect(Collectors.toSet());
+
+        Set<ChatgptCarInfoView> lowestScoreFleets = getLowestScoreFleets(10);
+
+        res.addAll(lowestScoreFleets);
+
+        return res;
+    }
+
+
+    // 更新体验并计算评分
+    public void updateExperienceAndScore(String carId, boolean isHighLevel, long timestamp) {
+        // 定义键名
+        String key = isHighLevel ? RedisService.key.CHATGPT_CAR_HIGH_CHAT.getName() + carId : RedisService.key.CHATGPT_CAR_LOW_CHAT.getName() + carId;
+        double scoreToAdd = isHighLevel ? 2.0 : 1.0; // 分数更新规则
+
+        // 更新体验数据
+        redisService.zAdd(key, timestamp, String.valueOf(timestamp));
+
+        // 更新车队评分
+        redisService.zIncrementScore(RedisService.key.CHATGPT_CAR_SCORES.getName(), carId, scoreToAdd);
+
+        // 清理旧数据(可选)和重新计算评分(根据需要实现)
+        cleanupOldExperiencesAndRecalculateScore(carId, timestamp);
+    }
+
+    // 清理旧数据和重新计算评分
+    public void cleanupOldExperiencesAndRecalculateScore(String carId, long currentTimestamp) {
+        long threeHoursAgo = currentTimestamp - (3 * 60 * 60 * 1000); // 3小时前的时间戳
+
+        // 清理高级体验旧数据
+        redisService.zRemoveRangeByScore(RedisService.key.CHATGPT_CAR_HIGH_CHAT.getName() + carId, 0, threeHoursAgo);
+
+        // 清理低级体验旧数据
+        redisService.zRemoveRangeByScore(RedisService.key.CHATGPT_CAR_LOW_CHAT.getName() + carId, 0, threeHoursAgo);
+
+        // 重新计算评分
+        recalculateScore(carId, currentTimestamp);
+    }
+
+
+    // 重新计算指定车队的评分
+    private void recalculateScore(String carId, long currentTimestamp) {
+        // 实际应用中,你需要根据高级体验和低级体验的数量重新计算得分
+        Double highExperienceScore = (double) redisService.zCount(RedisService.key.CHATGPT_CAR_HIGH_CHAT.getName() + carId, currentTimestamp - (3 * 60 * 60 * 1000), currentTimestamp);
+        Double lowExperienceScore = (double) redisService.zCount(RedisService.key.CHATGPT_CAR_LOW_CHAT.getName() + carId, currentTimestamp - (3 * 60 * 60 * 1000), currentTimestamp) / 2;
+        double newScore = highExperienceScore + lowExperienceScore;
+        redisService.zAdd(RedisService.key.CHATGPT_CAR_SCORES.getName(), newScore, carId);
+    }
+
+
+    // 获取得分最低的N个车队的方法
+    public Set<ChatgptCarInfoView> getLowestScoreFleets(int count) {
+        Set<ZSetOperations.TypedTuple<Object>> lowestScorecarIds;
+        Long fleetsSize = redisService.zCard(RedisService.key.CHATGPT_CAR_SCORES.getName());
+        // 构建ChatgptCarInfoView集合
+        if (fleetsSize != null && fleetsSize > 10) {
+            TASK_EXECUTOR.execute(() -> {
+                initFleets(true);
+            });
+        } else {
+            initFleets(false);
+        }
+        lowestScorecarIds = redisService.zRangeWithScores(RedisService.key.CHATGPT_CAR_SCORES.getName(), 0L, count - 1);
+
+        return lowestScorecarIds.stream()
+                .map(typedTuple -> {
+                    String value = StringUtil.getString(typedTuple.getValue());
+                    Double score = typedTuple.getScore(); // 获取分数
+                    // 根据需要处理value和score
+                    return buildChatgptCarInfoView(value, score); // 假设这个方法现在也接收分数
+                })
+                .collect(Collectors.toSet());
+    }
+
+    public void initFleets(Boolean flag) {
+        LambdaQueryWrapper<ChatgptSession> wrapper = Wrappers.lambdaQuery(ChatgptSession.class);
+        if (flag) {
+            Set<ZSetOperations.TypedTuple<Object>> fleets = redisService.zRangeWithScores(RedisService.key.CHATGPT_CAR_SCORES.getName(), 0L, -1);
+            List<Object> collect = fleets.stream().map(ZSetOperations.TypedTuple::getValue).collect(Collectors.toList());
+            wrapper.notIn(collect.size() > 0, ChatgptSession::getCarId, collect);
+        }
+        //如果存在未存在redis中的车辆则同步进 chatgpt:car:scores
+        List<ChatgptSession> chatgptSessions = chatgptSessionMapper.selectList(wrapper.eq(ChatgptSession::getIsCar, true));
+
+        chatgptSessions.forEach((chatgptSession) -> {
+            if (!redisService.checkValueExistsInZSet(RedisService.key.CHATGPT_CAR_SCORES.getName(), chatgptSession.getCarId())) {
+                redisService.zAdd(RedisService.key.CHATGPT_CAR_SCORES.getName(), 0, chatgptSession.getCarId());
+            }
+        });
+
+    }
+
+
+    // 构建ChatgptCarInfoView对象
+    private ChatgptCarInfoView buildChatgptCarInfoView(String carId, Double score) {
+        // 在这里根据carId获取相关信息并填充到ChatgptCarInfoView对象中
+        ChatgptCarInfoView view = new ChatgptCarInfoView();
+        view.setCarId(carId);
+        // 假设以下方法从Redis或其他服务获取数据
+        view.setStatus(score >= 50 ? "繁忙" : "空闲"); // 或“繁忙”
+        view.setType("plus");
+        view.setGptLimit(40); // 假设值
+        int use = getCarConversationCount(carId, 3L).intValue();
+        view.setUse(Math.min(use, 40));
+        Long aLong = carOaiLimit(carId);
+        if (aLong != 0L) {
+            view.setStatus("停运");
+            view.setExpTime(new DateTime(System.currentTimeMillis() + aLong * 1000));
+        }
+        // 设置其他必要的属性...
+        return view;
+    }
+
+    @Override
+    public ChatGptUserView getUserInfo(long userId, Long relationId) {
+        if (checkCarAccount(userId, relationId)) {
+            GroupsRelation groupsRelation = getGroupsRelation(userId, relationId);
+            GroupsTrips groupsTrips = getGroupsTrips(groupsRelation);
+            GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId());
+            ChatgptUser chatgptUser = chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getRelationId, relationId));
+            return ChatGptUserView.builder()
+                    .skuName(goodsDonSku.getGName())
+                    .expireTime(chatgptUser.getExpireTime())
+                    .limitNum(chatgptUser.getLimitNum())
+                    .limitTime(chatgptUser.getLimitTime())
+                    .use(getConversationCount(chatgptUser.getUserToken(), chatgptUser.getLimitTime()))
+                    .build();
+        } else {
+            throw BusinessRuntimeException.getInstance("您还未购买该车票");
+        }
+    }
+
+    @Override
+    public void genTitleSync(String messageId, String carid, String userToken) {
+        //同步对话
+        ChatgptUserConversationRecord chatgptUserConversationRecord = chatgptUserConversationRecordMapper.selectOne(Wrappers.lambdaQuery(ChatgptUserConversationRecord.class).eq(ChatgptUserConversationRecord::getMessageId, messageId));
+        if (chatgptUserConversationRecord != null) {
+            if (StringUtils.isBlank(chatgptUserConversationRecord.getConversationId())) {
+                ChatgptUserConversation conversation = chatgptUserConversationMapper.selectOne(Wrappers.lambdaQuery(ChatgptUserConversation.class).eq(ChatgptUserConversation::getMessageId, messageId).last(" limit 1"));
+                if (conversation != null) {
+                    chatgptUserConversationRecord.setConversationId(conversation.getConversationId());
+                    chatgptUserConversationRecordMapper.updateById(chatgptUserConversationRecord);
+                }
+            }
+        }
+    }
+
+    @PostConstruct
+    public void init() {
+        //如果存在未存在redis中的车辆则同步进 chatgpt:car:scores
+        TASK_EXECUTOR.execute(() -> {
+            Set<ZSetOperations.TypedTuple<Object>> lowestScorecarIds = redisService.zRangeWithScores(RedisService.key.CHATGPT_CAR_SCORES.getName(), 0L, -1);
+            List<Object> collect = lowestScorecarIds.stream().map(ZSetOperations.TypedTuple::getValue).collect(Collectors.toList());
+            List<ChatgptSession> chatgptSessions = chatgptSessionMapper.selectList(Wrappers.lambdaQuery(ChatgptSession.class).notIn(collect.size() > 0, ChatgptSession::getCarId, collect).eq(ChatgptSession::getIsCar, true));
+            chatgptSessions.forEach((chatgptSession) -> {
+                if (!redisService.checkValueExistsInZSet(RedisService.key.CHATGPT_CAR_SCORES.getName(), chatgptSession.getCarId())) {
+                    redisService.zAdd(RedisService.key.CHATGPT_CAR_SCORES.getName(), 0, chatgptSession.getCarId());
+                }
+            });
+        });
+    }
+
 }
 

+ 85 - 30
netflix-web/src/main/java/com/cyksj/web/controller/mirror/MirrorController.java

@@ -1,17 +1,24 @@
 package com.cyksj.web.controller.mirror;
 
+import cn.hutool.json.JSONObject;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.common.util.IoKit;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
-import com.cyksj.model.entity.ChatgptSession;
 import com.cyksj.model.entity.ChatgptUser;
 import com.cyksj.model.request.gpt.ConversationRequest;
+import com.cyksj.model.response.ConversationLimitResponse;
+import com.cyksj.model.views.ChatGptUserConversationRecordHistoryView;
+import com.cyksj.model.views.ChatGptUserView;
+import com.cyksj.model.views.ChatgptCarInfoView;
 import com.cyksj.service.chatgpt.ChatGptAccountService;
 import com.cyksj.web.util.StpUserUtil;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.SearchResult;
+import com.ejlchina.searcher.util.MapBuilder;
+import com.ejlchina.searcher.util.MapUtils;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
@@ -19,6 +26,7 @@ import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.time.LocalDateTime;
+import java.util.Set;
 
 /**
  * /server/镜像服务
@@ -38,6 +46,9 @@ public class MirrorController {
 
     private final HttpServletRequest request;
 
+    private final BeanSearcher beanSearcher;
+
+
 
     /**
      * GPT车票跳转登录
@@ -52,29 +63,26 @@ public class MirrorController {
     }
 
     /**
-     * GPT车票跳转登录
-     * @param userToken 用户token
-     * @param carId 车票id
-     * @return 登陆结果
+     * GPT车队跳转登录
+     *
+     * @param carId 车队id
      */
-    @GetMapping("/gpt/oauth")
-    public Result<String> gptOauth(@RequestParam("usertoken") String userToken, @RequestParam("carid") String carId) {
-        try {
-            ChatgptUser user = chatGptAccountService.findByUserTokenAndExpireTimeAfter(userToken, LocalDateTime.now());
-            if (user == null) {
-                return GatewayResponse.SUCCESS.newBuilder().setMsg("用户不存在或已过期").setCode(0).toResult();
-            }
-
-            ChatgptSession session = chatGptAccountService.checkSession(carId);
-            if (user.isPlus() || (user.isPlus() == carInfo.isPlus())) {
-                return GatewayResponse.SUCCESS.newBuilder().setMsg("登陆成功").setCode(1).toResult();
-            } else {
-                return GatewayResponse.FAIL.newBuilder().setMsg("您不是PLUS用户,无法登陆该车").setCode(0).toResult();
-            }
-        } catch (Exception e) {
-            logger.error("服务器错误", e);
-            return GatewayResponse.FAIL.newBuilder().setMsg("服务器错误").setCode(0).toResult();
-        }
+    @GetMapping("/chatGptMirror/{relationId}/{carId}")
+    public Result<String> chatGPtCarLogin(@PathVariable Long relationId, @PathVariable String carId) throws IOException {
+        Long userId = StpUserUtil.getLoginIdAsLong();
+        chatGptAccountService.checkCarAccount(userId, relationId);
+        String url = chatGptAccountService.getCarLoginUrl(userId, relationId, carId);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(url);
+    }
+
+    @GetMapping("/gpt/genTitleSync")
+    public Result<String> genTitleSync(String messageId){
+        //1.从request获取请求头Authorization 并取 值内 'Bearer ' 后的值为usertoken
+        String authorization = request.getHeader("Authorization");
+        String carid = request.getHeader("Carid");
+        String userToken = authorization.substring(7);
+        chatGptAccountService.genTitleSync(messageId, carid, userToken);
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
     }
 
 
@@ -86,7 +94,7 @@ public class MirrorController {
         //1.从request获取请求头Authorization 并取 值内 'Bearer ' 后的值为usertoken
         String authorization = request.getHeader("Authorization");
         String carid = request.getHeader("Carid");
-        conversationRequest.setCardId(carid);
+        conversationRequest.setCarId(carid);
         String userToken = authorization.substring(7);
         //2.根据usertoken 查询 chatgpt_user 表中的记录
         ChatgptUser user = chatGptAccountService.findByUserTokenAndExpireTimeAfter(userToken, LocalDateTime.now());
@@ -95,15 +103,19 @@ public class MirrorController {
             response.setStatus(401);
         }
         //4.获取gpt-4 的规则限制
-        boolean flag = chatGptAccountService.conversationLimit(userToken, conversationRequest.getModel());
+        //text-davinci-002-render-sha 3.5
+        ConversationLimitResponse conversationLimitResponse = chatGptAccountService.conversationLimit(userToken, conversationRequest.getModel(), conversationRequest.getCarId());
         //记录提问时间,车次,标题和模型
         chatGptAccountService.saveConversationRecord(userToken, conversationRequest);
         OutputStream out = null;
         String messgae = "";
-        if(flag){
+        if (conversationLimitResponse.isLimited()) {
             response.setStatus(429);
-            messgae = "对话限制";
-        }else {
+            String json = "{\"detail\":{\"message\":\"您的账号已达到GPT-4的使用上限。您现在可以继续使用默认模型,或者重试在\",\"code\":\"model_cap_exceeded\",\"clears_in\":2687}}";
+            JSONObject res = new JSONObject(json);
+            res.putOpt("clears_in",conversationLimitResponse.getNextAvailableTime()/1000);
+            messgae = res.toString();
+        } else {
             response.setStatus(200);
         }
         //5.获取 conversationRequest 中的model 字段,判断是否为 gpt-4 如果为gpt-4 执行 查看是否达到限制方法
@@ -120,5 +132,48 @@ public class MirrorController {
     }
 
 
-    public Result<>
+    /**
+     * 获取车队列表
+     * @param relationId
+     * @return
+     */
+    @GetMapping("/gpt/cars")
+    public Result<Set<ChatgptCarInfoView>> getCarInfoList(Long relationId) {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        //查看用户是否存在车票
+        ChatgptUser carChatGptUser = chatGptAccountService.getCarChatGptUser(userId, relationId);
+        if (carChatGptUser == null) {
+            throw BusinessRuntimeException.getInstance("您还未购买车票");
+        }
+
+        Set<ChatgptCarInfoView> carInfoList = chatGptAccountService.getCarInfoList(carChatGptUser.getUserToken());
+        return GatewayResponse.SUCCESS.newBuilder().toResult(carInfoList);
+    }
+
+
+    /**
+     * 获取gpt车票信息
+     */
+    @GetMapping("/gpt/userInfo")
+    public Result<ChatGptUserView> getUserInfo(Long relationId) {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        ChatGptUserView user = chatGptAccountService.getUserInfo(userId, relationId);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(user);
+    }
+
+    /**
+     * 获取车队历史记录
+     */
+    @GetMapping("/gpt/car/history")
+    public Result<SearchResult<ChatGptUserConversationRecordHistoryView>> getCarHistory(Long relationId) {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        ChatgptUser carChatGptUser = chatGptAccountService.getCarChatGptUser(userId, relationId);
+        if(carChatGptUser == null){
+            throw BusinessRuntimeException.getInstance("车票出现了异常.");
+        }
+        MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap()).field("r.user_token", carChatGptUser.getUserToken());
+        SearchResult<ChatGptUserConversationRecordHistoryView> search = beanSearcher.search(ChatGptUserConversationRecordHistoryView.class, builder.build());
+        return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+    }
+
 }

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
netflix-web/src/main/resources/application-dev.yml


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
netflix-web/src/main/resources/application-prd.yml


Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác