ilhamap commited on
Commit
2474dcb
·
verified ·
1 Parent(s): ff8e5ca

Upload 3 files

Browse files
Files changed (3) hide show
  1. public/index.html +34 -0
  2. public/sketch.js +444 -0
  3. public/style.css +137 -0
public/index.html ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <script src="https://cdn.socket.io/4.5.4/socket.io.min.js" integrity="sha384-/KNQL8Nu5gCHLqwqfQjA689Hhoqgi2S84SNUxC3roTe4EhJ9AfLkp8QiQcU8AMzI" crossorigin="anonymous"></script>
5
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
6
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/addons/p5.sound.min.js"></script>
7
+ <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css" crossorigin="anonymous">
8
+ <link rel="stylesheet" type="text/css" href="style.css">
9
+ <meta charset="utf-8" />
10
+ </head>
11
+ <body>
12
+ <div id="main-container">
13
+ <div id="title">
14
+ <h2>Google Gemini Pro Vision - live vision</h2>
15
+ <h3>1. turn on your camera - 2. start live vision</h3>
16
+ </div>
17
+ <div id="appcontent-ctn">
18
+ <div id="left-ctn">
19
+ <div id="canvas-container"></div>
20
+ <div id="buttons-container"></div>
21
+ <div id="checkbox-rear"></div>
22
+ </div>
23
+ <div id="right-ctn">
24
+ <div id="instructions-container"></div>
25
+ <div id="loading-div"></div>
26
+ <div id="vision-text-container"></div>
27
+ </div>
28
+ </div>
29
+
30
+
31
+ </div>
32
+ <script src="./sketch.js"></script>
33
+ </body>
34
+ </html>
public/sketch.js ADDED
@@ -0,0 +1,444 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ let myCanvas
2
+ const arrows = []
3
+ let current_points = []
4
+ let t_size
5
+ let button
6
+ let isOnCanvas = false;
7
+ let socket;
8
+ let live = false;
9
+ let timer;
10
+ let capture;
11
+ let instructions;
12
+ let current_instructions;
13
+ let messages_list = []
14
+ let timerWaiting;
15
+ let waiting = false;
16
+
17
+ let active_rearcam = false;
18
+ let camConfig = "user";
19
+ let isOnMobile;
20
+ let camIsON = false;
21
+ let device_orientation;
22
+
23
+ let graphicsToSend;
24
+
25
+ function isMobileDevice() {
26
+ return (typeof window.orientation !== "undefined") || (navigator.userAgent.indexOf('IEMobile') !== -1);
27
+ }
28
+
29
+ //-----------------------------------------------------
30
+ //-----------------------------------------------------
31
+
32
+ function preload(){
33
+
34
+ isOnMobile = isMobileDevice()
35
+ console.log("is on mobile ? " + isOnMobile)
36
+
37
+ if(isOnMobile){
38
+ device_orientation = screen.orientation.type;
39
+ }
40
+
41
+
42
+
43
+ // Socket events handlers
44
+ socket = io();
45
+ // client-side
46
+ socket.on("connect", () => {
47
+ console.log(socket.id);
48
+ });
49
+
50
+ socket.on("hello", (arg) => {
51
+ let api_data_test = arg[1]
52
+ console.log(api_data_test)
53
+ });
54
+
55
+ socket.on("api_error", (arg) => {
56
+ let message = arg
57
+ console.log(message)
58
+ });
59
+ // ————————
60
+ }
61
+
62
+ function call_api(socket, instructions){
63
+ console.log("Calling API ... ")
64
+ waiting = true;
65
+ show_loading()
66
+ //cnv_data = myCanvas.elt.toDataURL('image/png');
67
+ graphicsToSend.loadPixels()
68
+ cnv_data = graphicsToSend.canvas.toDataURL('image/png');
69
+
70
+ let data = [
71
+ cnv_data,
72
+ instructions
73
+ ]
74
+ socket.emit("ask_api", data);
75
+ }
76
+
77
+ function windowResized() {
78
+ if(windowWidth <= 500){
79
+ resizeCanvas(380, 380*320/576);
80
+ } else {
81
+ resizeCanvas(576, 320);
82
+ }
83
+ }
84
+
85
+ function setup() {
86
+
87
+ screen.orientation.addEventListener("change", function(e) {
88
+ device_orientation = screen.orientation.type
89
+ console.log(device_orientation)
90
+ if(camIsON){
91
+ if(capture){
92
+ capture.remove()
93
+ capture = undefined
94
+ }
95
+
96
+ if(active_rearcam == true){
97
+ let new_constraints = {
98
+ audio: false,
99
+ video: {
100
+ facingMode: {
101
+ exact: "environment"
102
+ }
103
+ }
104
+ };
105
+ capture = createCapture(new_constraints)
106
+ capture.hide()
107
+ } else {
108
+ let new_constraints = {
109
+ audio: false,
110
+ video: {
111
+ facingMode: "user"
112
+ }
113
+ //video: {
114
+ //facingMode: "user"
115
+ //}
116
+ };
117
+ capture = createCapture(new_constraints)
118
+ capture.hide()
119
+ }
120
+ }
121
+ });
122
+ pixelDensity(1)
123
+ if(windowWidth <= 500){
124
+ myCanvas = createCanvas(380, 380*320/576);
125
+
126
+ } else {
127
+ myCanvas = createCanvas(576, 320);
128
+
129
+ }
130
+ background(220)
131
+ myCanvas.id('myCanvas')
132
+ myCanvas.parent("canvas-container")
133
+
134
+ graphicsToSend = createGraphics(myCanvas.width, myCanvas.height)
135
+
136
+ socket.on("api_response", (response) => {
137
+ waiting = false;
138
+ clearTimeout(timerWaiting)
139
+
140
+
141
+ vision_text = response
142
+ messages_list.push(vision_text)
143
+
144
+ if(live === true){
145
+ loadingDiv = document.getElementById("loading-div")
146
+ loadingDiv.innerHTML = "_"
147
+ display_messages()
148
+ console.log("Sending new requestion in 3 seconds")
149
+
150
+ timer = setTimeout(() => {
151
+ console.log(current_instructions)
152
+ call_api(socket, current_instructions)
153
+ }, 3000)
154
+ }
155
+ });
156
+
157
+ // Watch if cursor is above canvas or not
158
+ let getCanvas = document.getElementById('myCanvas');
159
+
160
+ getCanvas.addEventListener("pointerdown", (e) => {
161
+ //console.log("pointerDown");
162
+ getCanvas.setPointerCapture(e.pointerId);
163
+ isOnCanvas = true;
164
+ }, false);
165
+
166
+ getCanvas.addEventListener("pointerup", (e) => {
167
+ //console.log("pointerUp");
168
+
169
+ if (isOnCanvas) {
170
+ getCanvas.releasePointerCapture(e.pointerId);
171
+ isOnCanvas = false;
172
+ }
173
+ }, false);
174
+ //—————————
175
+
176
+ // Buttons
177
+ start_capture_button=createButton("turn on cam")
178
+ start_capture_button.mousePressed(() => {
179
+ camIsON = true;
180
+ if(!active_rearcam){
181
+ camConfig = "user"
182
+ } else {
183
+ camConfig = {
184
+ exact: "environment"
185
+ }
186
+ }
187
+ let constraints = {
188
+ audio: false,
189
+ video: {
190
+ facingMode: camConfig
191
+ }
192
+ };
193
+ capture = createCapture(constraints);
194
+ capture.hide();
195
+ })
196
+
197
+ if(isOnMobile){
198
+ checkbox_rearcam = createCheckbox("switch to rear cam");
199
+ checkbox_rearcam.parent("checkbox-rear");
200
+
201
+ checkbox_rearcam.mousePressed( () => {
202
+
203
+ if(active_rearcam == false){
204
+ active_rearcam = true;
205
+ } else {
206
+ active_rearcam = false
207
+ }
208
+
209
+ if(camIsON){
210
+ if(capture){
211
+ capture.remove()
212
+ capture = undefined
213
+ }
214
+
215
+ if(active_rearcam == true){
216
+ let new_constraints = {
217
+ audio: false,
218
+ video: {
219
+ facingMode: {
220
+ exact: "environment"
221
+ }
222
+ }
223
+ };
224
+ capture = createCapture(new_constraints)
225
+ capture.hide()
226
+ } else {
227
+ let new_constraints = {
228
+ audio: false,
229
+ video: {
230
+ facingMode: "user"
231
+ }
232
+ //video: {
233
+ //facingMode: "user"
234
+ //}
235
+ };
236
+ capture = createCapture(new_constraints)
237
+ capture.hide()
238
+ }
239
+ }
240
+ })
241
+
242
+ }
243
+
244
+ start_button = createButton('start live vision');
245
+ start_button.mousePressed(() => {
246
+ live = true;
247
+ current_instructions = input_instructions.value()
248
+ console.log("Live in ON")
249
+ console.log(current_instructions)
250
+ call_api(socket, current_instructions)
251
+ })
252
+
253
+ stop_button = createButton('stop all');
254
+ stop_button.mousePressed(() => {
255
+ live = false;
256
+ waiting = false;
257
+ // Abort the timer
258
+ clearTimeout(timer);
259
+ clearTimeout(timerWaiting)
260
+ loadingDiv.innerHTML = "_"
261
+ if(capture){
262
+ capture.remove();
263
+ capture = undefined
264
+ camIsON = false;
265
+ }
266
+ console.log("live is OFF")
267
+ //redraw()
268
+ })
269
+
270
+ input_instructions = createInput("What is happening ? ")
271
+
272
+ change_instructions = createButton("change instructions")
273
+ change_instructions.mousePressed(() => {
274
+ current_instructions = input_instructions.value()
275
+ })
276
+
277
+ start_capture_button.parent("buttons-container")
278
+ start_button.parent("buttons-container")
279
+ stop_button.parent("buttons-container")
280
+ input_instructions.parent("instructions-container")
281
+ change_instructions.parent("instructions-container")
282
+
283
+ loadingDiv = document.getElementById("loading-div")
284
+
285
+ }
286
+
287
+ function draw() {
288
+ background(220);
289
+ textAlign(CENTER);
290
+ text('turn on your webcam', width/2, height/2);
291
+
292
+ if(capture != undefined){
293
+
294
+ if(!active_rearcam){
295
+
296
+
297
+ if(isOnMobile){
298
+ if(device_orientation == "portrait" || device_orientation == "portrait-primary" || device_orientation == "portrait-secondary"){
299
+ graphicsToSend.image(capture,(myCanvas.width/2)-(capture.width/2), -(capture.height/4))
300
+ push()
301
+ //move image by the width of image to the left
302
+ translate(myCanvas.width, 0);
303
+ //then scale push()
304
+ //move image by the width of image to the left
305
+ //to flip the image
306
+ scale(-1, 1);
307
+ image(capture,(myCanvas.width/2)-(capture.width/2), -(capture.height/4))
308
+ pop()
309
+ } else {
310
+ graphicsToSend.image(capture, 0, 0)
311
+ push()
312
+ //move image by the width of image to the left
313
+ translate(myCanvas.width, 0);
314
+ //then scale push()
315
+ //move image by the width of image to the left
316
+ //to flip the image
317
+ scale(-1, 1);
318
+ image(capture, 0, 0)
319
+ pop()
320
+ }
321
+ } else {
322
+ graphicsToSend.image(capture, 0, 0)
323
+ push()
324
+ //move image by the width of image to the left
325
+ translate(myCanvas.width, 0);
326
+ //then scale push()
327
+ //move image by the width of image to the left
328
+ //to flip the image
329
+ scale(-1, 1);
330
+ image(capture, 0, 0)
331
+ pop()
332
+ }
333
+
334
+ } else {
335
+ if(isOnMobile){
336
+ if(device_orientation == "portrait" || device_orientation == "portrait-primary" || device_orientation == "portrait-secondary"){
337
+ graphicsToSend.image(capture,(myCanvas.width/2)-(capture.width/2), -(capture.height/4))
338
+ image(capture,(myCanvas.width/2)-(capture.width/2), -(capture.height/4))
339
+ } else {
340
+ graphicsToSend.image(capture, 0, 0)
341
+ image(capture, 0, 0)
342
+
343
+
344
+ }
345
+ } else {
346
+ graphicsToSend.image(capture, 0, 0)
347
+ image(capture, 0, 0)
348
+ }
349
+ }
350
+
351
+ }
352
+ }
353
+
354
+ function display_messages(){
355
+ visionDiv = document.getElementById("vision-text-container")
356
+ visionDiv.innerHTML = ""
357
+ //for(i=0; i < messages_list.length - 1; i++){
358
+ // newNode = document.createElement('div');
359
+ // newNode.classList.add('text-msg')
360
+ // newNode.innerHTML = messages_list[i];
361
+ // visionDiv.appendChild(newNode);
362
+ //}
363
+ newNode_last = document.createElement('div');
364
+ newNode_last.classList.add('text-msg')
365
+ visionDiv.appendChild(newNode_last);
366
+ const text_msg = messages_list[messages_list.length - 1]
367
+ const words = text_msg.split(" "); // splits the text into an array of words
368
+
369
+ // Function that returns a promise which resolves after a specified number of milliseconds
370
+ function wait(ms) {
371
+ return new Promise((resolve) => setTimeout(resolve, ms));
372
+ }
373
+
374
+ async function streamText(words) {
375
+ for (let word of words) {
376
+ newNode_last.innerHTML += " " + word;
377
+ //visionDiv.scrollTop = visionDiv.scrollHeight;
378
+ await wait(30); // Wait for 1 second before logging next word
379
+ }
380
+ }
381
+
382
+ streamText(words);
383
+
384
+ }
385
+
386
+ function clean(){
387
+ if(waiting == true){
388
+ loadingDiv.innerHTML = ""
389
+ timerWaiting = setTimeout(show_loading, 500)
390
+ } else {
391
+ loadingDiv.innerHTML = "_"
392
+ }
393
+
394
+ }
395
+
396
+ function show_loading(){
397
+
398
+ if(waiting == true){
399
+ loadingDiv.innerHTML = ""
400
+ loading_text = ". . ."
401
+ } else {
402
+ loading_text = "_"
403
+ }
404
+
405
+ const dots = loading_text.split(" "); // splits the text into an array of words
406
+
407
+ // Function that returns a promise which resolves after a specified number of milliseconds
408
+ function wait(ms) {
409
+ if(waiting == true){
410
+
411
+ return new Promise((resolve) => resolveTimer = setTimeout(resolve, ms));
412
+ } else {
413
+ clearTimeout(resolveTimer)
414
+ loadingDiv.innerHTML = "_"
415
+ }
416
+
417
+ }
418
+
419
+ async function streamDots(words) {
420
+
421
+ if(waiting == true){
422
+
423
+ for (let word of words) {
424
+ //console.log(word);
425
+ loadingDiv.innerHTML += " " + word;
426
+ //visionDiv.scrollTop = visionDiv.scrollHeight;
427
+ await wait(500); // Wait for 1 second before logging next word
428
+ }
429
+
430
+
431
+ //console.log("ENLEVE")
432
+
433
+ //timerWaiting = setTimeout(show_loading, 500)
434
+ clean()
435
+ } else {
436
+ clearTimeout(timerWaiting)
437
+ //loadingDiv.innerHTML = "_"
438
+ }
439
+ }
440
+
441
+ streamDots(dots);
442
+
443
+
444
+ }
public/style.css ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ body {
2
+ display: flex;
3
+ align-items: center;
4
+ justify-content: center;
5
+ height: 100vh;
6
+ margin: 0;
7
+ color: #3E3E3E;
8
+ overflow: scroll;
9
+ }
10
+
11
+ div#main-container {
12
+ display: flex;
13
+ flex-direction: column;
14
+ flex-wrap: nowrap;
15
+ height: 100vh;
16
+ align-items: center;
17
+ row-gap: 40px;
18
+ }
19
+
20
+ div#title {
21
+ font-family: sans-serif;
22
+ text-align: center;
23
+ }
24
+
25
+ div#appcontent-ctn {
26
+ display: flex;
27
+ column-gap: 30px;
28
+ flex-wrap: wrap;
29
+ justify-content: center;
30
+ row-gap: 4px;
31
+ }
32
+
33
+ div#left-ctn {
34
+ display: flex;
35
+ flex-direction: column;
36
+ row-gap: 4px;
37
+ }
38
+
39
+ div#right-ctn {
40
+ display: flex;
41
+ flex-direction: column;
42
+ row-gap: 4px;
43
+ overflow: scroll;
44
+ height: 320px;
45
+ }
46
+
47
+ div#checkbox-rear {
48
+ width: 100%;
49
+ }
50
+
51
+ div#checkbox-rear > div {
52
+ display: flex;
53
+ flex-direction: row;
54
+ justify-content: flex-start;
55
+ width: 100%;
56
+ align-items: center;
57
+ height: 30px;
58
+ font-family: sans-serif;
59
+ }
60
+
61
+ div#buttons-container {
62
+ display: flex;
63
+ justify-content: flex-start;
64
+ flex-direction: row;
65
+ width: 100%;
66
+ height: 40px;
67
+ gap: 4px;
68
+ }
69
+
70
+ div#instructions-container {
71
+ display: flex;
72
+ flex-direction: row;
73
+ justify-content: flex-start;
74
+ width: 100%;
75
+ height: 40px;
76
+ gap: 4px;
77
+ }
78
+
79
+ div#canvas-container {
80
+ margin: 0;
81
+ }
82
+
83
+ canvas#myCanvas {
84
+ border-radius: 4px;
85
+ }
86
+
87
+ #buttons-container > button {
88
+ cursor: pointer;
89
+ flex: 1;
90
+ }
91
+
92
+ div#instructions-container > input[type="text"] {
93
+ flex: 3;
94
+ padding: 0 10px;
95
+ font-size: large;
96
+ }
97
+ div#instructions-container > button {
98
+ cursor: pointer;
99
+ flex: 1;
100
+ }
101
+
102
+ div#loading-div {
103
+ font-size: 40px;
104
+ width: 100%;
105
+ height: 40px;
106
+ }
107
+
108
+ div#vision-text-container {
109
+ width: 576px;
110
+ font-family: sans-serif;
111
+ display: flex;
112
+ flex-direction: column;
113
+ flex: 1;
114
+ overflow: scroll;
115
+ }
116
+
117
+ .text-msg {
118
+ font-size: 0.8em;
119
+ line-height: 1.4em;
120
+ }
121
+
122
+ .text-msg:last-child{
123
+ font-size: 1.2em;
124
+ line-height: 1.3em;
125
+ font-weight: bold;
126
+ }
127
+
128
+ div#vision-text-container > div {
129
+ margin: 10px 0;
130
+ padding-bottom: 10px;
131
+ }
132
+
133
+ @media screen and (max-width: 500px) {
134
+ div#vision-text-container {
135
+ width: 380px;
136
+ }
137
+ }