feat: add extend api

- Added extend API
- Added documentation for extend API
This commit is contained in:
blueeon 2024-04-27 17:58:27 +08:00
parent fc3d59a4e9
commit dd5a5208de
7 changed files with 177 additions and 6 deletions

View File

@ -123,6 +123,7 @@ Suno API currently mainly implements the following APIs:
- `/api/get`: Get music information based on the id. Use “,” to separate multiple ids. - `/api/get`: Get music information based on the id. Use “,” to separate multiple ids.
If no IDs are provided, all music will be returned. If no IDs are provided, all music will be returned.
- `/api/get_limit`: Get quota Info - `/api/get_limit`: Get quota Info
- `/api/extend_audio`: Extend audio length
``` ```
For more detailed documentation, please check out the demo site: For more detailed documentation, please check out the demo site:
@ -146,6 +147,11 @@ def custom_generate_audio(payload):
return response.json() return response.json()
def extend_audio(payload):
url = f"{base_url}/api/extend_audio"
response = requests.post(url, json=payload, headers={'Content-Type': 'application/json'})
return response.json()
def generate_audio_by_prompt(payload): def generate_audio_by_prompt(payload):
url = f"{base_url}/api/generate" url = f"{base_url}/api/generate"
response = requests.post(url, json=payload, headers={'Content-Type': 'application/json'}) response = requests.post(url, json=payload, headers={'Content-Type': 'application/json'})
@ -209,6 +215,14 @@ async function generateAudioByPrompt(payload) {
return response.data; return response.data;
} }
async function extendAudio(payload) {
const url = `${baseUrl}/api/extend_audio`;
const response = await axios.post(url, payload, {
headers: { "Content-Type": "application/json" },
});
return response.data;
}
async function getAudioInformation(audioIds) { async function getAudioInformation(audioIds) {
const url = `${baseUrl}/api/get?ids=${audioIds}`; const url = `${baseUrl}/api/get?ids=${audioIds}`;
const response = await axios.get(url); const response = await axios.get(url);
@ -273,13 +287,13 @@ LGPL-3.0 or later
## Contact Us ## Contact Us
- Contact us: <support@gcui.art> - Contact us: <support@gcui.ai>
## Related Links ## Related Links
- Project repository: [github.com/gcui-art/suno-api](https://github.com/gcui-art/suno-api) - Project repository: [github.com/gcui-art/suno-api](https://github.com/gcui-art/suno-api)
- Suno.ai official website: [suno.ai](https://suno.ai) - Suno.ai official website: [suno.ai](https://suno.ai)
- Demo: [suno.gcui.art](https://suno.gcui.art) - Demo: [suno.gcui.ai](https://suno.gcui.ai)
## Statement ## Statement

View File

@ -33,7 +33,7 @@ Suno.ai v3 是一个令人惊叹的 AI 音乐服务,虽然官方还没有开
- 完美的实现了 app.suno.ai 中的大部分 API - 完美的实现了 app.suno.ai 中的大部分 API
- 自动保持账号活跃 - 自动保持账号活跃
- 兼容OpenAI的 `/v1/chat/completions` API 格式 - 兼容 OpenAI `/v1/chat/completions` API 格式
- 支持 Custom Mode - 支持 Custom Mode
- 一键部署到 vercel - 一键部署到 vercel
- 除了标准 API还适配了 GPTs、coze 等 Agent 平台的 API Schema所以你可以把它当做一个 LLM 的工具/插件/Action集成到任意 AI Agent 中。 - 除了标准 API还适配了 GPTs、coze 等 Agent 平台的 API Schema所以你可以把它当做一个 LLM 的工具/插件/Action集成到任意 AI Agent 中。
@ -120,6 +120,7 @@ Suno API 目前主要实现了以下 API:
- `/api/generate_lyrics`: 根据Prompt创建歌词 - `/api/generate_lyrics`: 根据Prompt创建歌词
- `/api/get`: 根据id获取音乐信息。获取多个请用","分隔不传ids则返回所有音乐 - `/api/get`: 根据id获取音乐信息。获取多个请用","分隔不传ids则返回所有音乐
- `/api/get_limit`: 获取配额信息 - `/api/get_limit`: 获取配额信息
- `/api/extend_audio`: 在一首音乐的基础上,扩展音乐长度
``` ```
详细文档请查看演示站点: 详细文档请查看演示站点:
@ -142,6 +143,11 @@ def custom_generate_audio(payload):
response = requests.post(url, json=payload, headers={'Content-Type': 'application/json'}) response = requests.post(url, json=payload, headers={'Content-Type': 'application/json'})
return response.json() return response.json()
def extend_audio(payload):
url = f"{base_url}/api/extend_audio"
response = requests.post(url, json=payload, headers={'Content-Type': 'application/json'})
return response.json()
def generate_audio_by_prompt(payload): def generate_audio_by_prompt(payload):
url = f"{base_url}/api/generate" url = f"{base_url}/api/generate"
@ -205,6 +211,13 @@ async function generateAudioByPrompt(payload) {
}); });
return response.data; return response.data;
} }
async function extendAudio(payload) {
const url = `${baseUrl}/api/extend_audio`;
const response = await axios.post(url, payload, {
headers: { "Content-Type": "application/json" },
});
return response.data;
}
async function getAudioInformation(audioIds) { async function getAudioInformation(audioIds) {
const url = `${baseUrl}/api/get?ids=${audioIds}`; const url = `${baseUrl}/api/get?ids=${audioIds}`;
@ -270,13 +283,13 @@ LGPL-3.0 或更高版本
## 联系方式 ## 联系方式
- 联系我们:<support@gcui.art> - 联系我们:<support@gcui.ai>
## 相关链接 ## 相关链接
- 项目仓库: [github.com/gcui-art/suno-api](https://github.com/gcui-art/suno-api) - 项目仓库: [github.com/gcui-art/suno-api](https://github.com/gcui-art/suno-api)
- Suno.ai 官网: [suno.ai](https://suno.ai) - Suno.ai 官网: [suno.ai](https://suno.ai)
- 演示站点: [suno.gcui.art](https://suno.gcui.art) - 演示站点: [suno.gcui.ai](https://suno.gcui.ai)
## 声明 ## 声明

View File

@ -0,0 +1,70 @@
import { NextResponse, NextRequest } from "next/server";
import { sunoApi } from "@/lib/SunoApi";
import { corsHeaders } from "@/lib/utils";
export const dynamic = "force-dynamic";
export async function POST(req: NextRequest) {
if (req.method === 'POST') {
try {
const body = await req.json();
const { audio_id, prompt, continue_at, tags, title } = body;
console.log(body)
if (!audio_id) {
return new NextResponse(JSON.stringify({ error: 'Audio ID is required' }), {
status: 400,
headers: {
'Content-Type': 'application/json',
...corsHeaders
}
});
}
const audioInfo = await (await sunoApi)
.extendAudio(audio_id, prompt, continue_at, tags, title);
return new NextResponse(JSON.stringify(audioInfo), {
status: 200,
headers: {
'Content-Type': 'application/json',
...corsHeaders
}
});
} catch (error: any) {
console.error('Error extend audio:', JSON.stringify(error.response.data));
if (error.response.status === 402) {
return new NextResponse(JSON.stringify({ error: error.response.data.detail }), {
status: 402,
headers: {
'Content-Type': 'application/json',
...corsHeaders
}
});
}
return new NextResponse(JSON.stringify({ error: 'Internal server error: ' + JSON.stringify(error.response.data.detail) }), {
status: 500,
headers: {
'Content-Type': 'application/json',
...corsHeaders
}
});
}
} else {
return new NextResponse('Method Not Allowed', {
headers: {
Allow: 'POST',
...corsHeaders
},
status: 405
});
}
}
export async function OPTIONS(request: Request) {
return new Response(null, {
status: 200,
headers: corsHeaders
});
}

View File

@ -28,6 +28,7 @@ export default function Docs() {
- \`/api/get\`: Get music information based on the id. Use “,” to separate multiple - \`/api/get\`: Get music information based on the id. Use “,” to separate multiple
ids. If no IDs are provided, all music will be returned. ids. If no IDs are provided, all music will be returned.
- \`/api/get_limit\`: Get quota Info - \`/api/get_limit\`: Get quota Info
- \`/api/extend_audio\`: Extend audio length
\`\`\` \`\`\`
Feel free to explore the detailed API parameters and conduct tests on this page. Feel free to explore the detailed API parameters and conduct tests on this page.

View File

@ -179,6 +179,50 @@
} }
} }
}, },
"/api/extend_audio": {
"post": {
"summary": "Extend audio length.",
"description": "Extend audio length.",
"tags": ["default"],
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["audio_id"],
"properties": {
"audio_id": {
"type": "string",
"description": "The ID of the audio clip to extend.",
"example": "e76498dc-6ab4-4a10-a19f-8a095790e28d"
},
"prompt": {
"type": "string",
"description": "Detailed prompt, including information such as music lyrics.",
"example": ""
},
"continue_at": {
"type": "string",
"description": "Extend a new clip from a song at mm:ss(e.g. 00:30). Default extends from the end of the song.",
"example": "109.96"
},
"title": {
"type": "string",
"description": "Music title",
"example": ""
},
"tags": {
"type": "string",
"description": "Music genre",
"example": ""
}
}
}
}
}
}
}
},
"/api/generate_lyrics": { "/api/generate_lyrics": {
"post": { "post": {
"summary": "Generate lyrics based on Prompt.", "summary": "Generate lyrics based on Prompt.",

View File

@ -105,6 +105,7 @@ Suno API currently mainly implements the following APIs:
- \`/api/get\`: Get music list - \`/api/get\`: Get music list
- \`/api/get?ids=\`: Get music Info by id, separate multiple id with ",". - \`/api/get?ids=\`: Get music Info by id, separate multiple id with ",".
- \`/api/get_limit\`: Get quota Info - \`/api/get_limit\`: Get quota Info
- \`/api/extend_audio\`: Extend audio length
\`\`\` \`\`\`
For more detailed documentation, please check out the demo site: For more detailed documentation, please check out the demo site:

View File

@ -255,6 +255,34 @@ class SunoApi {
return lyricsResponse.data; return lyricsResponse.data;
} }
/**
* Extends an existing audio clip by generating additional content based on the provided prompt.
*
* @param audioId The ID of the audio clip to extend.
* @param prompt The prompt for generating additional content.
* @param continueAt Extend a new clip from a song at mm:ss(e.g. 00:30). Default extends from the end of the song.
* @param tags Style of Music.
* @param title Title of the song.
* @returns A promise that resolves to an AudioInfo object representing the extended audio clip.
*/
public async extendAudio(
audioId: string,
prompt: string = "",
continueAt: string = "0",
tags: string = "",
title: string = ""
): Promise<AudioInfo> {
const response = await this.client.post(`${SunoApi.BASE_URL}/api/generate/v2/`, {
continue_clip_id: audioId,
continue_at: continueAt,
mv: "chirp-v3-0",
prompt: prompt,
tags: tags,
title: ""
});
return response.data;
}
/** /**
* Processes the lyrics (prompt) from the audio metadata into a more readable format. * Processes the lyrics (prompt) from the audio metadata into a more readable format.
* @param prompt The original lyrics text. * @param prompt The original lyrics text.
@ -327,7 +355,7 @@ const newSunoApi = async (cookie: string) => {
return await sunoApi.init(); return await sunoApi.init();
} }
if (! process.env.SUNO_COOKIE) { if (!process.env.SUNO_COOKIE) {
console.log("Environment does not contain SUNO_COOKIE.", process.env) console.log("Environment does not contain SUNO_COOKIE.", process.env)
} }