|
|
@@ -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,25 +8,38 @@ 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.SearchResult;
|
|
|
+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;
|
|
|
-import java.util.HashMap;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Map;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
* @author chan
|
|
|
@@ -39,8 +53,19 @@ 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;
|
|
|
|
|
|
private final ChatgptSessionMapper chatgptSessionMapper;
|
|
|
@@ -55,6 +80,13 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
|
|
|
|
|
|
private final UserBindRelationService userBindRelationService;
|
|
|
|
|
|
+ private final ChatgptUserConversationRecordMapper chatgptUserConversationRecordMapper;
|
|
|
+
|
|
|
+ private final ChatgptUserConversationMapper chatgptUserConversationMapper;
|
|
|
+
|
|
|
+ private final AccountMapper accountMapper;
|
|
|
+
|
|
|
+ private final BeanSearcher beanSearcher;
|
|
|
|
|
|
@Override
|
|
|
public String addAccount(Account account) {
|
|
|
@@ -80,6 +112,24 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
|
|
|
return refreshToken;
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public String getGptSession(String account, String password) {
|
|
|
+ String officialSession = "";
|
|
|
+ try {
|
|
|
+ Account at = new Account();
|
|
|
+ at.setAccount(account);
|
|
|
+ at.setPassword(password);
|
|
|
+ JSONObject loginResult = getLoginResult(at);
|
|
|
+ if (StringUtils.isBlank(loginResult.getStr("accessToken"))) {
|
|
|
+ throw BusinessRuntimeException.getInstance(loginResult.getStr("detail"));
|
|
|
+ }
|
|
|
+ officialSession = loginResult.toString();
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw BusinessRuntimeException.getInstance("登录获取token错误 error:" + e.getMessage());
|
|
|
+ }
|
|
|
+ return officialSession;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 判断账号是否存在
|
|
|
*
|
|
|
@@ -159,13 +209,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 CAR_GPT_DOMAIN + "/auth/logintoken?carid=" + carId + "&usertoken=" + chatgptUser.getUserToken();
|
|
|
+ } else {
|
|
|
+ throw BusinessRuntimeException.getInstance("服务器出了点问题");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 获取车位信息
|
|
|
*
|
|
|
@@ -196,11 +266,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, 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, groupsTrips, user);
|
|
|
+ chatgptUser = createChatgptUser(groupsRelation, null, user, goodsDonSku);
|
|
|
} else {
|
|
|
updateChatgptUser(groupsRelation, user, chatgptUser);
|
|
|
}
|
|
|
@@ -210,12 +291,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 synchronized 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());
|
|
|
@@ -255,5 +361,407 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public ChatgptUser findByUserTokenAndExpireTimeAfter(String userToken, LocalDateTime now) {
|
|
|
+ return chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getUserToken, userToken).gt(ChatgptUser::getExpireTime, now));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void saveConversationRecord(String userToken, ConversationRequest conversationRequest) {
|
|
|
+ LambdaQueryWrapper<ChatgptSession> wrapper = Wrappers.lambdaQuery(ChatgptSession.class);
|
|
|
+
|
|
|
+ if(StringUtils.isNotBlank(conversationRequest.getCarId())){
|
|
|
+ wrapper.eq(ChatgptSession::getCarId, conversationRequest.getCarId());
|
|
|
+ }else {
|
|
|
+ ChatgptUser chatgptUser = chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getUserToken, userToken));
|
|
|
+ if (chatgptUser.getSessionId() != null) {
|
|
|
+ wrapper.eq(ChatgptSession::getId, chatgptUser.getSessionId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ChatgptSession chatgptSession = chatgptSessionMapper.selectOne(wrapper);
|
|
|
+ ChatgptUserConversationRecord chatgptUserConversationRecord = new ChatgptUserConversationRecord();
|
|
|
+ chatgptUserConversationRecord.setUserToken(userToken);
|
|
|
+ chatgptUserConversationRecord.setCarId(chatgptSession.getCarId());
|
|
|
+ chatgptUserConversationRecord.setCarName(chatgptSession.getCarName());
|
|
|
+ if (StringUtils.isBlank(conversationRequest.getConversation_id())) {
|
|
|
+ chatgptUserConversationRecord.setMessageId(conversationRequest.getMessages().get(0).getId());
|
|
|
+ } else {
|
|
|
+ chatgptUserConversationRecord.setConversationId(conversationRequest.getConversation_id());
|
|
|
+ }
|
|
|
+
|
|
|
+ chatgptUserConversationRecord.setModel(conversationRequest.getModel());
|
|
|
+ chatgptUserConversationRecordMapper.insert(chatgptUserConversationRecord);
|
|
|
+
|
|
|
+ if(StringUtils.isNotBlank(conversationRequest.getCarId())){
|
|
|
+ updateExperienceAndScore(conversationRequest.getCarId(), !"text-davinci-002-render-sha".equals(conversationRequest.getModel()), System.currentTimeMillis());
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ConversationLimitResponse conversationLimit(String userToken, String model, String carId, ChatgptUser chatgptUser, Boolean isCar) {
|
|
|
+ ConversationLimitResponse conversationLimitResponse = new ConversationLimitResponse();
|
|
|
+ conversationLimitResponse.setLimited(false);
|
|
|
+ if (!"text-davinci-002-render-sha".equals(model)) {
|
|
|
+ //如果不为车队 直接返回
|
|
|
+ if (chatgptUser.getIsCar()) {
|
|
|
+ conversationLimitResponse = isConversationAllowed(userToken, chatgptUser.getLimitNum(), chatgptUser.getLimitTime());
|
|
|
+ }
|
|
|
+ if(carId == null){
|
|
|
+ if (StringUtils.isNotBlank(userToken)) {
|
|
|
+ if (chatgptUser.getSessionId() != null) {
|
|
|
+ ChatgptSession chatgptSession = chatgptSessionMapper.selectById(chatgptUser.getSessionId());
|
|
|
+ if(chatgptSession != null){
|
|
|
+ carId = chatgptSession.getCarId();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //车队次数记录
|
|
|
+ String finalCarId = carId;
|
|
|
+ TASK_EXECUTOR.execute(() -> {
|
|
|
+ cardConversationRecord(finalCarId);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ return conversationLimitResponse;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查是否允许进行进行提问
|
|
|
+ *
|
|
|
+ * @param userToken 用户token
|
|
|
+ * @return true 如果允许请求,false 如果请求被限制
|
|
|
+ */
|
|
|
+ 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) {
|
|
|
+ // 如果当前请求次数超过限制,则拒绝请求
|
|
|
+ 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);
|
|
|
+ conversationLimitResponse.setLimited(false);
|
|
|
+ return conversationLimitResponse;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 记录车队的提问次数
|
|
|
+ */
|
|
|
+ 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;
|
|
|
+
|
|
|
+ // 清除时间窗口之前的请求记录
|
|
|
+ redisService.zRemoveRangeByScore(key, 0, windowStartMillis);
|
|
|
+
|
|
|
+ Long currentSize = redisService.zCard(key);
|
|
|
+ if (currentSize != null && currentSize >= MAX_REQUESTS) {
|
|
|
+ // 如果当前请求次数超过限制,则拒绝请求
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ // 如果未超过限制,记录当前请求的时间戳
|
|
|
+ redisService.zAdd(key, currentTimeMillis, currentTimeMillis);
|
|
|
+ // 设置ZSet的过期时间,窗口大小加上一段冗余时间
|
|
|
+ redisService.expire(key, (WINDOW_SIZE * 60 * 60) + 20);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取指定用户ID在滑动窗口内的提问次数
|
|
|
+ *
|
|
|
+ * @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;
|
|
|
+
|
|
|
+ // 清除时间窗口之前的请求记录(可选,根据需要决定是否在此处清理过期记录)
|
|
|
+ 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);
|
|
|
+
|
|
|
+ // 获取当前窗口内的请求次数
|
|
|
+ Long currentSize = redisService.zCard(key);
|
|
|
+ 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("chatgpt:clears_in:" + carId)) {
|
|
|
+ return redisService.getExpire("chatgpt: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) {
|
|
|
+ SearchResult<ChatGptUserConversationRecordHistoryView> search = beanSearcher.search(ChatGptUserConversationRecordHistoryView.class, MapUtils.builder().field("userToken", userToken).limit(0, 2).build());
|
|
|
+ Set<ChatgptCarInfoView> res = search.getDataList().stream()
|
|
|
+ .map((historyView) -> {
|
|
|
+ ChatgptCarInfoView chatgptCarInfoView = buildChatgptCarInfoView(historyView.getCarId(), historyView.getCarName(), historyView.getIsPLus(), redisService.zScore(RedisService.key.CHATGPT_CAR_SCORES.getName(), historyView.getCarId()));
|
|
|
+ chatgptCarInfoView.setIsHistory(true);
|
|
|
+ chatgptCarInfoView.setScore(Math.min(redisService.zScore(RedisService.key.CHATGPT_CAR_SCORES.getName(), historyView.getCarId()), 100));
|
|
|
+
|
|
|
+ return chatgptCarInfoView;
|
|
|
+ }).collect(Collectors.toCollection(LinkedHashSet::new));
|
|
|
+
|
|
|
+ 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) * 2;
|
|
|
+ Double lowExperienceScore = (double) redisService.zCount(RedisService.key.CHATGPT_CAR_LOW_CHAT.getName() + carId, currentTimestamp - (3 * 60 * 60 * 1000), currentTimestamp);
|
|
|
+ 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);
|
|
|
+ Map<Object, Double> collect = lowestScorecarIds.stream().collect(Collectors.toMap(ZSetOperations.TypedTuple::getValue, ZSetOperations.TypedTuple::getScore));
|
|
|
+ List<ChatgptSession> chatgptSessions = chatgptSessionMapper.selectList(Wrappers.lambdaQuery(ChatgptSession.class).in(ChatgptSession::getCarId, collect.keySet()));
|
|
|
+ return chatgptSessions.stream().map((chatgptSession)-> buildChatgptCarInfoView(chatgptSession.getCarId(),chatgptSession.getCarName(), chatgptSession.getIsPlus(), collect.get(chatgptSession.getCarId())))
|
|
|
+ .sorted(Comparator.comparing(ChatgptCarInfoView::getScore)).collect(Collectors.toCollection(LinkedHashSet::new));
|
|
|
+ }
|
|
|
+
|
|
|
+ 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, String carName, Integer isPlus, Double score) {
|
|
|
+ // 在这里根据carId获取相关信息并填充到ChatgptCarInfoView对象中
|
|
|
+ ChatgptCarInfoView view = new ChatgptCarInfoView();
|
|
|
+ view.setCarId(carId);
|
|
|
+ // 假设以下方法从Redis或其他服务获取数据
|
|
|
+ view.setScore(Math.min(score,100));
|
|
|
+ view.setStatus(score >= 50 ? "繁忙" : "空闲"); // 或“繁忙”
|
|
|
+
|
|
|
+ view.setType(isPlus == 1 ? "plus" : "3.5");
|
|
|
+ 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));
|
|
|
+ }
|
|
|
+ view.setCarName(carName);
|
|
|
+ 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.getSubTitle())
|
|
|
+ .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 conversationId, String carid, String userToken) {
|
|
|
+ //同步对话
|
|
|
+ if (!StringUtils.isAnyBlank(conversationId, carid, userToken)) {
|
|
|
+ ChatgptUserConversationRecord chatgptUserConversationRecord = chatgptUserConversationRecordMapper.selectOne(Wrappers.lambdaQuery(ChatgptUserConversationRecord.class)
|
|
|
+ .isNull(ChatgptUserConversationRecord::getConversationId)
|
|
|
+ .eq(ChatgptUserConversationRecord::getCarId, carid)
|
|
|
+ .eq(ChatgptUserConversationRecord::getUserToken, userToken)
|
|
|
+ .orderByDesc(ChatgptUserConversationRecord::getId)
|
|
|
+ .last(" limit 1"));
|
|
|
+ chatgptUserConversationRecord.setConversationId(conversationId);
|
|
|
+ chatgptUserConversationRecordMapper.updateById(chatgptUserConversationRecord);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void carLimited(String carId, String userToken, Integer expTime) {
|
|
|
+ if(carId == null){
|
|
|
+ if (StringUtils.isNotBlank(userToken)) {
|
|
|
+ ChatgptUser chatgptUser = chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getUserToken, userToken));
|
|
|
+ if (chatgptUser != null && chatgptUser.getSessionId() != null) {
|
|
|
+ ChatgptSession chatgptSession = chatgptSessionMapper.selectById(chatgptUser.getSessionId());
|
|
|
+ if(chatgptSession != null){
|
|
|
+ carId = chatgptSession.getCarId();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ redisService.set("chatgpt:clears_in:" + carId, expTime);
|
|
|
+ }
|
|
|
+
|
|
|
+ @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());
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|