درس 4 — Produire

Vidéo Veo et textes par canal

50 min

هذا المحتوى غير مترجم بعد. تُعرض النسخة الأصلية.

Sur LinkedIn, un post avec une vidéo courte retient l'œil plus longtemps qu'une image fixe ; c'est l'argument que l'équipe d'Ondée entend de toutes les agences. Mais une vidéo générée coûte de 4 à 9 fois une image (0,30 aˋ0,60à 0,60 contre 0,068 $), met d'une dizaine de secondes à plusieurs minutes à revenir, et ne se retouche pas comme une image. On en fait donc une, courte, à partir d'un plan déjà validé, et on connaît son prix avant de cliquer. Les textes, eux, sont bon marché mais piégés : longueurs par canal, mots interdits, mention IA.

Le mécanisme

flowchart LR
  subgraph Video["Vidéo"]
    A["Fond LinkedIn 16:9 validé"] --> B["premiere-image.jpg 1280x720"]
    B --> C["Veo 3.1 Lite, 6 s, 720p<br/>opération longue, sondée toutes les 10 s"]
    C --> D["ffmpeg : logo en calque, H.264 2,3 Mbit/s"]
  end
  subgraph Textes["Textes"]
    E["Schéma Textes"] --> F["gemini-3.5-flash-lite"]
    F --> G{"verifier() : longueurs,<br/>5 diapositives, hashtags,<br/>mots interdits"}
    G -- "écarts" --> H["1 tour de correction<br/>avec la liste exacte"]
    G -- "ok" --> I["Mention IA ajoutée par le code"]
    H --> I
  end

Tarifs relevés le 2026-10-15 sur la page officielle, par seconde de vidéo générée :

Modèle720p1080p (8 s uniquement)Clip de 6 s en 720p
veo-3.1-lite-generate-preview0,05 $0,08 $0,30 $
veo-3.1-fast-generate-preview0,10 $0,12 $0,60 $

Veo 3.1 Lite accepte 4, 6 ou 8 secondes, en 16:9 ou 9:16, à partir d'un texte ou d'une image de départ. Les vidéos restent 2 jours sur le serveur : le studio les télécharge immédiatement.

La mise en œuvre

L'appel et l'attente, dans models.py :

files/studio/models.py
op = self.client.models.generate_videos(
    model=model, prompt=prompt,
    image=types.Image(image_bytes=image, mime_type=_mime(image)),
    config=types.GenerateVideosConfig(number_of_videos=1, duration_seconds=secondes,
                                      aspect_ratio=aspect, resolution="720p"),
)
while not op.done:
    if time.time() - debut > 600:
        raise TimeoutError("Veo n'a pas répondu en 10 minutes")
    time.sleep(10)
    op = self.client.operations.get(op)
v = op.response.generated_videos[0].video
if not v.video_bytes:                 # Gemini API : fichier à télécharger ; Vertex : octets directs
    self.client.files.download(file=v)
self._noter("video", model, cout=PRIX[model]["s720"] * secondes)

La finalisation par ffmpeg (pipeline.py) pose le logo en calque, comme sur les images, et vise un débit qui garde 8 s sous 3 Mo :

files/studio/pipeline.py
"[0:v]scale=-2:720[v];[1:v]scale=84:84[l];[v][l]overlay=W-w-36:36",
"-c:v", "libx264", "-b:v", "2300k", "-maxrate", "2500k", "-bufsize", "5000k", ...

Côté textes, textes.py déclare les limites dans le schéma (le modèle les voit) et les vérifie dans le code (le modèle ne les respecte pas toujours) :

files/studio/textes.py
textes = models.json(prompt, Textes, nature="textes")
problemes = verifier(textes, kit)
if problemes:   # un seul tour : le modèle reçoit la liste exacte des écarts
    textes = models.json(prompt + "\n\nCorrige ces écarts :\n- " + "\n- ".join(problemes) + ..., Textes)
    problemes = verifier(textes, kit)

