|
@@ -1,15 +1,20 @@
|
|
|
package com.cyksj.service.mini.impl;
|
|
package com.cyksj.service.mini.impl;
|
|
|
|
|
|
|
|
|
|
+import cn.hutool.core.collection.CollUtil;
|
|
|
import cn.hutool.core.date.DateTime;
|
|
import cn.hutool.core.date.DateTime;
|
|
|
|
|
+import cn.hutool.core.io.FileUtil;
|
|
|
import cn.hutool.core.util.RandomUtil;
|
|
import cn.hutool.core.util.RandomUtil;
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
import cn.hutool.http.ContentType;
|
|
import cn.hutool.http.ContentType;
|
|
|
import cn.hutool.http.Header;
|
|
import cn.hutool.http.Header;
|
|
|
|
|
+import cn.hutool.http.HttpUtil;
|
|
|
import cn.hutool.json.JSONArray;
|
|
import cn.hutool.json.JSONArray;
|
|
|
import cn.hutool.json.JSONObject;
|
|
import cn.hutool.json.JSONObject;
|
|
|
import cn.hutool.json.JSONUtil;
|
|
import cn.hutool.json.JSONUtil;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.cyksj.common.exception.BusinessRuntimeException;
|
|
import com.cyksj.common.exception.BusinessRuntimeException;
|
|
|
|
|
+import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
|
|
|
|
|
+import com.cyksj.common.util.Jsons;
|
|
|
import com.cyksj.common.util.SignatureUtils;
|
|
import com.cyksj.common.util.SignatureUtils;
|
|
|
import com.cyksj.common.util.StringUtil;
|
|
import com.cyksj.common.util.StringUtil;
|
|
|
import com.cyksj.mapper.mini.*;
|
|
import com.cyksj.mapper.mini.*;
|
|
@@ -24,20 +29,20 @@ import com.cyksj.service.mini.MiniPopularizeFrontService;
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
-import okhttp3.MediaType;
|
|
|
|
|
-import okhttp3.OkHttpClient;
|
|
|
|
|
-import okhttp3.Request;
|
|
|
|
|
-import okhttp3.RequestBody;
|
|
|
|
|
|
|
+import okhttp3.*;
|
|
|
import okhttp3.sse.EventSource;
|
|
import okhttp3.sse.EventSource;
|
|
|
import okhttp3.sse.EventSources;
|
|
import okhttp3.sse.EventSources;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
|
|
|
|
+import javax.imageio.stream.FileImageOutputStream;
|
|
|
|
|
+import java.io.File;
|
|
|
|
|
+import java.io.FileOutputStream;
|
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
|
import java.math.BigDecimal;
|
|
import java.math.BigDecimal;
|
|
|
-import java.util.List;
|
|
|
|
|
-import java.util.Map;
|
|
|
|
|
-import java.util.Optional;
|
|
|
|
|
|
|
+import java.nio.file.Files;
|
|
|
|
|
+import java.nio.file.Path;
|
|
|
|
|
+import java.util.*;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
|
|
|
|
@@ -53,6 +58,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontService {
|
|
public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontService {
|
|
|
public static final String GPT_URL = "https://api.nf.video/v1/chat/completions";
|
|
public static final String GPT_URL = "https://api.nf.video/v1/chat/completions";
|
|
|
|
|
|
|
|
|
|
+ public static final String NEW_MODEL_GPT_URL = "https://api.nf.video/v1/images/generations";
|
|
|
|
|
+
|
|
|
|
|
+ public static final String NEW_MODEL_GPT_EDIT_URL = "https://api.nf.video/v1/images/edits";
|
|
|
|
|
+
|
|
|
public static final String GPT_DRAW_TOKEN = "sk-Tsxxyfly6RCuyJ6hq6iNdPkSD1SzUxQX3mgO0ItF1AaLWacR";
|
|
public static final String GPT_DRAW_TOKEN = "sk-Tsxxyfly6RCuyJ6hq6iNdPkSD1SzUxQX3mgO0ItF1AaLWacR";
|
|
|
|
|
|
|
|
public static final String SIGN_SECRET = "6mR7XvKbPeShVmYq3t5w9z$C&FH@McQ";
|
|
public static final String SIGN_SECRET = "6mR7XvKbPeShVmYq3t5w9z$C&FH@McQ";
|
|
@@ -73,6 +82,8 @@ public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontServic
|
|
|
|
|
|
|
|
private final MiniPopularizeUserIncrTimesRecordMapper miniPopularizeUserIncrTimesRecordMapper;
|
|
private final MiniPopularizeUserIncrTimesRecordMapper miniPopularizeUserIncrTimesRecordMapper;
|
|
|
|
|
|
|
|
|
|
+ private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance();
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 连接超时
|
|
* 连接超时
|
|
|
*/
|
|
*/
|
|
@@ -80,7 +91,7 @@ public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontServic
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
@Transactional(rollbackFor = Throwable.class)
|
|
@Transactional(rollbackFor = Throwable.class)
|
|
|
- public MiniPopularizeResp createPictures(MiniAiPicturesReq miniAiPicturesReq) throws IOException {
|
|
|
|
|
|
|
+ public MiniPopularizeResp createPictures(MiniAiPicturesReq miniAiPicturesReq) throws Exception {
|
|
|
String conversationId = miniAiPicturesReq.getConversationId();
|
|
String conversationId = miniAiPicturesReq.getConversationId();
|
|
|
AtomicBoolean recoverNum = new AtomicBoolean(true);
|
|
AtomicBoolean recoverNum = new AtomicBoolean(true);
|
|
|
Long userId = miniAiPicturesReq.getUserId();
|
|
Long userId = miniAiPicturesReq.getUserId();
|
|
@@ -100,7 +111,7 @@ public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontServic
|
|
|
miniAiPicturesReq.setTips(miniPopularizeConfig.getTips());
|
|
miniAiPicturesReq.setTips(miniPopularizeConfig.getTips());
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+ int model = miniAiPicturesReq.getModel();
|
|
|
//聊天记录
|
|
//聊天记录
|
|
|
MiniPopularizeUserConversationChat chat = MiniPopularizeUserConversationChat.builder()
|
|
MiniPopularizeUserConversationChat chat = MiniPopularizeUserConversationChat.builder()
|
|
|
.conversationId(conversationId)
|
|
.conversationId(conversationId)
|
|
@@ -112,17 +123,6 @@ public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontServic
|
|
|
.userId(userId)
|
|
.userId(userId)
|
|
|
.build();
|
|
.build();
|
|
|
conversationChatMapper.insert(chat);
|
|
conversationChatMapper.insert(chat);
|
|
|
-// if (StrUtil.isNotBlank(miniAiPicturesReq.getImg())) {
|
|
|
|
|
-// //聊天记录
|
|
|
|
|
-// MiniPopularizeUserConversationChat imag = MiniPopularizeUserConversationChat.builder()
|
|
|
|
|
-// .conversationId(conversationId)
|
|
|
|
|
-// .img(miniAiPicturesReq.getImg())
|
|
|
|
|
-// .type(MiniPopularizeUserConversationChat.Type.image)
|
|
|
|
|
-// .role(MiniPopularizeUserConversationChat.Role.user)
|
|
|
|
|
-// .userId(userId)
|
|
|
|
|
-// .build();
|
|
|
|
|
-// conversationChatMapper.insert(imag);
|
|
|
|
|
-// }
|
|
|
|
|
//图像生成记录
|
|
//图像生成记录
|
|
|
MiniPopularizeUserConversationChat imageRecord = MiniPopularizeUserConversationChat.builder()
|
|
MiniPopularizeUserConversationChat imageRecord = MiniPopularizeUserConversationChat.builder()
|
|
|
.userId(miniAiPicturesReq.getUserId())
|
|
.userId(miniAiPicturesReq.getUserId())
|
|
@@ -131,17 +131,24 @@ public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontServic
|
|
|
.type(MiniPopularizeUserConversationChat.Type.image)
|
|
.type(MiniPopularizeUserConversationChat.Type.image)
|
|
|
.status(MiniPopularizeUserConversationChat.Status.processing)
|
|
.status(MiniPopularizeUserConversationChat.Status.processing)
|
|
|
.build();
|
|
.build();
|
|
|
-
|
|
|
|
|
miniPopularizeCommonService.saveImgRecord(imageRecord);
|
|
miniPopularizeCommonService.saveImgRecord(imageRecord);
|
|
|
- ConsoleStreamListener listener = ConsoleStreamListener.builder()
|
|
|
|
|
- .userId(userId)
|
|
|
|
|
- .miniPopularizeCommonService(miniPopularizeCommonService)
|
|
|
|
|
- .conversationId(conversationId)
|
|
|
|
|
- .imgRecordId(imageRecord.getId())
|
|
|
|
|
- .recoverNum(recoverNum.get())
|
|
|
|
|
- .build();
|
|
|
|
|
- streamChatCompletion(miniAiPicturesReq, listener);
|
|
|
|
|
-
|
|
|
|
|
|
|
+ //新版模型
|
|
|
|
|
+ if (model == 0) {
|
|
|
|
|
+ //只要上传了图片 就是垫图
|
|
|
|
|
+ if (StrUtil.isNotEmpty(miniAiPicturesReq.getImg())) {
|
|
|
|
|
+ miniAiPicturesReq.setType(2);
|
|
|
|
|
+ }
|
|
|
|
|
+ newGptModelCreateImage(miniAiPicturesReq, imageRecord);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ConsoleStreamListener listener = ConsoleStreamListener.builder()
|
|
|
|
|
+ .userId(userId)
|
|
|
|
|
+ .miniPopularizeCommonService(miniPopularizeCommonService)
|
|
|
|
|
+ .conversationId(conversationId)
|
|
|
|
|
+ .imgRecordId(imageRecord.getId())
|
|
|
|
|
+ .recoverNum(recoverNum.get())
|
|
|
|
|
+ .build();
|
|
|
|
|
+ streamChatCompletion(miniAiPicturesReq, listener);
|
|
|
|
|
+ }
|
|
|
MiniPopularizeResp resp = MiniPopularizeResp.builder()
|
|
MiniPopularizeResp resp = MiniPopularizeResp.builder()
|
|
|
.conversationId(conversationId)
|
|
.conversationId(conversationId)
|
|
|
.chatId(imageRecord.getId())
|
|
.chatId(imageRecord.getId())
|
|
@@ -191,6 +198,7 @@ public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontServic
|
|
|
}
|
|
}
|
|
|
//检验分享次数
|
|
//检验分享次数
|
|
|
shareCountCheck(userId);
|
|
shareCountCheck(userId);
|
|
|
|
|
+ //1次
|
|
|
Integer addNum = BigDecimal.ONE.intValue();
|
|
Integer addNum = BigDecimal.ONE.intValue();
|
|
|
MiniPopularizeUserIncrTimesRecord miniPopularizeUserIncrTimesRecord = new MiniPopularizeUserIncrTimesRecord();
|
|
MiniPopularizeUserIncrTimesRecord miniPopularizeUserIncrTimesRecord = new MiniPopularizeUserIncrTimesRecord();
|
|
|
miniPopularizeUserIncrTimesRecord.setUserId(userId);
|
|
miniPopularizeUserIncrTimesRecord.setUserId(userId);
|
|
@@ -361,4 +369,114 @@ public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontServic
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private void newGptModelCreateImage(MiniAiPicturesReq miniAiPicturesReq, MiniPopularizeUserConversationChat imageRecord) throws Exception {
|
|
|
|
|
+ String tips = miniAiPicturesReq.getTips();
|
|
|
|
|
+ Integer type = miniAiPicturesReq.getType();
|
|
|
|
|
+ Request request;
|
|
|
|
|
+ List<Path> temFilePaths = new ArrayList<>();
|
|
|
|
|
+ //按提示词出图
|
|
|
|
|
+ if (type == 1) {
|
|
|
|
|
+ //出图数量 1-10 默认4张
|
|
|
|
|
+ JSONObject json = new JSONObject();
|
|
|
|
|
+ json.putOpt("model", "gpt-image-1");
|
|
|
|
|
+ json.putOpt("n", 4);
|
|
|
|
|
+ json.putOpt("size", "1024x1024");
|
|
|
|
|
+ json.putOpt("prompt", tips);
|
|
|
|
|
+ ObjectMapper mapper = new ObjectMapper();
|
|
|
|
|
+ String requestBody = mapper.writeValueAsString(json);
|
|
|
|
|
+ request = new Request.Builder()
|
|
|
|
|
+ .url(NEW_MODEL_GPT_URL)
|
|
|
|
|
+ .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()),
|
|
|
|
|
+ requestBody))
|
|
|
|
|
+ .header(Header.AUTHORIZATION.name(), GPT_DRAW_TOKEN)
|
|
|
|
|
+ .build();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ String img = miniAiPicturesReq.getImg();
|
|
|
|
|
+ JSONArray imgs = JSONUtil.parseArray(img);
|
|
|
|
|
+ // 创建 MultipartBody.Builder 来处理多个文件上传
|
|
|
|
|
+ MultipartBody.Builder builder = new MultipartBody.Builder()
|
|
|
|
|
+ .setType(MultipartBody.FORM)
|
|
|
|
|
+ .addFormDataPart("model", "gpt-image-1")
|
|
|
|
|
+ .addFormDataPart("n", "4")
|
|
|
|
|
+ .addFormDataPart("prompt", tips);
|
|
|
|
|
+ //垫图
|
|
|
|
|
+ imgs.forEach(mg -> {
|
|
|
|
|
+ byte[] body = HttpUtil.downloadBytes(mg.toString());
|
|
|
|
|
+ Path tempFile = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ tempFile = Files.createTempFile("mgpt", ".jpeg");
|
|
|
|
|
+ try (FileImageOutputStream imageOutput = new FileImageOutputStream(tempFile.toFile())) {
|
|
|
|
|
+ imageOutput.write(body, 0, body.length);
|
|
|
|
|
+ }
|
|
|
|
|
+ // 读取图片文件
|
|
|
|
|
+ builder.addFormDataPart("image[]", tempFile.getFileName().toString(), RequestBody.create(MediaType.parse("image/png"), tempFile.toFile()));
|
|
|
|
|
+ temFilePaths.add(tempFile);
|
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
|
+ log.error("垫图失败:{}", StringUtil.getErrorText(e));
|
|
|
|
|
+ if (CollUtil.isNotEmpty(temFilePaths)) {
|
|
|
|
|
+ temFilePaths.forEach(file -> FileUtil.del(file));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ // 创建请求体
|
|
|
|
|
+ RequestBody requestBody = builder.build();
|
|
|
|
|
+ // 创建请求对象
|
|
|
|
|
+ request = new Request.Builder()
|
|
|
|
|
+ .url(NEW_MODEL_GPT_EDIT_URL)
|
|
|
|
|
+ .header(Header.AUTHORIZATION.name(), GPT_DRAW_TOKEN)
|
|
|
|
|
+ .post(requestBody)
|
|
|
|
|
+ .build();
|
|
|
|
|
+ }
|
|
|
|
|
+ OkHttpClient client = new OkHttpClient.Builder()
|
|
|
|
|
+ // 设置连接超时,单位:秒
|
|
|
|
|
+ .connectTimeout(300, TimeUnit.SECONDS)
|
|
|
|
|
+ // 设置读取超时,单位:秒
|
|
|
|
|
+ .readTimeout(120, TimeUnit.SECONDS)
|
|
|
|
|
+ .build();
|
|
|
|
|
+ TASK_EXECUTOR.execute(() -> {
|
|
|
|
|
+ try {
|
|
|
|
|
+ Response execute = client.newCall(request).execute();
|
|
|
|
|
+ ResponseBody body = execute.body();
|
|
|
|
|
+ JSONObject jsonObject = Jsons.parseObject(body.bytes(), JSONObject.class);
|
|
|
|
|
+ List<String> imgUrls = new ArrayList<>();
|
|
|
|
|
+ for (Object data : jsonObject.getJSONArray("data")) {
|
|
|
|
|
+ JSONObject b64Json = Jsons.parseObject(data, JSONObject.class);
|
|
|
|
|
+ String base64Image = b64Json.getStr("b64_json");
|
|
|
|
|
+ // 解码 Base64 字符串
|
|
|
|
|
+ byte[] imageBytes = Base64.getDecoder().decode(base64Image);
|
|
|
|
|
+ String fileName = new StringBuilder().append("mgpt").append(RandomUtil.randomString(9)).append(".png").toString();
|
|
|
|
|
+ // 保存为图片文件
|
|
|
|
|
+ try (FileOutputStream fos = new FileOutputStream(fileName)) {
|
|
|
|
|
+ fos.write(imageBytes);
|
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
|
+ e.printStackTrace();
|
|
|
|
|
+ }
|
|
|
|
|
+ File file = new File(fileName);
|
|
|
|
|
+ Map<String, Object> paramMap = new HashMap<>();
|
|
|
|
|
+ paramMap.put("file", file);
|
|
|
|
|
+ JSONObject result = JSONUtil.parseObj(HttpUtil.post("https://files.liuliangbang.vip/pic/ups", paramMap));
|
|
|
|
|
+ String imgUrl = result.getJSONObject("value").getJSONArray("saved").getJSONObject(0).getJSONObject("info").getStr("cdnUrl");
|
|
|
|
|
+ imgUrls.add(imgUrl);
|
|
|
|
|
+ if (file.exists()) {
|
|
|
|
|
+ file.delete();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ imageRecord.setStatus(MiniPopularizeUserConversationChat.Status.success);
|
|
|
|
|
+ imageRecord.setImg(imgUrls.toString());
|
|
|
|
|
+ imageRecord.setIsUpload(true);
|
|
|
|
|
+ conversationChatMapper.updateById(imageRecord);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("生成小程序GPT图片错误:{}", StringUtil.getErrorText(e));
|
|
|
|
|
+ //将用户使用次数返回
|
|
|
|
|
+ miniPopularizeCommonService.recoverUserLimit(imageRecord.getUserId(), true);
|
|
|
|
|
+ imageRecord.setStatus(MiniPopularizeUserConversationChat.Status.fail);
|
|
|
|
|
+ imageRecord.setContent(StringUtil.getErrorText(e));
|
|
|
|
|
+ miniPopularizeCommonService.saveImgRecord(imageRecord);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ if (CollUtil.isNotEmpty(temFilePaths)) {
|
|
|
|
|
+ temFilePaths.forEach(file -> FileUtil.del(file));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|