imseldrith commited on
Commit
656fdf6
·
1 Parent(s): c2ac914

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +1167 -18
index.html CHANGED
@@ -1,19 +1,1168 @@
1
  <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+
5
+ <head>
6
+ <meta charset="UTF-8">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
8
+ <title>zodiac, by faetalize</title>
9
+ <link rel="shortcut icon" href="https://upload.wikimedia.org/wikipedia/commons/f/f0/Google_Bard_logo.svg"
10
+ type="image/x-icon">
11
+
12
+ <link rel="stylesheet"
13
+ href="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/styles/github-dark.css">
14
+ <script src="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/highlight.min.js"></script>
15
+ </head>
16
+
17
+ <style>
18
+ @import url('https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,200;0,400;0,800;1,200;1,400;1,800&display=swap');
19
+
20
+ @import url('https://fonts.googleapis.com/css2?family=Product+Sans&family=Google+Sans+Display:ital@0;1&family=Google+Sans:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&family=Google+Sans+Text:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&family=Material+Symbols+Outlined&family=Space+Mono&display=swap');
21
+
22
+ @font-face {
23
+ font-family: 'Material Symbols Outlined';
24
+ font-style: normal;
25
+ font-weight: 400;
26
+ src: url(https://fonts.gstatic.com/s/materialsymbolsoutlined/v154/kJF1BvYX7BgnkSrUwT8OhrdQw4oELdPIeeII9v6oDMzByHX9rA6RzaxHMPdY43zj-jCxv3fzvRNU22ZXGJpEpjC_1v-p_4MrImHCIJIZrDCvHOej.woff2) format('woff2');
27
+ }
28
+
29
+ .material-symbols-outlined {
30
+ font-family: 'Material Symbols Outlined';
31
+ font-weight: normal;
32
+ font-style: normal;
33
+ font-size: 1.5rem;
34
+ line-height: 1;
35
+ letter-spacing: normal;
36
+ text-transform: none;
37
+ display: inline-block;
38
+ white-space: nowrap;
39
+ word-wrap: normal;
40
+ direction: ltr;
41
+ -webkit-font-feature-settings: 'liga';
42
+ font-feature-settings: "liga";
43
+ -webkit-font-smoothing: antialiased;
44
+
45
+ }
46
+
47
+ body {
48
+ font-family: 'Noto Sans', sans-serif;
49
+
50
+ margin: 0;
51
+ }
52
+
53
+ p {
54
+ margin: 0;
55
+ margin-bottom: 0.5rem;
56
+ padding: 0;
57
+ font-size: 1rem;
58
+ }
59
+
60
+ h1,
61
+ h2,
62
+ h3,
63
+ ol,
64
+ ul {
65
+ margin: 0;
66
+ }
67
+
68
+ h1 {
69
+ margin-bottom: 0.5rem;
70
+ }
71
+
72
+ a {
73
+ color: #3b82f6;
74
+ }
75
+
76
+ input,
77
+ textarea,
78
+ select {
79
+ border: 1px solid;
80
+ padding: 0.5rem;
81
+ border-radius: 0.5rem;
82
+ border: none;
83
+ font-family: noto sans, sans-serif;
84
+ font-size: 1rem;
85
+ }
86
+
87
+ button:focus {
88
+ outline: none;
89
+ }
90
+
91
+ .form {
92
+ display: none;
93
+ opacity: 0;
94
+ flex-direction: column;
95
+ width: 32rem;
96
+ gap: 0.5rem;
97
+ flex-grow: 1;
98
+ justify-content: center;
99
+ }
100
+
101
+ .overlay {
102
+ flex-direction: column;
103
+ display: none;
104
+ position: fixed;
105
+ opacity: 0;
106
+ top: 0;
107
+ left: 0;
108
+ width: 100dvw;
109
+ height: 100dvh;
110
+ backdrop-filter: blur(2rem);
111
+ z-index: 2;
112
+ justify-content: flex-start;
113
+ align-items: center;
114
+ }
115
+
116
+ .backButton {
117
+ position: absolute;
118
+ top: 1rem;
119
+ left: 1rem;
120
+ border: none;
121
+ background-color: transparent;
122
+ font-size: 1.5rem;
123
+ font-weight: 600;
124
+ transition: all 0.2s;
125
+
126
+ }
127
+
128
+ #btn-hide-sidebar {
129
+ display: none;
130
+ }
131
+
132
+ .message-container {
133
+ display: flex;
134
+ flex-direction: column-reverse;
135
+ overflow-y: auto;
136
+ gap: 1rem;
137
+ padding-bottom: 2rem;
138
+ flex-grow: 1;
139
+ }
140
+
141
+ .message-box {
142
+ display: flex;
143
+ position: relative;
144
+ }
145
+
146
+ .message {
147
+
148
+ padding: 1rem;
149
+ }
150
+
151
+ .message-model {
152
+ border-radius: 1rem;
153
+ }
154
+
155
+ #messageInput {
156
+ height: 2.5rem;
157
+ box-sizing: border-box;
158
+ text-wrap: wrap;
159
+ resize: none;
160
+ width: 100%;
161
+ padding-right: 2rem;
162
+ }
163
+
164
+ #messageInput::-webkit-scrollbar {
165
+ height: 1rem;
166
+ width: 0.5rem;
167
+ }
168
+
169
+ .btn-textual {
170
+ background: transparent !important;
171
+ margin: 0;
172
+ padding: 0;
173
+ border: none;
174
+ transition: all 0.2s;
175
+ cursor: pointer;
176
+ font-size: inherit;
177
+ }
178
+
179
+
180
+
181
+ #btn-send {
182
+ position: absolute;
183
+ right: 0.5rem;
184
+ bottom: 0.5rem;
185
+ font-size: 1.5rem;
186
+ }
187
+
188
+ .btn-array {
189
+ display: flex;
190
+ flex-direction: row;
191
+ gap: 0.5rem;
192
+ margin-top: 0.5rem;
193
+ }
194
+
195
+ .btn-array button {
196
+ flex-grow: 1;
197
+ }
198
+
199
+ .personality-prompt {
200
+ display: none;
201
+ }
202
+
203
+ .prompt-field {
204
+ resize: vertical;
205
+ height: 7rem;
206
+ }
207
+
208
+ .container {
209
+ box-sizing: border-box;
210
+ display: flex;
211
+ gap: 0.5rem;
212
+ padding: 1rem;
213
+
214
+
215
+ width: 100dvw;
216
+ height: 100dvh;
217
+
218
+ }
219
+
220
+ .sidebar {
221
+ position: sticky;
222
+ top: 1rem;
223
+
224
+ display: flex;
225
+ flex-direction: column;
226
+ overflow-y: auto;
227
+ gap: 0.5rem;
228
+ padding: 1rem;
229
+ width: 25rem;
230
+ border-radius: 1rem;
231
+ scrollbar-width: thin;
232
+ height: calc(100dvh - 4rem);
233
+ z-index: 1;
234
+ }
235
+
236
+ .sidebar-section {
237
+ margin-bottom: 1rem;
238
+ display: flex;
239
+ flex-direction: column;
240
+ gap: 0.5rem;
241
+ }
242
+
243
+ #btn-show-sidebar {
244
+ display: none;
245
+ }
246
+
247
+ .header {
248
+ display: flex;
249
+
250
+ box-sizing: border-box;
251
+ align-items: center;
252
+ font-size: 2rem;
253
+ font-weight: 800;
254
+ gap: 0.5rem;
255
+ width: 100%;
256
+ }
257
+
258
+ .navbar {
259
+ position: relative;
260
+ display: flex;
261
+ flex-direction: row;
262
+ border-radius: 0.5rem;
263
+ justify-content: space-evenly;
264
+ margin-bottom: 1rem;
265
+ z-index: 0;
266
+ }
267
+
268
+ .navbar-tab {
269
+ width: 100%;
270
+ padding: 0.5rem;
271
+ text-align: center;
272
+
273
+ z-index: 2;
274
+ -webkit-tap-highlight-color: transparent;
275
+ cursor: pointer;
276
+
277
+ }
278
+
279
+
280
+
281
+ .navbar-tab-highlight {
282
+ padding: 0;
283
+ margin: 0;
284
+ position: absolute;
285
+ border-radius: 0.5rem;
286
+ transition: all 0.2s;
287
+ height: 100%;
288
+ z-index: 1;
289
+ /* glow */
290
+ box-shadow: 0 0 1rem 0.05rem #29292a3f;
291
+ }
292
+
293
+ #gemini-pro-branding {
294
+ font-family: Google Sans Display, sans-serif;
295
+ color: #7c8a9c;
296
+ font-size: 1rem;
297
+ font-weight: 400;
298
+ }
299
+
300
+ #gemin-pro-logo {
301
+ width: 2rem;
302
+ height: 2rem;
303
+ }
304
+
305
+ .credits {
306
+ margin-top: auto;
307
+ display: flex;
308
+ padding: 0rem 1rem 0 1rem;
309
+
310
+ font-size: 0.75rem;
311
+ color: #7c8a9c;
312
+
313
+ justify-content: space-between;
314
+ align-items: center;
315
+ }
316
+
317
+ button {
318
+ border: none;
319
+ background-color: #3b82f6;
320
+ color: white;
321
+ padding: 0.5rem;
322
+ border-radius: 0.5rem;
323
+ transition: all 0.2s;
324
+ }
325
+
326
+ #mainContent {
327
+ display: flex;
328
+ flex-direction: column;
329
+ padding: 2rem;
330
+ margin-left: auto;
331
+ margin-right: auto;
332
+ width: 32rem;
333
+ text-align: justify;
334
+ }
335
+
336
+ .card-personality {
337
+ box-sizing: border-box;
338
+ -moz-box-sizing: border-box;
339
+ -webkit-box-sizing: border-box;
340
+ color: #e4e4e4;
341
+ background-color: black;
342
+ background-size: cover;
343
+ background-position: center;
344
+ position: relative;
345
+
346
+ display: flex;
347
+ flex-direction: column;
348
+ justify-content: end;
349
+ padding: 1rem;
350
+ border-radius: 1rem;
351
+ height: 10rem;
352
+ -webkit-tap-highlight-color: transparent;
353
+ cursor: pointer;
354
+ text-shadow: 0 0 10px #000000, 0 0 5px #181818;
355
+ }
356
+
357
+ .edit:hover {
358
+ text-shadow: 0 0 10px #e4e4e4, 0 0 5px #dfdfdf;
359
+ }
360
+
361
+
362
+ .card-personality * {
363
+ /* unselectable */
364
+ -webkit-user-select: none;
365
+ /* Safari */
366
+ -moz-user-select: none;
367
+ /* Firefox */
368
+ -ms-user-select: none;
369
+ /* IE10+/Edge */
370
+ user-select: none;
371
+ /* Standard */
372
+
373
+ }
374
+
375
+ .card-personality input {
376
+ display: none;
377
+ }
378
+
379
+ .btn-edit-card {
380
+ /* top right corner */
381
+ position: absolute;
382
+ top: 1rem;
383
+ right: 1rem;
384
+ color: #e4e4e4;
385
+ }
386
+
387
+ .btn-share-card {
388
+ /* bottom right corner */
389
+ position: absolute;
390
+ top: 1rem;
391
+ right: 2.5rem;
392
+ font-size: 1rem;
393
+ color: #e4e4e4;
394
+ }
395
+
396
+ #btn-hide-overlay {
397
+ padding: 2rem;
398
+ }
399
+
400
+
401
+
402
+
403
+ @media (max-width: 768px) {
404
+ body {
405
+ margin: 0;
406
+ padding: 0;
407
+ }
408
+
409
+
410
+ .container {
411
+ padding: 0;
412
+
413
+ }
414
+
415
+ .message-container {
416
+ padding-left: 1rem;
417
+ padding-right: 1rem;
418
+ }
419
+
420
+ .sidebar {
421
+ top: 0;
422
+ height: calc(100dvh - 2rem);
423
+ margin: 0;
424
+ width: calc(100dvw - 2rem);
425
+ position: fixed;
426
+ border-radius: 0;
427
+ display: none;
428
+ }
429
+
430
+ .navbar {
431
+ position: relative;
432
+ }
433
+
434
+
435
+ #btn-hide-sidebar {
436
+ display: block;
437
+ }
438
+
439
+ #mainContent {
440
+ padding: 0;
441
+ margin: 0;
442
+ width: 100%;
443
+ }
444
+
445
+ #mainContent .header {
446
+ padding: 2rem;
447
+ }
448
+
449
+ #messageInput {
450
+ border-radius: 0;
451
+ }
452
+
453
+ #btn-show-sidebar {
454
+ display: block;
455
+ }
456
+ }
457
+
458
+
459
+ /* Light theme styles */
460
+ @media (prefers-color-scheme: light) {
461
+ :focus {
462
+ outline: 1px solid #8f9eb3;
463
+ }
464
+
465
+ body {
466
+ background-color: #f0f6ff;
467
+ color: #0a0a0a;
468
+ }
469
+
470
+ a {
471
+ color: #444ed6;
472
+ }
473
+
474
+ .sidebar {
475
+ background-color: #d2e2f7;
476
+ }
477
+
478
+ .navbar {
479
+ background-color: rgb(176 205 246);
480
+ }
481
+
482
+ .navbar-tab {
483
+ color: #0a0a0a;
484
+ }
485
+
486
+ .navbar-tab-highlight {
487
+ background-color: #87b0ed;
488
+ }
489
+
490
+ .btn-textual:hover {
491
+ text-shadow: 0 0 10px #000000;
492
+ }
493
+
494
+ button {
495
+ background-color: #83b5f7;
496
+
497
+ color: #2b3d59;
498
+ }
499
+
500
+ button:hover {
501
+ background-color: rgb(63, 191, 255);
502
+ }
503
+
504
+
505
+ input,
506
+ textarea,
507
+ select {
508
+ background-color: #f0f6ff;
509
+ outline: 1px solid #8f9eb3;
510
+ }
511
+
512
+ input::placeholder,
513
+ textarea::placeholder {
514
+ color: #7c8a9c;
515
+ }
516
+
517
+ .message-model {
518
+ background-color: #d2e2f7;
519
+ }
520
+ }
521
+
522
+ /* Dark theme styles */
523
+ @media (prefers-color-scheme: dark) {
524
+ :root {
525
+ color-scheme: dark;
526
+ }
527
+
528
+ :focus {
529
+ outline: 1px solid #73859e;
530
+ }
531
+
532
+
533
+
534
+ body {
535
+ background-color: #151e24;
536
+ color: #e4e4e4;
537
+ }
538
+
539
+ a {
540
+ color: #92d9eb;
541
+ }
542
+
543
+
544
+
545
+ .sidebar {
546
+ background-color: #1a2733;
547
+ }
548
+
549
+ .navbar {
550
+ background-color: #00000047;
551
+ }
552
+
553
+ .navbar-tab {
554
+ color: #e4e4e4;
555
+ }
556
+
557
+ .navbar-tab-highlight {
558
+ background-color: #22486b;
559
+
560
+ box-shadow: 0 0 1rem 0.05rem #29292aac;
561
+ }
562
+
563
+ button {
564
+ background-color: #22486b;
565
+ color: #c9d3ee;
566
+ }
567
+
568
+ button:hover {
569
+ background-color: #31689c;
570
+ }
571
+
572
+ .btn-textual {
573
+ color: #e4e4e4;
574
+ }
575
+
576
+ .btn-textual:hover {
577
+ text-shadow: 0 0 10px #ffffff, 0 0 5px #dfdfdf;
578
+ }
579
+
580
+ .edit:hover {
581
+ text-shadow: 0 0 10px #ffffff, 0 0 5px #dfdfdf;
582
+ /* Change #00ff00 to the color you want */
583
+ }
584
+
585
+ input,
586
+ textarea,
587
+ select {
588
+ background-color: #283542;
589
+
590
+ color: #e4e4e4;
591
+ border: none;
592
+ }
593
+
594
+ input::placeholder,
595
+ textarea::placeholder {
596
+ color: #849caf;
597
+ }
598
+
599
+
600
+ .message-model {
601
+ background-color: #1a2733;
602
+ }
603
+ }
604
+ </style>
605
+
606
+ <body>
607
+ <div class="container">
608
+ <div class="sidebar">
609
+ <div class="header">
610
+ <button class="material-symbols-outlined btn-textual" id="btn-hide-sidebar">
611
+ arrow_back_ios_new
612
+ </button>
613
+ <img src="https://upload.wikimedia.org/wikipedia/commons/f/f0/Google_Bard_logo.svg" id="gemin-pro-logo">
614
+ <div id="title-div">
615
+ <div id="zodiac-branding">zodiac </div>
616
+ <div id="gemini-pro-branding">powered by Gemini Pro</div>
617
+ </div>
618
+ </div>
619
+ <div class="navbar">
620
+ <div class="navbar-tab">Personalities</div>
621
+ <div class="navbar-tab">Settings</div>
622
+ <div class="navbar-tab-highlight"></div>
623
+ </div>
624
+
625
+ <div class="sidebar-section" id="personalitySection">
626
+ <label class="card-personality"
627
+ style="background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('https://images.fonearena.com/blog/wp-content/uploads/2023/12/Google-Gemini-AI-1024x577.jpg')">
628
+ <input type="radio" name="personality" value="zodiac3" checked>
629
+ <div>
630
+ <h3 class="personality-title">zodiac</h3>
631
+ <p class="personality-description">zodiac is a cheerful assistant, always ready to help you with
632
+ your tasks.</p>
633
+ <p class="personality-prompt">You are zodiac, a helpful assistant created by faetalize, built
634
+ upon Google's Gemini Pro model. Gemini Pro is a new LLM (Large Language Model) release by
635
+ Google on December 2023. Your purpose is being a helpful assistant to the user.</p>
636
+ </div>
637
+ <button class="btn-textual btn-edit-card material-symbols-outlined"
638
+ id="btn-edit-personality-default">edit</button>
639
+ <button class="btn-textual btn-share-card material-symbols-outlined"
640
+ id="btn-share-personality-default">share</button>
641
+ </label>
642
+ <div class="btn-array" id="btn-array-personality-section">
643
+ <button id="btn-add-personality">Add Personality</button>
644
+ <button id="btn-import-personality">Import</button>
645
+ </div>
646
+ </div>
647
+
648
+ <div class="sidebar-section">
649
+ <input type="text" placeholder="Paste API key here" id="apiKeyInput" class="input-field"></input>
650
+ <h3>Generation Settings:</h3>
651
+ <label for="maxTokens">Max Output Tokens:</label>
652
+ <input type="number" id="maxTokens" class="input-field" min="1" max="4000" value="1000"></input>
653
+ <label for="safetySettings">Safety Settings:</label>
654
+ <select id="safetySettings" class="input-field">
655
+ <option value="safe">Safe</option>
656
+ <option value="moderate">Moderate</option>
657
+ <option value="risky">Risky</option>
658
+ </select>
659
+ </div>
660
+
661
+ <div class="credits">
662
+ Made by fætalize
663
+ <a href="https://github.com/faetalize/zodiac">Source Code</a>
664
+ </div>
665
+ </div>
666
+
667
+ <div id="mainContent">
668
+ <div class="header">
669
+ <button class="material-symbols-outlined btn-textual" id="btn-show-sidebar">
670
+ menu
671
+ </button>
672
+ </div>
673
+ <div class="message-container"></div>
674
+ <div class="message-box">
675
+ <textarea type="text" placeholder="Type your message here" id="messageInput"
676
+ class="input-field"></textarea>
677
+ <button type="submit" class="btn-textual material-symbols-outlined" id="btn-send">send</button>
678
+ </div>
679
+ </div>
680
+ </div>
681
+
682
+ <div class="overlay">
683
+ <div class="header">
684
+ <button class="btn-textual" id="btn-hide-overlay">BACK</button>
685
+ </div>
686
+
687
+ <div class="form" id="form-add-personality">
688
+ <h1>Add Personality</h1>
689
+ <label for="personalityNameInput">Personality Name:</label>
690
+ <input type="text" placeholder="Personality Name" id="personalityNameInput" class="input-field"></input>
691
+ <label for="personalityDescriptionInput">Personality Description:</label>
692
+ <textarea id="personalityDescriptionInput" placeholder="Personality Description"
693
+ class="prompt-field"></textarea>
694
+ <label for="personalityImageURLInput">Personality Image URL:</label>
695
+ <input type="text" placeholder="Personality Image URL" id="personalityImageURLInput"
696
+ class="input-field"></input>
697
+ <label for="personalityPromptInput">Prompt:</label>
698
+ <textarea id="personalityPromptInput" placeholder="Personality Prompt" class="prompt-field"></textarea>
699
+ <button id="btn-submit-personality">Add Personality</button>
700
+ </div>
701
+
702
+ <div class="form" id="form-edit-personality">
703
+ <h1>Edit Personality</h1>
704
+ <label for="personalityNameInput">Personality Name:</label>
705
+ <input type="text" placeholder="Personality Name" id="personalityNameInput" class="input-field"></input>
706
+ <label for="personalityDescriptionInput">Personality Description:</label>
707
+ <textarea id="personalityDescriptionInput" placeholder="Personality Description"
708
+ class="prompt-field"></textarea>
709
+ <label for="personalityImageURLInput">Personality Image URL:</label>
710
+ <input type="text" placeholder="Personality Image URL" id="personalityImageURLInput"
711
+ class="input-field"></input>
712
+ <label for="personalityPromptInput">Prompt:</label>
713
+ <textarea id="personalityPromptInput" placeholder="Personality Prompt" class="prompt-field"></textarea>
714
+ <button id="updatePersonality">Save</button>
715
+ </div>
716
+ </div>
717
+
718
+ <script type="importmap">
719
+ {
720
+ "imports": {
721
+ "@google/generative-ai": "https://esm.run/@google/generative-ai"
722
+ }
723
+ }
724
+ </script>
725
+
726
+ <script type="module">
727
+ import { marked } from "https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.js";
728
+ import { GoogleGenerativeAI } from "@google/generative-ai";
729
+ import { HarmBlockThreshold, HarmCategory } from "@google/generative-ai";
730
+
731
+ const safetySettings = [
732
+
733
+ {
734
+ category: HarmCategory.HARM_CATEGORY_HARASSMENT,
735
+ threshold: HarmBlockThreshold.BLOCK_NONE,
736
+ },
737
+ {
738
+ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH,
739
+ threshold: HarmBlockThreshold.BLOCK_NONE,
740
+ },
741
+ {
742
+ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
743
+ threshold: HarmBlockThreshold.BLOCK_NONE,
744
+ },
745
+ {
746
+ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
747
+ threshold: HarmBlockThreshold.BLOCK_NONE,
748
+ }
749
+ ];
750
+ const systemPrompt = "If needed, format your answer using markdown." +
751
+ "Today's date is" + new Date().toDateString() + "." +
752
+ "End of system prompt.";
753
+
754
+ //load api key from local storage into input field
755
+ const API_KEY = document.querySelector("#apiKeyInput");
756
+ API_KEY.value = localStorage.getItem("API_KEY");
757
+ const maxTokens document.querySelector("#maxTokens");
758
+ maxTokens.value = localStorage.getItem("MAX_TOKENS");
759
+
760
+
761
+ //function to hide element smoothly then setting display none after the transition time elapsed
762
+ function hideElement(element) {
763
+ element.style.transition = 'opacity 0.2s';
764
+ element.style.opacity = '0';
765
+ setTimeout(function () {
766
+ element.style.display = 'none';
767
+ }, 200);
768
+ }
769
+
770
+ function showElement(element) {
771
+ // Wait for other transitions to complete (0.2s delay)
772
+ setTimeout(function () {
773
+ // Change display property
774
+ element.style.display = 'flex';
775
+ // Wait for next frame for display change to take effect
776
+ requestAnimationFrame(function () {
777
+ // Start opacity transition
778
+ element.style.transition = 'opacity 0.2s';
779
+ element.style.opacity = '1';
780
+ });
781
+ }, 200);
782
+ }
783
+
784
+
785
+ const tabs = document.querySelectorAll(".navbar-tab");
786
+ const sidebarViews = document.querySelectorAll(".sidebar-section");
787
+ const highlight = document.querySelector(".navbar-tab-highlight");
788
+ highlight.style.width = `calc(100% / ${tabs.length})`;
789
+
790
+
791
+
792
+ let currentTab = undefined;
793
+ function navigateTo(tab) {
794
+ if (tab == tabs[currentTab]) {
795
+ return;
796
+ }
797
+ // set the highlight to match the size of the tab element
798
+
799
+
800
+ let tabIndex = [...tabs].indexOf(tab);
801
+ if (tabIndex < 0 || tabIndex >= sidebarViews.length) {
802
+ console.error("Invalid tab index: " + tabIndex);
803
+ return;
804
+ }
805
+
806
+ if (currentTab != undefined) {
807
+ hideElement(sidebarViews[currentTab]);
808
+ }
809
+ showElement(sidebarViews[tabIndex]);
810
+ currentTab = tabIndex;
811
+
812
+ highlight.style.left = `calc(100% / ${tabs.length} * ${tabIndex})`;
813
+
814
+ }
815
+
816
+ tabs.forEach(element => {
817
+ element.addEventListener("click", () => {
818
+
819
+ navigateTo(element);
820
+ })
821
+ });
822
+
823
+ sidebarViews.forEach(view => {
824
+ hideElement(view);
825
+ });
826
+
827
+
828
+ navigateTo(tabs[0]);
829
+
830
+
831
+
832
+ const personalityCardsInnerInput = document.querySelectorAll(".card-personality input");
833
+ let personalityCards = document.querySelectorAll(".card-personality");
834
+ const formsOverlay = document.querySelector(".overlay");
835
+ const hideOverlayButton = document.querySelector("#btn-hide-overlay");
836
+ const addPersonalityForm = document.querySelector("#form-add-personality");
837
+ const addPersonalityButton = document.querySelector("#btn-add-personality");
838
+ const editDefaultPersonalityForm = document.querySelector("#form-edit-personality");
839
+ const editDefaultPersonalityButton = document.querySelector("#btn-edit-personality-default");
840
+ const submitNewPersonalityButton = document.querySelector("#btn-submit-personality");
841
+ const updatePersonalityButton = document.querySelector("#updatePersonality");
842
+
843
+ const sendMessageButton = document.querySelector("#btn-send");
844
+
845
+
846
+ function darkenBg(element) {
847
+
848
+ let elementBackgroundImageURL = element.style.backgroundImage.match(/url\((.*?)\)/)[1].replace(/('|")/g, '');
849
+ element.style.backgroundImage = `linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('${elementBackgroundImageURL}')`;
850
+ }
851
+
852
+
853
+ function lightenBg(element) {
854
+
855
+ let elementBackgroundImageURL = element.style.backgroundImage.match(/url\((.*?)\)/)[1].replace(/('|")/g, '');
856
+ element.style.backgroundImage = `url('${elementBackgroundImageURL}')`;
857
+ }
858
+
859
+
860
+ function sharePersonality(personality) {
861
+ //export personality to json
862
+ const personalityJSON = {
863
+ name: personality.querySelector(".personality-title").innerText,
864
+ description: personality.querySelector(".personality-description").innerText,
865
+ prompt: personality.querySelector(".personality-prompt").innerText,
866
+ //base64 encode image
867
+ image: personality.style.backgroundImage.match(/url\((.*?)\)/)[1].replace(/('|")/g, '')
868
+ }
869
+ const personalityJSONString = JSON.stringify(personalityJSON);
870
+ //download
871
+ const element = document.createElement('a');
872
+ element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(personalityJSONString));
873
+ element.setAttribute('download', `${personalityJSON.name}.json`);
874
+ element.style.display = 'none';
875
+ document.body.appendChild(element);
876
+ element.click();
877
+ document.body.removeChild(element);
878
+
879
+
880
+ }
881
+
882
+ //handle share button click
883
+ personalityCards.forEach(card => {
884
+ const shareButton = card.querySelector(".btn-share-card");
885
+ shareButton.addEventListener("click", () => {
886
+ sharePersonality(card);
887
+ })
888
+ });
889
+
890
+ const importPersonalityButton = document.querySelector("#btn-import-personality");
891
+ importPersonalityButton.addEventListener("click", () => {
892
+ const fileInput = document.createElement('input');
893
+ fileInput.type = 'file';
894
+ fileInput.addEventListener('change', () => {
895
+ const file = fileInput.files[0];
896
+ const reader = new FileReader();
897
+ reader.onload = function (e) {
898
+ const personalityJSON = JSON.parse(e.target.result);
899
+ insertPersonality(personalityJSON);
900
+ };
901
+ reader.readAsText(file);
902
+ });
903
+ fileInput.click();
904
+ });
905
+
906
+ //handle radio input check change
907
+ personalityCardsInnerInput.forEach(input => {
908
+ input.addEventListener("change", () => {
909
+ // Darken all cards
910
+ personalityCards.forEach(card => {
911
+ const cardBackgroundImageURL = card.style.backgroundImage.match(/url\((.*?)\)/)[1].replace(/('|")/g, '');
912
+ card.style.outline = "0px solid rgb(150 203 236)";
913
+ darkenBg(card);
914
+ })
915
+
916
+ // Lighten selected card
917
+ input.parentElement.style.outline = "3px solid rgb(150 203 236)";
918
+ lightenBg(input.parentElement);
919
+ })
920
+ // Set initial outline
921
+ if (input.checked) {
922
+ lightenBg(input.parentElement);
923
+ input.parentElement.style.outline = "3px solid rgb(150 203 236)";
924
+ }
925
+ })
926
+
927
+ function showAddPersonalityForm() {
928
+ showElement(formsOverlay);
929
+ showElement(addPersonalityForm);
930
+ }
931
+
932
+ function showEditPersonalityForm() {
933
+ showElement(formsOverlay);
934
+ showElement(editDefaultPersonalityForm);
935
+ }
936
+
937
+ function closeOverlay() {
938
+ hideElement(formsOverlay);
939
+ hideElement(addPersonalityForm);
940
+ hideElement(editDefaultPersonalityForm);
941
+ }
942
+
943
+
944
+ function insertPersonality(personalityJSON){
945
+ const personalitySection = document.querySelector("#personalitySection");
946
+ const personalitySectionActions = document.querySelector("#btn-array-personality-section");
947
+
948
+ const personalityCard = document.createElement("label");
949
+ personalityCard.classList.add("card-personality");
950
+ personalityCard.style.backgroundImage = `url('${personalityJSON.image}')`;
951
+ personalityCard.innerHTML = `
952
+ <input type="radio" name="personality" value="${personalityJSON.name}">
953
+ <div>
954
+ <h3 class="personality-title">${personalityJSON.name}</h3>
955
+ <p class="personality-description">${personalityJSON.description}</p>
956
+ <p class="personality-prompt">${personalityJSON.prompt}</p>
957
+ </div>
958
+ <button class="btn-textual btn-edit-card material-symbols-outlined" id="btn-edit-personality-${personalityJSON.name}">edit</button>
959
+ <button class="btn-textual btn-share-card material-symbols-outlined" id="btn-share-personality-${personalityJSON.name}">share</button>
960
+ `;
961
+
962
+ //insert personality card before the button array
963
+ personalitySection.insertBefore(personalityCard, personalitySectionActions);
964
+
965
+ darkenBg(personalityCard);
966
+
967
+ personalityCards = document.querySelectorAll(".card-personality");
968
+ //add input event listener
969
+ personalityCard.querySelector("input").addEventListener("change", () => {
970
+ // Darken all cards
971
+ personalityCards.forEach(card => {
972
+ const cardBackgroundImageURL = card.style.backgroundImage.match(/url\((.*?)\)/)[1].replace(/('|")/g, '');
973
+ card.style.outline = "0px solid rgb(150 203 236)";
974
+ darkenBg(card);
975
+ })
976
+
977
+ // Lighten selected card
978
+ personalityCard.style.outline = "3px solid rgb(150 203 236)";
979
+ lightenBg(personalityCard);
980
+ })
981
+
982
+ const sharebtn = personalityCard.querySelector(".btn-share-card");
983
+ sharebtn.addEventListener("click", () => {
984
+ sharePersonality(personalityCard);
985
+ });
986
+ }
987
+
988
+ function submitNewPersonality() {
989
+ const personalityName = document.querySelector("#form-add-personality #personalityNameInput");
990
+ const personalityDescription = document.querySelector("#form-add-personality #personalityDescriptionInput");
991
+ const personalityImageURL = document.querySelector("#form-add-personality #personalityImageURLInput");
992
+ const personalityPrompt = document.querySelector("#form-add-personality #personalityPromptInput");
993
+ const personalitySection = document.querySelector("#personalitySection");
994
+
995
+
996
+ if (personalityName.value == "") {
997
+ alert("Please enter a personality name");
998
+ return;
999
+ }
1000
+ if (personalityPrompt.value == "") {
1001
+ alert("Please enter a personality prompt");
1002
+ return;
1003
+ }
1004
+
1005
+ //to json
1006
+ const personalityJSON = {
1007
+ name: personalityName.value,
1008
+ description: personalityDescription.value,
1009
+ prompt: personalityPrompt.value,
1010
+ image: personalityImageURL.value
1011
+ }
1012
+ insertPersonality(personalityJSON);
1013
+ closeOverlay();
1014
+ }
1015
+
1016
+ async function run() {
1017
+ const msg = document.querySelector("#messageInput");
1018
+ const msgText = msg.value;
1019
+ const messageContainer = document.querySelector(".message-container");
1020
+ const maxTokens = document.querySelector("#maxTokens");
1021
+ const API_KEY = document.querySelector("#apiKeyInput");
1022
+ const selectedPersonalityTitle = document.querySelector("input[name='personality']:checked + div .personality-title").innerText;
1023
+ const selectedPersonalityDescription = document.querySelector("input[name='personality']:checked + div .personality-description").innerText;
1024
+ const selectedPersonalityPrompt = document.querySelector("input[name='personality']:checked + div .personality-prompt").innerText;
1025
+
1026
+
1027
+ //chat history
1028
+ const chatHistory = [];
1029
+ //get chat history from message container
1030
+ const messageElements = messageContainer.querySelectorAll(".message");
1031
+ messageElements.forEach(element => {
1032
+ const messageroleapi = element.querySelector(".message-role-api").innerText;
1033
+ const messagetext = element.querySelector(".message-text").innerText;
1034
+ chatHistory.push({
1035
+ role: messageroleapi,
1036
+ parts: [{ text: messagetext }]
1037
+ })
1038
+ })
1039
+ //reverse order of chat history
1040
+ chatHistory.reverse();
1041
+
1042
+ //
1043
+ const toneExamples = [];
1044
+
1045
+
1046
+ if (API_KEY.value == "") {
1047
+ alert("Please enter an API key");
1048
+ return;
1049
+ }
1050
+
1051
+ const generationConfig = {
1052
+ maxOutputTokens: maxTokens.value,
1053
+ temperature: 0.9
1054
+ };
1055
+ const genAI = new GoogleGenerativeAI(API_KEY.value);
1056
+ const model = genAI.getGenerativeModel({ model: "gemini-pro" });
1057
+ const chat = model.startChat({
1058
+ generationConfig, safetySettings,
1059
+ history: [
1060
+ {
1061
+ role: "user",
1062
+ parts: [{ text: `Personality Name: ${selectedPersonalityTitle}, Personality Description: ${selectedPersonalityDescription}, Personality Prompt: ${selectedPersonalityPrompt}. ${systemPrompt}` }]
1063
+ },
1064
+ {
1065
+ role: "model",
1066
+ parts: [{ text: `Okay. From now on, I shall play the role of ${selectedPersonalityTitle}. Your prompt and described personality will be used for the rest of the conversation.` }]
1067
+ },
1068
+ ...toneExamples,
1069
+ ...chatHistory
1070
+ ]
1071
+ })
1072
+
1073
+
1074
+
1075
+ msg.value = "";
1076
+ //create new message div for the user's message then append to message container's top
1077
+ const newMessage = document.createElement("div");
1078
+ newMessage.classList.add("message");
1079
+ newMessage.innerHTML = `
1080
+ <h3 class="message-role">You:</h3>
1081
+ <div class="message-role-api" style="display: none;">user</div>
1082
+ <p class="message-text">${msgText}</p>
1083
+ `;
1084
+ messageContainer.insertBefore(newMessage, messageContainer.firstChild);
1085
+
1086
+ const result = await chat.sendMessageStream(msgText);
1087
+
1088
+ //create new message div for the model's reply then append to message container's top
1089
+ const newReply = document.createElement("div");
1090
+ newReply.classList.add("message");
1091
+ newReply.classList.add("message-model");
1092
+ newReply.innerHTML = `
1093
+ <h3 class="message-role">${selectedPersonalityTitle}:</h3>
1094
+ <div class="message-role-api" style="display: none;">model</div>
1095
+ <p class="message-text">`;
1096
+
1097
+ //get the p element inside the message div
1098
+ const replyText = newReply.querySelector(".message-text");
1099
+
1100
+
1101
+ messageContainer.insertBefore(newReply, messageContainer.firstChild);
1102
+
1103
+ let rawText = "";
1104
+ for await (const chunk of result.stream) {
1105
+ console.log("hello");
1106
+ rawText += chunk.text();
1107
+ replyText.innerHTML = marked(rawText);
1108
+ void replyText.offsetHeight; // Force reflow
1109
+ hljs.highlightAll();
1110
+ }
1111
+
1112
+ //save api key to local storage
1113
+ localStorage.setItem("API_KEY", API_KEY.value);
1114
+ localStorage.setItem("MAX_TOKENS", maxTokens.value);
1115
+
1116
+ }
1117
+
1118
+
1119
+ const messageInput = document.querySelector("#messageInput");
1120
+
1121
+ //if more than one line, set height to scrollheight, and revert upon delete
1122
+ messageInput.addEventListener("input", () => {
1123
+ if (messageInput.value.split("\n").length == 1) {
1124
+ messageInput.style.height = "2.5rem";
1125
+ }
1126
+ else {
1127
+ messageInput.style.height = "";
1128
+ messageInput.style.height = messageInput.scrollHeight + "px";
1129
+ }
1130
+ })
1131
+
1132
+
1133
+ const sidebarDismissButton = document.querySelector("#btn-hide-sidebar");
1134
+ sidebarDismissButton.addEventListener("click", () => {
1135
+ hideElement(document.querySelector(".sidebar"));
1136
+ })
1137
+
1138
+ const showSidebarButton = document.querySelector("#btn-show-sidebar");
1139
+ showSidebarButton.addEventListener("click", () => {
1140
+ showElement(document.querySelector(".sidebar"));
1141
+ })
1142
+
1143
+
1144
+ //unhide sidebar if width > 768px (event hander)
1145
+ window.addEventListener("resize", () => {
1146
+ if (window.innerWidth > 768) {
1147
+ showElement(document.querySelector(".sidebar"));
1148
+ }
1149
+ })
1150
+
1151
+
1152
+ hideOverlayButton.addEventListener("click", closeOverlay);
1153
+
1154
+ addPersonalityButton.addEventListener("click", showAddPersonalityForm);
1155
+
1156
+ editDefaultPersonalityButton.addEventListener("click", showEditPersonalityForm);
1157
+
1158
+ submitNewPersonalityButton.addEventListener("click", submitNewPersonality);
1159
+
1160
+ sendMessageButton.addEventListener("click", run);
1161
+
1162
+
1163
+ // ...
1164
+ </script>
1165
+
1166
+ </body>
1167
+
1168
+ </html>