Selaa lähdekoodia

GPT小程序新版模型生图

zoujiajian 1 vuosi sitten
vanhempi
sitoutus
3190125789

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/MiniPopularizeUserConversationChat.java

@@ -36,6 +36,11 @@ public class MiniPopularizeUserConversationChat extends BaseEntity {
 	 */
 	private Long cid;
 
+	/**
+	 * 是否上传至oss
+	 */
+	private Boolean isUpload;
+
 	@Getter
 	public enum Type {
 		image("图像"),

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/request/MiniAiPicturesReq.java

@@ -44,4 +44,9 @@ public class MiniAiPicturesReq {
 	 * 默认普通1  2.垫图风格
 	 */
 	private Integer type = 1;
+
+	/**
+	 * 模型 默认新版模型
+	 */
+	private int model = 0;
 }

+ 2 - 0
netflix-dao/src/main/java/com/cyksj/model/response/MiniPopularizeResp.java

@@ -19,4 +19,6 @@ public class MiniPopularizeResp {
 	private String conversationId;
 
 	private Long chatId;
+
+	private String url;
 }

+ 1 - 1
netflix-service/src/main/java/com/cyksj/service/mini/MiniPopularizeFrontService.java

@@ -15,7 +15,7 @@ import java.io.IOException;
  * 创建时间:2025/4/8 16:51
  */
 public interface MiniPopularizeFrontService {
-	MiniPopularizeResp createPictures(MiniAiPicturesReq miniAiPicturesReq) throws IOException;
+	MiniPopularizeResp createPictures(MiniAiPicturesReq miniAiPicturesReq) throws Exception;
 
 	MiniPopularizeUser getUser(long userId);
 

+ 148 - 30
netflix-service/src/main/java/com/cyksj/service/mini/impl/MiniPopularizeFrontServiceImpl.java

@@ -1,15 +1,20 @@
 package com.cyksj.service.mini.impl;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateTime;
+import cn.hutool.core.io.FileUtil;
 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.http.HttpUtil;
 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.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.StringUtil;
 import com.cyksj.mapper.mini.*;
@@ -24,20 +29,20 @@ 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.*;
 import okhttp3.sse.EventSource;
 import okhttp3.sse.EventSources;
 import org.springframework.stereotype.Service;
 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.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.atomic.AtomicBoolean;
 
@@ -53,6 +58,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
 public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontService {
 	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 SIGN_SECRET = "6mR7XvKbPeShVmYq3t5w9z$C&FH@McQ";
@@ -73,6 +82,8 @@ public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontServic
 
 	private final MiniPopularizeUserIncrTimesRecordMapper miniPopularizeUserIncrTimesRecordMapper;
 
+	private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance();
+
 	/**
 	 * 连接超时
 	 */
@@ -80,7 +91,7 @@ public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontServic
 
 	@Override
 	@Transactional(rollbackFor = Throwable.class)
-	public MiniPopularizeResp createPictures(MiniAiPicturesReq miniAiPicturesReq) throws IOException {
+	public MiniPopularizeResp createPictures(MiniAiPicturesReq miniAiPicturesReq) throws Exception {
 		String conversationId = miniAiPicturesReq.getConversationId();
 		AtomicBoolean recoverNum = new AtomicBoolean(true);
 		Long userId = miniAiPicturesReq.getUserId();
@@ -100,7 +111,7 @@ public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontServic
 				miniAiPicturesReq.setTips(miniPopularizeConfig.getTips());
 			}
 		}
-
+		int model = miniAiPicturesReq.getModel();
 		//聊天记录
 		MiniPopularizeUserConversationChat chat = MiniPopularizeUserConversationChat.builder()
 				.conversationId(conversationId)
@@ -112,17 +123,6 @@ public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontServic
 				.userId(userId)
 				.build();
 		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()
 				.userId(miniAiPicturesReq.getUserId())
@@ -131,17 +131,24 @@ public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontServic
 				.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);
-
+		//新版模型
+		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()
 				.conversationId(conversationId)
 				.chatId(imageRecord.getId())
@@ -191,6 +198,7 @@ public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontServic
 		}
 		//检验分享次数
 		shareCountCheck(userId);
+		//1次
 		Integer addNum = BigDecimal.ONE.intValue();
 		MiniPopularizeUserIncrTimesRecord miniPopularizeUserIncrTimesRecord = new MiniPopularizeUserIncrTimesRecord();
 		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));
+				}
+			}
+		});
+	}
 }

+ 1 - 1
netflix-web/src/main/java/com/cyksj/web/controller/mini/PopularizeMiniController.java

@@ -54,7 +54,7 @@ public class PopularizeMiniController {
 	 * 创作 图片
 	 */
 	@PostMapping("/create/pictures")
-	public Result<MiniPopularizeResp> createPictures(@RequestBody MiniAiPicturesReq miniAiPicturesReq) throws IOException {
+	public Result<MiniPopularizeResp> createPictures(@RequestBody MiniAiPicturesReq miniAiPicturesReq) throws Exception {
 		long userId = StpUserUtil.getLoginIdAsLong();
 		miniAiPicturesReq.setUserId(userId);
 		MiniPopularizeResp resp = miniPopularizeFrontService.createPictures(miniAiPicturesReq);