Discussions

Ask a Question

come mettere in pausa abbonamento

come mettere in pausa abbonamento

Intermittent LiveKit Not Supported Error

Hello HeyGen Support Team,

Session Time Limitations

Essential plan limits each session to 20 minutes, Business plan allows 60 minute sessions.

Daily Comfort and Mindfulness: How Small Items Make a Big Difference

Daily routines shape our mood and focus more than we realize. I’ve recently started using a namaz chadar during my prayers, and it has added a sense of calm and mindfulness to my day. I’m curious, what small items or habits do you rely on to stay peaceful and organized? Let’s discuss the little things that make life more comfortable, meaningful, and stress-free!

400569 errors

I am suddenly getting 400569 errors when using the video status endpoint and the video ID returned from the video agent endpoint. I can see the video generating when I go to the UI and look, but the ID there is bfeef1a4-811f-4273-acb7-962aeb45ea1d while the id returned is {
"error": null,
"data": {
"video_id": "4d2394edcaf64a628ccb73aed2853422"
}
}

Avatar Default Voice Not Being Used in API Video Agent

Hi HeyGen Team,

video_agent/interactive_chat

are you planing to release?

Keeping the avatar look the same in all videos

We have an app in which we create avatars & videos using Heygen

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); } ?>

Requests

  • Let Video Agent API to retrieve CC (subtitles) or allow for burning it into video
  • Let Video Agent API to give another prompt to edit the video
  • Allow to edit the plan with Video Agent API.