awacke1 commited on
Commit
88b617e
·
verified ·
1 Parent(s): f55a08c

Update frontend/index.html

Browse files
Files changed (1) hide show
  1. frontend/index.html +204 -3
frontend/index.html CHANGED
@@ -1,10 +1,211 @@
1
  <!DOCTYPE html>
2
  <html>
3
  <head>
4
- <title>Paste Image to Chat</title>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  </head>
6
  <body>
7
- <div id="paste-target">Paste an image here (Ctrl+V)</div>
8
- <script src="main.js"></script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  </body>
10
  </html>
 
1
  <!DOCTYPE html>
2
  <html>
3
  <head>
4
+ <title>ASR and Image Paster Demo</title>
5
+ <style>
6
+ body {
7
+ font-family: sans-serif;
8
+ padding: 20px;
9
+ max-width: 800px;
10
+ margin: 0 auto;
11
+ }
12
+ button {
13
+ padding: 10px 20px;
14
+ margin: 10px 5px;
15
+ font-size: 16px;
16
+ }
17
+ #status {
18
+ margin: 10px 0;
19
+ padding: 10px;
20
+ background: #e8f5e9;
21
+ border-radius: 4px;
22
+ }
23
+ #output {
24
+ white-space: pre-wrap;
25
+ padding: 15px;
26
+ background: #f5f5f5;
27
+ border-radius: 4px;
28
+ margin: 10px 0;
29
+ min-height: 100px;
30
+ max-height: 400px;
31
+ overflow-y: auto;
32
+ }
33
+ .controls {
34
+ margin: 10px 0;
35
+ }
36
+ #paste-target {
37
+ border: 2px dashed #ccc;
38
+ padding: 20px;
39
+ text-align: center;
40
+ cursor: pointer;
41
+ margin: 10px 0;
42
+ }
43
+ </style>
44
  </head>
45
  <body>
