mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-15 11:18:54 +02:00
feat(reels): voix Gemini complète, sous-titres mot à mot et rendu de qualité
Service ffmpeg-api réécrit (ffmpeg-service/app/) : - Appels FFmpeg asynchrones : le service ne se fige plus pendant un rendu - Vidéo récupérée par téléchargement (GET /files/…) au lieu de base64 en JSON - Vraies erreurs HTTP ; échec explicite si la voix demandée est impossible - 30 voix Gemini + ton de lecture (dynamique, chaleureux, promo, calme), clé en en-tête, modèle configurable avec repli - Edge TTS 7 (minutage des mots restauré), secours en voix françaises - Voix traitée : filtre, compression, niveau constant ; musique bouclée et baissée automatiquement sous la voix ; mix final à -14 LUFS - Sous-titres calés mot à mot (Whisper pour Gemini et la voix d'origine, à la place de ffsubsync), style Montserrat, placés hors des boutons Reels - Vidéo : plus de retouche luminosité forcée, scaling lanczos, HDR iPhone converti, BT.709, AAC 48 kHz 192k ; la vidéo s'allonge si la voix dépasse - Grand logo de fin affiché après la voix ; FFmpeg 7.0.2 épinglé, polices et modèle Whisper intégrés à l'image ; tests pytest et ruff Application : - Sélecteur de voix partagé (4 pages) : moteur, 30 voix, ton, écoute - Reel images : minutage réel des mots, interrupteur voix respecté - sync-info ne génère plus de voix à chaque frappe (estimation locale) - Stabilisation désactivée par défaut, route /reels/preview inutilisée retirée - Log « [ReelQueue] Worker démarré » pour vérifier la version déployée Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Ze4bs7tpF1KGWUk6ZZSZ4
This commit is contained in:
47 files changed
+2206
-2285
No files matched your search
+16
-3
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { z } from "zod";
|
||||
import { TTS_ENGINES, TTS_STYLES } from "./voices";
|
||||
|
||||
const optionalText = z
|
||||
.string()
|
||||
@@ -24,9 +25,11 @@ export const videoReelParamsSchema = z.object({
|
||||
description: optionalText,
|
||||
ttsEnabled: z.boolean().default(false),
|
||||
ttsVoice: optionalText,
|
||||
ttsEngine: z.enum(["gemini", "edge"]).optional(),
|
||||
ttsEngine: z.enum(TTS_ENGINES).optional(),
|
||||
ttsStyle: z.enum(TTS_STYLES).optional(),
|
||||
scheduledFor: optionalText,
|
||||
wordDuration: z.number().positive().max(5).default(0.6),
|
||||
// Ancien réglage, ignoré : le minutage vient désormais de la voix elle-même
|
||||
wordDuration: z.number().optional(),
|
||||
fontSize: z.number().int().min(16).max(200).default(64),
|
||||
musicVolume: z.number().min(0).max(2).default(0.25),
|
||||
drawText: z.boolean().default(true),
|
||||
@@ -45,13 +48,23 @@ export const imagesReelParamsSchema = z.object({
|
||||
overlayText: optionalText,
|
||||
musicUrl: optionalText,
|
||||
musicVolume: z.number().min(0).max(2).default(0.3),
|
||||
ttsEngine: z.enum(["gemini", "edge"]).optional(),
|
||||
ttsEnabled: z.boolean().default(true),
|
||||
ttsEngine: z.enum(TTS_ENGINES).optional(),
|
||||
ttsVoice: optionalText,
|
||||
ttsStyle: z.enum(TTS_STYLES).optional(),
|
||||
storeName: z.string().optional(),
|
||||
// Fichiers temporaires à supprimer une fois le rendu terminé
|
||||
tempFiles: z.array(z.string()).default([]),
|
||||
});
|
||||
|
||||
/** Aperçu de la voix. */
|
||||
export const ttsPreviewSchema = z.object({
|
||||
text: z.string({ required_error: "Texte requis" }).trim().min(1, "Texte requis").max(2000),
|
||||
ttsVoice: optionalText,
|
||||
ttsEngine: z.enum(TTS_ENGINES).optional(),
|
||||
ttsStyle: z.enum(TTS_STYLES).optional(),
|
||||
});
|
||||
|
||||
export type ImagesReelParams = z.infer<typeof imagesReelParamsSchema>;
|
||||
|
||||
export type ReelJobKind = "video" | "images";
|
||||
|
||||
Reference in new issue
Block a user