Spaces:
Running
Running
| import express from 'express'; | |
| import { generateCompletion } from '../ai_engine.js'; | |
| import { supabase } from '../config/supabaseClient.js'; | |
| import fetch from 'node-fetch'; | |
| const router = express.Router(); | |
| const FASTAPI_URL = process.env.FASTAPI_SERVER_URL || 'http://localhost:8000'; | |
| router.get('/trending', async (req, res) => { | |
| try { | |
| const { data, error } = await supabase.from('viral_cat_trending').select('*').order('created_at', { ascending: false }); | |
| if (error) throw error; | |
| res.json({ success: true, data }); | |
| } catch (err) { | |
| res.status(500).json({ success: false, error: err.message }); | |
| } | |
| }); | |
| router.post('/admin/template', async (req, res) => { | |
| try { | |
| const { title, video_url, platform, video_base64 } = req.body; | |
| const mediaRes = await fetch(`${FASTAPI_URL}/process-video`, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ video_base64 }) | |
| }); | |
| const mediaData = await mediaRes.json(); | |
| console.log(mediaData); | |
| if (!mediaData.success) throw new Error(mediaData.error); | |
| const aiPrompt = `Analyze this video transcript and these 15 frames. | |
| TRANSCRIPT: "${mediaData.transcript}" | |
| Format: TRANSCRIPT:[text], ENVIRONMENT:[text], PACING:[text]`; | |
| const aiResult = await generateCompletion({ | |
| model: "maverick", | |
| prompt: aiPrompt, | |
| images: mediaData.frames | |
| }); | |
| console.log(aiResult); | |
| const transcriptMatch = aiResult.data.match(/TRANSCRIPT:\s*(.*?)(?=ENVIRONMENT:)/is); | |
| const envMatch = aiResult.data.match(/ENVIRONMENT:\s*(.*?)(?=PACING:)/is); | |
| const pacingMatch = aiResult.data.match(/PACING:\s*(.*)/is); | |
| const { error } = await supabase.from('viral_cat_trending').insert([{ | |
| platform, video_url, title, | |
| thumbnail_url: `data:image/jpeg;base64,${mediaData.thumbnail}`, | |
| transcript: transcriptMatch ? transcriptMatch[1].trim() : mediaData.transcript, | |
| ai_environment_data: envMatch ? envMatch[1].trim() : "N/A", | |
| ai_scene_changes: pacingMatch ? pacingMatch[1].trim() : "N/A", | |
| }]); | |
| if (error) throw error; | |
| res.json({ success: true }); | |
| } catch (err) { | |
| res.status(500).json({ success: false, error: err.message }); | |
| } | |
| }); | |
| router.post('/custom_remix', async (req, res) => { | |
| try { | |
| const { user_niche, video_base64 } = req.body; | |
| const mediaRes = await fetch(`${FASTAPI_URL}/process-video`, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ video_base64 }) | |
| }); | |
| const mediaData = await mediaRes.json(); | |
| if (!mediaData.success) throw new Error(mediaData.error); | |
| const result = await generateCompletion({ | |
| model: "maverick", | |
| prompt: `Remix for niche: "${user_niche}". Transcript: ${mediaData.transcript}`, | |
| images: mediaData.frames | |
| }); | |
| res.json(result); | |
| } catch (err) { | |
| res.status(500).json({ success: false, error: err.message }); | |
| } | |
| }); | |
| router.delete('/admin/template/:id', async (req, res) => { | |
| await supabase.from('viral_cat_trending').delete().eq('id', req.params.id); | |
| res.json({ success: true }); | |
| }); | |
| router.get('/admin', (req, res) => { | |
| res.send(`<!DOCTYPE html><html><head><title>Viral Cat Admin</title><script src="https://cdn.tailwindcss.com"></script></head> | |
| <body class="bg-[#090A0F] text-white p-8"><h1 class="text-3xl font-bold text-[#12D8C3] mb-8">Viral Cat Admin</h1> | |
| <div class="grid grid-cols-2 gap-8"><div class="bg-[#16181F] p-6 rounded-2xl"> | |
| <form id="f" class="space-y-4"><input id="t" placeholder="Title" class="w-full p-2 bg-black border border-gray-700 rounded"/> | |
| <input id="u" placeholder="Embed URL" class="w-full p-2 bg-black border border-gray-700 rounded"/> | |
| <select id="p" class="w-full p-2 bg-black border border-gray-700 rounded"><option value="tiktok">TikTok</option><option value="instagram">Instagram</option></select> | |
| <input type="file" id="v" accept="video/mp4" class="w-full"/><button type="submit" class="w-full bg-[#12D8C3] text-black p-2 rounded font-bold">Process Video</button></form></div> | |
| <div id="list" class="space-y-2"></div></div> | |
| <script> | |
| const toB64 = f => new Promise((res,rej)=>{const r=new FileReader();r.readAsDataURL(f);r.onload=()=>res(r.result.split(',')[1]);}); | |
| async function load(){const r=await fetch('/api/viralcat/trending');const j=await r.json();document.getElementById('list').innerHTML=j.data.map(t=>\`<div class="p-4 bg-gray-900 flex justify-between"><span>\${t.title}</span><button onclick="del('\${t.id}')">Delete</button></div>\`).join('');} | |
| async function del(id){await fetch('/api/viralcat/admin/template/'+id,{method:'DELETE'});load();} | |
| document.getElementById('f').onsubmit=async e=>{e.preventDefault();const b=e.target.querySelector('button');b.innerText="Wait..."; | |
| const b64=await toB64(document.getElementById('v').files[0]); | |
| await fetch('/api/viralcat/admin/template',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({title:document.getElementById('t').value,video_url:document.getElementById('u').value,platform:document.getElementById('p').value,video_base64:b64})}); | |
| b.innerText="Process Video";load();};load(); | |
| </script></body></html>`); | |
| }); | |
| export default router; |