Referência: Módulo "Reference Lab" — ideação e referência, não engine principal.
- Opcional: FunkLab funciona sem Suno. A integração é um módulo adicional.
- Isolado: Toda comunicação com Suno passa por uma camada interna.
- Referência: Áudio Suno → input para análise FunkLab → extração de grooves/BPM.
- Não substitui: Engine local continua sendo o core do produto.
UI (Next.js)
│
▼
FunkLab API (FastAPI)
│
├──► Engine local (sketch, bassline, analyze)
│
└──► Suno Integration Layer
│
├── suno_client.py # HTTP client
├── idea_service.py # orquestração
└── references/ # armazenamento
Fluxo Reference Lab:
prompt → Suno gera áudio → download → analyze → salvar em references/
funklab/
├── api/
│ ├── integrations/
│ │ __init__.py
│ │ suno_client.py # Cliente HTTP para api.sunoapi.org
│ │
│ ├── idea_service.py # Orquestra generate + analyze + save
│ ├── routes_idea.py # POST /idea/generate, GET /idea/{id}, POST /idea/{id}/analyze
│ └── schemas.py # + IdeaGenerateRequest, IdeaStatusResponse, etc.
│
├── projects/
│ └── references/ # Ideias geradas pelo Suno
│ └── {idea_id}/
│ ├── manifest.json
│ ├── audio_0.mp3
│ ├── audio_1.mp3
│ └── analysis_0.json
│
└── .env.example
SUNO_API_KEY=
SUNO_API_BASE=https://api.sunoapi.org
- Chamar
POST /api/v1/generate(geração de música) - Chamar
GET /api/v1/generate/record-info?taskId=...(polling) - Baixar áudio de
audioUrloustreamAudioUrl
- customMode: false — mais simples, só
promptobrigatório - instrumental: true — referências instrumentais para análise de groove
- model: V4_5 ou V4_5ALL — bom custo/qualidade, até 8 min
- callBackUrl — opcional; preferir polling para controle
# api/integrations/suno_client.py
class SunoClient:
def __init__(self, api_key: str, base_url: str = "https://api.sunoapi.org"):
...
async def generate(
self,
prompt: str,
instrumental: bool = True,
model: str = "V4_5",
custom_mode: bool = False,
) -> str:
"""Envia geração. Retorna task_id."""
async def get_status(self, task_id: str) -> SunoTaskStatus:
"""Poll status. Retorna status, suno_data quando SUCCESS."""
async def download_audio(self, url: str, dest: Path) -> Path:
"""Baixa MP3 e salva em dest."""{
"prompt": "Brazilian funk groove, 130 BPM, deep bass, minimal drums",
"customMode": false,
"instrumental": true,
"model": "V4_5",
"callBackUrl": ""
}Response: { "code": 200, "data": { "taskId": "5c79****be8e" } }
- Chamar
GET /api/v1/generate/record-info?taskId=...a cada 5–10 s - Status:
PENDING→TEXT_SUCCESS→FIRST_SUCCESS→SUCCESS - Em
SUCCESS,data.response.sunoDataé array de tracks (até 2) - Cada track:
id,audioUrl,streamAudioUrl,duration,title, etc.
-
run_idea_generate(prompt, model?)- Chama
SunoClient.generate() - Cria pasta
projects/references/{idea_id} - Salva
manifest.jsoncomtask_id,prompt,status: pending - Retorna
idea_id(UUID) etask_id
- Chama
-
get_idea_status(idea_id)- Lê manifest
- Se
status == pending, faz polling no Suno - Atualiza manifest
- Retorna status +
tracksquando pronto
-
run_idea_analyze(idea_id, track_index=0)- Garante que áudio já foi baixado (se não, baixa)
- Chama
run_analyze(audio_path)(engine existente) - Salva
analysis_{track_index}.json - Atualiza manifest com resultado
- Retorna
AnalyzeResponse
{
"idea_id": "uuid",
"task_id": "suno_task_id",
"prompt": "...",
"model": "V4_5",
"status": "complete",
"created_at": "ISO8601",
"tracks": [
{
"id": "suno_audio_id",
"audio_url": "https://...",
"local_path": "audio_0.mp3",
"duration": 120.5,
"analysis": { "bpm": 130, "pattern": "...", ... }
}
]
}| Método | Endpoint | Descrição |
|---|---|---|
| POST | /api/v1/idea/generate |
Inicia geração Suno, retorna idea_id |
| GET | /api/v1/idea/{idea_id} |
Status da ideia + tracks (com polling se pendente) |
| POST | /api/v1/idea/{idea_id}/analyze |
Analisa track no FunkLab, retorna BPM/groove |
| GET | /api/v1/idea/{idea_id}/files/{path} |
Serve áudio ou JSON (proxy para projeto) |
# api/schemas.py (adicionar)
class IdeaGenerateRequest(BaseModel):
prompt: str = Field(..., max_length=500)
model: str = Field(default="V4_5")
instrumental: bool = Field(default=True)
class IdeaGenerateResponse(BaseModel):
idea_id: str
task_id: str
status: str = "pending"
message: str = "Geração iniciada. Use GET /idea/{id} para acompanhar."
class IdeaTrackInfo(BaseModel):
id: str
audio_url: str | None
local_path: str | None
duration: float | None
analysis: dict | None = None
class IdeaStatusResponse(BaseModel):
idea_id: str
status: str # pending, complete, failed
prompt: str
tracks: list[IdeaTrackInfo]
error: str | None = None-
POST /idea/generate
- Se
SUNO_API_KEYnão estiver configurado →503 Service Unavailable - Retorna
idea_idimediatamente - Geração é assíncrona
- Se
-
GET /idea/{idea_id}
- Se
status == pending, faz até 1 poll no Suno - Se SUCCESS, baixa áudios para
projects/references/{idea_id}/ - Retorna status + tracks
- Se
-
POST /idea/{idea_id}/analyze
- Body opcional:
{ "track_index": 0 } - Usa
run_analyzeexistente - Persiste análise no manifest e retorna
AnalyzeResponse
- Body opcional:
# .env ou .env.local
SUNO_API_KEY= # Obrigatório para o módulo Idea
SUNO_API_BASE=https://api.sunoapi.org- Se
SUNO_API_KEYvazio: rotas/idea/*retornam 503 com mensagem clara.
Sugestões de prompt para geração instrumental focada em groove:
Brazilian funk groove, 130 BPM, deep bass, minimal drums, swing feel
Phonk style, 140 BPM, heavy 808, dark atmosphere, instrumental
Tech house loop, 125 BPM, rolling bassline, percussion, no vocals
Mandelão groove, 128 BPM, brasileiro, instrumental
| Código Suno | Ação |
|---|---|
| 401 | Log + 503 "Suno API: credenciais inválidas" |
| 429 | 503 "Créditos insuficientes na Suno API" |
| 430 | 503 "Rate limit. Tente em alguns segundos" |
| 500 | 503 "Suno API temporariamente indisponível" |
| SENSITIVE_WORD_ERROR | 400 "Prompt contém termos bloqueados" |
| GENERATE_AUDIO_FAILED | 500 "Falha na geração. Tente outro prompt" |
- Criar
api/integrations/__init__.py - Criar
api/integrations/suno_client.py(generate, get_status, download_audio) - Criar
api/idea_service.py(run_idea_generate, get_idea_status, run_idea_analyze) - Adicionar schemas em
api/schemas.py - Criar
api/routes_idea.py - Registrar router em
api/server.py - Criar
projects/references/.gitkeep - Adicionar
SUNO_API_KEYem.env.example - Tratar ausência de API key (503)
- Testar fluxo: generate → poll → analyze
- Form: prompt, model (select), instrumental (checkbox)
- Botão "Gerar referência"
- Área de status (polling ou SSE)
- Quando pronto: player de áudio, botão "Analisar no FunkLab"
- Exibir resultado da análise (BPM, pattern, etc.)
- Listar ideias em
projects/references/ - Endpoint
GET /api/v1/references(opcional) - Filtrar por prompt, BPM, data
Cole o bloco abaixo para implementar a Fase 1:
Implementar a integração Suno conforme docs/SUNO_INTEGRATION_DESIGN.md.
Tarefas:
1. Criar api/integrations/suno_client.py com SunoClient (generate, get_status, download_audio).
- Usar httpx para requests assíncronos.
- generate: POST /api/v1/generate com customMode=false, instrumental=true.
- get_status: GET /api/v1/generate/record-info?taskId=...
- download_audio: GET na URL do áudio, salvar em Path.
2. Criar api/idea_service.py com run_idea_generate, get_idea_status, run_idea_analyze.
- idea_id = uuid4().hex
- Persistir manifest.json em projects/references/{idea_id}/
- Integrar com engine_service.run_analyze para análise.
3. Adicionar schemas IdeaGenerateRequest, IdeaGenerateResponse, IdeaStatusResponse, IdeaTrackInfo em api/schemas.py.
4. Criar api/routes_idea.py com POST /generate, GET /{idea_id}, POST /{idea_id}/analyze.
- Retornar 503 se SUNO_API_KEY não configurado.
- Incluir router em api/server.py com prefix /api/v1/idea e tags ["idea"].
5. Criar projects/references/.gitkeep e atualizar .env.example com SUNO_API_KEY.
6. Garantir que httpx esteja em requirements/dependencies se necessário.
- Suno API Docs
- Generate Music
- Get Music Generation Details
api/engine_service.py—run_analyzecore/groove_analyzer.py—GrooveAnalyzer