package com.cyksj.service.gemini.impl; import cn.hutool.core.date.DateTime; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; 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.toolkit.Wrappers; import com.cyksj.common.exception.BusinessRuntimeException; import com.cyksj.common.util.StringUtil; import com.cyksj.mapper.*; import com.cyksj.model.entity.*; import com.cyksj.model.response.ConversationLimitResponse; import com.cyksj.model.response.GeminiCarAccount; import com.cyksj.model.response.GeminiCarPageResponse; import com.cyksj.model.response.GeminiCarStatusResponse; import com.cyksj.model.response.GeminiConversationCountResponse; import com.cyksj.model.views.GeminiCarInfoView; import com.cyksj.model.views.GeminiUserView; import com.cyksj.redis.RedisService; import com.cyksj.service.gemini.GeminiService; import com.cyksj.service.sys.SysConfigService; import com.cyksj.service.user.UserBindRelationService; import com.ejlchina.searcher.SearchResult; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.UUID; /** * Gemini镜像服务实现 * * @author chan * @date 2025/1/4 */ @Service @RequiredArgsConstructor @Slf4j public class GeminiServiceImpl implements GeminiService { private final GeminiUserMapper geminiUserMapper; private final GroupsRelationMapper groupsRelationMapper; private final GroupsMapper groupsMapper; private final GoodsDonSkuMapper skuMapper; private final UserBindRelationService userBindRelationService; private final UserMapper userMapper; private final SysConfigService sysConfigService; private final RedisService redisService; /** * 获取默认域名 */ private String getDefaultDomain(String domain) { if (StrUtil.isNotEmpty(domain)) { return domain; } String defaultDomain = "https://gemini.bestaistore.com"; try { SysConfig sysConfig = sysConfigService.getOne( Wrappers.lambdaQuery(SysConfig.class).eq(SysConfig::getSysKey, "mirror_gemini_domain") ); if (sysConfig != null) { String sysValue = sysConfig.getSysValue(); if (JSONUtil.isJsonArray(sysValue)) { List domainList = JSONUtil.parseArray(sysValue).toList(String.class); defaultDomain = domainList.get(RandomUtil.randomInt(domainList.size())); } } } catch (Exception e) { log.error("获取Gemini域名错误. msg:{}", StringUtil.getErrorText(e)); } return defaultDomain; } @Override public GeminiUserView getUserInfo(long userId, Long relationId) { GeminiUser geminiUser = checkCarAccount(userId, relationId); if (geminiUser != null) { GroupsRelation groupsRelation = getGroupsRelation(userId, relationId); GroupsTrips groupsTrips = getGroupsTrips(groupsRelation); GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId()); GeminiUserView view = GeminiUserView.builder() .skuName(goodsDonSku.getSubTitle()) .expireTime(geminiUser.getExpireTime()) .userToken(geminiUser.getUserToken()) .limitNum(geminiUser.getLimitNum()) .limitTime(geminiUser.getLimitTime()) .build(); return view; } else { throw BusinessRuntimeException.getInstance("您还未购买该车票"); } } @Override public GeminiUser findByUserTokenAndExpireTimeAfter(String userToken, LocalDateTime now) { return geminiUserMapper.selectOne( Wrappers.lambdaQuery(GeminiUser.class) .eq(GeminiUser::getUserToken, userToken) .gt(GeminiUser::getExpireTime, now) ); } @Override public GeminiUser 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()) { return getGeminiUser(userId, relationId, groupsRelation, goodsDonSku); } else { return null; } } @Override public GeminiUser getGeminiUser(long userId, Long relationId) { GroupsRelation groupsRelation = getGroupsRelation(userId, relationId); GroupsTrips groupsTrips = getGroupsTrips(groupsRelation); GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId()); if (goodsDonSku != null && goodsDonSku.getIsMirror()) { return getGeminiUser(userId, relationId, groupsRelation, goodsDonSku); } else { throw BusinessRuntimeException.getInstance("服务器出了点问题"); } } @Override public String getCarLoginUrl(String domain, 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()) { GeminiUser geminiUser = getGeminiUser(userId, relationId, groupsRelation, goodsDonSku); String DOMAIN = getDefaultDomain(domain); log.info("domain:{},用户:{},所在车次:{},座位id:{},在{}获取跳转Gemini镜像的登录url", DOMAIN, userId, groupsTrips.getId(), relationId, DateTime.now()); return DOMAIN + "/logintoken?access_token=" + geminiUser.getUserToken() + "&account=" + carId; } else { throw BusinessRuntimeException.getInstance("服务器出了点问题"); } } /** * Gemini镜像端API域名 */ private static final String GEMINI_MIRROR_API = "https://saas.galaxyva.com"; @Override public void clearNum(String userToken) throws Exception { String url = GEMINI_MIRROR_API + "/gemini/cleanUserTokenLimit?userToken=" + userToken; HttpRequest request = new HttpRequest(url); HttpResponse execute = request.method(Method.GET).setConnectionTimeout(3000).timeout(3000).execute(); String body = execute.body(); JSONObject re = JSONUtil.parseObj(body); if (!body.contains("清除成功")) { throw BusinessRuntimeException.getInstance(re.getStr("message")); } } @Override public void clearNumByRelationId(Long relationId) throws Exception { String url = GEMINI_MIRROR_API + "/gemini/cleanUserTokenLimit?relationId=" + relationId; HttpRequest request = new HttpRequest(url); HttpResponse execute = request.method(Method.GET).setConnectionTimeout(3000).timeout(3000).execute(); String body = execute.body(); JSONObject re = JSONUtil.parseObj(body); if (!body.contains("清除成功")) { throw BusinessRuntimeException.getInstance(re.getStr("message")); } } @Override public GeminiCarPageResponse getCarPage(String domain, int page, int size) { String DOMAIN = getDefaultDomain(domain); try { JSONObject requestBody = new JSONObject(); requestBody.put("page", page); requestBody.put("size", size); String res = HttpUtil.post(DOMAIN + "/carpage", requestBody.toString()); if (!JSONUtil.isJson(res)) { res = res.substring(2,res.length()-1); } return JSONUtil.toBean(res, GeminiCarPageResponse.class); } catch (Exception e) { log.error("调用Gemini /carpage 接口失败: {}", StringUtil.getErrorText(e)); GeminiCarPageResponse response = new GeminiCarPageResponse(); response.setCode(-1); response.setMessages("获取车队列表失败"); return response; } } @Override public GeminiCarStatusResponse getCarStatus(String domain, String carId) { String DOMAIN = getDefaultDomain(domain); try { String res = HttpUtil.get(DOMAIN + "/status?carid=" + carId); return JSONUtil.toBean(res, GeminiCarStatusResponse.class); } catch (Exception e) { log.error("调用Gemini /status 接口失败: {}", StringUtil.getErrorText(e)); GeminiCarStatusResponse response = new GeminiCarStatusResponse(); response.setAccountReady(false); return response; } } /** * 获取车位信息 */ private GroupsRelation getGroupsRelation(Long userId, Long relationId) { List 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; } /** * 获取车队信息 */ private GroupsTrips getGroupsTrips(GroupsRelation groupsRelation) { GroupsTrips groupsTrips = groupsMapper.selectById(groupsRelation.getGroupsId()); if (groupsTrips == null) { throw BusinessRuntimeException.getInstance("车队异常"); } return groupsTrips; } private GeminiUser getGeminiUser(Long userId, Long relationId, GroupsRelation groupsRelation, GoodsDonSku goodsDonSku) { GeminiUser geminiUser = geminiUserMapper.selectOne( Wrappers.lambdaQuery(GeminiUser.class).eq(GeminiUser::getRelationId, relationId) ); User user = userMapper.selectById(userId); if (geminiUser == null) { geminiUser = createGeminiUser(groupsRelation, user, goodsDonSku); } else { updateGeminiUser(groupsRelation, user, geminiUser); } return geminiUser; } /** * 创建GeminiUser */ private synchronized GeminiUser createGeminiUser(GroupsRelation groupsRelation, User user, GoodsDonSku goodsDonSku) { GeminiUser geminiUser = new GeminiUser(); if (goodsDonSku.getIsCar()) { geminiUser.setLimitNum(goodsDonSku.getGptLimitNum()); geminiUser.setLimitTime(goodsDonSku.getGptLimitTime()); } try { geminiUser.setExpireTime(groupsRelation.getExpiryTime()); geminiUser.setIsPlus(true); geminiUser.setName(user.getNickname()); geminiUser.setRelationId(groupsRelation.getId()); geminiUser.setUserToken(UUID.randomUUID().toString()); geminiUserMapper.insert(geminiUser); } catch (DuplicateKeyException e) { log.error("重复插入Gemini镜像用户:{}token,errmsg:{}", user.getNickname(), StringUtil.getErrorText(e)); } return geminiUser; } private void updateGeminiUser(GroupsRelation groupsRelation, User user, GeminiUser geminiUser) { geminiUser.setName(user.getNickname()); geminiUser.setExpireTime(groupsRelation.getExpiryTime()); geminiUserMapper.updateById(geminiUser); } @Override public SearchResult getCarInfoList(String domain, int page, int size) { GeminiCarPageResponse carPageResponse = getCarPage(domain, page, size); List carInfoList = new ArrayList<>(); if (carPageResponse.getCode() != null && carPageResponse.getCode() == 1000 && carPageResponse.getData() != null && carPageResponse.getData().getList() != null) { for (GeminiCarAccount account : carPageResponse.getData().getList()) { GeminiCarInfoView carInfo = new GeminiCarInfoView(); carInfo.setCarId(account.getCarID()); carInfo.setCarName(account.getNickName()); // 根据carType设置isPlus: Ultra=3, Pro=2, Free=1 if ("Ultra".equalsIgnoreCase(account.getCarType())) { carInfo.setIsPlus(3); } else if ("Pro".equalsIgnoreCase(account.getCarType())) { carInfo.setIsPlus(2); } else { carInfo.setIsPlus(1); } // 根据status设置状态 if (account.getStatus() != null && account.getStatus()) { carInfo.setAccountReady(true); carInfo.setStatus("空闲"); } else { carInfo.setAccountReady(false); carInfo.setStatus("停运"); } carInfoList.add(carInfo); } } int total = 0; if (carPageResponse.getData() != null && carPageResponse.getData().getPagination() != null && carPageResponse.getData().getPagination().getTotal() != null) { total = carPageResponse.getData().getPagination().getTotal(); } SearchResult result = new SearchResult<>(carInfoList); result.setTotalCount(total); return result; } @Override public GeminiCarInfoView getCarInfo(String domain, String carId) { GeminiCarStatusResponse statusResponse = getCarStatus(domain, carId); GeminiCarInfoView carInfo = new GeminiCarInfoView(); carInfo.setCarId(carId); carInfo.setCarName(carId); if (statusResponse.getAccountReady() != null && statusResponse.getAccountReady()) { carInfo.setAccountReady(true); carInfo.setClearsIn(statusResponse.getClearsIn() != null ? statusResponse.getClearsIn().longValue() : 0L); carInfo.setUse(statusResponse.getCount()); // 根据isPlus设置账号类型 if (statusResponse.getIsPlus() != null && statusResponse.getIsPlus()) { carInfo.setIsPlus(2); // pro } else { carInfo.setIsPlus(1); // free } if (carInfo.getClearsIn() > 0) { carInfo.setStatus("停运"); carInfo.setExpTime(new DateTime(System.currentTimeMillis() + carInfo.getClearsIn() * 1000)); } else { carInfo.setScore(statusResponse.getCount() != null ? statusResponse.getCount().doubleValue() : 0.0); carInfo.setStatus(carInfo.getScore() > 50 ? "繁忙" : "空闲"); } } else { carInfo.setAccountReady(false); carInfo.setStatus("停运"); } return carInfo; } @Override public GeminiConversationCountResponse getConversationCountDetail(String userToken) { try { String url = GEMINI_MIRROR_API + "/gemini/getConversationCount?userToken=" + userToken; String res = HttpUtil.get(url, 5000); JSONObject json = JSONUtil.parseObj(res); // 检查是否有错误 if (json.containsKey("message")) { throw BusinessRuntimeException.getInstance(json.getStr("message")); } GeminiConversationCountResponse response = new GeminiConversationCountResponse(); response.setCount(json.getLong("count")); response.setLimit(json.getInt("limit")); response.setRemaining(json.getLong("remaining")); response.setTime(json.getLong("time")); response.setIsVip(json.getBool("isVip")); return response; } catch (BusinessRuntimeException e) { throw e; } catch (Exception e) { log.error("调用Gemini getConversationCount接口失败: {}", StringUtil.getErrorText(e)); throw BusinessRuntimeException.getInstance("获取对话次数失败"); } } }