| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921 |
- package com.cyksj.service.chatgpt.impl;
- import cn.hutool.core.date.DateTime;
- import cn.hutool.core.date.DateUnit;
- import cn.hutool.core.date.DateUtil;
- import cn.hutool.core.lang.UUID;
- import cn.hutool.http.HttpRequest;
- import cn.hutool.http.HttpResponse;
- 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.mapper.station.CollegeStudentStationUseTicketRecordMapper;
- 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.dao.DuplicateKeyException;
- import org.springframework.data.redis.core.ZSetOperations;
- import org.springframework.stereotype.Service;
- import javax.annotation.PostConstruct;
- import javax.imageio.stream.FileImageOutputStream;
- import java.math.BigDecimal;
- import java.nio.file.Files;
- import java.nio.file.Path;
- import java.time.LocalDateTime;
- import java.util.*;
- import java.util.stream.Collectors;
- /**
- * @author chan
- * @date 2024/3/19 11:01
- */
- @Service
- @Slf4j
- @RequiredArgsConstructor
- 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;
- private final GroupsRelationMapper groupsRelationMapper;
- private final GroupsMapper groupsMapper;
- private final GoodsDonSkuMapper skuMapper;
- private final UserMapper userMapper;
- private final UserBindRelationService userBindRelationService;
- private final ChatgptUserConversationRecordMapper chatgptUserConversationRecordMapper;
- private final ChatgptUserConversationMapper chatgptUserConversationMapper;
- private final AccountMapper accountMapper;
- private final BeanSearcher beanSearcher;
- private final ChatgptUserTokenPrepareMapper chatgptUserTokenPrepareMapper;
- private final ChatgptUserCarUsedRecordMapper chatgptUserCarUsedRecordMapper;
- private final CollegeStudentStationUseTicketRecordMapper collegeStudentStationUseTicketRecordMapper;
- @Override
- public String addAccount(Account account) {
- if (isAccountExists(account)) {
- throw BusinessRuntimeException.getInstance("镜像服务该账号已存在.");
- }
- String refreshToken = "";
- String officialSession = "";
- try {
- JSONObject loginResult = getLoginResult(account);
- if (StringUtils.isBlank(loginResult.getStr("accessToken"))) {
- throw BusinessRuntimeException.getInstance(loginResult.getStr("detail"));
- }
- refreshToken = loginResult.getStr("refresh_token");
- officialSession = loginResult.toString();
- } catch (Exception e) {
- throw BusinessRuntimeException.getInstance("登录获取token错误 error:" + e.getMessage());
- }
- createChatgptSession(account, officialSession);
- 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;
- }
- /**
- * 判断账号是否存在
- *
- * @param account 账号
- * @return 是否存在
- */
- private boolean isAccountExists(Account account) {
- Integer count = chatgptSessionMapper.selectCount(Wrappers.lambdaQuery(ChatgptSession.class).eq(ChatgptSession::getEmail, account.getAccount()));
- return count > 0;
- }
- /**
- * 获取登录结果
- *
- * @param account
- * @return
- * @throws Exception
- */
- private JSONObject getLoginResult(Account account) throws Exception {
- HttpRequest request = new HttpRequest(GPT_PROXY + "/getsession");
- request.form("username", account.getAccount());
- request.form("password", account.getPassword());
- request.header("Content-Type", "application/x-www-form-urlencoded");
- HttpResponse execute = request.method(Method.POST).execute();
- return new JSONObject(execute.body());
- }
- /**
- * 创建chatgptSession
- *
- * @param account
- * @param officialSession
- */
- private void createChatgptSession(Account account, String officialSession) {
- ChatgptSession chatgptSession = new ChatgptSession();
- chatgptSession.setOfficialSession(officialSession);
- chatgptSession.setEmail(account.getAccount());
- chatgptSession.setPassword(account.getPassword());
- chatgptSession.setIsPlus(1);
- chatgptSession.setAccountId(account.getId());
- chatgptSession.setStatus(1);
- chatgptSessionMapper.insert(chatgptSession);
- }
- /**
- * 更新账号
- *
- * @param account
- */
- @Override
- public void upAccount(Account account) {
- ChatgptSession chatgptSession = chatgptSessionMapper.selectOne(Wrappers.lambdaQuery(ChatgptSession.class).eq(ChatgptSession::getEmail, account.getAccount()));
- if (chatgptSession != null) {
- if (StringUtils.isNotBlank(account.getGptRefreshToken())) {
- chatgptSession.setOfficialSession(account.getGptRefreshToken());
- }
- chatgptSession.setEmail(account.getAccount());
- chatgptSession.setPassword(account.getPassword());
- chatgptSession.setIsPlus(1);
- chatgptSession.setAccountId(account.getId());
- chatgptSession.setStatus(1);
- chatgptSessionMapper.updateById(chatgptSession);
- }
- }
- /**
- * 获取登录url
- *
- * @param userId
- * @param relationId
- * @return
- */
- @Override
- public String getLoginUrl(Long userId, Long relationId) {
- GroupsRelation groupsRelation = getGroupsRelation(userId, relationId);
- GroupsTrips groupsTrips = getGroupsTrips(groupsRelation);
- GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId());
- log.info("用户:{},所在车次:{},座位id:{},在{}获取跳转GPT镜像的登录url", userId, groupsTrips.getId(), relationId, DateTime.now());
- if (goodsDonSku != null && goodsDonSku.getIsMirror()) {
- ChatgptUser chatgptUser = getChatgptUser(userId, relationId, groupsRelation, groupsTrips, goodsDonSku);
- if (214610L == relationId) {
- return "https://cdn.galaxydvd.com/login_token?access_token=" + chatgptUser.getUserToken();
- }
- 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);
- String DOMAIN = "https://chat.galaxydvd.com";
- log.info("domain:{},用户:{},所在车次:{},座位id:{},在{}获取跳转GPT镜像的登录url", DOMAIN, userId, groupsTrips.getId(), relationId, DateTime.now());
- return DOMAIN + "/auth/logintoken?carid=" + carId + "&usertoken=" + chatgptUser.getUserToken();
- } else {
- throw BusinessRuntimeException.getInstance("服务器出了点问题");
- }
- }
- /**
- * 根据userToken获取车队登录url
- */
- @Override
- public String getCarLoginUrlWithToken(String userToken, String carId) {
- ChatgptUser chatgptUser = getCarChatGptUserWithToken(userToken);
- if (chatgptUser != null) {
- String DOMAIN = "https://chat.galaxydvd.com";
- log.info("domain:{},渠道用户:{},在{}获取跳转GPT镜像的登录url", DOMAIN, userToken, DateTime.now());
- return DOMAIN + "/auth/logintoken?carid=" + carId + "&usertoken=" + chatgptUser.getUserToken();
- } else {
- throw BusinessRuntimeException.getInstance("服务出了点问题");
- }
- }
- /**
- * 获取车位信息
- *
- * @param userId
- * @param relationId
- * @return
- */
- private GroupsRelation getGroupsRelation(Long userId, Long relationId) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- GroupsRelation groupsRelation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class).in(GroupsRelation::getUserId, userIdList).eq(GroupsRelation::getId, relationId));
- if (groupsRelation == null) {
- throw BusinessRuntimeException.getInstance("车票不存在");
- }
- return groupsRelation;
- }
- /**
- * 获取车队信息
- *
- * @param groupsRelation
- * @return
- */
- private GroupsTrips getGroupsTrips(GroupsRelation groupsRelation) {
- GroupsTrips groupsTrips = groupsMapper.selectById(groupsRelation.getGroupsId());
- if (groupsTrips == null) {
- throw BusinessRuntimeException.getInstance("车队异常");
- }
- return 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, null, user, goodsDonSku);
- } else {
- updateChatgptUser(groupsRelation, user, chatgptUser);
- }
- return chatgptUser;
- }
- /**
- * 创建chatgptUser
- */
- 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());
- }
- try {
- chatgptUser.setExpireTime(groupsRelation.getExpiryTime());
- chatgptUser.setIsPlus(1);
- chatgptUser.setName(user.getNickname());
- chatgptUser.setImg(getWxImg(user.getHeadimgurl(), user));
- chatgptUser.setRelationId(groupsRelation.getId());
- chatgptUser.setUserToken(UUID.randomUUID().toString());
- chatgptUserMapper.insert(chatgptUser);
- //是否是大学生限时车队
- Date expiryTime = groupsRelation.getExpiryTime();
- Date startTime = groupsRelation.getStartTime();
- //大学生站 1天免费试用
- if (DateUtil.between(startTime, expiryTime, DateUnit.DAY) <= 1) {
- CollegeStudentStationUseTicketRecord useTicketRecord = new CollegeStudentStationUseTicketRecord();
- useTicketRecord.setUserId(user.getId());
- useTicketRecord.setUserToken(chatgptUser.getUserToken());
- collegeStudentStationUseTicketRecordMapper.insert(useTicketRecord);
- }
- } catch (DuplicateKeyException e) {
- log.error("重复插入镜像用户:{}token,errmsg:{}", user.getNickname(), StringUtil.getErrorText(e));
- }
- return chatgptUser;
- }
- /**
- * 创建chatgptUser 无需车队
- */
- public ChatgptUser generateChatGptUserUnderPrepare(ChatgptUserTokenPrepare prepare) {
- ChatgptUser chatgptUser = new ChatgptUser();
- GoodsDonSku goodsDonSku = skuMapper.selectById(prepare.getSkuId());
- if (goodsDonSku == null) {
- throw BusinessRuntimeException.getInstance("车队规格不存在,请联系客服..");
- }
- if (goodsDonSku.getIsCar()) {
- chatgptUser.setIsCar(true);
- chatgptUser.setLimitNum(goodsDonSku.getGptLimitNum());
- chatgptUser.setLimitTime(goodsDonSku.getGptLimitTime());
- }
- try {
- chatgptUser.setExpireTime(DateUtil.offsetMonth(DateTime.now(), goodsDonSku.getMonths()));
- chatgptUser.setIsPlus(1);
- chatgptUser.setName(prepare.getName());
- chatgptUser.setImg(prepare.getImg());
- chatgptUser.setUserToken(prepare.getUserToken());
- chatgptUserMapper.insert(chatgptUser);
- prepare.setStatus(true);
- chatgptUserTokenPrepareMapper.updateById(prepare);
- log.info("用户激活userToken:{}成功", prepare.getUserToken());
- } catch (DuplicateKeyException e) {
- log.error("重复插入镜像车队用户:{}token,errmsg:{}" + chatgptUser.getId(), StringUtil.getErrorText(e));
- }
- return chatgptUser;
- }
- private void updateChatgptUser(GroupsRelation groupsRelation, User user, ChatgptUser chatgptUser) {
- chatgptUser.setName(user.getNickname());
- chatgptUser.setImg(getWxImg(user.getHeadimgurl(), user));
- chatgptUser.setExpireTime(groupsRelation.getExpiryTime());
- chatgptUserMapper.updateById(chatgptUser);
- }
- /**
- * 更换wx头像至oss
- */
- private String getWxImg(String headimgurl, User user) {
- if (headimgurl.contains("thirdwx.qlogo.cn")) {
- try {
- byte[] body = HttpUtil.downloadBytes(headimgurl);
- Path tempFile = Files.createTempFile("wxheadimg-" + user.getId(), ".jpeg");
- try (FileImageOutputStream imageOutput = new FileImageOutputStream(tempFile.toFile())) {
- imageOutput.write(body, 0, body.length);
- }
- Map<String, Object> paramMap = new HashMap<>();
- paramMap.put("file", tempFile.toFile());
- JSONObject result = JSONUtil.parseObj(HttpUtil.post("https://files.liuliangbang.vip/pic/ups", paramMap));
- return result.getJSONObject("value").getJSONArray("saved").getJSONObject(0).getJSONObject("info").getStr("cdnUrl");
- } catch (Exception ex) {
- log.error("上传微信头像错误!msg:{}", StringUtil.getErrorText(ex));
- return "./avatars.png";
- }
- } else {
- return user.getHeadimgurl();
- }
- }
- @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);
- ChatgptUser chatgptUser = chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getUserToken, userToken));
- if (StringUtils.isNotBlank(conversationRequest.getCarId())) {
- wrapper.eq(ChatgptSession::getCarId, conversationRequest.getCarId());
- } else {
- 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(!"text-davinci-002-render-sha".equals(conversationRequest.getModel())){
- String key = RedisService.key.CHATGPT_CONVERSATION_LIMIT.getName() + ":" + userToken;
- long currentTimeMillis = System.currentTimeMillis();
- redisService.del();
- if(redisService.hasKey("chatgpt:team:clears_in:" + chatgptSession.getCarId())){
- redisService.del("chatgpt:team:clears_in:" + chatgptSession.getCarId());
- }
- if (redisService.hasKey("chatgpt:clears_in:" + chatgptSession.getCarId())) {
- redisService.del("chatgpt:clears_in:" + chatgptSession.getCarId());
- }
- // 如果未超过限制,记录当前请求的时间戳
- redisService.zAdd(key, currentTimeMillis, currentTimeMillis);
- // 设置ZSet的过期时间,窗口大小加上一段冗余时间
- redisService.expire(key, (chatgptUser.getLimitTime() * 60 * 60) + 20);
- }
- if (StringUtils.isNotBlank(chatgptSession.getCarId())) {
- updateExperienceAndScore(chatgptSession.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());
- }
- }
- 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);
- //用户次数使用限制
- ChatgptUserCarUsedRecord chatgptUserCarUsedRecord = new ChatgptUserCarUsedRecord();
- chatgptUserCarUsedRecord.setUserToken(userToken);
- chatgptUserCarUsedRecord.setIsUserLimit(true);
- chatgptUserCarUsedRecordMapper.insert(chatgptUserCarUsedRecord);
- return conversationLimitResponse;
- } else {
- conversationLimitResponse.setLimited(false);
- return conversationLimitResponse;
- }
- }
- /**
- * 获取指定用户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_HIGH_CHAT.getName() + carId;
- long timestamp = System.currentTimeMillis();
- long windowStartMillis = timestamp - (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, Boolean isTeam) {
- if(isTeam && redisService.hasKey("chatgpt:team:clears_in:" + carId)){
- return redisService.getExpire("chatgpt:team:clears_in:" + 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 Boolean checkCarAccountWithToken(String userToken) {
- ChatgptUser chatgptUser = getCarChatGptUserWithToken(userToken);
- return chatgptUser != null;
- }
- @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()) {
- return getChatgptCarUser(userId, relationId, groupsRelation, goodsDonSku);
- }
- return null;
- }
- @Override
- public ChatgptUser getCarChatGptUserWithToken(String userToken) {
- ChatgptUser chatgptUser = chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getUserToken, userToken).last(" limit 1"));
- if (chatgptUser == null) {
- //是否是用户token预备账号
- ChatgptUserTokenPrepare chatgptUserTokenPrepare = chatgptUserTokenPrepareMapper.selectOne(Wrappers.lambdaQuery(ChatgptUserTokenPrepare.class)
- .eq(ChatgptUserTokenPrepare::getUserToken, userToken).last("limit 1"));
- if (chatgptUserTokenPrepare != null) {
- chatgptUser = generateChatGptUserUnderPrepare(chatgptUserTokenPrepare);
- }
- }
- if (chatgptUser != null) {
- if(!chatgptUser.getIsCar()){
- throw BusinessRuntimeException.getInstance("您非车队用户,请购买车队套餐");
- }
- if (chatgptUser.getRelationId() != null) {
- throw BusinessRuntimeException.getInstance("非渠道用户,请通过官网登录!");
- }
- return chatgptUser;
- }
- return null;
- }
- /**
- * 获取车队信息
- */
- @Override
- public Set<ChatgptCarInfoView> getCarInfoList(String userToken, Integer limit, Boolean isPlus) {
- 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()), 200));
- return chatgptCarInfoView;
- }).collect(Collectors.toCollection(LinkedHashSet::new));
- Set<ChatgptCarInfoView> lowestScoreFleets = getLowestScoreFleets(limit, isPlus);
- 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));
- // 清理旧数据(可选)和重新计算评分(根据需要实现)
- 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;
- if(carId.contains("T")){
- newScore = BigDecimal.valueOf(newScore).divide(BigDecimal.valueOf(5), 2, BigDecimal.ROUND_HALF_UP).doubleValue();
- }
- redisService.zAdd(RedisService.key.CHATGPT_CAR_SCORES.getName(), newScore, carId);
- }
- // 获取得分最低的N个车队的方法
- public Set<ChatgptCarInfoView> getLowestScoreFleets(int count, Boolean isPlus) {
- 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()).eq(isPlus !=null && isPlus, ChatgptSession::getIsPlus, true));
- 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, 200));
- view.setStatus(score >= 50 ? "繁忙" : "空闲"); // 或“繁忙”
- if(carName.contains("T")){
- view.setType("Team");
- Long team = carOaiLimit(carId, true);
- if (team != 0L) {
- view.setTeamExpTime(new DateTime(System.currentTimeMillis() + team * 1000));
- }
- Long aLong = carOaiLimit(carId, false);
- if (aLong != 0L) {
- view.setExpTime(new DateTime(System.currentTimeMillis() + aLong * 1000));
- }
- if (view.getExpTime() != null && view.getTeamExpTime() != null) {
- view.setStatus("全部停运");
- }else if(view.getExpTime() != null || view.getTeamExpTime() != null) {
- view.setStatus("部分停运");
- }
- }else {
- view.setType(isPlus == 1 ? "Plus" : "3.5");
- Long aLong = carOaiLimit(carId, false);
- if (aLong != 0L) {
- view.setStatus("停运");
- view.setExpTime(new DateTime(System.currentTimeMillis() + aLong * 1000));
- }
- }
- int use = getCarConversationCount(carId, 3L).intValue();
- view.setUse(use);
- 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(Math.min(chatgptUser.getLimitNum(),getConversationCount(chatgptUser.getUserToken(), chatgptUser.getLimitTime())))
- .build();
- } else {
- throw BusinessRuntimeException.getInstance("您还未购买该车票");
- }
- }
- @Override
- public ChatGptUserView getUserInfoWithToken(String userToken) {
- if (checkCarAccountWithToken(userToken)) {
- ChatgptUser chatgptUser = getCarChatGptUserWithToken(userToken);
- return ChatGptUserView.builder()
- .skuName("")
- .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"));
- if (chatgptUserConversationRecord != null) {
- chatgptUserConversationRecord.setConversationId(conversationId);
- chatgptUserConversationRecordMapper.updateById(chatgptUserConversationRecord);
- }
- }
- }
- @Override
- public void carLimited(String carId, String userToken, Long expTime, Boolean isTeam) {
- 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();
- }
- }
- }
- }
- if(isTeam){
- redisService.set("chatgpt:team:clears_in:" + carId, expTime, expTime);
- }else {
- redisService.set("chatgpt:clears_in:" + carId, expTime, expTime);
- }
- try {
- //记录用户触发限制
- ChatgptUserCarUsedRecord chatgptUserCarUsedRecord = new ChatgptUserCarUsedRecord();
- chatgptUserCarUsedRecord.setUserToken(userToken);
- chatgptUserCarUsedRecord.setCarId(carId);
- String highCarChatKey = RedisService.key.CHATGPT_CAR_HIGH_CHAT.getName() + carId;
- String lowCarChatKey = RedisService.key.CHATGPT_CAR_LOW_CHAT.getName() + carId;
- Long highCarChatNum = redisService.zCard(highCarChatKey);
- if (highCarChatNum != null) {
- chatgptUserCarUsedRecord.setGptFour(Integer.parseInt(highCarChatNum.toString()));
- }
- Long lowCarChatNum = redisService.zCard(lowCarChatKey);
- if (lowCarChatNum != null) {
- chatgptUserCarUsedRecord.setGpt(Integer.parseInt(lowCarChatNum.toString()));
- }
- chatgptUserCarUsedRecordMapper.insert(chatgptUserCarUsedRecord);
- log.info("记录userToken:{}访问对应镜像车队carId:{}操作成功", userToken, carId);
- } catch (Exception e) {
- log.info("记录userToken:{}访问对应镜像车队carId:{}操作失败e:{}", userToken, carId, StringUtil.getErrorText(e));
- }
- }
- @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::getIsPlus, 1).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());
- }
- });
- });
- }
- }
|