Piyush23890/Sign_Language_Decoder
0
1/**2 * SignBridge — script.js3 * ======================4 * Handles all client-side logic:5 * - WebSocket connection to Flask-SocketIO backend6 * - Real-time sign + sentence display updates7 * - Keyboard shortcut bindings8 * - Text-to-Speech (Web Speech API)9 * - Speech-to-Text (Web Speech API)10 * - Language switching (→ emits to backend for translation)11 * - Clipboard copy12 */13 14"use strict";15 16// ── WebSocket ────────────────────────────────────────────────────────────────────17const socket = io();18 19socket.on("connect", () => {20 console.log("[SignBridge] WebSocket connected — id:", socket.id);21});22 23socket.on("disconnect", () => {24 console.warn("[SignBridge] WebSocket disconnected.");25});26 27// ── DOM refs ─────────────────────────────────────────────────────────────────────28const signEl = document.getElementById("current-sign");29const sentenceEl = document.getElementById("sentence-display");30const speechEl = document.getElementById("speech-display");31const micBtn = document.getElementById("mic-btn");32const langSel = document.getElementById("lang-select");33 34// ── Real-time update from backend ─────────────────────────────────────────────────35socket.on("update_status", ({ sign, sentence }) => {36 // Sign badge37 if (sign) {38 signEl.textContent = sign;39 signEl.style.color = "#10b981"; // accent green when active40 } else {41 signEl.textContent = "Listening…";42 signEl.style.color = "#94a3b8"; // muted when idle43 }44 45 // Sentence46 sentenceEl.textContent = sentence || "";47});48 49// ── Command helpers ───────────────────────────────────────────────────────────────50function sendCommand(action) {51 socket.emit("command", { action });52}53 54// ── Language selector ─────────────────────────────────────────────────────────────55function changeLanguage() {56 const lang = langSel.value;57 socket.emit("set_language", { language: lang });58}59 60// ── Text-to-Speech ────────────────────────────────────────────────────────────────61function speakText() {62 const text = sentenceEl.textContent.trim();63 if (!text || !window.speechSynthesis) return;64 65 const lang = langSel.value === "hi" ? "hi-IN" : "en-US";66 const utt = new SpeechSynthesisUtterance(text);67 utt.lang = lang;68 utt.rate = 0.95;69 window.speechSynthesis.cancel(); // cancel any ongoing speech first70 window.speechSynthesis.speak(utt);71}72 73// ── Speech-to-Text ────────────────────────────────────────────────────────────────74let recognition = null;75let isListening = false;76 77(function initSTT() {78 const SR = window.SpeechRecognition || window.webkitSpeechRecognition;79 if (!SR) {80 if (speechEl) speechEl.textContent = "STT not supported in this browser.";81 if (micBtn) micBtn.disabled = true;82 return;83 }84 85 recognition = new SR();86 recognition.continuous = false;87 recognition.interimResults = false;88 recognition.lang = "en-US";89 90 recognition.onstart = () => {91 isListening = true;92 micBtn.textContent = "🔴 Listening…";93 micBtn.classList.add("active");94 speechEl.textContent = "…";95 };96 97 recognition.onresult = (event) => {98 const transcript = event.results[0][0].transcript;99 const lang = langSel.value;100 101 if (lang === "hi") {102 // Ask backend to translate103 socket.emit("translate_now", { text: transcript, target: "hi" });104 } else {105 speechEl.textContent = transcript;106 }107 };108 109 // Receive translation from backend110 socket.on("stt_translation", ({ translated }) => {111 if (speechEl) speechEl.textContent = translated;112 });113 114 recognition.onerror = (event) => {115 stopListening();116 const errorMap = {117 "network" : "Network error — internet required for STT.",118 "not-allowed": "Microphone access denied.",119 "no-speech" : "No speech detected. Try again.",120 };121 speechEl.textContent = errorMap[event.error] ?? `Error: ${event.error}`;122 };123 124 recognition.onend = stopListening;125})();126 127function toggleSpeech() {128 if (!recognition) return;129 isListening ? recognition.stop() : recognition.start();130}131 132function stopListening() {133 isListening = false;134 micBtn.textContent = "🎤 Tap to Speak";135 micBtn.classList.remove("active");136}137 138// ── Clipboard helpers ─────────────────────────────────────────────────────────────139function _copyAndFlash(text, btn) {140 if (!text) return;141 navigator.clipboard.writeText(text).then(() => {142 const orig = btn.textContent;143 btn.textContent = "✅";144 setTimeout(() => { btn.textContent = orig; }, 2000);145 });146}147 148function copyToClipboard() {149 const btn = document.querySelector(".sentence-card .icon-btn");150 _copyAndFlash(sentenceEl.textContent, btn);151}152 153function copySpeechToClipboard() {154 const btn = document.querySelector(".speech-card .icon-btn");155 _copyAndFlash(speechEl.textContent, btn);156}157 158// ── Keyboard shortcuts ────────────────────────────────────────────────────────────159document.addEventListener("keydown", (e) => {160 // Don't fire when typing in an input161 if (document.activeElement.tagName === "INPUT") return;162 163 switch (e.key) {164 case "Enter": speakText(); break;165 case "Backspace": sendCommand("backspace"); e.preventDefault(); break;166 case "c":167 case "C": sendCommand("clear"); break;168 }169});170 171// ── Init ──────────────────────────────────────────────────────────────────────────172// Sync language on page load173window.addEventListener("DOMContentLoaded", () => {174 changeLanguage();175});176 