/dev/null'; exec($cmd, $out, $code); } } if (file_exists($audioPath) && filesize($audioPath) > 1000) { $audioData = file_get_contents($audioPath); $ch = curl_init("https://router.huggingface.co/hf-inference/models/$whisperModel"); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $hfToken, 'Content-Type: application/octet-stream' ], CURLOPT_POSTFIELDS => $audioData, CURLOPT_TIMEOUT => 120 ]); $raw = curl_exec($ch); $err = curl_error($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($raw && $status >= 200 && $status < 300) { $decoded = json_decode($raw, true); if (isset($decoded['text'])) { $transcript = $decoded['text']; $transcriptSource = 'hf_whisper'; $receipt['transcript'] = $transcript; $receipt['transcript_source'] = $transcriptSource; write_json_file($receiptPath, $receipt); } } } } // ─── 2. GATHER EVIDENCE ────────────────────────────── $ocrText = ''; if (!empty($receipt['ocr_samples'])) { $ocrText = implode("\n", array_map(fn($o) => ($o['text'] ?? ''), array_slice($receipt['ocr_samples'], 0, 20))); } $metadata = sprintf( "Duration: %.1fs, Resolution: %dx%d, Keyframes: %d, OCR blocks: %d, Video: %s", $receipt['duration'] ?? 0, $receipt['width'] ?? 0, $receipt['height'] ?? 0, $receipt['keyframe_count'] ?? 0, count($receipt['ocr_samples'] ?? []), $receipt['videoName'] ?? 'unknown' ); // ─── 3. LLM: UNDERSTAND VIDEO + DESIGN GAME ────────── $prompt = "You are a creative game designer. You analyze video evidence to understand what a video is ABOUT, then design a unique micro-game inspired by that content.\n\n" . "The game must be:\n" . "- A real, playable browser game (HTML5 canvas or DOM)\n" . "- UNIQUE to this specific video — not a template\n" . "- Inspired by the video's subject matter, not a display of its contents\n" . "- Playable in under 2 minutes\n" . "- Fun and replayable\n\n" . "First, understand what the video is about from the evidence below.\n" . "Then design a game that captures the ESSENCE of what's happening.\n\n" . "Return STRICT JSON:\n" . "{\n" . " \"understanding\": \"What this video is about (2-3 sentences)\",\n" . " \"game_title\": \"Catchy game name\",\n" . " \"game_concept\": \"Core game loop in one sentence\",\n" . " \"game_mechanic\": \"How the game works — controls, scoring, win/lose\",\n" . " \"game_theme\": \"Visual theme derived from video content\",\n" . " \"game_genre\": \"arcade|puzzle|action|strategy|simulation|clicker\",\n" . " \"game_colors\": {\"bg\": \"#hex\", \"primary\": \"#hex\", \"accent\": \"#hex\", \"text\": \"#hex\"},\n" . " \"game_entities\": [\"List of game objects/characters derived from video content\"],\n" . " \"game_scoring\": \"How score works\",\n" . " \"game_difficulty\": \"How difficulty scales\",\n" . " \"game_win\": \"Win condition\",\n" . " \"game_lose\": \"Lose condition\",\n" . " \"game_powerups\": [\"Optional powerups if any\"],\n" . " \"inspiration\": \"How the game connects to the video content\"\n" . "}\n\n" . "VIDEO EVIDENCE:\n" . "Metadata: $metadata\n" . "Transcript: " . substr($transcript, 0, 2000) . "\n" . "OCR (screen text): " . substr($ocrText, 0, 2000) . "\n"; $analysis = [ 'understanding' => '', 'game_title' => 'MicroGame', 'game_concept' => '', 'game_mechanic' => '', 'game_theme' => '', 'game_genre' => 'arcade', 'game_colors' => ['bg' => '#0a0a0f', 'primary' => '#ff8c32', 'accent' => '#3aff7a', 'text' => '#eee8df'], 'game_entities' => [], 'game_scoring' => '', 'game_difficulty' => '', 'game_win' => '', 'game_lose' => '', 'game_powerups' => [], 'inspiration' => '', 'transcript' => $transcript, 'transcript_source' => $transcriptSource ]; if ($hfToken) { $payload = [ 'model' => $hfModel, 'messages' => [ ['role' => 'system', 'content' => 'You are a creative game designer. You analyze video evidence and design unique micro-games. Always respond with valid JSON only, no markdown.'], ['role' => 'user', 'content' => $prompt] ], 'max_tokens' => 1000, 'temperature' => 0.8, 'top_p' => 0.92 ]; $ch = curl_init("https://router.huggingface.co/v1/chat/completions"); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $hfToken, 'Content-Type: application/json' ], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_TIMEOUT => 120 ]); $raw = curl_exec($ch); $err = curl_error($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($raw && $status >= 200 && $status < 300) { $decoded = json_decode($raw, true); $text = ''; // OpenAI chat completions format if (isset($decoded['choices'][0]['message']['content'])) { $text = $decoded['choices'][0]['message']['content']; } elseif (isset($decoded['choices'][0]['text'])) { $text = $decoded['choices'][0]['text']; } elseif (isset($decoded[0]['generated_text'])) { $text = $decoded[0]['generated_text']; } if ($text) { $jsonStart = strpos($text, '{'); $jsonEnd = strrpos($text, '}'); if ($jsonStart !== false && $jsonEnd !== false && $jsonEnd > $jsonStart) { $maybe = json_decode(substr($text, $jsonStart, $jsonEnd - $jsonStart + 1), true); if (is_array($maybe)) { $analysis = array_merge($analysis, $maybe); } } $analysis['hf_raw'] = $text; } } else { $analysis['hf_warning'] = $err ?: "HF status $status"; } } else { $analysis['hf_warning'] = 'HF_TOKEN not set — using fallback. Set HF_TOKEN for AI-designed unique games.'; } $analysisPath = RECEIPT_DIR . "/$id/analysis.json"; write_json_file($analysisPath, $analysis); json_response([ 'ok' => true, 'id' => $id, 'analysis' => $analysis ]);