> ## Documentation Index
> Fetch the complete documentation index at: https://docs.youka.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Automatiser les vidéos de paroles

> Choisir des modèles, corriger les timings et exporter une version de projet choisie

Utilisez `@youka/sdk` et `@youka/cli` version 0.2.0 ou ultérieure pour ces exemples. Les projets créés via l’API restent disponibles dans votre bibliothèque Youka.

## Choisir un workflow et un modèle

`kind` sélectionne le workflow du projet. `karaoke` sépare les stems. `lyric-video` utilise l’audio d’origine et ne facture pas la séparation. Si `kind` est omis, le comportement karaoke existant est conservé. Le traitement des paroles est un choix séparé : alignement, transcription ou aucun traitement.

Découvrez les modèles et l’éligibilité du compte avant de choisir un modèle.

```sh theme={null}
youka capabilities --json
```

```ts theme={null}
const capabilities = await client.capabilities.get();
const eligibleModels = capabilities.models.filter(
  (model) => model.eligible && model.workflows.includes("lyric-video"),
);
```

La réponse décrit les IDs de modèle, les opérations, les entrées audio, la sémantique du texte fourni, les workflows, la prise en charge des langues et les fonctionnalités requises. `suppliedTextHandling` distingue l’alignement, les mots-clés du fournisseur et la correction après transcription. L’éligibilité reflète le compte authentifié. La découverte décrit la prise en charge configurée, pas une garantie de disponibilité du fournisseur. La validation des requêtes et les devis de prix restent la référence.

Les modèles qui exigent des voix isolées ne peuvent pas traiter une vidéo de paroles sans séparation. Utilisez-les dans un workflow karaoke avec un modèle de séparation qui produit des voix. Wav2Vec2 est un modèle d’alignement. ElevenLabs Scribe est un modèle de transcription. Le texte de transcription fourni sert d’indication, sans garantie d’une sortie textuelle identique.

## Créer des projets et obtenir un devis

```ts theme={null}
import { AlignmentModel, YoukaClient } from "@youka/sdk";

const client = new YoukaClient({ apiKey: process.env.YOUKA_API_KEY! });
const operation = await client.projects.create(
  {
    kind: "lyric-video",
    source: { type: "path", path: "./song.wav" },
    title: "Example song",
    lyricsSource: {
      type: "transcribe",
      syncModel: AlignmentModel.ElevenLabsTranscription,
      lyrics: "Optional reference lyrics",
    },
  },
  { idempotencyKey: "example-song-create-v1" },
);
const { project } = await client.projects.wait(operation);
```

Alignez les paroles fournies avec un modèle annoncé pour les vidéos de paroles.

```sh theme={null}
youka project create ./song.wav --kind lyric-video --mode align \
  --sync-model audioshake-alignment --lyrics 'Line one
Line two' --json
```

Conservez la séparation pour les projets karaoke. Omettez `--kind` ou passez `--kind karaoke` et choisissez `--split-model`. Utilisez `--mode none` pour créer sans traitement des paroles. Les requêtes lyric-video rejettent les options de séparation.

Obtenez un devis pour la même source, le même workflow et les mêmes options de traitement avant la création.

```sh theme={null}
youka project quote ./song.wav --kind lyric-video --mode transcribe \
  --sync-model elevenlabs-transcription --json
```

Un devis vérifie la même compatibilité de modèle, la politique de langue, les fonctionnalités du compte, la durée et les règles de stockage que la création. Son détail de crédits comporte zéro crédit de séparation pour les vidéos de paroles. Un devis ne réserve ni capacité ni crédits ; l’état du compte peut changer avant la création.

## Corriger les timings sans jobs de traitement

Lisez les alignements via `GET /projects/{projectId}/alignments`, puis récupérez la ressource choisie via `GET /projects/{projectId}/alignments/{alignmentId}`. La liste contient `alignments`, `selectedAlignmentId` et `selectionRevision`. Chaque ressource inclut la charge utile de timing, `revision`, `selected` et `selectionRevision`.

