aigorithm commited on
Commit
c204e52
·
verified ·
1 Parent(s): 6ef077a

Upload 2 files

Browse files
Files changed (2) hide show
  1. index.html +78 -74
  2. main.js +34 -30
index.html CHANGED
@@ -2,115 +2,119 @@
2
  <!DOCTYPE html>
3
  <html lang="en">
4
  <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>AiCut Pro Replica</title>
8
  <style>
9
  body {
10
  margin: 0;
 
11
  background: #000;
12
- font-family: -apple-system, BlinkMacSystemFont, sans-serif;
13
- display: flex;
14
- flex-direction: column;
15
- align-items: center;
16
- }
17
- .container {
18
  display: flex;
19
  flex-direction: column;
20
  align-items: center;
21
  padding: 16px;
22
- color: white;
23
  }
24
- .phone {
 
25
  width: 360px;
26
- height: 720px;
27
- background: #f0f2f5;
28
- border-radius: 40px;
29
  overflow: hidden;
30
- box-shadow: 0 0 12px rgba(0,0,0,0.25);
31
- display: flex;
32
- flex-direction: column;
33
- margin-top: 10px;
34
  }
35
- .topbar {
36
- background: #fff;
37
- text-align: center;
38
- padding: 10px;
39
- font-weight: bold;
40
- font-size: 16px;
41
- border-bottom: 1px solid #ddd;
42
  }
43
- .chat {
44
- flex: 1;
 
 
45
  padding: 10px;
46
- display: flex;
47
- flex-direction: column;
48
- gap: 10px;
49
  overflow-y: auto;
 
50
  }
51
  .message {
52
  display: flex;
53
  align-items: flex-end;
54
- gap: 8px;
 
 
 
 
 
 
55
  }
56
  .bubble {
57
- padding: 10px 14px;
58
  border-radius: 18px;
59
  max-width: 70%;
60
  font-size: 14px;
61
- line-height: 1.4;
62
- animation: fadeSlideUp 0.4s ease forwards;
63
  opacity: 0;
 
64
  }
65
- .left {
66
- flex-direction: row;
67
- }
68
- .right {
69
- flex-direction: row-reverse;
70
- }
71
- .left .bubble {
72
- background: #e5e5ea;
73
- color: black;
74
- }
75
- .right .bubble {
76
- background: #007aff;
77
- color: white;
78
- }
79
- .avatar {
80
- width: 28px;
81
- height: 28px;
82
- border-radius: 50%;
83
- }
84
- @keyframes fadeSlideUp {
85
- from { opacity: 0; transform: translateY(20px); }
86
  to { opacity: 1; transform: translateY(0); }
 
87
  }
88
- textarea {
89
- width: 90%;
90
- height: 100px;
91
- margin-top: 10px;
92
- font-size: 14px;
93
- font-family: monospace;
94
  }
95
- button {
96
- padding: 8px 16px;
97
- margin-top: 10px;
 
 
98
  }
99
  </style>
100
  </head>
101
  <body>
102
- <div class="container">
103
- <h2>AiCut Pro Chat Generator</h2>
104
- <textarea id="scriptInput">[
105
- { "side": "left", "text": "Hey, are you there?" },
106
- { "side": "right", "text": "Yeah, just got here." }
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  ]</textarea>
108
- <button onclick="startPlayback()">🎬 Export Video with Voice</button>
109
- <div class="phone">
110
- <div class="topbar">Messages</div>
111
- <div id="chat" class="chat"></div>
112
- </div>
 
 
113
  </div>
 
114
  <script type="module" src="main.js"></script>
115
  </body>
116
  </html>
 
2
  <!DOCTYPE html>
3
  <html lang="en">
4
  <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
7
+ <title>Full Fake Chat Animator</title>
8
  <style>
9
  body {
10
  margin: 0;
11
+ font-family: sans-serif;
12
  background: #000;
13
+ color: white;
 
 
 
 
 
14
  display: flex;
15
  flex-direction: column;
16
  align-items: center;
17
  padding: 16px;
 
18
  }
19
+ .phone-frame {
20
+ position: relative;
21
  width: 360px;
22
+ height: 640px;
 
 
23
  overflow: hidden;
24
+ border-radius: 24px;
25
+ box-shadow: 0 0 10px rgba(0,0,0,0.4);
26
+ z-index: 1;
 
27
  }
28
+ #background-video {
29
+ position: absolute;
30
+ width: 100%;
31
+ height: 100%;
32
+ object-fit: cover;
33
+ z-index: 1;
 
34
  }
