Spaces:
Running
Running
const chat = document.getElementById("chat"); | |
const bg = document.getElementById("bg"); | |
const messages = [ | |
{ name: "Suren", side: "left", avatar: "https://i.pravatar.cc/30?img=5", voice: "Rachel", text: "Are you ready to launch?" }, | |
{ name: "Elon", side: "right", avatar: "https://i.pravatar.cc/30?img=9", voice: "Adam", text: "Always ready. 3...2...1..." }, | |
{ name: "Suren", side: "left", avatar: "https://i.pravatar.cc/30?img=5", voice: "Rachel", text: "We’re live on TikTok now!" } | |
]; | |
const voiceMap = { | |
Rachel: "21m00Tcm4TlvDq8ikWAM", | |
Adam: "pNInz6obpgDQGcFmaJgB", | |
Bella: "EXAVITQu4vr4xnSDxMaL" | |
}; | |
const apiKey = "sk_4e67c39c0e9cbc87462cd2643e1f4d1d9959d7d81203adc2"; | |
function loadBackground(e) { | |
const file = e.target.files[0]; | |
const url = URL.createObjectURL(file); | |
bg.src = url; | |
bg.play(); | |
} | |
async function getVoiceBlob(text, voice) { | |
const voiceId = voiceMap[voice] || voiceMap.Rachel; | |
const res = await fetch("https://api.elevenlabs.io/v1/text-to-speech/" + voiceId, { | |
method: "POST", | |
headers: { | |
"Content-Type": "application/json", | |
"xi-api-key": apiKey | |
}, | |
body: JSON.stringify({ text, model_id: "eleven_monolingual_v1", voice_settings: { stability: 0.4, similarity_boost: 0.75 } }) | |
}); | |
return await res.blob(); | |
} | |
async function start() { | |
chat.innerHTML = ""; | |
bg.currentTime = 0; | |
const stream = document.querySelector(".phone-frame").captureStream(30); | |
const recorder = new MediaRecorder(stream); | |
const chunks = []; | |
recorder.ondataavailable = e => chunks.push(e.data); | |
recorder.onstop = () => { | |
const blob = new Blob(chunks, { type: "video/webm" }); | |
const a = document.createElement("a"); | |
a.href = URL.createObjectURL(blob); | |
a.download = "chat_tiktok_ready.mp4"; | |
a.click(); | |
}; | |
recorder.start(); | |
bg.play(); | |
for (const msg of messages) { | |
const typing = document.createElement("div"); | |
typing.className = "typing"; | |
typing.innerHTML = "<span></span><span></span><span></span>"; | |
chat.appendChild(typing); | |
chat.scrollTop = chat.scrollHeight; | |
await new Promise(r => setTimeout(r, 1200)); | |
chat.removeChild(typing); | |
const wrap = document.createElement("div"); | |
wrap.className = "message " + msg.side; | |
const avatar = document.createElement("img"); | |
avatar.src = msg.avatar; | |
avatar.className = "avatar"; | |
const bubble = document.createElement("div"); | |
bubble.className = "bubble"; | |
bubble.textContent = msg.text; | |
wrap.appendChild(avatar); | |
wrap.appendChild(bubble); | |
chat.appendChild(wrap); | |
chat.scrollTop = chat.scrollHeight; | |
const blob = await getVoiceBlob(msg.text, msg.voice); | |
const audio = new Audio(URL.createObjectURL(blob)); | |
await new Promise(r => { | |
audio.onended = r; | |
audio.play(); | |
}); | |
} | |
recorder.stop(); | |
} | |