Les mises à jour remplacent l’objet `alignment` en entier. Elles n’exécutent pas de synchronisation et ne créent pas de retenue de crédits de traitement. Conservez les IDs, le texte, les index ligne/mot/sous-mot, les informations de chanteur et les traductions lors de l’édition. Les temps sont des secondes décimales absolues. Appliquez toute correction souhaitée une seule fois dans les valeurs soumises. N’ajoutez pas la même correction une seconde fois en tant que décalage d’export.

```ts theme={null}
const snapshot = await client.projects.alignments.list(project.id);
const current = snapshot.alignments.find(
  (alignment) => alignment.id === snapshot.selectedAlignmentId,
);
if (!current) throw new Error("Project has no alignment to edit");

const corrected = structuredClone(current.alignment);
corrected.items[0]!.start = 0.75;
corrected.items[0]!.end = 1.25;

const saved = await client.projects.alignments.update(project.id, current.id, {
  alignment: corrected,
  expectedRevision: current.revision,
  select: true,
  expectedSelectionRevision: snapshot.selectionRevision,
});
```

Utilisez `select: true` pour enregistrer et sélectionner de manière atomique. Pour sélectionner des timings existants sans les remplacer, appelez `client.projects.alignments.select(projectId, alignmentId, { expectedRevision, expectedSelectionRevision })`.

La révision d’alignement protège le contenu des timings. La révision de sélection protège quel alignement est actif. Un jeton périmé produit HTTP 409. Récupérez la ressource la plus récente, comparez les modifications et soumettez un remplacement volontaire. Ne rafraîchissez pas automatiquement le jeton en écrasant les changements d’un autre éditeur.

Le CLI accepte un fichier JSON ou l’entrée standard. Un fichier d’import contient `{ "alignment": { "items": [...] }, "expectedRevision": "..." }`. Incluez `select` et `expectedSelectionRevision` lors d’une sélection atomique. Les ressources exportées contiennent aussi des métadonnées de réponse ; extrayez donc les champs de requête avant l’import.

```sh theme={null}
youka project timings list proj_example --json
youka project timings get proj_example aln_example --json > timing-resource.json
youka project timings import proj_example aln_example --body corrected-request.json --json
youka project timings select proj_example aln_example \
  --expected-revision "$ALIGNMENT_REVISION" \
  --expected-selection-revision "$SELECTION_REVISION" --json
```

Les imports acceptent jusqu’à 100 000 éléments. Chaque temps de fin doit être strictement supérieur à son début. Les nombres invalides, les temps négatifs, les index invalides, les plages de durée nulle ou inversées, ainsi que les timings au-delà d’une durée de projet connue sont rejetés. Les chevauchements légitimes et le timing en duo restent pris en charge. Rouvrez ou rafraîchissez un projet d’application déjà ouvert après une modification externe.

## Exporter une version choisie

```sh theme={null}
youka project versions proj_example --json
youka export create proj_example --version-id ver_example --local \
  --transparent --mute-all --fps 30 --output ./overlay.mov --json
```

`versionId` est optionnel dans les requêtes d’export et les mises à jour des paramètres, ainsi que dans la requête GET des paramètres. L’omettre conserve le comportement de version principale. L’alignement sélectionné appartient au projet, tandis que le style et les paramètres appartiennent à la version choisie.

```ts theme={null}
const versions = await client.projects.versions.list(project.id);
const versionId = versions[0]!.id;
const stemVolumes = Object.fromEntries(
  project.stems.map((stem) => [stem.id, 0]),
);
const payload = await client.exports.prepareLocal(project.id, {
  versionId,
  transparent: true,
  stemVolumes,
  fps: 30,
});
console.log(payload.versionId, payload.alignmentId, payload.alignmentRevision);

await client.exports.create(project.id, {
  target: "local",
  versionId,
  transparent: true,
  stemVolumes,
  fps: 30,
  outputPath: "./overlay.mov",
});
```

