codai docs
Gateway

Versuri și jam live

Uneltele de compoziție din codai Studio — scrii versuri cu verificarea silabelor și a rimelor, le aliniezi la un clip vocal pentru sincronizare karaoke și LRC și cânți live cu muzică generată printr-un WebSocket.

Lângă creațiile audio stau trei unelte: un scriitor de versuri care verifică metrica și rima, alinierea versurilor care sincronizează rândurile cu un clip vocal și un jam live care transmite muzică generată pe care o dirijezi în timp real.

MetodăCaleRezultatFacturare
POST/v1/studio/lyricsVersuri cu raport de silabe și rimeTokeni (codai::lyrics)
POST/v1/studio/lyrics/alignRânduri sincronizate + LRC, aplicate ca setLyricsGratuit cu cuvinte din cache, altfel speech-to-text (codai::lyrics-align)
WS/v1/studio/jamAudio PCM live dirijat prin prompturiPe minut început (codai::jam)

Scrierea versurilor

curl https://ai.codai.ro/v1/studio/lyrics \
  -H "Authorization: Bearer $CODAI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: song-7" \
  -d '{
    "brief": "o noapte de vară la mare, doi prieteni care se regăsesc",
    "language": "ro",
    "genre": "pop",
    "structure": ["verse", "chorus", "verse", "chorus"],
    "syllables_per_line": 8,
    "rhyme_scheme": "AABB",
    "lines_per_section": 4
  }'
CâmpImplicitObservații
briefobligatoriu3–4000 de caractere; nu se jurnalizează niciodată
languageobligatoriuro sau en; româna folosește diacriticele corecte (ș ț ă î â)
genre, mood, title—Text liber (100 / 100 / 200 de caractere)
structureverse, chorus, verse, chorus, bridge, chorus1–12 dintre intro, verse, pre_chorus, chorus, bridge, outro, instrumental, custom
syllables_per_line—3–20; verificat cu o toleranță de ±1
rhyme_schemefreeAABB, ABAB sau free
lines_per_section42–8

Scriitorul rulează o singură tură codai limitată, cu un tool forțat, apoi verifică fiecare vers cu numărătorile proprii codai: silabe (regulile pentru română tratează diftongii, triftongii și hiatul; în engleză se numără grupurile de vocale după eliminarea unui -e / -es / -ed mut) și terminații de rimă (ultimul cuvânt de la vocala accentuată în română, de la ultimul grup de vocale în engleză, fără diacritice). Când peste 30 % din versuri nu se potrivesc — un număr de silabe în afara țintei ±1 sau un vers dintr-o pereche nerimată — o singură tură de reparare numește problemele și se întoarce cel mai bun dintre cele două răspunsuri (repaired: true când a câștigat reparația).

{
  "object": "studio.lyrics",
  "title": "Noapte de vară",
  "language": "ro",
  "rhyme_scheme": "AABB",
  "syllables_per_line": 8,
  "sections": [
    {
      "kind": "verse",
      "lines": [
        { "text": "Marea cântă lin sub lună", "syllables": 8, "rhyme": "una", "letter": "A", "off": false },
        { "text": "Ne-am regăsit iar împreună", "syllables": 8, "rhyme": "una", "letter": "A", "off": false }
      ]
    }
  ],
  "text": "[verse]\nMarea cântă lin sub lună\nNe-am regăsit iar împreună",
  "report": { "lines": 16, "off_lines": 1, "off_ratio": 0.063, "pairs": 8, "rhymed": 7, "repair_ratio": 0.125 },
  "repaired": false,
  "cost_micro_usd": "4210"
}

text este tot cântecul, cu un antet [kind] pe secțiune — îl trimiți ca lyrics_text la aliniere sau ca parametrul lyrics al music.generate_ace.

Facturare. Turele se taxează după tokeni sub modelul public codai (model de utilizare codai::lyrics, prompt caching activ). Mai întâi se rezervă în portofel o sumă mică, 20 000 µUSD (402 insufficient_funds dacă nu încape), decontată apoi cu costul real în tokeni. Când modelul nu reușește deloc să producă versuri răspunsul este 422 no_lyrics și se taxează doar turele care au rulat.

