Niansuh commited on
Commit
17fcca9
·
verified ·
1 Parent(s): 5d2bc65

Upload 18 files

Browse files
.eslintrc.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ {
2
+ "extends": "next/core-web-vitals"
3
+ }
.gitignore ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2
+
3
+ # dependencies
4
+ /node_modules
5
+ /.pnp
6
+ .pnp.js
7
+ .yarn/install-state.gz
8
+
9
+ # testing
10
+ /coverage
11
+
12
+ # next.js
13
+ /.next/
14
+ /out/
15
+
16
+ # production
17
+ /build
18
+
19
+ # misc
20
+ .DS_Store
21
+ *.pem
22
+
23
+ # debug
24
+ npm-debug.log*
25
+ yarn-debug.log*
26
+ yarn-error.log*
27
+
28
+ # local env files
29
+ .env*.local
30
+
31
+ # vercel
32
+ .vercel
33
+
34
+ # typescript
35
+ *.tsbuildinfo
36
+ next-env.d.ts
37
+
38
+ .vercel
app/chat.css ADDED
@@ -0,0 +1,393 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .chat-container{
2
+ width: 90%;
3
+ display: flex;
4
+ flex-direction: column;
5
+ max-width: 800px;
6
+ background-color: rgba(225, 242, 251, 0);
7
+ height: 100%;
8
+ border-radius: 20px;
9
+ align-self: center;
10
+ /* box-shadow: 0 0 100px 100px rgba(168, 232, 255, 0.177); */
11
+ }
12
+ .history.chat-container{
13
+ margin: 0;
14
+ background-color: #dafbff6e;
15
+ height: 100dvh;
16
+ border-radius: 0px 0px 0px 0px;
17
+ border-top-right-radius: 80px;
18
+ border-right: 2px solid #8ed2ff61;
19
+ }
20
+
21
+ input::placeholder{
22
+ text-align: center;
23
+ }
24
+ pre, code {
25
+ white-space: pre-wrap; /* Ensures the content wraps */
26
+ word-wrap: break-word; /* Forces long words to break */
27
+ overflow-wrap: break-word; /* Handles unbreakable words */
28
+ overflow-x: scroll; /* Allows horizontal scrolling if content exceeds width */
29
+ max-width: calc(100dvw - 130px); /* Ensures the block doesn't exceed its container's width */
30
+ }
31
+ .message-options{
32
+ display: flex;
33
+ flex-direction: row;
34
+ gap: 10px;
35
+ margin: 10px;
36
+ background-color: rgba(180, 226, 255, 0.333);
37
+ padding: 10px;
38
+ border-radius: 20px;
39
+ width: fit-content;
40
+ }
41
+
42
+ .message-container{
43
+ margin-top: 0px;
44
+ height: 100%;
45
+ width: calc(100% - 0px);
46
+ overflow-y: auto;
47
+ overflow-x: hidden;
48
+ display: flex;
49
+ padding: 10px;
50
+ flex-direction: column;
51
+ }
52
+
53
+ .inp{
54
+
55
+ width: 100%;
56
+
57
+ border-radius: 10px;
58
+ border: none;
59
+ outline: none;
60
+ margin: 0px 10px 0px 10px;
61
+ background: transparent;
62
+ box-shadow: none;
63
+ }
64
+
65
+ .inpsection{
66
+
67
+
68
+ width: 100%;
69
+
70
+ }
71
+ .inpsection .btn2{
72
+ min-width: 0px;
73
+ min-height: 0px;
74
+ height: 30px;
75
+ border-radius: 20px;
76
+ display: flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ }
80
+
81
+ /*
82
+ disabled button css
83
+ */
84
+ .inpsection .btn2:disabled{
85
+ opacity: 0.5;
86
+ cursor: not-allowed;
87
+ }
88
+
89
+ .inpsection{
90
+ background-color: rgba(168, 227, 255, 0.329);
91
+ display: flex;
92
+ align-items: center;
93
+ justify-content: center;
94
+ border-radius: 30px;
95
+ padding: 10px;
96
+
97
+
98
+ }
99
+
100
+ .message{
101
+ background-color: rgba(26, 26, 26, 0);
102
+ backdrop-filter: blur(5px);
103
+ color: rgb(84, 84, 84);
104
+ padding: 10px;
105
+ border-radius: 10px;
106
+ border: 2px solid #db34697f;
107
+ max-width: 600px;
108
+ width: fit-content;
109
+ word-wrap: break-word;
110
+
111
+ }
112
+ .message-holder{
113
+ display: flex;
114
+ flex-direction: column;
115
+ align-self: flex-end;
116
+ margin: 10px;
117
+ }
118
+
119
+ .user-message{
120
+ align-self: flex-end;
121
+ border: 2px solid #3498db7f;
122
+ background-color: rgba(200, 238, 255, 0);
123
+ }
124
+
125
+ .small{
126
+ font-size: 12px;
127
+ color:gray;
128
+ }
129
+
130
+ /* width */
131
+ ::-webkit-scrollbar {
132
+ width: 3px;
133
+ height: 3px;
134
+ border-radius: 50px;
135
+ }
136
+
137
+ /* Track */
138
+ ::-webkit-scrollbar-track {
139
+ background: transparent
140
+ }
141
+
142
+ /* Handle */
143
+ ::-webkit-scrollbar-thumb {
144
+ background: #a5a5a564;
145
+ border-radius: 20px;
146
+ }
147
+
148
+ .ld-ripple {
149
+ position: relative;
150
+ width: 40px;
151
+ height: 40px;
152
+ }
153
+
154
+ .ld-ripple div {
155
+ position: absolute;
156
+ border: 2px solid #fff;
157
+ opacity: 1;
158
+ border-radius: 50%;
159
+ animation: ld-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
160
+ }
161
+
162
+ .ld-ripple div:nth-child(2) {
163
+ animation-delay: -0.5s;
164
+ }
165
+
166
+ @keyframes ld-ripple {
167
+ 0% {
168
+ top: 18px;
169
+ left: 18px;
170
+ width: 0;
171
+ height: 0;
172
+ opacity: 0;
173
+ }
174
+
175
+ 4.9% {
176
+ top: 18px;
177
+ left: 18px;
178
+ width: 0;
179
+ height: 0;
180
+ opacity: 0;
181
+ }
182
+
183
+ 5% {
184
+ top: 18px;
185
+ left: 18px;
186
+ width: 0;
187
+ height: 0;
188
+ opacity: 1;
189
+ }
190
+
191
+ 100% {
192
+ top: 0px;
193
+ left: 0px;
194
+ width: 36px;
195
+ height: 36px;
196
+ opacity: 0;
197
+ }
198
+ }
199
+
200
+
201
+ /* Style Select */
202
+ select {
203
+ background-color: rgba(1, 95, 135, 0.265);
204
+ color: white;
205
+ padding: 10px;
206
+ border-radius: 10px;
207
+ width: fit-content;
208
+ word-wrap: break-word;
209
+ }
210
+
211
+ select option{
212
+ background-color: rgba(35, 93, 97, 0.897);
213
+ color: white;
214
+ padding: 10px;
215
+ border-radius: 10px;
216
+ width: fit-content;
217
+ word-wrap: break-word;
218
+ }
219
+
220
+
221
+ code{
222
+ /* Fix so that don't get outside parent */
223
+ position: relative;
224
+ white-space: pre-wrap;
225
+ word-wrap: break-word;
226
+
227
+ }
228
+
229
+ pre{
230
+ padding: 10px;
231
+ background-color: rgba(180, 226, 255, 0.333);
232
+ border-radius: 20px;
233
+ border: 2px solid #34a9db7f;
234
+ /* box-shadow: 0 0 10px #db34697f; */
235
+ color: rgb(84, 84, 84);
236
+ margin: 20px 0px 20px 0px;
237
+
238
+ }
239
+
240
+ pre code{
241
+ background-color: transparent;
242
+ padding: 0px 0px 0px 0px;
243
+ border: none;
244
+ border-radius: 0px;
245
+ }
246
+
247
+ code{
248
+ background-color: rgba(227, 227, 227, 0.399);
249
+ color: rgb(84, 84, 84);
250
+ padding: 0px 10px 0px 10px;
251
+ border-radius: 5px;
252
+ }
253
+
254
+ .goToConv{
255
+ background-color: rgba(255, 255, 255, 0.267);
256
+ padding: 20px;
257
+ border-radius: 20px;
258
+ border: 2px solid rgba(1, 207, 222, 0.382);
259
+ cursor: pointer;
260
+
261
+ }
262
+
263
+ .titler{
264
+ font-size: 20px;
265
+ font-weight: bold;
266
+ color: #009898;
267
+ }
268
+ .goToConv p{
269
+ color: gray;
270
+ font-size: small;
271
+ }
272
+ .info{
273
+ padding: 20px;
274
+ }
275
+ .perinfo{
276
+ background-color: rgba(255, 255, 255, 0.267);
277
+ border: 2px solid rgba(1, 207, 222, 0.382);
278
+ width: 100%;
279
+ padding: 20px;
280
+ margin-top: 10px;
281
+ border-radius: 20px;
282
+ }
283
+
284
+ .message-holder .btn3{
285
+ box-shadow: none;
286
+ background-color: transparent;
287
+ padding: 10px;
288
+ border-radius: 15px;
289
+ border: 2px solid rgb(0, 71, 95);
290
+ cursor: pointer;
291
+ color: rgb(84, 84, 84);
292
+ transition-duration: 300ms;
293
+ }
294
+
295
+ .message-holder .btn3:hover{
296
+ background-color: rgb(0, 71, 95);
297
+ }
298
+
299
+ .history{
300
+
301
+ max-width: "400px";
302
+ display: "flex";
303
+ flex-direction: "column";
304
+ align-items: "center";
305
+ justify-content: "flex-start";
306
+ padding: "20px";
307
+ }
308
+
309
+ .info{
310
+
311
+ max-width: "300px";
312
+ display: "flex";
313
+ flex-direction: "column";
314
+ align-items: "center";
315
+ justify-content: "flex-start";
316
+ padding: "20px";
317
+ }
318
+
319
+ .message-holder .small{
320
+ color: gray;
321
+ }
322
+ .message-holder .small:hover{
323
+ color: white;
324
+ }
325
+ .tabsForMobile{
326
+ display: none;
327
+ }
328
+ .chat{
329
+ display: flex;
330
+ height: 100%;
331
+ padding: 10px;
332
+ }
333
+ .history{
334
+ display: flex;
335
+ margin-top: 30px;
336
+
337
+
338
+ }
339
+ .info{
340
+ display: flex;
341
+ margin-top: 30px;
342
+
343
+ }
344
+ @media screen and (max-width: 1200px) {
345
+ .history{
346
+ display: none;
347
+ margin-top: 0px;
348
+ width: '90%';
349
+
350
+
351
+ }
352
+
353
+ .chat-container.history{
354
+ height: 90dvh;
355
+ border: none;
356
+ border-radius: 20px;
357
+ }
358
+ .tabsForMobile{
359
+ display: flex;
360
+ margin-top: 10px;
361
+ }
362
+ .chat-container{
363
+ height: 90dvh;
364
+ }
365
+ .info {
366
+ display: none;
367
+ width: '90%';
368
+ margin-top: 0px;
369
+
370
+ }
371
+
372
+ .chat{
373
+ display: none;
374
+ margin-top: 0px;
375
+
376
+ }
377
+
378
+ }
379
+
380
+ .btn4{
381
+ padding: 5px 10px 5px 10px;
382
+ border-radius: 10px;
383
+ border: 2px solid rgb(0, 71, 95);
384
+ cursor: pointer;
385
+ color: rgb(84, 84, 84);
386
+ transition-duration: 300ms;
387
+ }
388
+
389
+ .btn4.active{
390
+ background-color: rgb(0, 71, 95);
391
+ color: white;
392
+ }
393
+
app/components/MessageOptions.jsx ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client";
2
+ import { useState } from 'react';
3
+ import { MdOutlineDone } from "react-icons/md";
4
+ import { MdContentCopy } from 'react-icons/md';
5
+ import { GrPowerReset } from 'react-icons/gr';
6
+
7
+ const MessageOptions = ({ message, regenerateMessage }) => {
8
+ const [icon, setIcon] = useState(<MdContentCopy />);
9
+
10
+ const handleCopy = () => {
11
+ navigator.clipboard.writeText(message.content);
12
+ setIcon(<MdOutlineDone />);
13
+
14
+ setTimeout(() => {
15
+ setIcon(<MdContentCopy />);
16
+ }, 1000);
17
+ };
18
+
19
+ return (
20
+ (
21
+ <div className="message-options">
22
+ <button onClick={handleCopy}>{icon}</button>
23
+ <button onClick={() => regenerateMessage(message)}><GrPowerReset /></button>
24
+ </div>
25
+ )
26
+ );
27
+ };
28
+
29
+ export default MessageOptions;
app/components/TextField.js ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client";
2
+ import { useEffect } from 'react';
3
+
4
+ const ResponsiveTextarea = ({ maxRows = 10, ...props }) => {
5
+ useEffect(() => {
6
+ const textarea = document.getElementById('responsive-textarea');
7
+
8
+ const adjustHeight = () => {
9
+ textarea.style.height = 'auto'; // Reset height to auto to recalculate
10
+ const lineHeight = parseInt(getComputedStyle(textarea).lineHeight); // Get line height
11
+ const rows = (textarea.scrollHeight / lineHeight)-2; // Calculate rows
12
+ console.log(rows);
13
+
14
+ if (rows <= maxRows) {
15
+ textarea.style.height = `${(textarea.scrollHeight)/2}px`; // Adjust height based on content
16
+ textarea.style.overflowY = 'hidden'; // Hide scrollbar if within limit
17
+ } else {
18
+ textarea.style.height = `${lineHeight * maxRows}px`; // Cap height at max rows
19
+ textarea.style.overflowY = 'auto'; // Show scrollbar if max rows are exceeded
20
+ }
21
+ };
22
+
23
+ textarea.addEventListener('input', adjustHeight);
24
+ // adjustHeight whenever input changes
25
+ textarea.addEventListener('change', adjustHeight);
26
+
27
+ // Initial adjustment for pre-filled content
28
+ adjustHeight();
29
+
30
+ // Cleanup event listener
31
+ return () => {
32
+ textarea.removeEventListener('input', adjustHeight);
33
+ };
34
+ }, [maxRows]);
35
+ useEffect(() => {
36
+ const textarea = document.getElementById('responsive-textarea');
37
+ const adjustHeight = () => {
38
+ textarea.style.height = 'auto'; // Reset height to auto to recalculate
39
+ const lineHeight = parseInt(getComputedStyle(textarea).lineHeight); // Get line height
40
+ const rows = (textarea.scrollHeight / lineHeight)-2; // Calculate rows
41
+ console.log(rows);
42
+
43
+ if (rows <= maxRows) {
44
+ textarea.style.height = `${(textarea.scrollHeight)/2}px`; // Adjust height based on content
45
+ textarea.style.overflowY = 'hidden'; // Hide scrollbar if within limit
46
+ } else {
47
+ textarea.style.height = `${lineHeight * maxRows}px`; // Cap height at max rows
48
+ textarea.style.overflowY = 'auto'; // Show scrollbar if max rows are exceeded
49
+ }
50
+ };
51
+ adjustHeight();
52
+ })
53
+
54
+ return (
55
+ <textarea
56
+ id="responsive-textarea"
57
+ style={{ resize: 'none', overflowY: 'hidden', display:'flex', alignItems:'center', justifyContent:'center' }}
58
+ {...props}
59
+ />
60
+ );
61
+ };
62
+
63
+ export default ResponsiveTextarea;
app/favicon.ico ADDED
app/globals.css ADDED
@@ -0,0 +1,515 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ html{
6
+ scroll-behavior: smooth;
7
+ margin: 0;
8
+ padding: 0;
9
+ height: 100dvh;
10
+ overflow: hidden;
11
+ transition-duration: 500ms;
12
+ }
13
+ :root {
14
+ --theme-font-family-base: "Comfortaa", sans-serif;
15
+ --theme-font-family-heading: system-ui;
16
+ --theme-font-color-base: var(--color-surface-900);
17
+ --theme-font-color-dark: var(--color-surface-50);
18
+ --theme-rounded-base: 24px;
19
+ --theme-rounded-container: 24px;
20
+ --theme-border-base: 1px;
21
+ --on-primary: 255 255 255;
22
+ --on-secondary: 255 255 255;
23
+ --on-tertiary: 0 0 0;
24
+ --on-success: 0 0 0;
25
+ --on-warning: 0 0 0;
26
+ --on-error: 0 0 0;
27
+ --on-surface: 255 255 255;
28
+ --color-primary-50: 249 220 226;
29
+ --color-primary-100: 246 208 216;
30
+ --color-primary-200: 244 197 206;
31
+ --color-primary-300: 238 162 177;
32
+ --color-primary-400: 225 92 119;
33
+ --color-primary-500: 212 22 60;
34
+ --color-primary-600: 191 20 54;
35
+ --color-primary-700: 159 17 45;
36
+ --color-primary-800: 127 13 36;
37
+ --color-primary-900: 104 11 29;
38
+ --color-secondary-50: 227 237 243;
39
+ --color-secondary-100: 218 231 239;
40
+ --color-secondary-200: 209 225 235;
41
+ --color-secondary-300: 181 206 223;
42
+ --color-secondary-400: 126 170 199;
43
+ --color-secondary-500: 70 133 175;
44
+ --color-secondary-600: 63 120 158;
45
+ --color-secondary-700: 53 100 131;
46
+ --color-secondary-800: 42 80 105;
47
+ --color-secondary-900: 34 65 86;
48
+ --color-tertiary-50: 242 230 254;
49
+ --color-tertiary-100: 238 221 253;
50
+ --color-tertiary-200: 233 213 253;
51
+ --color-tertiary-300: 220 187 252;
52
+ --color-tertiary-400: 194 136 249;
53
+ --color-tertiary-500: 168 85 247;
54
+ --color-tertiary-600: 151 77 222;
55
+ --color-tertiary-700: 126 64 185;
56
+ --color-tertiary-800: 101 51 148;
57
+ --color-tertiary-900: 82 42 121;
58
+ --color-success-50: 228 247 220;
59
+ --color-success-100: 219 245 208;
60
+ --color-success-200: 210 242 197;
61
+ --color-success-300: 183 234 161;
62
+ --color-success-400: 130 219 91;
63
+ --color-success-500: 76 203 21;
64
+ --color-success-600: 68 183 19;
65
+ --color-success-700: 57 152 16;
66
+ --color-success-800: 46 122 13;
67
+ --color-success-900: 37 99 10;
68
+ --color-warning-50: 253 246 223;
69
+ --color-warning-100: 253 243 212;
70
+ --color-warning-200: 252 240 202;
71
+ --color-warning-300: 251 230 170;
72
+ --color-warning-400: 247 212 106;
73
+ --color-warning-500: 244 193 42;
74
+ --color-warning-600: 220 174 38;
75
+ --color-warning-700: 183 145 32;
76
+ --color-warning-800: 146 116 25;
77
+ --color-warning-900: 120 95 21;
78
+ --color-error-50: 248 236 236;
79
+ --color-error-100: 246 229 230;
80
+ --color-error-200: 244 223 224;
81
+ --color-error-300: 237 204 205;
82
+ --color-error-400: 224 165 167;
83
+ --color-error-500: 210 127 129;
84
+ --color-error-600: 189 114 116;
85
+ --color-error-700: 158 95 97;
86
+ --color-error-800: 126 76 77;
87
+ --color-error-900: 103 62 63;
88
+ --color-surface-50: 223 224 226;
89
+ --color-surface-100: 213 213 217;
90
+ --color-surface-200: 202 203 207;
91
+ --color-surface-300: 170 171 179;
92
+ --color-surface-400: 107 109 121;
93
+ --color-surface-500: 43 46 64;
94
+ --color-surface-600: 39 41 58;
95
+ --color-surface-700: 32 35 48;
96
+ --color-surface-800: 26 28 38;
97
+ --color-surface-900: 21 23 31;
98
+ }
99
+ textarea{
100
+ resize: none;
101
+ line-height: 1.5;
102
+ }
103
+ body {
104
+ transition-duration: 500ms;
105
+ color: rgb(82, 82, 82);
106
+ background: #ffffff; /* fallback for old browsers */
107
+ display: flex;
108
+ flex-direction: column;
109
+ justify-content: center;
110
+ align-items: center;
111
+ height: 100dvh;
112
+ background-image: radial-gradient(at 0% 0%, rgba(var(--color-secondary-500) / .33) 0px, transparent 50%), radial-gradient(at 98% 1%, rgba(var(--color-error-500) / .33) 0px, transparent 50%);
113
+
114
+ }
115
+
116
+ .flex-col {
117
+ display: flex;
118
+ flex-direction: column;
119
+ }
120
+
121
+ .flex-row {
122
+ display: flex;
123
+ flex-direction: row;
124
+ }
125
+
126
+ .fade-in-text {
127
+ opacity: 0;
128
+ transition: opacity 0.5s ease-in-out;
129
+ }
130
+
131
+ .fade-in-text.active {
132
+ opacity: 1;
133
+ }
134
+ .loader {
135
+ position: relative;
136
+ width: 120px;
137
+ height: 90px;
138
+ margin: 0 auto;
139
+ }
140
+
141
+ .loader:before {
142
+ content: "";
143
+ position: absolute;
144
+ bottom: 30px;
145
+ left: 50px;
146
+ height: 30px;
147
+ width: 30px;
148
+ border-radius: 50%;
149
+ background: #00b7ff;
150
+ animation: loading-bounce 0.5s ease-in-out infinite alternate;
151
+ }
152
+ .links-about{
153
+ background-color: #373737;
154
+ border: 2px solid #00b7ff;
155
+ border-radius: 10px;
156
+ padding: 5px;
157
+ width: fit-content;
158
+ flex-wrap: wrap;
159
+ align-self: center;
160
+
161
+ }
162
+ .mid {
163
+ display: flex;
164
+ flex-direction: column;
165
+ overflow-y: hidden;
166
+ justify-content: center;
167
+ text-align: center;
168
+ align-items: flex-start;
169
+ width: 100%;
170
+ }
171
+ .mid span{
172
+ width: 100%;
173
+ }
174
+ progress{
175
+ width: 70%;
176
+ color: #68d5d3;
177
+ height: 7px;
178
+
179
+
180
+
181
+ }
182
+ progress{
183
+ height: 10px;
184
+ border-radius: 60px;
185
+ box-sizing: border-box;
186
+ margin-bottom: 3px;
187
+
188
+
189
+ }
190
+ progress::-webkit-progress-value {
191
+ border-radius: 30px;
192
+
193
+
194
+ }
195
+ progress::-webkit-progress-bar{
196
+ background: transparent;
197
+
198
+ }
199
+ progress::-webkit-progress-value{
200
+ background-image: linear-gradient(90deg, #00b7ff, #68d5d3);
201
+ }
202
+ .links-about a{
203
+ margin: 0;
204
+
205
+ }
206
+ .loader:after {
207
+ content: "";
208
+ position: absolute;
209
+ right: 0;
210
+ top: 0;
211
+ height: 7px;
212
+ width: 45px;
213
+ border-radius: 4px;
214
+ box-shadow: 0 5px 0 #f2f2f2, -35px 50px 0 #f2f2f2, -70px 95px 0 #f2f2f2;
215
+ animation: loading-step 1s ease-in-out infinite;
216
+ }
217
+
218
+ @keyframes loading-bounce {
219
+ 0% {
220
+ transform: scale(1, 0.7);
221
+ }
222
+
223
+ 40% {
224
+ transform: scale(0.8, 1.2);
225
+ }
226
+
227
+ 60% {
228
+ transform: scale(1, 1);
229
+ }
230
+
231
+ 100% {
232
+ bottom: 140px;
233
+ }
234
+ }
235
+
236
+ @keyframes loading-step {
237
+ 0% {
238
+ box-shadow: 0 10px 0 rgba(0, 0, 0, 0),
239
+ 0 10px 0 #f2f2f2,
240
+ -35px 50px 0 #f2f2f2,
241
+ -70px 90px 0 #f2f2f2;
242
+ }
243
+
244
+ 100% {
245
+ box-shadow: 0 10px 0 #f2f2f2,
246
+ -35px 50px 0 #f2f2f2,
247
+ -70px 90px 0 #f2f2f2,
248
+ -70px 90px 0 rgba(0, 0, 0, 0);
249
+ }
250
+ }
251
+ .modal {
252
+ position: fixed;
253
+ top: 50%;
254
+ left: 50%;
255
+ transform: translate(-50%, -50%);
256
+ right: 0;
257
+ bottom: 0;
258
+ background-color: rgba(0, 0, 0, 0.8);
259
+ backdrop-filter: blur(10px);
260
+ display: flex;
261
+ flex-direction: column;
262
+ border-radius: 20px;
263
+ justify-content: center;
264
+ align-items: center;
265
+ z-index: 9999;
266
+ padding: 20px;
267
+ width: 90%;
268
+ max-width: 800px;
269
+ }
270
+
271
+ .modal iframe {
272
+ width: 100%;
273
+ height: 100%;
274
+ border-radius: 10px;
275
+ }
276
+
277
+ .btn {
278
+ padding: 10px;
279
+ border-radius: 10px;
280
+ /* background-color: white; */
281
+ background: radial-gradient(
282
+ 231.94% 231.94% at 50% 100%,
283
+ #00c8ff 0,
284
+ rgba(38, 53, 193, 0) 25.24%
285
+ ),
286
+ linear-gradient(180deg, rgba(243, 238, 255, 0), rgba(243, 238, 255, 0.04)),
287
+ rgba(147, 130, 255, 0.01);
288
+ background-image: linear-gradient(to right, #00c8ff, #2635c1);
289
+
290
+ color: white;
291
+ transition: 200ms;
292
+ box-shadow: 0 0 140px rgb(0, 162, 255);
293
+ -webkit-background-clip: text; /* Clip the gradient to the text */
294
+ background-clip: text;
295
+ -webkit-text-fill-color: transparent; /* Make the text transparent */
296
+ }
297
+
298
+ input {
299
+ padding: 10px;
300
+ border-radius: 10px;
301
+ border: none;
302
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
303
+ background-color: transparent;
304
+ color: white;
305
+ padding: 10px;
306
+ border: #00c8ff 2px solid;
307
+ }
308
+
309
+ .btn:hover {
310
+ -webkit-background-clip: text; /* Clip the gradient to the text */
311
+ background-clip: text;
312
+ background: linear-gradient(to right, #00c8ff, #2635c1);
313
+ color: white;
314
+ -webkit-text-fill-color: white;
315
+ box-shadow: 0 0 100px rgba(255, 255, 255, 0.55);
316
+ }
317
+
318
+ .gradient-text {
319
+ background: linear-gradient(to right, #00c8ff, #2635c1);
320
+ -webkit-background-clip: text; /* Clip the gradient to the text */
321
+ background-clip: text;
322
+ -webkit-text-fill-color: transparent; /* Make the text transparent */
323
+ }
324
+ .title {
325
+ font-size: 70px;
326
+ font-weight: "300";
327
+ }
328
+ @media screen and (max-width: 510px) {
329
+ .title {
330
+ font-size: 30px;
331
+ font-weight: bold;
332
+ }
333
+ }
334
+
335
+ .thin-scroll::-webkit-scrollbar {
336
+ width: 4px;
337
+ background-color: rgba(0, 89, 255, 0.158); /* make scrollbar transparent */
338
+ border-radius: 10px;
339
+ cursor: pointer;
340
+ }
341
+
342
+ .thin-scroll::-webkit-scrollbar-thumb {
343
+ background-color: rgba(
344
+ 0,
345
+ 89,
346
+ 255,
347
+ 0.2
348
+ ); /* make scrollbar thumb transparent */
349
+ border-radius: 10px;
350
+ cursor: pointer;
351
+ }
352
+
353
+ .row {
354
+ flex-wrap: wrap;
355
+ }
356
+
357
+ .card {
358
+ margin-top: 100px;
359
+ border-radius: 30px;
360
+ box-shadow: 0 20px 50px rgba(0, 172, 240, 0.717);
361
+ background-color: rgba(67, 67, 67, 0.1);
362
+ backdrop-filter: blur(10px);
363
+ transition-duration: 300ms;
364
+ }
365
+
366
+ .card h3 {
367
+ background: linear-gradient(to right, #1c758e, #2635c1);
368
+ font-size: 30px;
369
+ padding: 10px;
370
+ border-radius: 30px 30px 0px 0px;
371
+ font-weight: 200;
372
+ margin: 0;
373
+ }
374
+ .category-label {
375
+ display: inline-block;
376
+ background: linear-gradient(90deg, #00d2ff, #3a7bd5);
377
+ padding: 5px 10px;
378
+ border-radius: 50px;
379
+ margin-bottom: 10px;
380
+ }
381
+
382
+ .category-label span {
383
+ font-size: 20px;
384
+ color: white;
385
+ }
386
+ .circle {
387
+ animation: shadowAnimation 3s infinite; /* Apply animation */
388
+ }
389
+
390
+ @keyframes shadowAnimation {
391
+ 0% {
392
+ box-shadow: 20px 20px 60px #00d2ff, -20px -20px 60px #3a7bd5;
393
+ }
394
+ 25% {
395
+ box-shadow: -20px 20px 60px #00d2ff, 20px -20px 60px #3a7bd5;
396
+ }
397
+ 50% {
398
+ box-shadow: -20px -20px 60px #00d2ff, 20px 20px 60px #3a7bd5;
399
+ }
400
+ 75% {
401
+ box-shadow: 20px -20px 60px #00d2ff, -20px 20px 60px #3a7bd5;
402
+ }
403
+ 100% {
404
+ box-shadow: 20px 20px 60px #00d2ff, -20px -20px 60px #3a7bd5;
405
+ }
406
+ }
407
+
408
+ .card p {
409
+ background: linear-gradient(to right, #1c758e, #2635c1);
410
+ -webkit-background-clip: text; /* Clip the gradient to the text */
411
+ background-clip: text;
412
+ -webkit-text-fill-color: transparent; /* Make the text transparent */
413
+ }
414
+
415
+ .card:hover {
416
+ box-shadow: 0 30px 50px rgba(0, 172, 240, 0.717);
417
+ transform: translateY(-10px);
418
+ }
419
+
420
+ .card p::before {
421
+ content: "";
422
+ display: inline-block;
423
+ width: 10px;
424
+ height: 10px;
425
+ background: linear-gradient(to right, #00c8ff, #2635c1);
426
+ border-radius: 50%;
427
+ margin-right: 20px;
428
+ }
429
+
430
+ .card p {
431
+ color: rgba(255, 255, 255, 0.516);
432
+ font-size: 17px;
433
+ text-align: left;
434
+ margin: 10px;
435
+ }
436
+
437
+ .ai-message {
438
+ background-color: #f9f9f9; /* Optional: background color */
439
+ padding: 16px; /* Adds padding inside the message block */
440
+ border-radius: 8px; /* Optional: rounded corners */
441
+ overflow-wrap: break-word; /* Breaks long words */
442
+ }
443
+
444
+ .card .line {
445
+ background: linear-gradient(to right, #00c8ff, #2635c1);
446
+ }
447
+
448
+ .card .n {
449
+ background-image: none;
450
+ border-radius: 0px 0px 30px 30px;
451
+ background-color: rgb(11, 11, 11);
452
+ display: flex;
453
+ justify-content: center;
454
+ align-items: center;
455
+ padding: 10px;
456
+ }
457
+ .sidenav a{
458
+ display: flex;
459
+ align-items: center;
460
+ justify-content: space-between;
461
+ text-align: center;
462
+ margin:0 ;
463
+ padding: 0;
464
+ padding-top: 10px;
465
+ padding-bottom: 10px;
466
+ }
467
+ .btn2 {
468
+ outline: 0;
469
+ display: inline-flex;
470
+ align-items: center;
471
+ justify-content: space-between;
472
+ background: linear-gradient(to right, #00c8ff, #2635c1);
473
+ min-width: 200px;
474
+ border: 0;
475
+ border-radius: 30px;
476
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
477
+ box-sizing: border-box;
478
+ padding: 16px 20px;
479
+ color: #fff;
480
+ font-size: 12px;
481
+ font-weight: 600;
482
+ letter-spacing: 1.2px;
483
+ text-transform: uppercase;
484
+ overflow: hidden;
485
+ cursor: pointer;
486
+ transition-duration: 400ms;
487
+ }
488
+
489
+ .btn2:hover {
490
+ opacity: 0.55;
491
+ padding: 16px 20px;
492
+ }
493
+
494
+ .btn2 .animation {
495
+ border-radius: 100%;
496
+ animation: ripple 0.6s linear infinite;
497
+ }
498
+
499
+ @keyframes ripple {
500
+ 0% {
501
+ box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.1),
502
+ 0 0 0 20px rgba(255, 255, 255, 0.1), 0 0 0 40px rgba(255, 255, 255, 0.1),
503
+ 0 0 0 60px rgba(255, 255, 255, 0.1);
504
+ }
505
+
506
+ 100% {
507
+ box-shadow: 0 0 0 20px rgba(255, 255, 255, 0.1),
508
+ 0 0 0 40px rgba(255, 255, 255, 0.1), 0 0 0 60px rgba(255, 255, 255, 0.1),
509
+ 0 0 0 80px rgba(255, 255, 255, 0);
510
+ }
511
+ }
512
+
513
+ .space {
514
+ height: 100px;
515
+ }
app/layout.js ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Comfortaa as Inter } from "next/font/google";
2
+ import "./globals.css";
3
+
4
+ const inter = Inter({ subsets: ["latin"], weight: ['variable'] });
5
+
6
+ export const metadata = {
7
+ title: "Smooth AI",
8
+ description: "Use smooth AI for generating AI responses in a lighting fast way.",
9
+ openGraph: {
10
+ title: "Smooth AI",
11
+ description: "Use smooth AI for generating AI responses in a lighting fast way.",
12
+ url: "https://smooth-ai.vercel.app",
13
+ siteName: "Smooth AI",
14
+ images: [
15
+ {
16
+ url: "https://smooth-ai.vercel.app/OIG4.jpeg",
17
+ width: 630,
18
+ height: 630,
19
+ },
20
+ ],
21
+ locale: "en-US",
22
+ type: "website",
23
+ },
24
+ icon: "https://smooth-ai.vercel.app/OIG4.jpeg",
25
+ };
26
+
27
+ export default function RootLayout({ children }) {
28
+ return (
29
+ <html lang="en">
30
+ <body className={inter.className}>{children}</body>
31
+ </html>
32
+ );
33
+ }
app/page.js ADDED
@@ -0,0 +1,642 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client";
2
+ import "./chat.css";
3
+ import { useState, useEffect } from "react";
4
+ import ReactMarkdown from "react-markdown";
5
+ import axios from "axios";
6
+ import { RiDeleteBinLine } from "react-icons/ri";
7
+ import TextField from '@/app/components/TextField';
8
+ import { MdContentCopy } from "react-icons/md";
9
+ import { GrPowerReset } from "react-icons/gr";
10
+ import {TiTick} from "react-icons/ti";
11
+ import MessageOptions from "./components/MessageOptions";
12
+
13
+ function generateRandomId(length) {
14
+ const id = Math.random().toString(36).substring(2, length + 2);
15
+ console.log(`ID GENERATION: ${id}`);
16
+ return id;
17
+ }
18
+ const ChatPage = () => {
19
+ const apiKey = 'hf_freeall'; // Replace with your OpenAI API key
20
+ const maxTokens = 3000;
21
+ const [isGenerating, setIsGenerating] = useState(false);
22
+ const chatSessionsKey = 'chatSessions';
23
+ let chatHistory = [];
24
+
25
+ process.on("uncaughtException", (err) => {
26
+ console.log(err);
27
+ });
28
+ const [currentModel, setCurrentModel] = useState("gpt-3.5-turbo-16k-0613");
29
+ const [sendButtonDisabled, setSendButtonDisabled] = useState(false);
30
+ const [bingSession, setBingSession] = useState(null);
31
+ const [currentTab, setCurrentTab] = useState("chat");
32
+ const [stop, setStop] = useState(false);
33
+ const [messages, setMessages] = useState([
34
+ // {
35
+ // role: "assistant",
36
+ // who: "AI: ",
37
+ // content: "Hello! How can I assist you today? 😊",
38
+ // greet: true,
39
+ // timestamp: 0,
40
+ // id: generateRandomId(6),
41
+ // }
42
+ ]);
43
+ const models = ["gpt-3.5-turbo", "gpt-3.5-turbo-0613", "gpt-3.5-turbo-16k", "gpt-3.5-turbo-16k-0613", "gpt-4", "gpt-4-0613", "gpt-4-32k", "gpt-4-32k-0613"];
44
+ const [modelSelectionModalOpen, setModelSelectionModalOpen] = useState(false);
45
+ const [conversations, setConversations] = useState({});
46
+
47
+
48
+ const saveToLocalStorage = () => {
49
+ localStorage.setItem("messages-"+messages[0].content+"|"+messages[0].id, JSON.stringify(messages));
50
+ setConversations({
51
+ ...localStorage
52
+ })
53
+ };
54
+
55
+
56
+ const getFromLocalStorage = () => {
57
+ if (localStorage.getItem("messages"+messages[0].content+"|"+messages[0].id)) {
58
+ setMessages(JSON.parse(localStorage.getItem("messages")));
59
+ }
60
+ };
61
+
62
+
63
+ useEffect(() => {
64
+ var localStorage = window.localStorage;
65
+ }, []);
66
+
67
+ const getAIResponse = async () => {
68
+ // setSendButtonDisabled(true);
69
+ // // ask for response buut also timeout if no response
70
+ // let resp = await axios.post("/api/v1/chat/completions", {
71
+ // messages: messages,
72
+ // model: currentModel,
73
+ // bingSession: bingSession
74
+ // }//,
75
+ // // {
76
+ // // timeout: 10000
77
+ // // }
78
+ // ).catch(err => {
79
+ // console.log(err);
80
+ // updateMessages({
81
+ // role: "assistant",
82
+ // who: "AI: ",
83
+ // content: "Error: " + err.message,
84
+ // timestamp: Date.now(),
85
+ // id: generateRandomId(6),
86
+ // })
87
+ // setSendButtonDisabled(false);
88
+ // });
89
+ // resp = resp.data;
90
+ // console.log(resp);
91
+ // if (resp.choices[resp.choices.length - 1].content) {
92
+ // if (resp.choices[resp.choices.length - 1].content.includes('BingProdUnAuthenticatedUsers')){
93
+ // let message = {
94
+ // role: "assistant",
95
+ // who: "AI: ",
96
+ // content: JSON.parse(resp.choices[resp.choices.length - 1].content).resultant,
97
+ // timestamp: Date.now(),
98
+ // id: generateRandomId(6),
99
+ // }
100
+ // setBingSession((prev) => JSON.parse(resp.choices[resp.choices.length - 1].content).session);
101
+ // console.log(bingSession);
102
+ // console.log(JSON.parse(resp.choices[resp.choices.length - 1].content));
103
+ // updateMessages(
104
+ // message
105
+ // )
106
+ // }
107
+ // else{
108
+ // updateMessages({
109
+ // ...resp.choices[resp.choices.length - 1],
110
+ // timestamp: Date.now(),
111
+ // });
112
+ // }
113
+ // }
114
+ // else{
115
+ // updateMessages({
116
+ // role: "assistant",
117
+ // who: "AI: ",
118
+ // content: "Error: No response. Try different AI Model or try again later.",
119
+ // timestamp: Date.now(),
120
+ // id: generateRandomId(6),
121
+ // })
122
+ // }
123
+
124
+ // setSendButtonDisabled(false);
125
+ // chatHistory.push({ role: 'user', content: messages[messages.length - 1].content });
126
+ for (let i = 0; i < messages.length; i++) {
127
+ chatHistory.push({ role: messages[i].role, content: messages[i].content });
128
+ }
129
+
130
+
131
+ let controller = new AbortController();
132
+ const signal = controller.signal;
133
+
134
+ const response = await fetch('https://hlb2vp60a9kpy2lu.us-east-1.aws.endpoints.huggingface.cloud/v1/chat/completions', {
135
+ method: 'POST',
136
+ headers: {
137
+ 'Authorization': `Bearer ${apiKey}`,
138
+ 'Content-Type': 'application/json'
139
+ },
140
+ body: JSON.stringify({
141
+ model: 'gpt-3.5-turbo',
142
+ messages: chatHistory,
143
+ max_tokens: maxTokens,
144
+ stream: true
145
+ }),
146
+ signal
147
+ });
148
+
149
+ if (!response.ok) {
150
+ throw new Error(`HTTP error! Status: ${response.status}`);
151
+ }
152
+
153
+ const reader = response.body.getReader();
154
+ const decoder = new TextDecoder();
155
+ let finalMessage = '';
156
+ while (true) {
157
+ setIsGenerating(true);
158
+ console.log(stop);
159
+ const { done, value } = await reader.read();
160
+ if (done || stop) {
161
+ setIsGenerating(false);
162
+
163
+ break;
164
+
165
+ };
166
+ const chunk = decoder.decode(value, { stream: true });
167
+ const lines = chunk.split('\n').filter(line => line.startsWith('data:'));
168
+ for (const line of lines) {
169
+ const json = line.replace('data:', '');
170
+ try {
171
+ const parsed = JSON.parse(json);
172
+ if (parsed.choices && parsed.choices.length > 0) {
173
+ finalMessage += parsed.choices[0].delta?.content || '';
174
+ updateMessages({
175
+ role: 'assistant',
176
+ who: 'AI: ',
177
+ content: finalMessage,
178
+ timestamp: Date.now(),
179
+ id: generateRandomId(6),
180
+ });
181
+ }
182
+ } catch (error) {
183
+ console.error('Error parsing JSON:', error);
184
+ }
185
+ }
186
+ };
187
+ setStop(false);
188
+ }
189
+
190
+ const regenerateMessage = (message) => {
191
+ updateMessages({
192
+ role: "user",
193
+ who: "You: ",
194
+ content: message.content,
195
+ timestamp: Date.now(),
196
+ id: generateRandomId(6),
197
+ });
198
+ }
199
+
200
+ const AIProcess = () => {
201
+
202
+ getAIResponse();
203
+ };
204
+
205
+ // message-container scroll to bottom on new message
206
+ useEffect(() => {
207
+ if (!messages?.length) return;
208
+ const messageContainer = document.querySelector(".message-container");
209
+ messageContainer.scrollTop = messageContainer.scrollHeight;
210
+ if (messages[messages?.length - 1]?.role === "user") {
211
+ AIProcess();
212
+ }
213
+ if (messages?.length > 1) {
214
+ saveToLocalStorage();
215
+ }
216
+ if (messages?.length === 1) {
217
+ setConversations({
218
+ ...localStorage
219
+ })
220
+ }
221
+ }, [messages]);
222
+
223
+
224
+ useEffect(() => {
225
+ setConversations({
226
+ ...localStorage
227
+ })
228
+ }, [])
229
+
230
+
231
+ useEffect(() => {
232
+ // scroll to bottom
233
+ const messageContainer = document.querySelector(".message-container");
234
+ messageContainer.scrollTop = messageContainer.scrollHeight;
235
+ }, [sendButtonDisabled])
236
+
237
+ const updateMessages = (message) => {
238
+ setMessages([...messages||[], message]);
239
+ };
240
+ return (
241
+ <div className="fullpage" style={{ display: "flex", flexDirection: "column", width: "100%", alignItems: "center", justifyContent: "center" }}>
242
+ <div className="tabsForMobile chat-container" style={{
243
+ flexDirection: "row",
244
+ justifyContent: "center",
245
+ width: "max-content",
246
+ gap: "10px",
247
+ padding: "10px",
248
+ alignItems: "center",
249
+
250
+ maxWidth: "600px",
251
+ height: "fit-content",
252
+ marginBottom: "0px",}
253
+ }>
254
+ <button
255
+ className={`btn4 ${currentTab === "history" ? "active" : ""}`}
256
+
257
+ onClick={()=>{
258
+ setCurrentTab("history");
259
+ }}
260
+ >
261
+ History
262
+ </button>
263
+ <button
264
+ className={`btn4 ${currentTab === "chat" ? "active" : ""}`}
265
+ onClick={()=>{
266
+ setCurrentTab("chat");
267
+ }}
268
+ >
269
+ Chat
270
+ </button>
271
+ {/* <button
272
+ className={`btn4 ${currentTab === "settings" ? "active" : ""}`}
273
+ onClick={()=>{
274
+ setCurrentTab("settings");
275
+ }}
276
+ >
277
+ Settings
278
+ </button> */}
279
+ </div>
280
+ <div className="whole-container" style={{
281
+ display: "flex",
282
+ flexDirection: "row",
283
+ justifyContent: "center",
284
+ gap: "5px",
285
+ alignItems: "center",
286
+ width: "100%",
287
+ padding: "0px 0px 0px 0px"
288
+ }}>
289
+
290
+ {/* Here goes available chats or conversation history */}
291
+ <div
292
+ className="history chat-container"
293
+ style={{
294
+ maxWidth: "400px",
295
+ display: currentTab === "history" ? "flex" : undefined,
296
+
297
+ flexDirection: "column",
298
+ alignItems: "center",
299
+ justifyContent: "flex-start",
300
+ padding: "20px",
301
+ }}
302
+ >
303
+ <h1
304
+ className="gradient-text"
305
+ style={{ textAlign: "center", fontSize: "30px", fontWeight: "bold", marginBottom: "20px" }}
306
+ >
307
+ History
308
+ </h1>
309
+ <div className="line"></div>
310
+
311
+ <main style={{width: '100%', overflowY: 'auto'}}>
312
+ <div className="goToConv" style={{width: '100%'}} onClick={()=>{
313
+ setMessages([]);
314
+ setCurrentTab("chat");
315
+ }}>
316
+ <div className="titler">New Conversation</div>
317
+ <p>Start a new conversation by simply clicking here!</p>
318
+
319
+ </div>
320
+ {typeof window !== 'undefined' &&
321
+ Object.keys(conversations).map((key,index)=>{
322
+ if (!key.includes('messages') && !key.includes('|')) return
323
+ let name = key.split('|')[0].replace('messages-', '')
324
+ // take only first 10 characters from name
325
+ name = name.slice(0, 20) + '...';
326
+
327
+ return <div key={index} style={{marginTop: '10px',width: '100%'}} className="goToConv" onClick={()=>{
328
+ setMessages(JSON.parse(localStorage.getItem(key)));
329
+ setCurrentTab("chat");
330
+ }}>
331
+ <div className="titler" style={{fontSize: '18px', display: 'flex', justifyContent: 'space-between'}}><span>{name}</span> {/*Delete button*/}
332
+ <button className="btn3" onClick={
333
+ ()=>{
334
+ setMessages({})
335
+ localStorage.removeItem(key);
336
+ setConversations({
337
+ ...localStorage
338
+ })
339
+ }
340
+ } style={{
341
+ color: '#0000ff',
342
+ }}>
343
+ <RiDeleteBinLine/>
344
+ </button></div>
345
+ <div className="row">
346
+ <p>{JSON.parse(localStorage.getItem(key)).length} messages</p>
347
+ <p>{Date(JSON.parse(localStorage.getItem(key))[0].timestamp)}</p>
348
+ </div>
349
+
350
+
351
+ </div>
352
+ })
353
+ }
354
+
355
+ </main>
356
+
357
+ </div>
358
+
359
+
360
+
361
+
362
+
363
+ {/* Here goes main chat UI */}
364
+ <div
365
+ className="chat"
366
+ style={{
367
+ width: "100%",
368
+ maxHeight: "100dvh",
369
+ minHeight: "100%",
370
+
371
+ display: currentTab === "chat" ? "flex" : undefined,
372
+ flexDirection: "column",
373
+ alignItems: "center",
374
+ justifyContent: "space-between",
375
+ }}
376
+ >
377
+ {modelSelectionModalOpen && (
378
+ <div
379
+ style={{
380
+ position: "fixed",
381
+ top: 0,
382
+ left: 0,
383
+ width: "100%",
384
+ height: "100%",
385
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
386
+ zIndex: 9999,
387
+ display: "flex",
388
+ alignItems: "center",
389
+ justifyContent: "center",
390
+ }}
391
+ >
392
+ <div
393
+ style={{
394
+ backgroundColor: "rgba(90, 90, 90, 0.2)",
395
+ backdropFilter: "blur(5px)",
396
+ padding: 20,
397
+ borderRadius: 10,
398
+ display: "flex",
399
+ flexDirection: "column",
400
+ alignItems: "center",
401
+ justifyContent: "center",
402
+ }}
403
+ >
404
+ <select
405
+ value={currentModel}
406
+ onChange={(e) => setCurrentModel(e.target.value)}
407
+ >
408
+ {models.map((model) => (
409
+ <option key={model} value={model}>
410
+ {model}
411
+ </option>
412
+ ))}
413
+ </select>
414
+ <button
415
+ onClick={() => setModelSelectionModalOpen(false)}
416
+ style={{
417
+ marginTop: 10,
418
+ }}
419
+ >
420
+ Close
421
+ </button>
422
+ </div>
423
+ </div>
424
+ )}
425
+ <div className="chat-container">
426
+ <div className="message-container">
427
+ {/* Welcome message if the messages array is empty */}
428
+ {(messages?.length === 0 || !messages) && (
429
+ <div
430
+ className="message-holder"
431
+ style={{
432
+ alignSelf: "center",
433
+ justifySelf: "center",
434
+ alignItems: "center",
435
+ justifyContent: "flex-start",
436
+ height: "100%",
437
+ }}
438
+ >
439
+ <div className="gradient-text" style={{fontSize: "30px", textAlign: "center", fontWeight: "bold" }}>Welcome to Smooth AI</div>
440
+ <div className="small" style={{
441
+ color: "gray",
442
+ }}>Get started by asking me a question!</div>
443
+ {/* Some random AI message and when clicked will be set as input value and be sent */}
444
+ <div
445
+ className="message-holder"
446
+ style={{
447
+ display: "flex",
448
+ flexDirection: "column",
449
+ width: "100%",
450
+ alignItems: "center",
451
+ justifyContent: "center",
452
+
453
+ }}
454
+ >
455
+
456
+ <button
457
+ className="btn3 small"
458
+ style={{
459
+ width: "90%",
460
+ marginTop: "10px",
461
+ marginLeft: "20px"
462
+ }}
463
+ onClick={(e) => {
464
+ document.querySelector('textarea').value = e.target.innerText
465
+
466
+ }}
467
+ >
468
+ How can I make a beautiful cup cake with extra chocolate flavour! Tell me step by step!
469
+ </button>
470
+ <button
471
+ className="btn3 small"
472
+ style={{
473
+ width: "90%",
474
+ marginTop: "10px",
475
+ marginLeft: "20px"
476
+
477
+
478
+ }}
479
+ onClick={(e) => {
480
+ document.querySelector('textarea').value = e.target.innerText
481
+
482
+ }}
483
+ >
484
+ I am bored! Can you tell me something special! Can we play games together or we would play a quiz game with each other?
485
+ </button>
486
+ <button
487
+ className="btn3 small"
488
+ style={{
489
+ marginTop: "10px",
490
+ width: "90%",
491
+ marginLeft: "20px"
492
+
493
+ }}
494
+ onClick={(e) => {
495
+ document.querySelector('textarea').value = e.target.innerText
496
+
497
+ }}
498
+ >
499
+ Ah, the world is beautiful! You, as an Artificial Intelligence, can tell me something about the world! You can express your own thinking and ideas about the world and the human being! I am eagerly waiting to hear from you!
500
+ </button>
501
+
502
+ </div>
503
+ </div>
504
+ )}
505
+ {messages?.map((message, index) => (
506
+ <div
507
+ className="message-holder"
508
+ key={index}
509
+ style={{
510
+ alignSelf: message.role === "user" ? "flex-end" : "flex-start",
511
+ }}
512
+ >
513
+ <div
514
+ className="small"
515
+ style={{
516
+ alignSelf:
517
+ message.role === "user" ? "flex-end" : "flex-start",
518
+ }}
519
+ >
520
+ {message.role.charAt(0).toUpperCase() + message.role.slice(1)}
521
+ {!message.greet &&
522
+ " - " + new Date(message.timestamp).toLocaleTimeString()}
523
+ </div>
524
+
525
+ <ReactMarkdown
526
+ key={index}
527
+ className={`message ${
528
+ message.role === "user" ? "user-message" : "ai-message"
529
+ }`}
530
+ >
531
+ {message.content}
532
+ </ReactMarkdown>
533
+ {message.role !== "user" && <MessageOptions message={
534
+ // previous message of AI
535
+ messages[index - 1]
536
+ } regenerateMessage={regenerateMessage} />}
537
+ </div>
538
+ ))}
539
+ {/* Loading Message */}
540
+ <div
541
+ className="message-holder"
542
+ style={{
543
+ alignSelf: "flex-start",
544
+ }}
545
+ >
546
+ <div
547
+ className="small"
548
+ style={{
549
+ alignSelf: "flex-start",
550
+ }}
551
+ >
552
+ {sendButtonDisabled && <div className="" style={{display:"flex", alignItems:"center", justifyContent:"center",}}>
553
+ <div className="ld-ripple">
554
+ <div></div>
555
+ <div></div>
556
+ </div> Generating Response ⚙️
557
+ </div>}
558
+ </div>
559
+ </div>
560
+ </div>
561
+ <div
562
+ className="inpsection"
563
+ style={{
564
+ display: "flex",
565
+ flexDirection: "row",
566
+ alignItems: "center",
567
+ justifyContent: "center",
568
+ margin: "0px 0px 10px 0px",
569
+
570
+ }}
571
+ >
572
+ <button className="btn2" onClick={() => setModelSelectionModalOpen(true)}>
573
+ <i className="animation"></i>AI<i className="animation"></i>
574
+ </button>
575
+ <TextField
576
+ type="text"
577
+ placeholder="Aa"
578
+ className="inp"
579
+ multiline
580
+ maxRows={10}
581
+ onKeyDown={(e) => {
582
+ // check if on mobile
583
+ function checkMobile() {
584
+ let check = false;
585
+ (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
586
+ return check;
587
+ }
588
+
589
+ if (e.key === "Enter" && !e.shiftKey && !checkMobile()) {
590
+ updateMessages({
591
+ role: "user",
592
+ content: e.target.value,
593
+ timestamp: Date.now(),
594
+ who: "You: ",
595
+ id: generateRandomId(),
596
+ });
597
+ document.querySelector(".inp").value = null;
598
+ }
599
+ }}
600
+ />
601
+ <button
602
+ disabled={sendButtonDisabled}
603
+ className="btn2"
604
+ onClick={() => {
605
+ if (isGenerating) {
606
+ setStop(true);
607
+ console.log("stop");
608
+ return;
609
+ }
610
+ let newMessage = {
611
+ role: "user",
612
+ who: "You: ",
613
+ id: generateRandomId(),
614
+ content: document.querySelector(".inp").value,
615
+ timestamp: Date.now(),
616
+ };
617
+ updateMessages(newMessage);
618
+ document.querySelector(".inp").value = null;
619
+ }}
620
+ >
621
+ <i className="animation"></i>{isGenerating? "Stop" : "Send"}<i className="animation"></i>
622
+ </button>
623
+ </div>
624
+
625
+ </div>
626
+
627
+ </div>
628
+
629
+
630
+
631
+
632
+ {/* Here goes chat info */}
633
+
634
+
635
+ </div>
636
+ </div>
637
+
638
+
639
+ );
640
+ };
641
+
642
+ export default ChatPage;
jsconfig.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "paths": {
4
+ "@/*": ["./*"]
5
+ }
6
+ }
7
+ }
next.config.mjs ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ /** @type {import('next').NextConfig} */
2
+ const nextConfig = {};
3
+
4
+ export default nextConfig;
package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
package.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "smooth-ai",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev",
7
+ "build": "next build",
8
+ "start": "next start",
9
+ "lint": "next lint"
10
+ },
11
+ "dependencies": {
12
+ "@emotion/react": "^11.13.0",
13
+ "@emotion/styled": "^11.13.0",
14
+ "@mui/material": "^5.16.7",
15
+ "axios": "^1.7.4",
16
+ "next": "14.2.5",
17
+ "react": "^18",
18
+ "react-dom": "^18",
19
+ "react-icons": "^5.3.0",
20
+ "react-markdown": "^9.0.1"
21
+ },
22
+ "devDependencies": {
23
+ "eslint": "^8",
24
+ "eslint-config-next": "14.2.5",
25
+ "postcss": "^8",
26
+ "tailwindcss": "^3.4.1"
27
+ }
28
+ }
postcss.config.mjs ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ /** @type {import('postcss-load-config').Config} */
2
+ const config = {
3
+ plugins: {
4
+ tailwindcss: {},
5
+ },
6
+ };
7
+
8
+ export default config;
public/OIG4.jpeg ADDED
public/next.svg ADDED
public/vercel.svg ADDED
tailwind.config.js ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /** @type {import('tailwindcss').Config} */
2
+ module.exports = {
3
+ content: [
4
+ "./pages/**/*.{js,ts,jsx,tsx,mdx}",
5
+ "./components/**/*.{js,ts,jsx,tsx,mdx}",
6
+ "./app/**/*.{js,ts,jsx,tsx,mdx}",
7
+ ],
8
+ theme: {
9
+ extend: {
10
+ backgroundImage: {
11
+ "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
12
+ "gradient-conic":
13
+ "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
14
+ },
15
+ },
16
+ },
17
+ plugins: [],
18
+ };