35
+ #chat {
36
+ position: absolute;
37
+ width: 100%;
38
+ height: 100%;
39
  padding: 10px;
 
 
 
40
  overflow-y: auto;
41
+ z-index: 2;
42
  }
43
  .message {
44
  display: flex;
45
  align-items: flex-end;
46
+ margin-bottom: 8px;
47
+ }
48
+ .avatar {
49
+ width: 28px;
50
+ height: 28px;
51
+ border-radius: 50%;
52
+ margin: 0 8px;
53
  }
54
  .bubble {
55
+ padding: 10px;
56
  border-radius: 18px;
57
  max-width: 70%;
58
  font-size: 14px;
 
 
59
  opacity: 0;
60
+ animation: fadeIn 0.5s forwards;
61
  }
62
+ .left { flex-direction: row; }
63
+ .right { flex-direction: row-reverse; }
64
+ .left .bubble { background: #eee; color: #000; }
65
+ .right .bubble { background: #007aff; color: #fff; }
66
+ .whatsapp .left .bubble { background: #e1ffc7; }
67
+ .imessage .right .bubble { background: #007aff; }
68
+ .instagram .bubble { background: #fff0f5; color: #000; }
69
+ .reddit .bubble { background: #f6f7f8; border-left: 4px solid #ff4500; padding-left: 12px; }
70
+
71
+ @keyframes fadeIn {
 
 
 
 
 
 
 
 
 
 
 
72
  to { opacity: 1; transform: translateY(0); }
73
+ from { opacity: 0; transform: translateY(10px); }
74
  }
75
+
76
+ .controls {
77
+ width: 100%;
78
+ max-width: 400px;
79
+ margin-top: 20px;
 
80
  }
81
+ .controls input, .controls select, .controls button {
82
+ width: 100%;
83
+ margin: 4px 0;
84
+ padding: 8px;
85
+ border-radius: 8px;
86
  }
87
  </style>
88
  </head>
89
  <body>
90
+ <h2>Fake Chat Animator Pro</h2>
91
+
92
+ <div class="controls">
93
+ <label>Background MP4 Video:</label>
94
+ <input type="file" accept="video/mp4" onchange="loadBackground(event)">
95
+
96
+ <label>Choose Style:</label>
97
+ <select id="styleSelect" onchange="switchStyle()">
98
+ <option value="whatsapp">WhatsApp</option>
99
+ <option value="imessage">iMessage</option>
100
+ <option value="instagram">Instagram</option>
101
+ <option value="reddit">Reddit</option>
102
+ </select>
103
+
104
+ <label>Chat Script (JSON):</label>
105
+ <textarea id="chatScript" style="height: 120px; width: 100%;">[
106
+ { "name": "Suren", "side": "left", "avatar": "https://i.pravatar.cc/30?img=1", "voice": "Rachel", "text": "Hey, are you there?" },
107
+ { "name": "You", "side": "right", "avatar": "https://i.pravatar.cc/30?img=3", "voice": "Adam", "text": "Yeah, just got here!" }
108
  ]</textarea>
109
+
110
+ <button onclick="renderAndRecord()">🎬 Export Chat with Voice</button>
111
+ </div>
112
+
113
+ <div class="phone-frame">
114
+ <video id="background-video" autoplay loop muted></video>
115
+ <div id="chat" class="whatsapp"></div>
116
  </div>
117
+
118
  <script type="module" src="main.js"></script>
119
  </body>
120
  </html>
main.js CHANGED
@@ -1,60 +1,64 @@
1
 
2
  const chat = document.getElementById("chat");
3
- const scriptInput = document.getElementById("scriptInput");
4
- const voiceId = "21m00Tcm4TlvDq8ikWAM"; // Rachel
 
 
 
 
5
  const apiKey = "sk_4e67c39c0e9cbc87462cd2643e1f4d1d9959d7d81203adc2";
6
 
7
- async function getVoiceBlob(text) {
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  const res = await fetch("https://api.elevenlabs.io/v1/text-to-speech/" + voiceId, {
9
  method: "POST",
10
  headers: {
11
  "Content-Type": "application/json",
12
  "xi-api-key": apiKey
13
  },
14
- body: JSON.stringify({
15
- text,
16
- model_id: "eleven_monolingual_v1",
17
- voice_settings: { stability: 0.5, similarity_boost: 0.75 }
18
- })
19
  });
20
  return await res.blob();
21
  }
22
 
23
- async function startPlayback() {
 
24
  chat.innerHTML = "";
25
- let messages;
26
- try {
27
- messages = JSON.parse(scriptInput.value);
28
- } catch (e) {
29
- alert("Invalid script format");
30
- return;
31
- }
32
 
33
- const phone = document.querySelector(".phone");
34
- const stream = phone.captureStream(30);
35
  const recorder = new MediaRecorder(stream);
36
  const chunks = [];
37
-
38
  recorder.ondataavailable = e => chunks.push(e.data);
39
  recorder.onstop = () => {
40
  const blob = new Blob(chunks, { type: "video/webm" });
41
- const url = URL.createObjectURL(blob);
42
  const a = document.createElement("a");
43
- a.href = url;
44
- a.download = "chat_aicutpro_ui.mp4";
45
  a.click();
46
  };
47
-
48
  recorder.start();
 
49
 
50
- for (const msg of messages) {
51
  const wrapper = document.createElement("div");
52
- wrapper.className = "message " + (msg.side || "left");
53
 
54
  const avatar = document.createElement("img");
55
- avatar.src = msg.side === "right"
56
- ? "https://i.pravatar.cc/30?img=3"
57
- : "https://i.pravatar.cc/30?img=7";
58
  avatar.className = "avatar";
59
 
60
  const bubble = document.createElement("div");
@@ -66,8 +70,8 @@ async function startPlayback() {
66
  chat.appendChild(wrapper);
67
  chat.scrollTop = chat.scrollHeight;
68
 
69
- const voice = await getVoiceBlob(msg.text);
70
- const audio = new Audio(URL.createObjectURL(voice));
71
  await new Promise(res => {
72
  audio.onended = res;
73
  audio.play();
 
1
 
2
  const chat = document.getElementById("chat");
3
+ const bgVideo = document.getElementById("background-video");
4
+ const voiceMap = {
5
+ Rachel: "21m00Tcm4TlvDq8ikWAM",
6
+ Adam: "pNInz6obpgDQGcFmaJgB",
7
+ Bella: "EXAVITQu4vr4xnSDxMaL"
8
+ };
9
  const apiKey = "sk_4e67c39c0e9cbc87462cd2643e1f4d1d9959d7d81203adc2";
10
 
11
+ function switchStyle() {
12
+ chat.className = document.getElementById("styleSelect").value;
13
+ }
14
+
15
+ function loadBackground(e) {
16
+ const file = e.target.files[0];
17
+ if (file) {
18
+ const url = URL.createObjectURL(file);
19
+ bgVideo.src = url;
20
+ }
21
+ }
22
+
23
+ async function getVoiceBlob(text, voice) {
24
+ const voiceId = voiceMap[voice] || voiceMap["Rachel"];
25
  const res = await fetch("https://api.elevenlabs.io/v1/text-to-speech/" + voiceId, {
26
  method: "POST",
27
  headers: {
28
  "Content-Type": "application/json",
29
  "xi-api-key": apiKey
30
  },
31
+ body: JSON.stringify({ text, model_id: "eleven_monolingual_v1", voice_settings: { stability: 0.5, similarity_boost: 0.75 } })
 
 
 
 
32
  });
33
  return await res.blob();
34
  }
35
 
36
+ async function renderAndRecord() {
37
+ const script = JSON.parse(document.getElementById("chatScript").value);
38
  chat.innerHTML = "";
39
+ bgVideo.pause();
40
+ bgVideo.currentTime = 0;
 
 
 
 
 
41
 
42
+ const stream = document.querySelector(".phone-frame").captureStream(30);
 
43
  const recorder = new MediaRecorder(stream);
44
  const chunks = [];
 
45
  recorder.ondataavailable = e => chunks.push(e.data);
46
  recorder.onstop = () => {
47
  const blob = new Blob(chunks, { type: "video/webm" });
 
48
  const a = document.createElement("a");
49
+ a.href = URL.createObjectURL(blob);
50
+ a.download = "fake_chat_with_voice.mp4";
51
  a.click();
52
  };
 
53
  recorder.start();
54
+ bgVideo.play();
55
 
56
+ for (const msg of script) {
57
  const wrapper = document.createElement("div");
58
+ wrapper.className = "message " + msg.side;
59
 
60
  const avatar = document.createElement("img");
61
+ avatar.src = msg.avatar;
 
 
62
  avatar.className = "avatar";
63
 
64
  const bubble = document.createElement("div");
 
70
  chat.appendChild(wrapper);
71
  chat.scrollTop = chat.scrollHeight;
72
 
73
+ const voiceBlob = await getVoiceBlob(msg.text, msg.voice);
74
+ const audio = new Audio(URL.createObjectURL(voiceBlob));
75
  await new Promise(res => {
76
  audio.onended = res;
77
  audio.play();