File size: 2,824 Bytes
7d41d24
557b9b9
 
 
 
 
 
36c293d
557b9b9
 
 
 
adef775
8a46dd4
36c293d
557b9b9
 
 
 
 
36c293d
 
8a46dd4
557b9b9
8a46dd4
 
 
 
 
 
557b9b9
8a46dd4
 
 
 
557b9b9
 
 
 
8a46dd4
 
557b9b9
8a46dd4
 
 
 
 
557b9b9
8a46dd4
 
557b9b9
8a46dd4
557b9b9
 
8a46dd4
557b9b9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8a46dd4
 
 
36c293d
557b9b9
8a46dd4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

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