Alinierea versurilor la un clip (karaoke)

Alinierea sincronizează versurile scrise cu un clip dintr-o creație audio (sau video) și le scrie în doc.audio.lyrics printr-o singură editare setLyrics:

curl https://ai.codai.ro/v1/studio/lyrics/align \
  -H "Authorization: Bearer $CODAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "creative_id": "8a1c…",
    "clip_id": "vox1",
    "lyrics_text": "[verse]\nMarea cântă lin sub lună\nNe-am regăsit iar împreună",
    "language": "ro"
  }'
CâmpImplicitObservații
creative_id, clip_idobligatoriiAsset-ul clipului trebuie să fie un asset speech, music, video sau upload al tău, gata
lyrics_textobligatoriuCel mult 5000 de caractere; liniile antet [verse] / [chorus] încep secțiuni
languagemeta.language al documentuluiIndiciu pentru transcriere, ro sau en
applytruefalse întoarce rândurile sincronizate și LRC-ul fără să editeze creația
base_seqversiunea curentăVersiunea pe care se bazează editarea; o editare în conflict dă 409 stale
retranscribefalseIgnoră cuvintele din cache și transcrie din nou (taxat)

Gateway-ul ia marcajele de timp ale cuvintelor din asset-ul clipului — din cache-ul pe care subtitrările și alinierile anterioare îl lasă pe asset (gratuit, cached: true) sau dintr-o transcriere Whisper nouă a clipului (cel mult 25 MB) —, le mută pe cronologie ținând cont de tăierea, poziția și întinderea clipului și potrivește cuvintele versurilor cu cele transcrise printr-o aliniere tolerantă la diacritice și greșeli de tipar. Rândurile ale căror cuvinte nu s-au auzit se interpolează între vecini. Răspunsul:

{
  "object": "studio.lyrics_alignment",
  "creative_id": "8a1c…",
  "clip_id": "vox1",
  "applied": true,
  "seq": 12,
  "doc_hash": "…",
  "lines": [{ "startMs": 12040, "endMs": 14880, "text": "Marea cântă lin sub lună", "sectionId": "verse1" }],
  "lrc": "[ti:Noapte de vară]\n[00:12.04]Marea cântă lin sub lună\n…",
  "match_ratio": 0.94,
  "cached": false,
  "cost_micro_usd": "18000"
}

match_ratio este proporția cuvintelor din versuri potrivite cu un cuvânt auzit; sub aproximativ 0,6 sincronizarea e mai mult interpolată — verifică clipul și limba. LRC-ul se exportă și la randarea audio (lrc: true).

Facturare. Cuvintele din cache sunt gratuite. O transcriere nouă se taxează codai::lyrics-align la tariful speech-to-text — 6 000 µUSD pe minut început din clip — sub o rezervare în portofel. Alinierea are nevoie de un serviciu de transcriere din afara UE și nu e disponibilă pentru conturile cu rezidența datelor în UE (403 residency_unavailable); când transcrierea nu e configurată, răspunsul este 503 transcription_unavailable.

Jam live (WebSocket)

wss://ai.codai.ro/v1/studio/jam deschide o sesiune muzicală live pe Lyria RealTime: trimiți prompturi text ponderate și câteva controale muzicale, iar gateway-ul transmite înapoi audio generat continuu. OpenAPI nu poate descrie WebSockets, așa că protocolul e documentat aici.

Conectarea

ClientCum te autentifici
Runtime de serverAuthorization: Bearer <cheie API sau token efemer> la upgrade
BrowserSubprotocoalele codai-jam și bearer.<token efemer>; serverul răspunde cu codai-jam și nu repetă niciodată credențialul
Browser (alternativ)?key=<token efemer> — o cheie de durată brută în query string e refuzată cu închiderea 4401

