thechsenone commited on
Commit
f68f346
·
verified ·
1 Parent(s): 20a54a7

Upload index.html with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +160 -1068
index.html CHANGED
@@ -1,1081 +1,173 @@
1
  <!DOCTYPE html>
2
  <html lang="en">
3
-
4
  <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Lovense Control - Remote Device Manager</title>
8
- <style>
9
- * {
10
- margin: 0;
11
- padding: 0;
12
- box-sizing: border-box;
13
- }
14
-
15
- :root {
16
- --primary: #ff3366;
17
- --primary-dark: #e61e5c;
18
- --secondary: #ff6b9d;
19
- --accent: #c9184a;
20
- --background: #0a0a0a;
21
- --surface: #1a1a1a;
22
- --surface-light: #2a2a2a;
23
- --text: #ffffff;
24
- --text-secondary: #a0a0a0;
25
- --success: #4ade80;
26
- --warning: #fbbf24;
27
- --danger: #ef4444;
28
- --gradient: linear-gradient(135deg, #ff3366 0%, #ff6b9d 50%, #c9184a 100%);
29
- --gradient-glow: linear-gradient(135deg, rgba(255, 51, 102, 0.3) 0%, rgba(255, 107, 157, 0.3) 100%);
30
- }
31
-
32
- body {
33
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
34
- background: var(--background);
35
- color: var(--text);
36
- min-height: 100vh;
37
- overflow-x: hidden;
38
- }
39
-
40
- .background-animation {
41
- position: fixed;
42
- width: 100%;
43
- height: 100%;
44
- top: 0;
45
- left: 0;
46
- z-index: -1;
47
- background: radial-gradient(circle at 20% 50%, rgba(255, 51, 102, 0.1) 0%, transparent 50%),
48
- radial-gradient(circle at 80% 80%, rgba(255, 107, 157, 0.1) 0%, transparent 50%),
49
- radial-gradient(circle at 40% 20%, rgba(201, 24, 74, 0.1) 0%, transparent 50%);
50
- animation: floatGradient 20s ease-in-out infinite;
51
- }
52
-
53
- @keyframes floatGradient {
54
- 0%, 100% { transform: translate(0, 0) scale(1); }
55
- 33% { transform: translate(-20px, -20px) scale(1.1); }
56
- 66% { transform: translate(20px, -10px) scale(0.9); }
57
- }
58
-
59
- header {
60
- background: rgba(26, 26, 26, 0.9);
61
- backdrop-filter: blur(20px);
62
- border-bottom: 1px solid rgba(255, 51, 102, 0.2);
63
- padding: 1rem 2rem;
64
- position: sticky;
65
- top: 0;
66
- z-index: 100;
67
- }
68
-
69
- .header-content {
70
- max-width: 1400px;
71
- margin: 0 auto;
72
- display: flex;
73
- justify-content: space-between;
74
- align-items: center;
75
- }
76
-
77
- .logo {
78
- display: flex;
79
- align-items: center;
80
- gap: 0.75rem;
81
- font-size: 1.5rem;
82
- font-weight: bold;
83
- background: var(--gradient);
84
- -webkit-background-clip: text;
85
- -webkit-text-fill-color: transparent;
86
- background-clip: text;
87
- }
88
-
89
- .logo-icon {
90
- width: 40px;
91
- height: 40px;
92
- background: var(--gradient);
93
- border-radius: 12px;
94
- display: flex;
95
- align-items: center;
96
- justify-content: center;
97
- color: white;
98
- font-size: 1.5rem;
99
- }
100
-
101
- .connection-status {
102
- display: flex;
103
- align-items: center;
104
- gap: 0.5rem;
105
- padding: 0.5rem 1rem;
106
- background: rgba(74, 222, 128, 0.1);
107
- border: 1px solid rgba(74, 222, 128, 0.3);
108
- border-radius: 20px;
109
- transition: all 0.3s ease;
110
- }
111
-
112
- .connection-status.disconnected {
113
- background: rgba(239, 68, 68, 0.1);
114
- border-color: rgba(239, 68, 68, 0.3);
115
- }
116
-
117
- .status-dot {
118
- width: 8px;
119
- height: 8px;
120
- border-radius: 50%;
121
- background: var(--success);
122
- animation: pulse 2s infinite;
123
- }
124
-
125
- .connection-status.disconnected .status-dot {
126
- background: var(--danger);
127
- animation: none;
128
- }
129
-
130
- @keyframes pulse {
131
- 0%, 100% { opacity: 1; }
132
- 50% { opacity: 0.5; }
133
- }
134
-
135
- main {
136
- max-width: 1400px;
137
- margin: 2rem auto;
138
- padding: 0 2rem;
139
- }
140
-
141
- .app-container {
142
- display: grid;
143
- grid-template-columns: 350px 1fr;
144
- gap: 2rem;
145
- margin-bottom: 2rem;
146
- }
147
-
148
- .device-panel {
149
- background: rgba(26, 26, 26, 0.6);
150
- backdrop-filter: blur(20px);
151
- border: 1px solid rgba(255, 51, 102, 0.1);
152
- border-radius: 20px;
153
- padding: 1.5rem;
154
- height: fit-content;
155
- }
156
-
157
- .panel-title {
158
- font-size: 1.25rem;
159
- font-weight: 600;
160
- margin-bottom: 1.5rem;
161
- display: flex;
162
- align-items: center;
163
- gap: 0.5rem;
164
- }
165
-
166
- .device-list {
167
- display: flex;
168
- flex-direction: column;
169
- gap: 1rem;
170
- }
171
-
172
- .device-card {
173
- background: rgba(42, 42, 42, 0.4);
174
- border: 1px solid rgba(255, 51, 102, 0.1);
175
- border-radius: 12px;
176
- padding: 1rem;
177
- cursor: pointer;
178
- transition: all 0.3s ease;
179
- position: relative;
180
- overflow: hidden;
181
- }
182
-
183
- .device-card::before {
184
- content: '';
185
- position: absolute;
186
- top: 0;
187
- left: 0;
188
- right: 0;
189
- bottom: 0;
190
- background: var(--gradient-glow);
191
- opacity: 0;
192
- transition: opacity 0.3s ease;
193
- }
194
-
195
- .device-card:hover {
196
- transform: translateY(-2px);
197
- box-shadow: 0 10px 30px rgba(255, 51, 102, 0.2);
198
- border-color: rgba(255, 51, 102, 0.3);
199
- }
200
-
201
- .device-card:hover::before {
202
- opacity: 0.1;
203
- }
204
-
205
- .device-card.connected {
206
- border-color: var(--primary);
207
- background: rgba(255, 51, 102, 0.1);
208
- }
209
-
210
- .device-info {
211
- position: relative;
212
- display: flex;
213
- justify-content: space-between;
214
- align-items: center;
215
- }
216
-
217
- .device-name {
218
- font-weight: 600;
219
- font-size: 1.1rem;
220
- margin-bottom: 0.25rem;
221
- }
222
-
223
- .device-type {
224
- color: var(--text-secondary);
225
- font-size: 0.875rem;
226
- }
227
-
228
- .device-signal {
229
- display: flex;
230
- gap: 2px;
231
- }
232
-
233
- .signal-bar {
234
- width: 3px;
235
- background: var(--text-secondary);
236
- border-radius: 2px;
237
- transition: all 0.3s ease;
238
- }
239
-
240
- .signal-bar:nth-child(1) { height: 8px; }
241
- .signal-bar:nth-child(2) { height: 12px; }
242
- .signal-bar:nth-child(3) { height: 16px; }
243
- .signal-bar:nth-child(4) { height: 20px; }
244
-
245
- .device-card.connected .signal-bar {
246
- background: var(--primary);
247
- animation: signalPulse 1s ease-in-out infinite;
248
- }
249
-
250
- @keyframes signalPulse {
251
- 0%, 100% { opacity: 1; }
252
- 50% { opacity: 0.6; }
253
- }
254
-
255
- .scan-button {
256
- width: 100%;
257
- padding: 0.75rem;
258
- background: var(--gradient);
259
- border: none;
260
- border-radius: 12px;
261
- color: white;
262
- font-weight: 600;
263
- cursor: pointer;
264
- transition: all 0.3s ease;
265
- margin-top: 1rem;
266
- }
267
-
268
- .scan-button:hover {
269
- transform: translateY(-2px);
270
- box-shadow: 0 10px 30px rgba(255, 51, 102, 0.3);
271
- }
272
-
273
- .scan-button:active {
274
- transform: translateY(0);
275
- }
276
-
277
- .control-panel {
278
- background: rgba(26, 26, 26, 0.6);
279
- backdrop-filter: blur(20px);
280
- border: 1px solid rgba(255, 51, 102, 0.1);
281
- border-radius: 20px;
282
- padding: 2rem;
283
- min-height: 500px;
284
- }
285
-
286
- .control-header {
287
- display: flex;
288
- justify-content: space-between;
289
- align-items: center;
290
- margin-bottom: 2rem;
291
- }
292
-
293
- .control-title {
294
- font-size: 1.5rem;
295
- font-weight: 600;
296
- }
297
-
298
- .control-modes {
299
- display: grid;
300
- grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
301
- gap: 1rem;
302
- margin-bottom: 2rem;
303
- }
304
-
305
- .mode-button {
306
- padding: 1rem;
307
- background: rgba(42, 42, 42, 0.4);
308
- border: 1px solid rgba(255, 51, 102, 0.1);
309
- border-radius: 12px;
310
- color: var(--text);
311
- cursor: pointer;
312
- transition: all 0.3s ease;
313
- text-align: center;
314
- position: relative;
315
- overflow: hidden;
316
- }
317
-
318
- .mode-button::before {
319
- content: '';
320
- position: absolute;
321
- top: 50%;
322
- left: 50%;
323
- width: 0;
324
- height: 0;
325
- background: radial-gradient(circle, rgba(255, 51, 102, 0.3) 0%, transparent 70%);
326
- transition: all 0.5s ease;
327
- transform: translate(-50%, -50%);
328
- }
329
-
330
- .mode-button:hover::before {
331
- width: 100%;
332
- height: 100%;
333
- }
334
-
335
- .mode-button.active {
336
- background: var(--gradient);
337
- border-color: transparent;
338
- transform: translateY(-2px);
339
- box-shadow: 0 10px 30px rgba(255, 51, 102, 0.3);
340
- }
341
-
342
- .mode-icon {
343
- font-size: 1.5rem;
344
- margin-bottom: 0.5rem;
345
- }
346
-
347
- .mode-name {
348
- font-size: 0.875rem;
349
- font-weight: 500;
350
- }
351
-
352
- .power-control {
353
- margin-bottom: 2rem;
354
- }
355
-
356
- .power-label {
357
- display: flex;
358
- justify-content: space-between;
359
- margin-bottom: 1rem;
360
- font-weight: 500;
361
- }
362
-
363
- .power-value {
364
- color: var(--primary);
365
- font-weight: 600;
366
- }
367
-
368
- .power-slider {
369
- position: relative;
370
- height: 8px;
371
- background: rgba(42, 42, 42, 0.5);
372
- border-radius: 4px;
373
- overflow: hidden;
374
- cursor: pointer;
375
- }
376
-
377
- .power-fill {
378
- position: absolute;
379
- height: 100%;
380
- background: var(--gradient);
381
- border-radius: 4px;
382
- width: 50%;
383
- transition: width 0.3s ease;
384
- }
385
-
386
- .power-handle {
387
- position: absolute;
388
- top: 50%;
389
- transform: translate(-50%, -50%);
390
- width: 24px;
391
- height: 24px;
392
- background: white;
393
- border-radius: 50%;
394
- box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
395
- cursor: grab;
396
- transition: all 0.3s ease;
397
- }
398
-
399
- .power-handle:active {
400
- cursor: grabbing;
401
- transform: translate(-50%, -50%) scale(1.2);
402
- }
403
-
404
- .pattern-grid {
405
- display: grid;
406
- grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
407
- gap: 0.75rem;
408
- margin-bottom: 2rem;
409
- }
410
-
411
- .pattern-button {
412
- aspect-ratio: 1;
413
- background: rgba(42, 42, 42, 0.4);
414
- border: 1px solid rgba(255, 51, 102, 0.1);
415
- border-radius: 12px;
416
- color: var(--text);
417
- cursor: pointer;
418
- transition: all 0.3s ease;
419
- display: flex;
420
- align-items: center;
421
- justify-content: center;
422
- font-size: 1.25rem;
423
- }
424
-
425
- .pattern-button:hover {
426
- background: rgba(255, 51, 102, 0.2);
427
- transform: scale(1.05);
428
- }
429
-
430
- .pattern-button.active {
431
- background: var(--gradient);
432
- border-color: transparent;
433
- animation: patternPulse 1s ease-in-out infinite;
434
- }
435
-
436
- @keyframes patternPulse {
437
- 0%, 100% { transform: scale(1); }
438
- 50% { transform: scale(1.05); }
439
- }
440
-
441
- .action-buttons {
442
- display: grid;
443
- grid-template-columns: repeat(2, 1fr);
444
- gap: 1rem;
445
- }
446
-
447
- .action-button {
448
- padding: 1rem;
449
- background: rgba(42, 42, 42, 0.4);
450
- border: 1px solid rgba(255, 51, 102, 0.1);
451
- border-radius: 12px;
452
- color: var(--text);
453
- cursor: pointer;
454
- transition: all 0.3s ease;
455
- font-weight: 500;
456
- display: flex;
457
- align-items: center;
458
- justify-content: center;
459
- gap: 0.5rem;
460
- }
461
-
462
- .action-button:hover {
463
- background: rgba(255, 51, 102, 0.2);
464
- transform: translateY(-2px);
465
- }
466
-
467
- .action-button.primary {
468
- background: var(--gradient);
469
- border: none;
470
- color: white;
471
- }
472
-
473
- .action-button.primary:hover {
474
- box-shadow: 0 10px 30px rgba(255, 51, 102, 0.3);
475
- }
476
-
477
- .action-button.danger {
478
- background: rgba(239, 68, 68, 0.2);
479
- border-color: rgba(239, 68, 68, 0.3);
480
- color: var(--danger);
481
- }
482
-
483
- .stats-panel {
484
- background: rgba(26, 26, 26, 0.6);
485
- backdrop-filter: blur(20px);
486
- border: 1px solid rgba(255, 51, 102, 0.1);
487
- border-radius: 20px;
488
- padding: 1.5rem;
489
- }
490
-
491
- .stats-grid {
492
- display: grid;
493
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
494
- gap: 1rem;
495
- }
496
-
497
- .stat-card {
498
- background: rgba(42, 42, 42, 0.4);
499
- border: 1px solid rgba(255, 51, 102, 0.1);
500
- border-radius: 12px;
501
- padding: 1rem;
502
- text-align: center;
503
- }
504
-
505
- .stat-value {
506
- font-size: 2rem;
507
- font-weight: bold;
508
- background: var(--gradient);
509
- -webkit-background-clip: text;
510
- -webkit-text-fill-color: transparent;
511
- background-clip: text;
512
- }
513
-
514
- .stat-label {
515
- color: var(--text-secondary);
516
- font-size: 0.875rem;
517
- margin-top: 0.25rem;
518
- }
519
-
520
- .notification {
521
- position: fixed;
522
- bottom: 2rem;
523
- right: 2rem;
524
- background: rgba(26, 26, 26, 0.95);
525
- backdrop-filter: blur(20px);
526
- border: 1px solid rgba(255, 51, 102, 0.2);
527
- border-radius: 12px;
528
- padding: 1rem 1.5rem;
529
- display: flex;
530
- align-items: center;
531
- gap: 1rem;
532
- transform: translateX(400px);
533
- transition: transform 0.3s ease;
534
- z-index: 1000;
535
- }
536
-
537
- .notification.show {
538
- transform: translateX(0);
539
- }
540
-
541
- .notification-icon {
542
- width: 24px;
543
- height: 24px;
544
- border-radius: 50%;
545
- display: flex;
546
- align-items: center;
547
- justify-content: center;
548
- }
549
-
550
- .notification.success .notification-icon {
551
- background: rgba(74, 222, 128, 0.2);
552
- color: var(--success);
553
- }
554
-
555
- .notification.error .notification-icon {
556
- background: rgba(239, 68, 68, 0.2);
557
- color: var(--danger);
558
- }
559
-
560
- @media (max-width: 768px) {
561
- .app-container {
562
- grid-template-columns: 1fr;
563
- }
564
-
565
- .control-modes {
566
- grid-template-columns: repeat(2, 1fr);
567
- }
568
-
569
- .pattern-grid {
570
- grid-template-columns: repeat(4, 1fr);
571
- }
572
-
573
- .action-buttons {
574
- grid-template-columns: 1fr;
575
- }
576
-
577
- main {
578
- padding: 0 1rem;
579
- }
580
- }
581
-
582
- footer {
583
- text-align: center;
584
- padding: 2rem;
585
- color: var(--text-secondary);
586
- border-top: 1px solid rgba(255, 51, 102, 0.1);
587
- margin-top: 3rem;
588
- }
589
-
590
- footer a {
591
- color: var(--primary);
592
- text-decoration: none;
593
- transition: color 0.3s ease;
594
- }
595
-
596
- footer a:hover {
597
- color: var(--primary-dark);
598
- }
599
-
600
- .preset-modal {
601
- position: fixed;
602
- top: 0;
603
- left: 0;
604
- right: 0;
605
- bottom: 0;
606
- background: rgba(0, 0, 0, 0.8);
607
- display: none;
608
- align-items: center;
609
- justify-content: center;
610
- z-index: 1000;
611
- }
612
-
613
- .preset-modal.show {
614
- display: flex;
615
- }
616
-
617
- .preset-content {
618
- background: var(--surface);
619
- border-radius: 20px;
620
- padding: 2rem;
621
- max-width: 500px;
622
- width: 90%;
623
- max-height: 80vh;
624
- overflow-y: auto;
625
- }
626
-
627
- .preset-header {
628
- display: flex;
629
- justify-content: space-between;
630
- align-items: center;
631
- margin-bottom: 1.5rem;
632
- }
633
-
634
- .preset-list {
635
- display: grid;
636
- grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
637
- gap: 1rem;
638
- }
639
-
640
- .preset-item {
641
- background: rgba(42, 42, 42, 0.4);
642
- border: 1px solid rgba(255, 51, 102, 0.1);
643
- border-radius: 12px;
644
- padding: 1rem;
645
- cursor: pointer;
646
- transition: all 0.3s ease;
647
- text-align: center;
648
- }
649
-
650
- .preset-item:hover {
651
- background: rgba(255, 51, 102, 0.2);
652
- transform: translateY(-2px);
653
- }
654
- </style>
655
  </head>
656
-
657
- <body>
658
- <div class="background-animation"></div>
659
-
660
- <header>
661
- <div class="header-content">
662
- <div class="logo">
663
- <div class="logo-icon">💕</div>
664
- <span>Lovense Control</span>
665
- </div>
666
- <div class="connection-status disconnected" id="connectionStatus">
667
- <span class="status-dot"></span>
668
- <span id="statusText">Disconnected</span>
669
- </div>
670
- </div>
671
- </header>
672
-
673
- <main>
674
- <div class="app-container">
675
- <aside class="device-panel">
676
- <h2 class="panel-title">
677
- <span>📱</span>
678
- Bluetooth Devices
679
- </h2>
680
- <div class="device-list" id="deviceList">
681
- <div class="device-card" data-device="lush2">
682
- <div class="device-info">
683
- <div>
684
- <div class="device-name">Lush 2</div>
685
- <div class="device-type">Vibrating Egg</div>
686
- </div>
687
- <div class="device-signal">
688
- <div class="signal-bar"></div>
689
- <div class="signal-bar"></div>
690
- <div class="signal-bar"></div>
691
- <div class="signal-bar"></div>
692
- </div>
693
- </div>
694
- </div>
695
- <div class="device-card" data-device="hush">
696
- <div class="device-info">
697
- <div>
698
- <div class="device-name">Hush</div>
699
- <div class="device-type">Butt Plug</div>
700
- </div>
701
- <div class="device-signal">
702
- <div class="signal-bar"></div>
703
- <div class="signal-bar"></div>
704
- <div class="signal-bar"></div>
705
- <div class="signal-bar" style="opacity: 0.5;"></div>
706
- </div>
707
- </div>
708
- </div>
709
- <div class="device-card" data-device="nora">
710
- <div class="device-info">
711
- <div>
712
- <div class="device-name">Nora</div>
713
- <div class="device-type">Rabbit Vibrator</div>
714
- </div>
715
- <div class="device-signal">
716
- <div class="signal-bar"></div>
717
- <div class="signal-bar"></div>
718
- <div class="signal-bar" style="opacity: 0.5;"></div>
719
- <div class="signal-bar" style="opacity: 0.3;"></div>
720
- </div>
721
  </div>
722
- </div>
723
- </div>
724
- <button class="scan-button" id="scanButton">
725
- <span>🔍</span> Scan for Devices
726
- </button>
727
- </aside>
728
-
729
- <section class="control-panel">
730
- <div class="control-header">
731
- <h2 class="control-title">Device Control</h2>
732
- <span id="connectedDeviceName" style="color: var(--text-secondary);">No device connected</span>
733
- </div>
734
-
735
- <div class="control-modes">
736
- <button class="mode-button active" data-mode="manual">
737
- <div class="mode-icon">🎮</div>
738
- <div class="mode-name">Manual</div>
739
- </button>
740
- <button class="mode-button" data-mode="pattern">
741
- <div class="mode-icon">〰️</div>
742
- <div class="mode-name">Pattern</div>
743
- </button>
744
- <button class="mode-button" data-mode="music">
745
- <div class="mode-icon">🎵</div>
746
- <div class="mode-name">Music</div>
747
- </button>
748
- <button class="mode-button" data-mode="wave">
749
- <div class="mode-icon">🌊</div>
750
- <div class="mode-name">Wave</div>
751
- </button>
752
- <button class="mode-button" data-mode="pulse">
753
- <div class="mode-icon">💗</div>
754
- <div class="mode-name">Pulse</div>
755
- </button>
756
- <button class="mode-button" data-mode="random">
757
- <div class="mode-icon">🎲</div>
758
- <div class="mode-name">Random</div>
759
- </button>
760
- </div>
761
-
762
- <div class="power-control">
763
- <div class="power-label">
764
- <span>Vibration Strength</span>
765
- <span class="power-value" id="powerValue">50%</span>
766
- </div>
767
- <div class="power-slider" id="powerSlider">
768
- <div class="power-fill" id="powerFill"></div>
769
- <div class="power-handle" id="powerHandle" style="left: 50%;"></div>
770
- </div>
771
- </div>
772
-
773
- <div class="pattern-grid" id="patternGrid" style="display: none;">
774
- <button class="pattern-button" data-pattern="wave">🌊</button>
775
- <button class="pattern-button" data-pattern="pulse">💗</button>
776
- <button class="pattern-button" data-pattern="ramp">📈</button>
777
- <button class="pattern-button" data-pattern="fire">🔥</button>
778
- <button class="pattern-button" data-pattern="ocean">🌊</button>
779
- <button class="pattern-button" data-pattern="thunder">⚡</button>
780
- <button class="pattern-button" data-pattern="zen">🧘</button>
781
- <button class="pattern-button" data-pattern="ecstasy">✨</button>
782
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
783
 
784
- <div class="action-buttons">
785
- <button class="action-button primary" id="startButton">
786
- <span>▶️</span> Start
787
- </button>
788
- <button class="action-button" id="pauseButton">
789
- <span>⏸️</span> Pause
790
- </button>
791
- <button class="action-button" id="presetButton">
792
- <span>⭐</span> Presets
793
- </button>
794
- <button class="action-button danger" id="stopButton">
795
- <span>⏹️</span> Stop
796
- </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
797
  </div>
798
- </section>
799
- </div>
800
 
801
- <section class="stats-panel">
802
- <h2 class="panel-title">
803
- <span>📊</span>
804
- Device Statistics
805
- </h2>
806
- <div class="stats-grid">
807
- <div class="stat-card">
808
- <div class="stat-value" id="batteryLevel">85%</div>
809
- <div class="stat-label">Battery Level</div>
810
- </div>
811
- <div class="stat-card">
812
- <div class="stat-value" id="runtime">0m</div>
813
- <div class="stat-label">Runtime</div>
814
- </div>
815
- <div class="stat-card">
816
- <div class="stat-value" id="temperature">36°C</div>
817
- <div class="stat-label">Temperature</div>
818
- </div>
819
- <div class="stat-card">
820
- <div class="stat-value" id="signalStrength">-45 dBm</div>
821
- <div class="stat-label">Signal Strength</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
822
  </div>
823
- </div>
824
- </section>
825
- </main>
826
-
827
- <footer>
828
- <p>© 2024 Lovense Control | <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">Built with anycoder</a></p>
829
- </footer>
830
 
831
- <div class="notification" id="notification">
832
- <div class="notification-icon" id="notificationIcon">✓</div>
833
- <div class="notification-message" id="notificationMessage">Device connected successfully</div>
834
- </div>
835
-
836
- <div class="preset-modal" id="presetModal">
837
- <div class="preset-content">
838
- <div class="preset-header">
839
- <h2>Choose Preset</h2>
840
- <button onclick="closePresetModal()" style="background: none; border: none; color: var(--text); font-size: 1.5rem; cursor: pointer;">✕</button>
841
- </div>
842
- <div class="preset-list">
843
- <div class="preset-item" onclick="selectPreset('Gentle')">
844
- <div style="font-size: 2rem;">🌸</div>
845
- <div>Gentle</div>
846
- </div>
847
- <div class="preset-item" onclick="selectPreset('Tease')">
848
- <div style="font-size: 2rem;">😏</div>
849
- <div>Tease</div>
850
- </div>
851
- <div class="preset-item" onclick="selectPreset('Intense')">
852
- <div style="font-size: 2rem;">🔥</div>
853
- <div>Intense</div>
854
- </div>
855
- <div class="preset-item" onclick="selectPreset('Edge')">
856
- <div style="font-size: 2rem;">⚡</div>
857
- <div>Edge</div>
858
- </div>
859
- <div class="preset-item" onclick="selectPreset('Wave')">
860
- <div style="font-size: 2rem;">🌊</div>
861
- <div>Wave</div>
862
- </div>
863
- <div class="preset-item" onclick="selectPreset('Pulse')">
864
- <div style="font-size: 2rem;">💗</div>
865
- <div>Pulse</div>
866
  </div>
867
- </div>
868
- </div>
869
- </div>
870
-
871
- <script>
872
- // App State
873
- const appState = {
874
- connectedDevice: null,
875
- currentMode: 'manual',
876
- powerLevel: 50,
877
- isRunning: false,
878
- runtime: 0,
879
- selectedPattern: null,
880
- selectedPreset: null
881
- };
882
-
883
- // DOM Elements
884
- const connectionStatus = document.getElementById('connectionStatus');
885
- const statusText = document.getElementById('statusText');
886
- const deviceList = document.getElementById('deviceList');
887
- const scanButton = document.getElementById('scanButton');
888
- const powerSlider = document.getElementById('powerSlider');
889
- const powerHandle = document.getElementById('powerHandle');
890
- const powerFill = document.getElementById('powerFill');
891
- const powerValue = document.getElementById('powerValue');
892
- const connectedDeviceName = document.getElementById('connectedDeviceName');
893
- const patternGrid = document.getElementById('patternGrid');
894
- const notification = document.getElementById('notification');
895
- const notificationMessage = document.getElementById('notificationMessage');
896
- const notificationIcon = document.getElementById('notificationIcon');
897
- const presetModal = document.getElementById('presetModal');
898
-
899
- // Initialize
900
- document.addEventListener('DOMContentLoaded', () => {
901
- initializeEventListeners();
902
- startRuntimeCounter();
903
- simulateSignalStrength();
904
- });
905
-
906
- function initializeEventListeners() {
907
- // Device selection
908
- deviceList.addEventListener('click', (e) => {
909
- const deviceCard = e.target.closest('.device-card');
910
- if (deviceCard) {
911
- connectDevice(deviceCard.dataset.device);
912
- }
913
- });
914
-
915
- // Scan button
916
- scanButton.addEventListener('click', () => {
917
- scanForDevices();
918
- });
919
-
920
- // Mode buttons
921
- document.querySelectorAll('.mode-button').forEach(button => {
922
- button.addEventListener('click', () => {
923
- selectMode(button.dataset.mode);
924
- });
925
- });
926
-
927
- // Pattern buttons
928
- document.querySelectorAll('.pattern-button').forEach(button => {
929
- button.addEventListener('click', () => {
930
- selectPattern(button.dataset.pattern);
931
- });
932
- });
933
-
934
- // Power slider
935
- initializePowerSlider();
936
-
937
- // Action buttons
938
- document.getElementById('startButton').addEventListener('click', startDevice);
939
- document.getElementById('pauseButton').addEventListener('click', pauseDevice);
940
- document.getElementById('stopButton').addEventListener('click', stopDevice);
941
- document.getElementById('presetButton').addEventListener('click', showPresets);
942
- }
943
-
944
- function initializePowerSlider() {
945
- let isDragging = false;
946
-
947
- powerHandle.addEventListener('mousedown', () => isDragging = true);
948
- document.addEventListener('mouseup', () => isDragging = false);
949
- document.addEventListener('mousemove', (e) => {
950
- if (isDragging) {
951
- updatePowerFromMouse(e);
952
- }
953
- });
954
-
955
- powerSlider.addEventListener('click', (e) => {
956
- if (!isDragging) {
957
- updatePowerFromMouse(e);
958
- }
959
- });
960
-
961
- // Touch support
962
- powerHandle.addEventListener('touchstart', () => isDragging = true);
963
- document.addEventListener('touchend', () => isDragging = false);
964
- document.addEventListener('touchmove', (e) => {
965
- if (isDragging) {
966
- const touch = e.touches[0];
967
- updatePowerFromTouch(touch);
968
- }
969
- });
970
- }
971
-
972
- function updatePowerFromMouse(e) {
973
- const rect = powerSlider.getBoundingClientRect();
974
- const x = e.clientX - rect.left;
975
- const percentage = Math.max(0, Math.min(100, (x / rect.width) * 100));
976
- updatePower(percentage);
977
- }
978
-
979
- function updatePowerFromTouch(touch) {
980
- const rect = powerSlider.getBoundingClientRect();
981
- const x = touch.clientX - rect.left;
982
- const percentage = Math.max(0, Math.min(100, (x / rect.width) * 100));
983
- updatePower(percentage);
984
- }
985
-
986
- function updatePower(percentage) {
987
- appState.powerLevel = Math.round(percentage);
988
- powerFill.style.width = `${percentage}%`;
989
- powerHandle.style.left = `${percentage}%`;
990
- powerValue.textContent = `${appState.powerLevel}%`;
991
-
992
- if (appState.connectedDevice && appState.isRunning) {
993
- sendCommandToDevice('vibrate', appState.powerLevel);
994
- updateTemperature(appState.powerLevel);
995
- }
996
- }
997
-
998
- function connectDevice(deviceId) {
999
- if (appState.connectedDevice === deviceId) return;
1000
-
1001
- // Update UI
1002
- document.querySelectorAll('.device-card').forEach(card => {
1003
- card.classList.remove('connected');
1004
- });
1005
- document.querySelector(`[data-device="${deviceId}"]`).classList.add('connected');
1006
-
1007
- // Update state
1008
- appState.connectedDevice = deviceId;
1009
-
1010
- // Update connection status
1011
- connectionStatus.classList.remove('disconnected');
1012
- statusText.textContent = `Connected to ${deviceId.toUpperCase()}`;
1013
-
1014
- // Update control panel
1015
- const deviceNames = {
1016
- 'lush2': 'Lush 2',
1017
- 'hush': 'Hush',
1018
- 'nora': 'Nora'
1019
- };
1020
- connectedDeviceName.textContent = deviceNames[deviceId] || 'Unknown Device';
1021
-
1022
- // Show notification
1023
- showNotification(`Connected to ${deviceNames[deviceId]}`, 'success');
1024
-
1025
- // Simulate device stats update
1026
- updateDeviceStats();
1027
- }
1028
-
1029
- function selectMode(mode) {
1030
- if (!appState.connectedDevice) {
1031
- showNotification('Please connect a device first', 'error');
1032
- return;
1033
- }
1034
-
1035
- appState.currentMode = mode;
1036
-
1037
- // Update UI
1038
- document.querySelectorAll('.mode-button').forEach(button => {
1039
- button.classList.remove('active');
1040
- });
1041
- document.querySelector(`[data-mode="${mode}"]`).classList.add('active');
1042
-
1043
- // Show/hide pattern grid for pattern mode
1044
- patternGrid.style.display = mode === 'pattern' ? 'grid' : 'none';
1045
-
1046
- // Send command to device
1047
- sendCommandToDevice('mode', mode);
1048
-
1049
- showNotification(`Switched to ${mode} mode`, 'success');
1050
- }
1051
-
1052
- function selectPattern(pattern) {
1053
- if (!appState.connectedDevice || appState.currentMode !== 'pattern') return;
1054
-
1055
- appState.selectedPattern = pattern;
1056
-
1057
- // Update UI
1058
- document.querySelectorAll('.pattern-button').forEach(button => {
1059
- button.classList.remove('active');
1060
- });
1061
- document.querySelector(`[data-pattern="${pattern}"]`).classList.add('active');
1062
-
1063
- // Send command to device
1064
- sendCommandToDevice('pattern', pattern);
1065
-
1066
- showNotification(`Pattern ${pattern} activated`, 'success');
1067
- }
1068
-
1069
- function startDevice() {
1070
- if (!appState.connectedDevice) {
1071
- showNotification('Please connect a device first', 'error');
1072
- return;
1073
- }
1074
-
1075
- appState.isRunning = true;
1076
- sendCommandToDevice('start', { mode: appState.currentMode, power: appState.powerLevel });
1077
- showNotification('Device started', 'success');
1078
- }
1079
 
1080
- function pauseDevice() {
1081
- if (!appState.connectedDevice
 
 
 
1
  <!DOCTYPE html>
2
  <html lang="en">
 
3
  <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>AI Device Control Demo - Transformers.js</title>
7
+ <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
8
+ <link rel="stylesheet" href="style.css">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  </head>
10
+ <body class="bg-gradient-to-br from-purple-900 via-blue-900 to-indigo-900 min-h-screen text-white">
11
+ <header class="bg-black bg-opacity-50 backdrop-blur-lg border-b border-white border-opacity-20">
12
+ <div class="container mx-auto px-4 py-4">
13
+ <div class="flex items-center justify-between">
14
+ <div class="flex items-center space-x-3">
15
+ <svg class="w-8 h-8 text-purple-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
16
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path>
17
+ </svg>
18
+ <h1 class="text-2xl font-bold bg-gradient-to-r from-purple-400 to-pink-400 bg-clip-text text-transparent">
19
+ AI Device Control Demo
20
+ </h1>
21
+ </div>
22
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank"
23
+ class="text-sm text-purple-300 hover:text-purple-200 transition-colors">
24
+ Built with anycoder
25
+ </a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  </div>
28
+ </header>
29
+
30
+ <main class="container mx-auto px-4 py-8">
31
+ <div class="grid lg:grid-cols-2 gap-8">
32
+ <!-- Control Panel -->
33
+ <div class="bg-white bg-opacity-10 backdrop-blur-lg rounded-2xl p-6 border border-white border-opacity-20">
34
+ <h2 class="text-xl font-semibold mb-4 flex items-center">
35
+ <svg class="w-5 h-5 mr-2 text-purple-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
36
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
37
+ </svg>
38
+ Natural Language Control
39
+ </h2>
40
+
41
+ <div class="space-y-4">
42
+ <div>
43
+ <label class="block text-sm font-medium mb-2">Enter Command</label>
44
+ <textarea id="commandInput"
45
+ class="w-full px-4 py-3 bg-black bg-opacity-30 rounded-lg border border-purple-400 border-opacity-30 focus:border-opacity-60 focus:outline-none resize-none"
46
+ rows="3"
47
+ placeholder="E.g., 'Create a gentle wave pattern', 'Increase intensity gradually', 'Make a pulsing rhythm'"></textarea>
48
+ </div>
49
+
50
+ <button id="processCommand"
51
+ class="w-full py-3 bg-gradient-to-r from-purple-600 to-pink-600 rounded-lg font-semibold hover:from-purple-700 hover:to-pink-700 transition-all transform hover:scale-105 disabled:opacity-50 disabled:cursor-not-allowed">
52
+ Process Command
53
+ </button>
54
+
55
+ <div id="commandResult" class="hidden p-4 bg-black bg-opacity-30 rounded-lg">
56
+ <h3 class="text-sm font-semibold mb-2 text-purple-300">Generated Pattern:</h3>
57
+ <pre id="patternOutput" class="text-xs font-mono text-green-400"></pre>
58
+ </div>
59
+ </div>
60
+ </div>
61
 
62
+ <!-- Pattern Generator -->
63
+ <div class="bg-white bg-opacity-10 backdrop-blur-lg rounded-2xl p-6 border border-white border-opacity-20">
64
+ <h2 class="text-xl font-semibold mb-4 flex items-center">
65
+ <svg class="w-5 h-5 mr-2 text-pink-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
66
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4"></path>
67
+ </svg>
68
+ AI Pattern Generator
69
+ </h2>
70
+
71
+ <div class="space-y-4">
72
+ <div>
73
+ <label class="block text-sm font-medium mb-2">Pattern Type</label>
74
+ <select id="patternType" class="w-full px-4 py-3 bg-black bg-opacity-30 rounded-lg border border-purple-400 border-opacity-30 focus:border-opacity-60 focus:outline-none">
75
+ <option value="wave">Wave</option>
76
+ <option value="pulse">Pulse</option>
77
+ <option value="ramp">Ramp</option>
78
+ <option value="random">Random</option>
79
+ <option value="custom">Custom AI Generated</option>
80
+ </select>
81
+ </div>
82
+
83
+ <div>
84
+ <label class="block text-sm font-medium mb-2">Duration (seconds)</label>
85
+ <input type="range" id="duration" min="5" max="60" value="20" class="w-full">
86
+ <div class="text-center text-sm mt-1">
87
+ <span id="durationValue">20</span>s
88
+ </div>
89
+ </div>
90
+
91
+ <div>
92
+ <label class="block text-sm font-medium mb-2">Intensity</label>
93
+ <input type="range" id="intensity" min="0" max="100" value="50" class="w-full">
94
+ <div class="text-center text-sm mt-1">
95
+ <span id="intensityValue">50</span>%
96
+ </div>
97
+ </div>
98
+
99
+ <button id="generatePattern"
100
+ class="w-full py-3 bg-gradient-to-r from-pink-600 to-purple-600 rounded-lg font-semibold hover:from-pink-700 hover:to-purple-700 transition-all transform hover:scale-105 disabled:opacity-50 disabled:cursor-not-allowed">
101
+ Generate Pattern
102
+ </button>
103
+
104
+ <div id="generatedPattern" class="hidden p-4 bg-black bg-opacity-30 rounded-lg">
105
+ <canvas id="patternCanvas" width="400" height="150" class="w-full rounded"></canvas>
106
+ <div class="mt-2 text-xs text-purple-300">
107
+ <span id="patternStats"></span>
108
+ </div>
109
+ </div>
110
+ </div>
111
+ </div>
112
  </div>
 
 
113
 
114
+ <!-- Safety & Settings -->
115
+ <div class="mt-8 bg-white bg-opacity-10 backdrop-blur-lg rounded-2xl p-6 border border-white border-opacity-20">
116
+ <h2 class="text-xl font-semibold mb-4 flex items-center">
117
+ <svg class="w-5 h-5 mr-2 text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
118
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path>
119
+ </svg>
120
+ Safety Settings & Limits
121
+ </h2>
122
+
123
+ <div class="grid md:grid-cols-3 gap-4">
124
+ <div class="bg-black bg-opacity-30 rounded-lg p-4">
125
+ <label class="flex items-center justify-between">
126
+ <span class="text-sm">Max Intensity Limit</span>
127
+ <input type="checkbox" id="maxIntensity" checked class="toggle-checkbox">
128
+ </label>
129
+ <p class="text-xs text-gray-400 mt-1">Caps maximum intensity at 80%</p>
130
+ </div>
131
+
132
+ <div class="bg-black bg-opacity-30 rounded-lg p-4">
133
+ <label class="flex items-center justify-between">
134
+ <span class="text-sm">Auto-stop Timer</span>
135
+ <input type="checkbox" id="autoStop" checked class="toggle-checkbox">
136
+ </label>
137
+ <p class="text-xs text-gray-400 mt-1">Automatically stop after 30 minutes</p>
138
+ </div>
139
+
140
+ <div class="bg-black bg-opacity-30 rounded-lg p-4">
141
+ <label class="flex items-center justify-between">
142
+ <span class="text-sm">Gradual Changes</span>
143
+ <input type="checkbox" id="gradualChanges" checked class="toggle-checkbox">
144
+ </label>
145
+ <p class="text-xs text-gray-400 mt-1">Smooth transitions between patterns</p>
146
+ </div>
147
+ </div>
148
  </div>
 
 
 
 
 
 
 
149
 
150
+ <!-- Status Display -->
151
+ <div id="statusBar" class="mt-8 bg-black bg-opacity-30 backdrop-blur-lg rounded-lg p-4 border border-white border-opacity-20">
152
+ <div class="flex items-center justify-between">
153
+ <div class="flex items-center space-x-3">
154
+ <div id="statusIndicator" class="w-3 h-3 bg-green-400 rounded-full animate-pulse"></div>
155
+ <span id="statusText" class="text-sm">Ready</span>
156
+ </div>
157
+ <div id="modelStatus" class="text-xs text-gray-400">
158
+ Model: Loading...
159
+ </div>
160
+ </div>
161
+ <div id="loadingBar" class="mt-2 hidden">
162
+ <div class="w-full bg-black bg-opacity-50 rounded-full h-2">
163
+ <div id="loadingProgress" class="bg-gradient-to-r from-purple-400 to-pink-400 h-2 rounded-full transition-all duration-300" style="width: 0%"></div>
164
+ </div>
165
+ <p id="loadingText" class="text-xs text-gray-400 mt-1">Initializing AI model...</p>
166
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  </div>
168
+ </main>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
 
170
+ <script src="https://cdn.jsdelivr.net/npm/@huggingface/transformers@2.17.2/dist/transformers.min.js"></script>
171
+ <script src="index.js"></script>
172
+ </body>
173
+ </html>