Les handles d’opération d’export cloud et les charges utiles locales incluent `versionId`, `alignmentId` et `alignmentRevision`. Ces champs identifient l’instantané de timing utilisé pour cet export ou cette préparation. Chaque préparation lit l’état courant ; un export séparé ultérieur peut donc observer des modifications plus récentes. Enregistrez la charge utile renvoyée lorsqu’un moteur de rendu externe doit rendre exactement cet instantané préparé, et rafraîchissez-la lorsque les URL média signées expirent.

La sortie locale transparente utilise ProRes 4444 dans un conteneur MOV. `--mute-all` associe tous les stems du projet à un volume nul. Le silence et l’absence de piste audio sont deux propriétés de sortie différentes ; inspectez le fichier rendu si un outil en aval exige l’un des deux. Le rendu local ne consomme pas de crédits d’export cloud et reste soumis à l’éligibilité des fonctionnalités existantes.

Le timing des mots, les offsets audio globaux et l’anticipation des paroles sont des paramètres distincts. Les mises en page existantes contrôlent la visibilité des lignes. Cette version ne promet pas un intervalle d’apparition fixe pour chaque ligne et n’ajoute pas d’API distincte de pièce jointe de backing track.

## Exploiter un catalogue en toute sécurité

Conservez un manifeste avec un ID d’élément stable, l’empreinte de la source, les paramètres d’opération, la clé d’idempotence, les IDs de projet/tâche et le dernier résultat terminal. Réutilisez une clé uniquement pour les retries de la même requête. Persistez les résultats de création avant d’attendre la fin afin qu’un redémarrage puisse reprendre le polling. Les uploads et la préparation de fichiers locaux ont leur propre cycle de vie ; une clé d’idempotence de création ne déduplique pas chaque upload.

L’[exemple de catalogue](/examples/catalogue.js) exécutable accepte des IDs de fichiers d’entrée déjà uploadés et persiste un checkpoint par élément. Un manifeste ressemble à ceci.

```json theme={null}
[
  {
    "id": "song-001",
    "request": {
      "kind": "lyric-video",
      "inputFileId": "owned-upload-id",
      "title": "Example song",
      "lyricsSource": {
        "type": "transcribe",
        "syncModel": "elevenlabs-transcription"
      }
    }
  }
]
```

Téléchargez l’exemple sous `catalogue.ts`. Installez ses dépendances et définissez `YOUKA_API_KEY`. Utilisez un projet Node.js avec `"type": "module"` dans son `package.json`.

```sh theme={null}
npm install @youka/sdk@^0.2.0 tsx
npx tsx ./catalogue.ts ./manifest.json ./catalogue-state 1
```

Relancez avec le même manifeste et le même répertoire d’état pour reprendre le polling des jobs acceptés ou retenter une soumission incertaine avec sa clé d’origine. Les jobs terminés et échoués sont enregistrés et ignorés. Les requêtes modifiées nécessitent de nouveaux IDs d’élément. Le verrou de répertoire empêche deux processus de soumettre simultanément le même manifeste. Après un crash brutal, supprimez un `.lock` obsolète uniquement après avoir confirmé que le PID qui y est stocké n’est plus en cours d’exécution.

Commencez avec un seul élément en cours. N’augmentez un nombre de workers borné qu’après avoir mesuré la latence de traitement et les réponses de rate limit pour votre compte. Retentez les erreurs de transport et les limites de débit avec backoff, en respectant `Retry-After`. Ne retentez pas aveuglément les erreurs de validation, les conflits de timing ou les échecs de traitement terminaux. Les erreurs d’authentification exigent des identifiants valides ; elles ne signifient pas qu’un job de traitement a échoué.

Conservez le polling existant des tâches cloud et la gestion des crédits en cas d’échec. Aucun endpoint batch, promesse de webhook, changement de tarification, changement de licence ou politique de rétention n’est introduit ici.