Tokenii efemeri se emit cu POST /v1/tokens (scope realtime sau live). ?session_id= se înregistrează pe rândul de utilizare.

Client → gateway (cadre text JSON)

MesajCâmpuri
{ "type": "prompts", "prompts": [{ "text", "weight" }] }1–8 prompturi; text de cel mult 200 de caractere; weight între −10 și 10, diferit de 0 (negativ îndepărtează)
{ "type": "config", "bpm"?, "density"?, "brightness"?, "scale"? }bpm 60–200, density și brightness 0–1, scale una dintre C_MAJOR_A_MINOR … B_MAJOR_A_FLAT_MINOR sau SCALE_UNSPECIFIED; actualizările parțiale se combină cu ultima configurație, iar o schimbare de bpm sau scale resetează contextul muzical
{ "type": "play" }, pause, stop, resetControlul redării

Mesajele trimise înainte ca upstream-ul să fie gata se pun în coadă. Orice altceva — JSON invalid, un tip necunoscut, un cadru binar — închide sesiunea cu 4400.

Gateway → client

  • Cadre binare: PCM16 little-endian brut, stereo intercalat, 48 000 Hz. Audio-ul se aruncă (nu se pune în buffer) cât timp socket-ul tău rămâne în urmă cu peste 4 MB.
  • { "type": "status", "state": "connecting" | "ready" | "playing" | "paused" | "stopped", "remaining_ms", "sample_rate"?, "channels"? } — ready vine cu sample_rate: 48000 și channels: 2.
  • { "type": "filtered", "text", "reason" } — filtrul de siguranță al modelului a ignorat un prompt.
  • { "type": "error", "code", "message" } — trimis înaintea unui refuz sau a unei închideri din upstream.

Coduri de închidere

CodÎnseamnă
4400Mesaj invalid de la client
4401Credențiale lipsă sau invalide, ori o cheie brută în query string
4402Rezervarea pentru 10 minute nu încape în portofel (insufficient_funds)
4403Cont cu rezidența datelor în UE, model nepermis pentru cheie sau plafon de cheltuieli atins
4408S-a atins limita de 10 minute a sesiunii (max_duration)
4409Ai deja un jam live deschis (jam_busy) — unul pe cont
4502Modelul muzical din upstream a eșuat sau s-a închis
4503Jam-ul live nu e configurat pe acest gateway (jam_unavailable)

Prețuri

0,03 USD pe minut început din sesiunea upstream deschisă (model de utilizare codai::jam, upstream lyria-realtime-exp). Prețul pentru 10 minute (0,30 USD) se rezervă la deschiderea sesiunii și se decontează la închidere cu minutele folosite efectiv; o sesiune care nu ajunge la upstream nu se taxează. Lyria RealTime e un model experimental, așa că prețul se poate schimba. Prompturile și audio-ul nu se jurnalizează niciodată.

SDK-uri

const song = await codai.lyrics.write({ brief: 'o noapte de vară', language: 'ro', rhyme_scheme: 'AABB' });
const aligned = await codai.lyrics.align({ creative_id: id, clip_id: 'vox1', lyrics_text: song.text });

const jam = codai.jam.connect({ token }); // browser: token efemer
jam.on('audio', (ev) => player.push(new Int16Array(ev.data)));
jam.on('close', (ev) => console.log('închis', ev.code));
jam.prompts([{ text: 'pian lo-fi cald', weight: 1 }]);
jam.config({ bpm: 90, density: 0.4 });
jam.play();
song = client.lyrics.write("o noapte de vară", "ro", rhyme_scheme="AABB", syllables_per_line=8)
aligned = client.lyrics.align(creative_id, "vox1", song["text"])

TypeScript: lyrics.write / align, jam.connect (JamSession: prompts, config, play, pause, stop, reset, close, on; JAM_CLOSE_CODES). Python: lyrics.write / align; SDK-ul Python nu are un helper WebSocket — folosește orice client WebSocket cu protocolul de mai sus.

Pe această pagină