Les mots interdits sont cherchés par préfixe (\bécologique attrape « écologiques »), dans tous les champs à la fois. La mention « Visuels créés avec l'IA (Gemini, Veo), sélectionnés et validés par notre équipe » n'est pas demandée au modèle : post_linkedin() l'ajoute, toujours, à la fin.

make test       # test_verifier_detecte_mot_interdit_et_longueurs, test_mention_ia_ajoutee_par_le_code,
                # test_finaliser_video_pose_le_logo_et_reste_sous_3_mo (vidéo de synthèse ffmpeg)

Résultat obtenu

Deux clips réels le 2026-10-15, 41 s de génération chacun, 0,30 $ chacun :

20:45:29 INFO studio.models video veo-3.1-lite-generate-preview coût=0.3000 $
20:45:29 INFO studio.models vidéo générée en 41 s
...
20:48:48 INFO studio.models video veo-3.1-lite-generate-preview coût=0.3000 $
20:48:48 INFO studio.models vidéo générée en 41 s
video.mp4 : 6,0 s, H.264 1280x720, AAC, 1,5 Mo

Et la boucle de correction des textes, au second test de bout en bout :

20:52:43 WARNING studio.textes textes à corriger : ['accroche linkedin : titre de 45 caractères > 42']
20:52:45 INFO studio.models textes gemini-3.5-flash-lite coût=0.0025 $
{"kit_corrections": [], "textes_problemes": []}

Ce qui casse en production

Les bandes noires. Le premier clip partait de l'image de référence, en portrait 4:5, pour une vidéo 16:9. Veo a conservé l'image entière : bandes noires à gauche et à droite sur la première seconde, puis un élargissement du cadre. 0,30 $ perdus.

Premier clip : la première image 4:5 laisse des bandes noires

Parade : la première image est toujours recadrée en 16:9 par le code avant l'appel (premiere-image.jpg, à partir du fond LinkedIn déjà validé). Second clip :

Second clip à partir d'une première image 16:9 : plein cadre dès la première image
Autre symptômeCauseParade
Veo n'a renvoyé aucune vidéofiltre de sécurité (personnes, marques réelles)message explicite, pas de nouvel essai automatique : chaque essai est facturé
Clip introuvable le surlendemainconservation serveur de 2 jourstéléchargement immédiat, fichier local dans la campagne
Régénération vidéo demandée depuis la galeriecoût et durée incompatibles avec un clicrefusée par l'API de la galerie ; make video en ligne de commande, en connaissance de cause
Post LinkedIn coupé à « …voir plus » au mauvais endroitpremière phrase trop longueconsigne « première ligne qui accroche » et limite de 1 300 caractères

La règle de décision

Vidéo : Lite en 720p pour un réseau social, 6 s, une seule par campagne, première image recadrée par le code au ratio de la vidéo. Passez à Fast seulement si un humain a constaté un défaut de mouvement que Lite reproduit. Textes : toute contrainte vérifiable est vérifiée par le code après la génération, et toute mention obligatoire est ajoutée par le code.

Pratique

La marque veut une story vidéo 9:16 de 8 s en 1080p. Combien coûte le clip en Veo 3.1 Lite et que changez-vous dans le code ?

Le modèle de texte écrit « nos flacons écologiques ». verifier() le signale, le tour de correction le remplace par « nos flacons éco-responsables ». Que faites-vous ?

Exercice. Ajoutez une limite : la légende Instagram doit contenir la date de lancement « 3 novembre ». Si elle manque, verifier() le signale.

Voir la solution
# textes.py, dans verifier()
if "3 novembre" not in t.legende_instagram:
    p.append("légende Instagram : la date de lancement « 3 novembre » est absente")

Mieux : la date vient du brief, pas du code. Ajoutez un champ date_lancement à Brief, passez le brief à verifier(), et testez avec une légende sans date dans tests/test_kit_et_textes.py.

  • Je sais lancer une génération Veo, attendre l'opération et récupérer le fichier
  • Je sais calculer le coût d'un clip avant de le lancer
  • Je sais pourquoi la première image doit avoir le ratio de la vidéo
  • Je sais faire vérifier par le code ce que le modèle a écrit
التالي