Charan5775 commited on
Commit
aa44aee
·
verified ·
1 Parent(s): f3dd1db

Create index.html

Browse files
Files changed (1) hide show
  1. index.html +180 -0
index.html ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <title>Whisper.cpp Live STT</title>
6
+ <style>
7
+ body {
8
+ font-family: Arial, sans-serif;
9
+ background: #0f172a;
10
+ color: #e5e7eb;
11
+ display: flex;
12
+ flex-direction: column;
13
+ align-items: center;
14
+ padding: 30px;
15
+ }
16
+ h1 {
17
+ margin-bottom: 10px;
18
+ }
19
+ .controls {
20
+ margin: 20px 0;
21
+ }
22
+ button {
23
+ margin: 0 10px;
24
+ padding: 10px 20px;
25
+ border-radius: 8px;
26
+ border: none;
27
+ cursor: pointer;
28
+ font-size: 16px;
29
+ }
30
+ #startBtn {
31
+ background: #22c55e;
32
+ color: #022c22;
33
+ }
34
+ #stopBtn {
35
+ background: #ef4444;
36
+ color: #fee2e2;
37
+ }
38
+ #status {
39
+ margin-top: 10px;
40
+ font-size: 14px;
41
+ opacity: 0.8;
42
+ }
43
+ #output {
44
+ margin-top: 20px;
45
+ width: 100%;
46
+ max-width: 700px;
47
+ min-height: 200px;
48
+ border-radius: 10px;
49
+ padding: 15px;
50
+ background: #020617;
51
+ box-shadow: 0 0 0 1px #1f2937 inset;
52
+ white-space: pre-wrap;
53
+ overflow-y: auto;
54
+ }
55
+ </style>
56
+ </head>
57
+ <body>
58
+ <h1>Whisper.cpp Live Speech-to-Text</h1>
59
+ <p>Click start, allow mic access, and speak. Partial transcripts will appear below.</p>
60
+
61
+ <div class="controls">
62
+ <button id="startBtn">🎤 Start</button>
63
+ <button id="stopBtn" disabled>⛔ Stop</button>
64
+ </div>
65
+
66
+ <div id="status">Status: idle</div>
67
+ <pre id="output"></pre>
68
+
69
+ <script>
70
+ let socket = null;
71
+ let mediaRecorder = null;
72
+ let isRecording = false;
73
+
74
+ const statusEl = document.getElementById("status");
75
+ const outputEl = document.getElementById("output");
76
+ const startBtn = document.getElementById("startBtn");
77
+ const stopBtn = document.getElementById("stopBtn");
78
+
79
+ function logStatus(text) {
80
+ statusEl.textContent = "Status: " + text;
81
+ console.log("[STATUS]", text);
82
+ }
83
+
84
+ function appendText(text) {
85
+ outputEl.textContent += text + "\n";
86
+ outputEl.scrollTop = outputEl.scrollHeight;
87
+ }
88
+
89
+ function createWebSocket() {
90
+ // Build ws/wss URL from current location (works local + HF Space)
91
+ const wsUrl = (location.origin.replace(/^http/, "ws") + "/ws/transcribe_stream");
92
+ console.log("Connecting to", wsUrl);
93
+
94
+ socket = new WebSocket(wsUrl);
95
+
96
+ socket.onopen = () => {
97
+ logStatus("WebSocket connected, mic ready");
98
+ };
99
+
100
+ socket.onmessage = (event) => {
101
+ const msg = event.data;
102
+ appendText(msg);
103
+ };
104
+
105
+ socket.onerror = (err) => {
106
+ console.error("WebSocket error:", err);
107
+ logStatus("WebSocket error");
108
+ };
109
+
110
+ socket.onclose = () => {
111
+ logStatus("WebSocket closed");
112
+ };
113
+ }
114
+
115
+ async function startRecording() {
116
+ if (isRecording) return;
117
+
118
+ // Make sure WebSocket exists and open
119
+ if (!socket || socket.readyState !== WebSocket.OPEN) {
120
+ createWebSocket();
121
+ // Wait briefly for connect (simple version)
122
+ await new Promise((resolve) => setTimeout(resolve, 500));
123
+ }
124
+
125
+ try {
126
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
127
+ const options = { mimeType: "audio/webm;codecs=opus" };
128
+
129
+ if (!MediaRecorder.isTypeSupported(options.mimeType)) {
130
+ alert("WebM/Opus not supported in this browser.");
131
+ return;
132
+ }
133
+
134
+ mediaRecorder = new MediaRecorder(stream, options);
135
+
136
+ mediaRecorder.onstart = () => {
137
+ isRecording = true;
138
+ startBtn.disabled = true;
139
+ stopBtn.disabled = false;
140
+ logStatus("Recording...");
141
+ };
142
+
143
+ mediaRecorder.ondataavailable = (event) => {
144
+ if (event.data && event.data.size > 0 && socket && socket.readyState === WebSocket.OPEN) {
145
+ event.data.arrayBuffer().then((buffer) => {
146
+ socket.send(buffer); // send binary audio chunk
147
+ });
148
+ }
149
+ };
150
+
151
+ mediaRecorder.onstop = () => {
152
+ isRecording = false;
153
+ startBtn.disabled = false;
154
+ stopBtn.disabled = true;
155
+ logStatus("Recording stopped");
156
+ };
157
+
158
+ // send chunks every 500ms
159
+ mediaRecorder.start(500);
160
+ } catch (err) {
161
+ console.error("Error starting microphone:", err);
162
+ logStatus("Mic permission denied or error");
163
+ }
164
+ }
165
+
166
+ function stopRecording() {
167
+ if (!isRecording || !mediaRecorder) return;
168
+ mediaRecorder.stop();
169
+
170
+ if (socket && socket.readyState === WebSocket.OPEN) {
171
+ // Tell server we are done
172
+ socket.send("__END__");
173
+ }
174
+ }
175
+
176
+ startBtn.addEventListener("click", startRecording);
177
+ stopBtn.addEventListener("click", stopRecording);
178
+ </script>
179
+ </body>
180
+ </html>