DIFFICULTIES TO GET GENERATED VIDEOS URL BACK IN ORDER TO DISPLAY THEM ON MY WEB APP
'Annie_expressive4_public',
'teaching' => 'Annie_expressive4_public',
'project_management'=> 'Annie_expressive4_public',
'pharmacy' => 'Annie_expressive4_public',
'agro' => 'Annie_expressive4_public',
];
$VOICE_ID = '0b41c487c6da4f5ba5782bbe462958e8';
// === UTILS ===
function logMessage($msg) {
$logFile = __DIR__ . '/logs/avatar_gen.log';
if (!is_dir(dirname($logFile))) mkdir(dirname($logFile), 0755, true);
$timestamp = date('Y-m-d H:i:s');
error_log("[$timestamp] [AvatarGen] $msg\n", 3, $logFile);
echo "[$timestamp] $msg\n";
}
function heyGenRequest($method, $url, $payload = null) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Accept: application/json',
'X-Api-Key: ' . HEYGEN_API_KEY
]);
if ($method === 'POST' && $payload) {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
}
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
throw new Exception("cURL error: $error");
}
// 🔍 Debug temporaire
if ($http_code !== 200) {
logMessage("DEBUG HTTP $http_code - URL: $url");
logMessage("DEBUG Response: " . substr($response, 0, 200));
}
return [$http_code, json_decode($response, true)];
}
// === ÉTAPE 1 : Lancer la génération ===
function generateVideo($text, $user_group) {
global $AVATAR_MAP, $VOICE_ID;
$avatar_id = $AVATAR_MAP[$user_group] ?? $AVATAR_MAP['default'];
$payload = [
"video_inputs" => [[
"character" => [
"type" => "avatar",
"avatar_id" => $avatar_id,
"scale" => 1
],
"voice" => [
"type" => "text",
"input_text" => $text,
"voice_id" => $VOICE_ID
],
"background" => ["type" => "color", "value" => "#f8fafc"]
]],
"dimension" => ["width" => 1920, "height" => 1080],
"test" => false,
"caption" => false
];
for ($attempt = 1; $attempt <= MAX_RETRIES; $attempt++) {
try {
[$code, $data] = heyGenRequest('POST', HEYGEN_API_URL, $payload);
if ($code === 200 && !empty($data['data']['video_id'])) {
return $data['data']['video_id'];
} else {
$msg = "HeyGen error (attempt $attempt): HTTP $code - " . ($data['message'] ?? json_encode($data));
logMessage($msg);
if ($attempt < MAX_RETRIES) sleep(RETRY_DELAY_SEC);
}
} catch (Exception $e) {
logMessage("Exception (attempt $attempt): " . $e->getMessage());
if ($attempt < MAX_RETRIES) sleep(RETRY_DELAY_SEC);
}
}
throw new Exception("Échec après " . MAX_RETRIES . " tentatives.");
}
// === ÉTAPE 2 : Attendre la fin de la génération ===
function waitForVideoCompletion($video_id) {
$elapsed = 0;
$check_interval = 5;
$max_checks = MAX_WAIT_SEC / $check_interval;
logMessage("⏳ Attente de la complétion de la vidéo (max " . MAX_WAIT_SEC . " sec)...");
logMessage("🔍 Video ID: $video_id");
// Délai initial plus long (HeyGen met du temps à indexer)
sleep(25);
for ($check = 1; $check <= $max_checks; $check++) {
try {
// ✅ CORRECTION DÉFINITIVE : POST avec video_id dans le body JSON (API v1)
$payload = ['video_id' => $video_id];
[$code, $data] = heyGenRequest('POST', HEYGEN_STATUS_URL, $payload);
if ($code === 200 && !empty($data['data'])) {
$status = $data['data']['status'] ?? 'unknown';
logMessage("CallCheck #$check (elapsed: {$elapsed}s) - Statut: $status");
if ($status === 'completed') {
$video_url = $data['data']['video_url'] ?? null;
if ($video_url) {
logMessage("✅ URL CDN trouvée : $video_url");
return $video_url;
}
// Recherche alternative dans assets
$assets = $data['data']['assets'] ?? [];
foreach ($assets as $asset) {
if (isset($asset['type']) && $asset['type'] === 'video' && isset($asset['url'])) {
$video_url = $asset['url'];
logMessage("✅ URL trouvée dans assets : $video_url");
return $video_url;
}
}
throw new Exception("Vidéo complétée mais URL non trouvée");
} elseif ($status === 'failed') {
$reason = $data['data']['reason'] ?? 'Unknown';
throw new Exception("Échec HeyGen : $reason");
}
} else {
$error_msg = $data['message'] ?? json_encode($data);
logMessage("⚠️ CheckCall #$check - HTTP $code - $error_msg");
}
sleep($check_interval);
$elapsed += $check_interval;
} catch (Exception $e) {
logMessage("⚠️ CheckCall #$check erreur: " . $e->getMessage());
sleep($check_interval);
$elapsed += $check_interval;
}
}
throw new Exception("Timeout après " . MAX_WAIT_SEC . " secondes");
}
// === ÉTAPE 3 : Mettre à jour la base ===
function updateMediaUrl($conn, $content_date, $user_group, $video_url) {
logMessage("💾 Mise à jour de la base de données...");
$stmt = $conn->prepare("
UPDATE daily_content
SET media_url = :url, media_type = 'video'
WHERE content_date = :date AND user_group = :group
");
$stmt->execute([
':url' => $video_url,
':date' => $content_date,
':group' => $user_group
]);
$rows = $stmt->rowCount();
logMessage("✅ Base mise à jour : $rows ligne(s) modifiée(s) - $user_group / $content_date → $video_url");
// Vérification
$verify = $conn->prepare("
SELECT media_url, media_type
FROM daily_content
WHERE content_date = :date AND user_group = :group
");
$verify->execute([':date' => $content_date, ':group' => $user_group]);
$result = $verify->fetch(PDO::FETCH_ASSOC);
if ($result && !empty($result['media_url'])) {
logMessage("🔍 Vérification BDD : OK → " . substr($result['media_url'], 0, 60) . "...");
} else {
logMessage("⚠️ Vérification BDD : ÉCHOUÉE");
}
}
// === SCRIPT PRINCIPAL ===
try {
logMessage("╔════════════════════════════════════════════════════════════╗");
logMessage("║ DÉMARRAGE GÉNÉRATION VIDÉO HEYGEN v2 ║");
logMessage("╚════════════════════════════════════════════════════════════╝");
$stmt = $conn->prepare("
SELECT id, content_date, user_group, reading_text
FROM daily_content
WHERE content_date = :today
AND (media_url IS NULL OR media_url = '' OR media_type != 'video')
AND reading_text IS NOT NULL AND TRIM(reading_text) != ''
");
$stmt->execute([':today' => date('Y-m-d')]);
$contents = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (empty($contents)) {
logMessage("ℹ️ Aucun contenu à traiter aujourd'hui.");
exit(0);
}
logMessage("📋 " . count($contents) . " contenu(s) trouvé(s) à traiter");
foreach ($contents as $row) {
$text = trim($row['reading_text']);
$user_group = $row['user_group'];
$content_date = $row['content_date'];
$content_id = $row['id'];
if (empty($text)) continue;
logMessage("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
logMessage("🎬 Traitement : $user_group / $content_date (ID: $content_id)");
logMessage("📝 Texte (premiers 50 caractères): " . substr($text, 0, 50) . "...");
try {
$video_id = generateVideo($text, $user_group);
logMessage("⏳ Job HeyGen lancé : $video_id");
logMessage("🌐 Suivre sur : https://app.heygen.com/videos/$video_id");
$video_url = waitForVideoCompletion($video_id);
if (empty($video_url)) {
throw new Exception("URL de vidéo vide");
}
updateMediaUrl($conn, $content_date, $user_group, $video_url);
logMessage("✅ VIDÉO GÉNÉRÉE ET STOCKÉE !");
logMessage("🎬 URL publique : $video_url");
} catch (Exception $e) {
logMessage("❌ ÉCHEC pour $user_group : " . $e->getMessage());
}
}
logMessage("╔════════════════════════════════════════════════════════════╗");
logMessage("║ GÉNÉRATION TERMINÉE ║");
logMessage("╚════════════════════════════════════════════════════════════╝");
logMessage("💡 Rechargez enregistrement.php pour voir la vidéo !");
} catch (Exception $e) {
logMessage("🔥 ERREUR CRITIQUE : " . $e->getMessage());
exit(1);
}
?>
10 hours ago by ADOUAN ANTOINE