Merge pull request #52 from gcui-art/main

release
This commit is contained in:
blueeon 2024-04-29 14:03:58 +08:00 committed by GitHub
commit 9f0723f91a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 181 additions and 6 deletions

View File

@ -27,7 +27,6 @@ yarn-error.log*
# local env files # local env files
.env*.local .env*.local
.env
# vercel # vercel
.vercel .vercel

View File

@ -10,6 +10,7 @@ RUN npm run build
FROM node:lts-alpine FROM node:lts-alpine
WORKDIR /app WORKDIR /app
COPY package*.json ./ COPY package*.json ./
COPY .env ./
RUN npm install --only=production RUN npm install --only=production
COPY --from=builder /src/.next ./.next COPY --from=builder /src/.next ./.next
EXPOSE 3000 EXPOSE 3000

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

@ -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,4 +355,8 @@ const newSunoApi = async (cookie: string) => {
return await sunoApi.init(); return await sunoApi.init();
} }
if (!process.env.SUNO_COOKIE) {
console.log("Environment does not contain SUNO_COOKIE.", process.env)
}
export const sunoApi = newSunoApi(process.env.SUNO_COOKIE || ''); export const sunoApi = newSunoApi(process.env.SUNO_COOKIE || '');