package com.cyksj.service.mini.impl; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.ContentType; import cn.hutool.http.Header; import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.cyksj.common.constant.Constant; import com.cyksj.common.exception.BusinessRuntimeException; import com.cyksj.common.util.SignatureUtils; import com.cyksj.common.util.StringUtil; import com.cyksj.mapper.mini.*; import com.cyksj.model.entity.*; import com.cyksj.model.request.MiniAiPicturesReq; import com.cyksj.model.request.MiniPopularizeIncrTimesReq; import com.cyksj.model.response.MiniPopularizeResp; import com.cyksj.redis.RedisService; import com.cyksj.server.listener.ConsoleStreamListener; import com.cyksj.service.mini.MiniPopularizeCommonService; import com.cyksj.service.mini.MiniPopularizeFrontService; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.sse.EventSource; import okhttp3.sse.EventSources; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; /** * 项目名: yhlxj2 * 文件名: MiniPopularizeFrontServiceImpl * 创建者: JavaZou * 创建时间:2025/4/8 16:51 */ @Service @RequiredArgsConstructor @Slf4j public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontService { public static final String GPT_URL = "https://api.nf.video/v1/chat/completions"; public static final String GPT_DRAW_TOKEN = "sk-3x6qkSeXJJoYkaIkhlv7mm0DWGizFc7V7sapmtoMoYI0Nd5Z"; public static final String SIGN_SECRET = "6mR7XvKbPeShVmYq3t5w9z$C&FH@McQ"; private final MiniPopularizeUserConversationMapper conversationMapper; private final MiniPopularizeUserMapper miniPopularizeUserMapper; private final RedisService redisService; private final MiniPopularizeCommonService miniPopularizeCommonService; private final MiniPopularizeConfigMapper miniPopularizeConfigMapper; private final MiniPopularizeUserConversationChatMapper conversationChatMapper; private final MiniPopularizeConfigUseRecordMapper miniPopularizeConfigUseRecordMapper; private final MiniPopularizeUserIncrTimesRecordMapper miniPopularizeUserIncrTimesRecordMapper; /** * 连接超时 */ private static final long TIMEOUT = 90; @Override @Transactional(rollbackFor = Throwable.class) public MiniPopularizeResp createPictures(MiniAiPicturesReq miniAiPicturesReq) throws IOException { String conversationId = miniAiPicturesReq.getConversationId(); AtomicBoolean recoverNum = new AtomicBoolean(true); Long userId = miniAiPicturesReq.getUserId(); conversationId = checkUser(MiniPopularizeUserConversation.builder() .userId(userId) .content(miniAiPicturesReq.getTips()) .build(), conversationId, recoverNum); miniAiPicturesReq.setConversationId(conversationId); Long configId = miniAiPicturesReq.getId(); if (configId != null) { MiniPopularizeConfig miniPopularizeConfig = miniPopularizeConfigMapper.selectById(miniAiPicturesReq.getId()); if (miniPopularizeConfig != null) { //垫图 if (miniPopularizeConfig.getType() == MiniPopularizeConfig.Type.Style || miniPopularizeConfig.getType() == MiniPopularizeConfig.Type.Banner) { miniAiPicturesReq.setType(2); miniAiPicturesReq.setImg(miniPopularizeConfig.getImg()); } miniAiPicturesReq.setTips(miniPopularizeConfig.getTips()); } } //聊天记录 MiniPopularizeUserConversationChat chat = MiniPopularizeUserConversationChat.builder() .conversationId(conversationId) .content(miniAiPicturesReq.getTips()) .type(MiniPopularizeUserConversationChat.Type.text) .role(MiniPopularizeUserConversationChat.Role.user) .userId(userId) .build(); conversationChatMapper.insert(chat); //图像生成记录 MiniPopularizeUserConversationChat imageRecord = MiniPopularizeUserConversationChat.builder() .userId(miniAiPicturesReq.getUserId()) .conversationId(miniAiPicturesReq.getConversationId()) .type(MiniPopularizeUserConversationChat.Type.image) .status(MiniPopularizeUserConversationChat.Status.processing) .build(); miniPopularizeCommonService.saveImgRecord(imageRecord); ConsoleStreamListener listener = ConsoleStreamListener.builder() .userId(userId) .miniPopularizeCommonService(miniPopularizeCommonService) .conversationId(conversationId) .imgRecordId(imageRecord.getId()) .recoverNum(recoverNum.get()) .build(); streamChatCompletion(miniAiPicturesReq, listener); MiniPopularizeResp resp = MiniPopularizeResp.builder() .conversationId(conversationId) .chatId(imageRecord.getId()) .build(); return resp; } @Override public MiniPopularizeUser getUser(long userId) { MiniPopularizeUser user = miniPopularizeUserMapper.selectOne(Wrappers.lambdaQuery(MiniPopularizeUser.class) .eq(MiniPopularizeUser::getUserId, userId).last("limit 1").select(MiniPopularizeUser::getNum, MiniPopularizeUser::getCloseTc)); return user; } @Override public String getImgResultById(long userId, Long imageId) { MiniPopularizeUserConversationChat miniPopularizeUserConversationChat = conversationChatMapper.selectOne(Wrappers.lambdaQuery(MiniPopularizeUserConversationChat.class) .eq(MiniPopularizeUserConversationChat::getUserId, userId) .eq(MiniPopularizeUserConversationChat::getId, imageId) .last("limit 1")); if (miniPopularizeUserConversationChat != null) { return miniPopularizeUserConversationChat.getImg(); } return null; } @Override @Transactional(rollbackFor = Throwable.class) public void incrGptTimes(MiniPopularizeIncrTimesReq req) throws Exception { Long userId = req.getUserId(); MiniPopularizeUser user = miniPopularizeUserMapper.selectById(userId); if (user == null) { throw BusinessRuntimeException.getInstance("系统错误,用户不存在"); } String sign = req.getSign(); if (StrUtil.isEmpty(sign)) { throw BusinessRuntimeException.getInstance("系统错误"); } Long timestamp = req.getTimestamp(); String bsign = SignatureUtils.generateSignature(Map.of("timestamp", timestamp.toString()), SIGN_SECRET); if (!StrUtil.equals(bsign, sign)) { throw BusinessRuntimeException.getInstance("系统错误"); } Integer addNum = Constant.Three; MiniPopularizeUserIncrTimesRecord miniPopularizeUserIncrTimesRecord = new MiniPopularizeUserIncrTimesRecord(); miniPopularizeUserIncrTimesRecord.setUserId(userId); miniPopularizeUserIncrTimesRecord.setSign(sign); miniPopularizeUserIncrTimesRecord.setNum(addNum); try { miniPopularizeUserIncrTimesRecordMapper.insert(miniPopularizeUserIncrTimesRecord); Integer oriNum = user.getNum(); miniPopularizeCommonService.incrGptTimes(userId, oriNum, addNum); } catch (Exception e) { } } @Override public void closeTc(long userId) { Optional.ofNullable(miniPopularizeUserMapper.selectOne(Wrappers.lambdaQuery(MiniPopularizeUser.class) .eq(MiniPopularizeUser::getUserId, userId) .last("limit 1"))) .ifPresent(user -> { if (!user.getCloseTc()) { user.setCloseTc(true); miniPopularizeUserMapper.updateById(user); } }); } private String checkUser(MiniPopularizeUserConversation conversation, String conversationId, AtomicBoolean recoverNum) { if (conversationId != null) { MiniPopularizeUserConversationChat miniPopularizeUserConversationChat = conversationChatMapper.selectOne(Wrappers.lambdaQuery(MiniPopularizeUserConversationChat.class) .eq(MiniPopularizeUserConversationChat::getConversationId, conversationId) .eq(MiniPopularizeUserConversationChat::getType, MiniPopularizeUserConversationChat.Type.image) .orderByDesc(MiniPopularizeUserConversationChat::getId) .last("limit 1")); if (miniPopularizeUserConversationChat == null || !miniPopularizeUserConversationChat.getUserId().equals(conversation.getUserId())) { throw BusinessRuntimeException.getInstance("系统错误"); } else if (miniPopularizeUserConversationChat.getStatus() != MiniPopularizeUserConversationChat.Status.success) { throw BusinessRuntimeException.getInstance("图片还未生成,无法进行修改"); } recoverNum.set(false); } Long userId = conversation.getUserId(); if (conversationId == null) { //查询当前用户信息 MiniPopularizeUser user = miniPopularizeUserMapper.selectOne(Wrappers.lambdaQuery(MiniPopularizeUser.class).eq(MiniPopularizeUser::getUserId, userId)); if (user.getNum() == 0) { throw BusinessRuntimeException.getInstance("无可用次数"); } int i = miniPopularizeUserMapper.decLumaNum(userId, 1, user.getNum()); if (i == 0) { throw BusinessRuntimeException.getInstance("网络异常,请稍后再试"); } conversation.setConversationId(RandomUtil.randomString(64)); conversationMapper.insert(conversation); } return conversationId; } /** * 流式输出 */ public void streamChatCompletion(MiniAiPicturesReq miniAiPicturesReq, ConsoleStreamListener eventSourceListener) { JSONObject json = new JSONObject(); json.putOpt("model", "gpt-4o-image-vip"); json.putOpt("stream", true); JSONArray messages = new JSONArray(); String conversationId = miniAiPicturesReq.getConversationId(); MiniPopularizeUserConversationChat miniPopularizeUserConversationChat = null; if (conversationId != null) { miniPopularizeUserConversationChat = conversationChatMapper.selectOne(Wrappers.lambdaQuery(MiniPopularizeUserConversationChat.class) .eq(MiniPopularizeUserConversationChat::getConversationId, conversationId) .eq(MiniPopularizeUserConversationChat::getStatus, MiniPopularizeUserConversationChat.Status.success) .last("limit 1")); } //原图上修改 if (miniPopularizeUserConversationChat != null && miniPopularizeUserConversationChat.getStatus() != null && miniPopularizeUserConversationChat.getStatus() == MiniPopularizeUserConversationChat.Status.success) { //组装上下文 contentMsg(messages, miniPopularizeUserConversationChat.getConversationId()); } else { if (miniAiPicturesReq.getType() == 2) { String img = miniAiPicturesReq.getImg(); messages.add(JSONUtil.createObj().set("role", "user").set("content", JSONUtil.createArray().set(JSONUtil.createObj().set("type", "text").set("text", miniAiPicturesReq.getTips())) .set(JSONUtil.createObj().set("type", "image_url").set("image_url", JSONUtil.createObj().set("url", img))))); } else { messages.add(JSONUtil.createObj().set("role", "user").set("content", miniAiPicturesReq.getTips())); } } json.putOpt("messages", messages); try { EventSource.Factory factory = EventSources.createFactory(getOkHttpClient()); ObjectMapper mapper = new ObjectMapper(); String requestBody = mapper.writeValueAsString(json); Request request = new Request.Builder() .url(GPT_URL) .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), requestBody)) .header(Header.AUTHORIZATION.name(), GPT_DRAW_TOKEN) .build(); factory.newEventSource(request, eventSourceListener); if (miniAiPicturesReq.getId() != null) { recordConfigUseRecord(miniAiPicturesReq.getId(), miniAiPicturesReq.getUserId()); } } catch (Exception e) { log.error("gpt create image请求出错:{}", StringUtil.getErrorText(e)); } } private void contentMsg(JSONArray messages, String conversationId) { List miniPopularizeUserConversationChats = conversationChatMapper.selectList(Wrappers.lambdaQuery(MiniPopularizeUserConversationChat.class) .eq(MiniPopularizeUserConversationChat::getConversationId, conversationId)); miniPopularizeUserConversationChats.forEach(chat -> { if (chat.getStatus() != null && chat.getStatus() == MiniPopularizeUserConversationChat.Status.processing) { return; } if (chat.getRole() != null && chat.getRole() == MiniPopularizeUserConversationChat.Role.sys) { return; } String content = chat.getContent(); if (chat.getType() == MiniPopularizeUserConversationChat.Type.text) { messages.add(JSONUtil.createObj().set("role", "user").set("content", content)); } else messages.add(JSONUtil.createObj().set("role", "assistant").set("content", content)); }); } public OkHttpClient getOkHttpClient() { OkHttpClient.Builder client = new OkHttpClient.Builder(); client.connectTimeout(TIMEOUT, TimeUnit.SECONDS); client.writeTimeout(TIMEOUT, TimeUnit.SECONDS); client.readTimeout(TIMEOUT, TimeUnit.SECONDS); return client.build(); } public void recordConfigUseRecord(Long configId, Long userId) { MiniPopularizeConfigUseRecord miniPopularizeConfigUseRecord = new MiniPopularizeConfigUseRecord(); miniPopularizeConfigUseRecord.setConfigId(configId); miniPopularizeConfigUseRecord.setUserId(userId); miniPopularizeConfigUseRecordMapper.insert(miniPopularizeConfigUseRecord); } }