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 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èle | 720p | 1080p (8 s uniquement) | Clip de 6 s en 720p |
|---|---|---|---|
veo-3.1-lite-generate-preview | 0,05 $ | 0,08 $ | 0,30 $ |
veo-3.1-fast-generate-preview | 0,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 :
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 :
"[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) :
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 MoEt 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.
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 :
| Autre symptôme | Cause | Parade |
|---|---|---|
Veo n'a renvoyé aucune vidéo | filtre de sécurité (personnes, marques réelles) | message explicite, pas de nouvel essai automatique : chaque essai est facturé |
| Clip introuvable le surlendemain | conservation serveur de 2 jours | téléchargement immédiat, fichier local dans la campagne |
| Régénération vidéo demandée depuis la galerie | coût et durée incompatibles avec un clic | refusée par l'API de la galerie ; make video en ligne de commande, en connaissance de cause |
| Post LinkedIn coupé à « …voir plus » au mauvais endroit | première phrase trop longue | consigne « 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 ?
8 s x 0,08 $ = 0,64 $ en 1080p (réservé aux clips de 8 s). La première image doit être au ratio de la vidéo, sinon les bandes noires reviennent. 0,40 $ est le prix en 720p.
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 ?
La loi AGEC vise l'allégation environnementale générique, pas un mot précis. « éco-responsable » contourne la liste sans changer le sens. Le prompt seul ne garantit rien ; une règle par préfixe et une relecture humaine si.
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