46
+ <div class="controls">
47
+ <button id="start">Start Listening</button>
48
+ <button id="stop" disabled>Stop Listening</button>
49
+ <button id="clear">Clear Text</button>
50
+ </div>
51
+ <div id="status">Ready</div>
52
+ <div id="output"></div>
53
+ <div id="paste-target">Paste an image here (Ctrl+V)</div>
54
+
55
+ <input type="hidden" id="streamlit-data" value="">
56
+
57
+ <script>
58
+ // Streamlit communication functions
59
+ function sendMessageToStreamlitClient(type, data) {
60
+ var outData = Object.assign({
61
+ isStreamlitMessage: true,
62
+ type: type,
63
+ }, data);
64
+ window.parent.postMessage(outData, "*");
65
+ }
66
+
67
+ function init() {
68
+ sendMessageToStreamlitClient("streamlit:componentReady", {apiVersion: 1});
69
+ }
70
+
71
+ function setFrameHeight(height) {
72
+ sendMessageToStreamlitClient("streamlit:setFrameHeight", {height: height});
73
+ }
74
+
75
+ function sendDataToPython(data) {
76
+ sendMessageToStreamlitClient("streamlit:setComponentValue", data);
77
+ }
78
+
79
+ // ASR Setup
80
+ if (!('webkitSpeechRecognition' in window)) {
81
+ alert('Speech recognition not supported');
82
+ } else {
83
+ const recognition = new webkitSpeechRecognition();
84
+ const startButton = document.getElementById('start');
85
+ const stopButton = document.getElementById('stop');
86
+ const clearButton = document.getElementById('clear');
87
+ const status = document.getElementById('status');
88
+ const output = document.getElementById('output');
89
+ let fullTranscript = '';
90
+ let lastUpdateTime = Date.now();
91
+
92
+ recognition.continuous = true;
93
+ recognition.interimResults = true;
94
+
95
+ const startRecognition = () => {
96
+ try {
97
+ recognition.start();
98
+ status.textContent = 'Listening...';
99
+ startButton.disabled = true;
100
+ stopButton.disabled = false;
101
+ } catch (e) {
102
+ console.error(e);
103
+ status.textContent = 'Error: ' + e.message;
104
+ }
105
+ };
106
+
107
+ window.addEventListener('load', () => {
108
+ setTimeout(startRecognition, 1000);
109
+ });
110
+
111
+ startButton.onclick = startRecognition;
112
+
113
+ stopButton.onclick = () => {
114
+ recognition.stop();
115
+ status.textContent = 'Stopped';
116
+ startButton.disabled = false;
117
+ stopButton.disabled = true;
118
+ };
119
+
120
+ clearButton.onclick = () => {
121
+ fullTranscript = '';
122
+ output.textContent = '';
123
+ sendDataToPython({ transcript: '', type: 'text' });
124
+ };
125
+
126
+ recognition.onresult = (event) => {
127
+ let interimTranscript = '';
128
+ let finalTranscript = '';
129
+
130
+ for (let i = event.resultIndex; i < event.results.length; i++) {
131
+ const transcript = event.results[i][0].transcript;
132
+ if (event.results[i].isFinal) {
133
+ finalTranscript += transcript + '\n';
134
+ } else {
135
+ interimTranscript += transcript;
136
+ }
137
+ }
138
+
139
+ if (finalTranscript || (Date.now() - lastUpdateTime > 5000)) {
140
+ if (finalTranscript) {
141
+ fullTranscript += finalTranscript;
142
+ sendDataToPython({ transcript: fullTranscript, type: 'text' });
143
+ }
144
+ lastUpdateTime = Date.now();
145
+ }
146
+
147
+ output.textContent = fullTranscript + (interimTranscript ? '... ' + interimTranscript : '');
148
+ output.scrollTop = output.scrollHeight;
149
+ };
150
+
151
+ recognition.onend = () => {
152
+ if (!stopButton.disabled) {
153
+ try {
154
+ recognition.start();
155
+ console.log('Restarted recognition');
156
+ } catch (e) {
157
+ console.error('Failed to restart recognition:', e);
158
+ status.textContent = 'Error restarting: ' + e.message;
159
+ startButton.disabled = false;
160
+ stopButton.disabled = true;
161
+ }
162
+ }
163
+ };
164
+
165
+ recognition.onerror = (event) => {
166
+ console.error('Recognition error:', event.error);
167
+ status.textContent = 'Error: ' + event.error;
168
+ if (event.error === 'not-allowed' || event.error === 'service-not-allowed') {
169
+ startButton.disabled = false;
170
+ stopButton.disabled = true;
171
+ }
172
+ };
173
+ }
174
+
175
+ // Image Pasting Setup
176
+ const pasteTarget = document.getElementById('paste-target');
177
+ pasteTarget.addEventListener("paste", (pasteEvent) => {
178
+ const items = (pasteEvent.clipboardData || window.clipboardData).items;
179
+ for (let i = 0; i < items.length; i++) {
180
+ if (items[i].type.indexOf('image') !== -1) {
181
+ const blob = items[i].getAsFile();
182
+ const reader = new FileReader();
183
+ reader.onload = (e) => {
184
+ sendDataToPython({ image: e.target.result, type: 'image' });
185
+ pasteTarget.innerHTML = "<p>Image pasted! Processing...</p>";
186
+ };
187
+ reader.readAsDataURL(blob);
188
+ }
189
+ }
190
+ pasteEvent.preventDefault();
191
+ });
192
+
193
+ // Handle data from Python (if needed)
194
+ function onDataFromPython(event) {
195
+ if (event.data.type !== "streamlit:render") return;
196
+ // Could handle Python-sent data here if needed
197
+ }
198
+
199
+ // Hook things up
200
+ window.addEventListener("message", onDataFromPython);
201
+ init();
202
+
203
+ // Set iframe height
204
+ window.addEventListener("load", function() {
205
+ window.setTimeout(function() {
206
+ setFrameHeight(document.documentElement.clientHeight);
207
+ }, 0);
208
+ });
209
+ </script>
210
  </body>
211
  </html>