From 146fb07209754da652739a22d937317e0cc42eb7 Mon Sep 17 00:00:00 2001 From: HuangHai <10402852@qq.com> Date: Thu, 15 May 2025 08:05:49 +0800 Subject: [PATCH] 'commit' --- .../Util/Suno/SunoMusicGenerator.java | 260 ++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/Suno/SunoMusicGenerator.java diff --git a/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/Suno/SunoMusicGenerator.java b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/Suno/SunoMusicGenerator.java new file mode 100644 index 00000000..6c2f804b --- /dev/null +++ b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/Suno/SunoMusicGenerator.java @@ -0,0 +1,260 @@ +package com.dsideal.aiSupport.Util.Suno; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.dsideal.aiSupport.Plugin.YamlProp; +import com.dsideal.aiSupport.Util.Midjourney.Kit.MjCommon; +import com.jfinal.kit.Prop; +import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static com.dsideal.aiSupport.AiSupportApplication.getEnvPrefix; + +public class SunoMusicGenerator { + + private static final String GENERATE_URL = "https://goapi.gptnb.ai/suno/v2/generate"; + private static final String FEED_URL = "https://goapi.gptnb.ai/suno/v2/feed"; + private static final int MAX_RETRIES = 30; // 最大重试次数 + private static final int RETRY_INTERVAL = 5000; // 重试间隔(毫秒) + private static final Logger log = LoggerFactory.getLogger(SunoMusicGenerator.class); + // 获取项目根目录路径 + protected static String projectRoot = System.getProperty("user.dir").replace("\\","/")+"/dsAiSupport"; + // 拼接相对路径 + protected static String basePath = projectRoot + "/src/main/java/com/dsideal/aiSupport/Util/Suno/Example/"; + + protected static String ak; // 填写access key + public static Prop PropKit; // 配置文件工具 + protected static final String BASE_URL = "https://goapi.gptnb.ai"; + + static { + //加载配置文件 + String configFile = "application_{?}.yaml".replace("{?}", getEnvPrefix()); + PropKit = new YamlProp(configFile); + ak = PropKit.get("GPTNB.sk"); + } + public static void main(String[] args) throws IOException, InterruptedException { + + // 创建OkHttpClient + OkHttpClient client = new OkHttpClient().newBuilder() + .build(); + + // 1. 生成音乐 + String musicDescription = "an anthemic dancepop song about dancing all night long"; + System.out.println("开始生成音乐: " + musicDescription); + + // 构建JSON请求体 + JSONObject requestJson = new JSONObject(); + requestJson.put("gpt_description_prompt", musicDescription); + requestJson.put("mv", "chirp-v3-5"); + requestJson.put("prompt", ""); + requestJson.put("make_instrumental", true); + + // 创建请求 + MediaType mediaType = MediaType.parse("application/json"); + RequestBody body = RequestBody.create(mediaType, requestJson.toJSONString()); + Request generateRequest = new Request.Builder() + .url(GENERATE_URL) + .method("POST", body) + .addHeader("Content-Type", "application/json") + .addHeader("Authorization", "Bearer " + ak) + .build(); + + // 执行生成请求 + Response generateResponse = client.newCall(generateRequest).execute(); + + // 处理生成响应 + if (!generateResponse.isSuccessful()) { + System.out.println("音乐生成请求失败,状态码: " + generateResponse.code()); + System.out.println("错误信息: " + generateResponse.message()); + return; + } + + String generateResponseBody = generateResponse.body().string(); + System.out.println("音乐生成响应: " + generateResponseBody); + + // 从响应中提取任务ID + JSONObject generateJson = JSON.parseObject(generateResponseBody); + String taskId = null; + + // 根据响应格式提取任务ID + // 注意:这里需要根据实际的响应格式进行调整 + if (generateJson.containsKey("id")) { + taskId = generateJson.getString("id"); + } else if (generateJson.containsKey("task_id")) { + taskId = generateJson.getString("task_id"); + } else if (generateJson.containsKey("clip_id")) { + taskId = generateJson.getString("clip_id"); + } + + if (taskId == null) { + System.out.println("无法从响应中提取任务ID,无法继续查询"); + return; + } + + System.out.println("音乐生成任务已提交,任务ID: " + taskId); + System.out.println("开始查询任务状态..."); + + // 存储任务ID列表 + List taskIds = new ArrayList<>(); + taskIds.add(taskId); + + // 2. 查询任务状态 + boolean isComplete = false; + int retryCount = 0; + String audioUrl = null; + + while (!isComplete && retryCount < MAX_RETRIES) { + // 等待一段时间再查询 + Thread.sleep(RETRY_INTERVAL); + + // 构建查询URL,添加ids参数 + HttpUrl.Builder urlBuilder = HttpUrl.parse(FEED_URL).newBuilder(); + + // 添加ids参数,用逗号分隔多个ID + if (!taskIds.isEmpty()) { + // 注意:这里我们查询的是clips的ID,而不是生成任务的ID + // 从生成响应中获取clips的ID + List clipIds = new ArrayList<>(); + if (generateJson.containsKey("clips")) { + JSONArray clipsArray = generateJson.getJSONArray("clips"); + for (int i = 0; i < clipsArray.size(); i++) { + JSONObject clip = clipsArray.getJSONObject(i); + if (clip.containsKey("id")) { + clipIds.add(clip.getString("id")); + } + } + } + + // 如果找到了clips的ID,则使用这些ID进行查询 + if (!clipIds.isEmpty()) { + String idsParam = String.join(",", clipIds); + urlBuilder.addQueryParameter("ids", idsParam); + log.info("使用clips ID查询: {}", idsParam); + } else { + // 否则使用任务ID + String idsParam = String.join(",", taskIds); + urlBuilder.addQueryParameter("ids", idsParam); + log.info("使用任务ID查询: {}", idsParam); + } + } + + // 创建查询请求 + Request feedRequest = new Request.Builder() + .url(urlBuilder.build()) + .method("GET", null) + .addHeader("Authorization", "Bearer " + ak) + .addHeader("Accept", "application/json") // 添加Accept头 + .build(); + + log.info("查询URL: {}", urlBuilder.build()); + + // 执行查询请求 + Response feedResponse = client.newCall(feedRequest).execute(); + + // 处理查询响应 + if (!feedResponse.isSuccessful()) { + System.out.println("查询任务状态失败,状态码: " + feedResponse.code()); + System.out.println("错误信息: " + feedResponse.message()); + retryCount++; + continue; + } + + String feedResponseBody = feedResponse.body().string(); + JSONObject jsonResponse = JSON.parseObject(feedResponseBody); + JSONArray clips = jsonResponse.getJSONArray("clips"); + + if (clips != null && !clips.isEmpty()) { + // 遍历所有返回的音乐片段 + for (int i = 0; i < clips.size(); i++) { + JSONObject clip = clips.getJSONObject(i); + String clipId = clip.getString("id"); + String status = clip.getString("status"); + String title = clip.getString("title"); + + System.out.println("\n查询结果 (第" + (retryCount + 1) + "次):"); + System.out.println("ID: " + clipId); + System.out.println("标题: " + title); + System.out.println("状态: " + status); + + // 检查是否是我们要查询的任务 + if (taskIds.contains(clipId)) { + // 检查是否完成 + if ("complete".equals(status)) { + audioUrl = clip.getString("audio_url"); + System.out.println("音乐生成已完成!"); + System.out.println("音频URL: " + audioUrl); + isComplete = true; + break; // 找到了我们要查询的任务,并且已完成 + } else if ("streaming".equals(status)) { + System.out.println("音乐生成中,继续等待..."); + } else if ("failed".equals(status)) { + System.out.println("音乐生成失败!"); + isComplete = true; // 任务失败,不再继续查询 + break; + } + } + } + } else { + System.out.println("未找到音乐片段,继续等待..."); + } + + retryCount++; + } + + // 3. 下载音频文件(如果生成成功) + if (isComplete && audioUrl != null) { + String fileName = "suno_music_" + System.currentTimeMillis() + ".mp3"; + String savePath = "./downloads/" + fileName; + downloadAudio(client, audioUrl, savePath); + } else if (retryCount >= MAX_RETRIES) { + System.out.println("达到最大重试次数,任务可能仍在处理中"); + System.out.println("请稍后手动查询任务ID: " + taskId); + } + } + + /** + * 下载音频文件 + * @param client OkHttpClient实例 + * @param audioUrl 音频URL + * @param savePath 保存路径 + */ + public static void downloadAudio(OkHttpClient client, String audioUrl, String savePath) throws IOException { + System.out.println("开始下载音频文件..."); + + Request request = new Request.Builder() + .url(audioUrl) + .method("GET", null) + .build(); + + Response response = client.newCall(request).execute(); + + if (response.isSuccessful()) { + // 确保目录存在 + java.io.File file = new java.io.File(savePath); + java.io.File parentDir = file.getParentFile(); + if (parentDir != null && !parentDir.exists()) { + parentDir.mkdirs(); + } + + // 保存文件 + try (java.io.InputStream inputStream = response.body().byteStream(); + java.io.FileOutputStream outputStream = new java.io.FileOutputStream(savePath)) { + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + outputStream.flush(); + } + + System.out.println("音频下载成功,保存路径: " + savePath); + } else { + System.out.println("下载音频失败,状态码: " + response.code()); + } + } +} \ No newline at end of file