Create script.js
Browse files
script.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// ================ CONFIG ===================
|
| 2 |
+
const BASE_WS = "wss://tricuspidate-tournois-michale.ngrok-free.dev";
|
| 3 |
+
// THAY BẰNG NGROK CỦA BẠN
|
| 4 |
+
// ===========================================
|
| 5 |
+
|
| 6 |
+
let ws = null;
|
| 7 |
+
let mediaRecorder = null;
|
| 8 |
+
let currentEmotion = "wenrou";
|
| 9 |
+
|
| 10 |
+
function setEmotion(e) {
|
| 11 |
+
currentEmotion = e;
|
| 12 |
+
const map = {
|
| 13 |
+
"wenrou": "wenrou(温柔)",
|
| 14 |
+
"sajiao": "sajiao(撒娇)",
|
| 15 |
+
"tiaopi": "tiaopi(调皮)",
|
| 16 |
+
"nuanxin": "nuanxin(暖心)",
|
| 17 |
+
};
|
| 18 |
+
document.getElementById("emotionLabel").textContent = map[e];
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
document.getElementById("startBtn").onclick = async () => {
|
| 22 |
+
|
| 23 |
+
const WS_URL = `${BASE_WS}/ws?emotion=${currentEmotion}`;
|
| 24 |
+
ws = new WebSocket(WS_URL);
|
| 25 |
+
|
| 26 |
+
ws.onopen = () => console.log("WS connected:", WS_URL);
|
| 27 |
+
|
| 28 |
+
ws.onmessage = async (event) => {
|
| 29 |
+
let data = JSON.parse(event.data);
|
| 30 |
+
|
| 31 |
+
// update subtitles
|
| 32 |
+
document.getElementById("userSubtitle").textContent = data.user;
|
| 33 |
+
document.getElementById("aiSubtitle").textContent = data.ai;
|
| 34 |
+
|
| 35 |
+
// play audio
|
| 36 |
+
const audio = new Audio("data:audio/mp3;base64," + data.audio);
|
| 37 |
+
audio.play();
|
| 38 |
+
};
|
| 39 |
+
|
| 40 |
+
// setup microphone
|
| 41 |
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
| 42 |
+
mediaRecorder = new MediaRecorder(stream, { mimeType: "audio/webm" });
|
| 43 |
+
|
| 44 |
+
mediaRecorder.ondataavailable = async (e) => {
|
| 45 |
+
const arrayBuffer = await e.data.arrayBuffer();
|
| 46 |
+
ws.send(arrayBuffer);
|
| 47 |
+
};
|
| 48 |
+
|
| 49 |
+
mediaRecorder.start(300); // 300ms chunk
|
| 50 |
+
};
|
| 51 |
+
|
| 52 |
+
document.getElementById("stopBtn").onclick = () => {
|
| 53 |
+
if (mediaRecorder) mediaRecorder.stop();
|
| 54 |
+
if (ws) ws.close();
|
| 55 |
+
};
|