Salt40404 commited on
Commit
f32ae54
·
verified ·
1 Parent(s): 83bdd65

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -617
app.py CHANGED
@@ -1,15 +1,11 @@
1
  import gradio as gr
2
  from huggingface_hub import InferenceClient
3
- import time
4
 
5
- # Função principal que chama o modelo
6
  def respond(message, history: list[dict[str, str]], hf_token: gr.OAuthToken):
7
  client = InferenceClient(token=hf_token.token, model="openai/gpt-oss-20b")
8
  system_message = """You are BitAI (or Bit for short), a friendly chatbot created by the user "Sal".
9
- You always respond politely and helpfully. If a user requests something appropriate, fulfill it.
10
- If a user requests something harmful, illegal, or inappropriate, politely refuse.
11
- If a user keeps insisting on harmful requests, firmly tell them to stop and that they cannot use the service for that purpose.
12
- Keep a simple, approachable, and friendly tone otherwise."""
13
 
14
  messages = [{"role": "system", "content": system_message}]
15
  messages.extend(history)
@@ -17,644 +13,91 @@ Keep a simple, approachable, and friendly tone otherwise."""
17
 
18
  response = ""
19
  for chunk in client.chat_completion(messages, max_tokens=512, stream=True, temperature=0.7, top_p=0.95):
20
- token = ""
21
- if chunk.choices and chunk.choices[0].delta.content:
22
- token = chunk.choices[0].delta.content
23
  response += token
24
  yield response
25
 
26
- # JS para animações suaves
27
  fade_js = """
28
  <script>
29
  document.addEventListener("DOMContentLoaded", () => {
30
- // Add title and subtitle
31
- setTimeout(() => {
32
- const chatContainer = document.querySelector(".chat-interface");
33
- const gradioContainer = document.querySelector(".gradio-container");
34
-
35
- if (gradioContainer && !document.querySelector(".chat-title")) {
36
- const titleContainer = document.createElement("div");
37
- titleContainer.className = "title-container";
38
-
39
- const title = document.createElement("h1");
40
- title.className = "chat-title";
41
- title.textContent = "Talk with BitAI (W.I.P)";
42
-
43
- const subtitle = document.createElement("p");
44
- subtitle.className = "chat-subtitle";
45
- subtitle.innerHTML = "Me, Sal is still updating this AI, he cannot search on internet, he might not know how to answer you, filter is a little broken";
46
-
47
- titleContainer.appendChild(title);
48
- titleContainer.appendChild(subtitle);
49
-
50
- // Insert before the login button
51
- const loginButton = document.querySelector(".gr-button.gr-login");
52
- if (loginButton) {
53
- gradioContainer.insertBefore(titleContainer, loginButton);
54
- } else {
55
- gradioContainer.insertBefore(titleContainer, gradioContainer.firstChild);
56
- }
57
-
58
- // Animate in
59
- setTimeout(() => {
60
- titleContainer.style.opacity = "1";
61
- titleContainer.style.transform = "translateY(0)";
62
- }, 100);
63
- }
64
- }, 100);
65
 
66
- // Add startup message
67
- setTimeout(() => {
68
- const chatContainer = document.querySelector(".chat-interface");
69
- if (chatContainer && chatContainer.children.length === 0) {
70
- const startupMsg = document.createElement("div");
71
- startupMsg.className = "startup-message";
72
- startupMsg.innerHTML = '<div class="startup-content"><div class="startup-icon">🤖</div><div class="startup-text"><div class="startup-title">BitAI</div><div class="startup-subtitle">How was your day? Good morning!</div><div class="startup-note">Entirely made by AI</div></div></div>';
73
- chatContainer.appendChild(startupMsg);
74
-
75
- // Animate in
76
- setTimeout(() => {
77
- startupMsg.style.opacity = "1";
78
- startupMsg.style.transform = "translateY(0)";
79
- }, 100);
80
- }
81
- }, 500);
82
 
83
- // Observer for chat messages
84
  const observer = new MutationObserver(mutations => {
85
  mutations.forEach(m => {
86
  m.addedNodes.forEach(node => {
87
- if (node.classList && node.classList.contains('chat-message')) {
88
- // Remove startup message when first real message appears
89
  const startupMsg = document.querySelector(".startup-message");
90
- if (startupMsg) {
91
- startupMsg.style.opacity = "0";
92
- startupMsg.style.transform = "translateY(20px)";
93
- setTimeout(() => {
94
- startupMsg.remove();
95
- }, 300);
96
- }
97
-
98
- // Enhanced message animation
99
- node.style.opacity = 0;
100
- node.style.transform = 'translateY(20px) scale(0.95)';
101
- node.style.transition = 'opacity 0.5s ease, transform 0.5s ease, box-shadow 0.3s ease';
102
-
103
- requestAnimationFrame(() => {
104
- node.style.opacity = 1;
105
- node.style.transform = 'translateY(0) scale(1)';
106
-
107
- // Add subtle shadow on appearance
108
- setTimeout(() => {
109
- node.style.boxShadow = '0 4px 15px rgba(0,0,0,0.2)';
110
- }, 500);
111
- });
112
  }
113
  });
114
  });
115
  });
 
116
 
117
- const chatContainer = document.querySelector(".chat-interface");
118
- if (chatContainer) observer.observe(chatContainer, {childList: true, subtree: true});
119
-
120
- // Enhanced typing animation for textarea
121
- const txt = document.querySelector("textarea");
122
- if (txt) {
123
- txt.addEventListener("focus", () => {
124
- txt.style.transition = "all 0.3s ease";
125
- txt.style.transform = "translateY(-2px)";
126
- txt.style.boxShadow = "0 5px 15px rgba(0,0,0,0.2)";
127
- });
128
-
129
- txt.addEventListener("blur", () => {
130
- txt.style.transform = "translateY(0)";
131
- txt.style.boxShadow = "0 2px 8px rgba(0,0,0,0.1)";
132
- });
133
- }
134
 
135
- // Move button inside textarea
136
- setTimeout(() => {
137
- const btn = document.querySelector(".send-btn");
138
- const textareaContainer = document.querySelector(".input-container");
139
-
140
- if (btn && textareaContainer) {
141
- // Position button inside textarea
142
- btn.style.position = "absolute";
143
- btn.style.right = "8px";
144
- btn.style.top = "8px";
145
- btn.style.zIndex = "10";
146
- btn.style.marginLeft = "0";
147
- btn.style.width = "40px";
148
- btn.style.height = "40px";
149
-
150
- // Add container for positioning
151
- textareaContainer.style.position = "relative";
152
- }
153
- }, 100);
154
-
155
- // Enhanced button animation
156
- const addButtonAnimations = () => {
157
- const btn = document.querySelector(".send-btn");
158
- if (btn) {
159
- btn.addEventListener("mouseenter", () => {
160
- btn.style.transform = "scale(1.05)";
161
- btn.style.boxShadow = "0 5px 15px rgba(0,0,0,0.3)";
162
- });
163
-
164
- btn.addEventListener("mouseleave", () => {
165
- btn.style.transform = "scale(1)";
166
- btn.style.boxShadow = "0 2px 8px rgba(0,0,0,0.2)";
167
- });
168
-
169
- btn.addEventListener("mousedown", () => {
170
- btn.style.transform = "scale(0.95)";
171
- });
172
-
173
- btn.addEventListener("mouseup", () => {
174
- btn.style.transform = "scale(1.05)";
175
- });
176
-
177
- btn.addEventListener("click", () => {
178
- // Bounce effect
179
- btn.style.transition = "transform 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55)";
180
- btn.style.transform = "scale(0.9)";
181
-
182
- setTimeout(() => {
183
- btn.style.transform = "scale(1)";
184
- }, 500);
185
-
186
- // Ripple effect
187
- const ripple = document.createElement("span");
188
- ripple.classList.add("ripple-effect");
189
- btn.appendChild(ripple);
190
-
191
- setTimeout(() => {
192
- ripple.remove();
193
- }, 600);
194
- });
195
- }
196
- };
197
-
198
- // Add button animations after a short delay
199
- setTimeout(addButtonAnimations, 200);
200
-
201
- // Add bounce effect to all buttons and interactive elements
202
- const addBounceToElements = () => {
203
- // All buttons
204
- const allButtons = document.querySelectorAll("button");
205
- allButtons.forEach(button => {
206
- // Skip if already has bounce effect
207
- if (button.hasAttribute("data-bounce-added")) return;
208
-
209
- button.setAttribute("data-bounce-added", "true");
210
-
211
- button.addEventListener("click", function() {
212
- this.style.transition = "transform 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55)";
213
- this.style.transform = "scale(0.95)";
214
-
215
- setTimeout(() => {
216
- this.style.transform = "scale(1)";
217
- }, 500);
218
- });
219
- });
220
-
221
- // Chat messages
222
- const chatMessages = document.querySelectorAll(".chat-message");
223
- chatMessages.forEach(message => {
224
- if (message.hasAttribute("data-bounce-added")) return;
225
-
226
- message.setAttribute("data-bounce-added", "true");
227
-
228
- message.addEventListener("click", function() {
229
- this.style.transition = "transform 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55)";
230
- this.style.transform = "scale(0.98)";
231
-
232
- setTimeout(() => {
233
- this.style.transform = "scale(1)";
234
- }, 500);
235
- });
236
- });
237
-
238
- // Textarea
239
- const textareas = document.querySelectorAll("textarea");
240
- textareas.forEach(textarea => {
241
- if (textarea.hasAttribute("data-bounce-added")) return;
242
-
243
- textarea.setAttribute("data-bounce-added", "true");
244
-
245
- textarea.addEventListener("click", function() {
246
- this.style.transition = "transform 0.3s cubic-bezier(0.68, -0.55, 0.27, 1.55)";
247
- this.style.transform = "scale(0.99)";
248
-
249
- setTimeout(() => {
250
- this.style.transform = "scale(1)";
251
- }, 300);
252
- });
253
- });
254
-
255
- // Login button
256
- const loginBtn = document.querySelector(".gr-button.gr-login");
257
- if (loginBtn && !loginBtn.hasAttribute("data-bounce-added")) {
258
- loginBtn.setAttribute("data-bounce-added", "true");
259
-
260
- loginBtn.addEventListener("click", function() {
261
- this.style.transition = "transform 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55)";
262
- this.style.transform = "scale(0.95)";
263
-
264
- setTimeout(() => {
265
- this.style.transform = "scale(1)";
266
- }, 500);
267
- });
268
- }
269
-
270
- // Title and subtitle
271
- const title = document.querySelector(".chat-title");
272
- const subtitle = document.querySelector(".chat-subtitle");
273
-
274
- if (title && !title.hasAttribute("data-bounce-added")) {
275
- title.setAttribute("data-bounce-added", "true");
276
-
277
- title.addEventListener("click", function() {
278
- this.style.transition = "transform 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55)";
279
- this.style.transform = "scale(0.98)";
280
-
281
- setTimeout(() => {
282
- this.style.transform = "scale(1)";
283
- }, 500);
284
- });
285
- }
286
-
287
- if (subtitle && !subtitle.hasAttribute("data-bounce-added")) {
288
- subtitle.setAttribute("data-bounce-added", "true");
289
-
290
- subtitle.addEventListener("click", function() {
291
- this.style.transition = "transform 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55)";
292
- this.style.transform = "scale(0.98)";
293
-
294
- setTimeout(() => {
295
- this.style.transform = "scale(1)";
296
- }, 500);
297
- });
298
- }
299
-
300
- // Startup message
301
- const startupMsg = document.querySelector(".startup-message");
302
- if (startupMsg && !startupMsg.hasAttribute("data-bounce-added")) {
303
- startupMsg.setAttribute("data-bounce-added", "true");
304
-
305
- startupMsg.addEventListener("click", function() {
306
- this.style.transition = "transform 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55)";
307
- this.style.transform = "scale(0.98)";
308
-
309
- setTimeout(() => {
310
- this.style.transform = "scale(1)";
311
- }, 500);
312
- });
313
- }
314
-
315
- // Chatbot container
316
- const chatbotContainer = document.querySelector(".gr-chatbot");
317
- if (chatbotContainer && !chatbotContainer.hasAttribute("data-bounce-added")) {
318
- chatbotContainer.setAttribute("data-bounce-added", "true");
319
-
320
- chatbotContainer.addEventListener("click", function() {
321
- this.style.transition = "transform 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55)";
322
- this.style.transform = "scale(0.995)";
323
-
324
- setTimeout(() => {
325
- this.style.transform = "scale(1)";
326
- }, 500);
327
- });
328
- }
329
  };
330
-
331
- // Add bounce to existing elements
332
- addBounceToElements();
333
-
334
- // Observe for new elements
335
- const elementObserver = new MutationObserver(addBounceToElements);
336
- elementObserver.observe(document.body, { childList: true, subtree: true });
337
-
338
- // Add subtle pulse animation to login button
339
- const loginBtn = document.querySelector(".gr-button.gr-login");
340
- if (loginBtn) {
341
- setInterval(() => {
342
- loginBtn.style.boxShadow = "0 0 0 0 rgba(68, 68, 68, 0.7)";
343
- setTimeout(() => {
344
- loginBtn.style.transition = "box-shadow 0.5s ease";
345
- loginBtn.style.boxShadow = "0 0 0 8px rgba(68, 68, 68, 0)";
346
- }, 50);
347
- }, 3000);
348
- }
349
  });
350
  </script>
351
  """
352
 
 
353
  with gr.Blocks(css="""
354
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Manrope:wght@300;400;500;600&family=Outfit:wght@300;400;500;600&display=swap');
355
-
356
- body {
357
- background-color: #000;
358
- margin: 0;
359
- padding: 0;
360
- }
361
- .gradio-container {
362
- border-radius: 20px;
363
- padding: 20px;
364
- max-width: 700px;
365
- margin: 30px auto;
366
- background: linear-gradient(145deg, #0f0f0f, #1a1a1a);
367
- box-shadow: 0 10px 30px rgba(0,0,0,0.4);
368
- overflow: hidden;
369
- transition: transform 0.3s ease;
370
- font-family: 'Manrope', 'Outfit', 'Inter', sans-serif;
371
- }
372
- .gradio-container:active {
373
- transform: scale(0.995);
374
- }
375
- /* Title container */
376
- .title-container {
377
- text-align: center;
378
- margin-bottom: 25px;
379
- opacity: 0;
380
- transform: translateY(-20px);
381
- transition: opacity 0.5s ease, transform 0.5s ease;
382
- }
383
- .chat-title {
384
- font-family: 'Inter', 'Manrope', 'Outfit', sans-serif;
385
- font-weight: 700;
386
- font-size: 32px;
387
- color: #fff;
388
- margin-bottom: 10px;
389
- letter-spacing: -0.02em;
390
- text-shadow: 0 2px 10px rgba(0,0,0,0.3);
391
- cursor: pointer;
392
- transition: transform 0.3s ease;
393
- }
394
- .chat-subtitle {
395
- font-family: 'Manrope', 'Outfit', 'Inter', sans-serif;
396
- font-weight: 400;
397
- font-size: 14px;
398
- color: #aaa;
399
- line-height: 1.5;
400
- max-width: 600px;
401
- margin: 0 auto;
402
- cursor: pointer;
403
- transition: transform 0.3s ease;
404
- }
405
- .chat-message {
406
- border-radius: 20px;
407
- padding: 16px 20px;
408
- margin: 12px 0;
409
- display: flex;
410
- flex-direction: column;
411
- opacity: 0;
412
- transition: all 0.3s ease;
413
- box-shadow: 0 4px 10px rgba(0,0,0,0.15);
414
- cursor: pointer;
415
- font-family: 'Outfit', 'Manrope', 'Inter', sans-serif;
416
- font-weight: 400;
417
- letter-spacing: -0.01em;
418
- }
419
- .chat-message.user {
420
- background: linear-gradient(145deg, #252525, #1f1f1f);
421
- color: #fff;
422
- align-items: flex-end;
423
- border-bottom-right-radius: 5px;
424
- margin-left: 40px;
425
- font-family: 'Inter', 'Manrope', 'Outfit', sans-serif;
426
- font-weight: 500;
427
- }
428
- .chat-message.bot {
429
- background: linear-gradient(145deg, #2e2e2e, #252525);
430
- color: #fff;
431
- align-items: flex-start;
432
- border-bottom-left-radius: 5px;
433
- margin-right: 40px;
434
- font-family: 'Manrope', 'Outfit', 'Inter', sans-serif;
435
- font-weight: 400;
436
- }
437
- /* Startup message */
438
- .startup-message {
439
- opacity: 0;
440
- transform: translateY(20px);
441
- transition: opacity 0.5s ease, transform 0.5s ease;
442
- margin: 20px 0;
443
- display: flex;
444
- justify-content: center;
445
- cursor: pointer;
446
- font-family: 'Outfit', 'Manrope', 'Inter', sans-serif;
447
- }
448
- .startup-content {
449
- display: flex;
450
- align-items: center;
451
- background: linear-gradient(145deg, #2e2e2e, #252525);
452
- padding: 20px;
453
- border-radius: 20px;
454
- box-shadow: 0 4px 15px rgba(0,0,0,0.2);
455
- max-width: 80%;
456
- transition: transform 0.3s ease;
457
- }
458
- .startup-icon {
459
- font-size: 32px;
460
- margin-right: 15px;
461
- }
462
- .startup-text {
463
- text-align: left;
464
- }
465
- .startup-title {
466
- font-weight: 600;
467
- font-size: 18px;
468
- margin-bottom: 5px;
469
- color: #fff;
470
- font-family: 'Inter', 'Manrope', 'Outfit', sans-serif;
471
- letter-spacing: -0.02em;
472
- }
473
- .startup-subtitle {
474
- font-size: 16px;
475
- margin-bottom: 3px;
476
- color: #eee;
477
- font-family: 'Manrope', 'Outfit', 'Inter', sans-serif;
478
- font-weight: 500;
479
- letter-spacing: -0.01em;
480
- }
481
- .startup-note {
482
- font-size: 12px;
483
- color: #aaa;
484
- font-style: italic;
485
- font-family: 'Inter', 'Manrope', 'Outfit', sans-serif;
486
- font-weight: 300;
487
- letter-spacing: 0.01em;
488
- }
489
- textarea {
490
- border: none;
491
- outline: none;
492
- border-radius: 25px;
493
- padding: 14px 20px;
494
- padding-right: 60px; /* Space for button */
495
- background-color: #1a1a1a;
496
- color: #fff;
497
- font-size: 16px;
498
- flex: 1;
499
- height: 56px;
500
- min-height: 56px;
501
- box-sizing: border-box;
502
- resize: none;
503
- transition: all 0.3s ease;
504
- box-shadow: 0 2px 8px rgba(0,0,0,0.1);
505
- width: 100%;
506
- cursor: pointer;
507
- line-height: 1.5;
508
- font-family: 'Inter', 'Manrope', 'Outfit', sans-serif;
509
- font-weight: 400;
510
- }
511
- .send-btn {
512
- border: none;
513
- border-radius: 20px;
514
- background: linear-gradient(145deg, #555, #444);
515
- color: #fff;
516
- width: 40px;
517
- height: 40px;
518
- font-size: 18px;
519
- display: flex;
520
- align-items: center;
521
- justify-content: center;
522
- cursor: pointer;
523
- transition: all 0.3s cubic-bezier(0.68, -0.55, 0.27, 1.55);
524
- box-shadow: 0 4px 10px rgba(0,0,0,0.2);
525
- position: absolute;
526
- right: 8px;
527
- top: 8px;
528
- overflow: hidden;
529
- font-family: 'Inter', 'Manrope', 'Outfit', sans-serif;
530
- }
531
- .send-btn:hover {
532
- background: linear-gradient(145deg, #666, #555);
533
- transform: scale(1.05);
534
- }
535
- .gr-button.gr-login {
536
- border-radius: 25px !important;
537
- background: linear-gradient(145deg, #333, #222) !important;
538
- color: #fff !important;
539
- margin-bottom: 20px;
540
- padding: 14px 24px;
541
- transition: all 0.3s ease !important;
542
- border: none !important;
543
- cursor: pointer !important;
544
- font-family: 'Manrope', 'Outfit', 'Inter', sans-serif !important;
545
- font-weight: 500 !important;
546
- }
547
- .gr-button.gr-login:hover {
548
- background: linear-gradient(145deg, #444, #333) !important;
549
- transform: translateY(-2px);
550
- }
551
- .input-container {
552
- display: flex;
553
- margin-top: 15px;
554
- position: relative;
555
- }
556
- .gr-chatbot {
557
- border-radius: 15px;
558
- overflow: hidden;
559
- background: #1a1a1a;
560
- padding: 15px;
561
- box-shadow: inset 0 2px 10px rgba(0,0,0,0.2);
562
- min-height: 400px;
563
- cursor: pointer;
564
- transition: transform 0.3s ease;
565
- font-family: 'Manrope', 'Outfit', 'Inter', sans-serif;
566
- }
567
- .gr-box {
568
- border-radius: 15px;
569
- }
570
- .gr-button-primary {
571
- border-radius: 25px !important;
572
- }
573
- /* Ripple effect */
574
- .ripple-effect {
575
- position: absolute;
576
- border-radius: 50%;
577
- background-color: rgba(255, 255, 255, 0.3);
578
- transform: scale(0);
579
- animation: ripple 0.6s linear;
580
- width: 100px;
581
- height: 100px;
582
- top: calc(50% - 50px);
583
- left: calc(50% - 50px);
584
- }
585
- @keyframes ripple {
586
- to {
587
- transform: scale(2.5);
588
- opacity: 0;
589
- }
590
- }
591
- /* Bounce animation */
592
- @keyframes bounce {
593
- 0%, 20%, 50%, 80%, 100% {transform: translateY(0);}
594
- 40% {transform: translateY(-10px);}
595
- 60% {transform: translateY(-5px);}
596
- }
597
- .bounce {
598
- animation: bounce 0.8s;
599
- }
600
- /* Scrollbar styling */
601
- ::-webkit-scrollbar {
602
- width: 8px;
603
- }
604
- ::-webkit-scrollbar-track {
605
- background: #1a1a1a;
606
- border-radius: 4px;
607
- }
608
- ::-webkit-scrollbar-thumb {
609
- background: #444;
610
- border-radius: 4px;
611
- }
612
- ::-webkit-scrollbar-thumb:hover {
613
- background: #555;
614
- }
615
- /* Message typing indicator */
616
- .typing-indicator {
617
- display: inline-block;
618
- position: relative;
619
- width: 60px;
620
- height: 20px;
621
- }
622
- .typing-dot {
623
- display: inline-block;
624
- width: 8px;
625
- height: 8px;
626
- border-radius: 50%;
627
- background-color: #888;
628
- position: absolute;
629
- animation: typing-animation 1.4s infinite ease-in-out;
630
- }
631
- .typing-dot:nth-child(1) {
632
- left: 0;
633
- animation-delay: 0s;
634
- }
635
- .typing-dot:nth-child(2) {
636
- left: 15px;
637
- animation-delay: 0.2s;
638
- }
639
- .typing-dot:nth-child(3) {
640
- left: 30px;
641
- animation-delay: 0.4s;
642
- }
643
- @keyframes typing-animation {
644
- 0%, 60%, 100% {
645
- transform: translateY(0);
646
- }
647
- 30% {
648
- transform: translateY(-5px);
649
- }
650
- }
651
  """) as demo:
652
 
653
- # Login direto na página
654
  gr.LoginButton()
655
-
656
- chatbot = gr.ChatInterface(respond, type="messages")
657
-
658
  gr.HTML(fade_js)
659
 
660
  if __name__ == "__main__":
 
1
  import gradio as gr
2
  from huggingface_hub import InferenceClient
 
3
 
4
+ # Função principal do chatbot
5
  def respond(message, history: list[dict[str, str]], hf_token: gr.OAuthToken):
6
  client = InferenceClient(token=hf_token.token, model="openai/gpt-oss-20b")
7
  system_message = """You are BitAI (or Bit for short), a friendly chatbot created by the user "Sal".
8
+ You respond politely, refuse inapropriate requests, and keep a friendly tone."""
 
 
 
9
 
10
  messages = [{"role": "system", "content": system_message}]
11
  messages.extend(history)
 
13
 
14
  response = ""
15
  for chunk in client.chat_completion(messages, max_tokens=512, stream=True, temperature=0.7, top_p=0.95):
16
+ token = chunk.choices[0].delta.content if chunk.choices and chunk.choices[0].delta.content else ""
 
 
17
  response += token
18
  yield response
19
 
20
+ # JS para animações e ajustes visuais
21
  fade_js = """
22
  <script>
23
  document.addEventListener("DOMContentLoaded", () => {
24
+ // Título animado
25
+ const grContainer = document.querySelector(".gradio-container");
26
+ if(grContainer && !document.querySelector(".chat-title")) {
27
+ const titleContainer = document.createElement("div");
28
+ titleContainer.className = "title-container";
29
+ titleContainer.innerHTML = `
30
+ <h1 class="chat-title">Talk with BitAI (W.I.P)</h1>
31
+ <p class="chat-subtitle">Still updating, might not know everything, filter slightly broken</p>
32
+ `;
33
+ grContainer.insertBefore(titleContainer, grContainer.firstChild);
34
+ setTimeout(()=>{titleContainer.style.opacity="1"; titleContainer.style.transform="translateY(0)";},100);
35
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
+ // Startup message
38
+ const chatContainer = document.querySelector(".chat-interface");
39
+ if(chatContainer && chatContainer.children.length===0){
40
+ const startupMsg = document.createElement("div");
41
+ startupMsg.className="startup-message";
42
+ startupMsg.innerHTML='<div class="startup-content"><div class="startup-icon">🤖</div><div class="startup-text"><div class="startup-title">BitAI</div><div class="startup-subtitle">How was your day? Good morning!</div><div class="startup-note">Entirely AI</div></div></div>';
43
+ chatContainer.appendChild(startupMsg);
44
+ setTimeout(()=>{startupMsg.style.opacity="1"; startupMsg.style.transform="translateY(0)";},100);
45
+ }
 
 
 
 
 
 
 
46
 
47
+ // Observador para animação de novas mensagens
48
  const observer = new MutationObserver(mutations => {
49
  mutations.forEach(m => {
50
  m.addedNodes.forEach(node => {
51
+ if(node.classList?.contains('chat-message')){
 
52
  const startupMsg = document.querySelector(".startup-message");
53
+ if(startupMsg){startupMsg.style.opacity="0"; startupMsg.style.transform="translateY(20px)"; setTimeout(()=>startupMsg.remove(),300);}
54
+ node.style.opacity=0; node.style.transform='translateY(20px) scale(0.95)';
55
+ node.style.transition='all 0.5s ease, box-shadow 0.3s ease';
56
+ requestAnimationFrame(()=>{node.style.opacity=1; node.style.transform='translateY(0) scale(1)'; setTimeout(()=>node.style.boxShadow='0 4px 15px rgba(0,0,0,0.2)',500);});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  }
58
  });
59
  });
60
  });
61
+ if(chatContainer) observer.observe(chatContainer, {childList:true, subtree:true});
62
 
63
+ // Button dentro do textarea
64
+ const btn = document.querySelector(".send-btn");
65
+ const txtCont = document.querySelector(".input-container");
66
+ if(btn && txtCont){txtCont.style.position="relative"; btn.style.position="absolute"; btn.style.right="8px"; btn.style.top="8px"; btn.style.width="40px"; btn.style.height="40px";}
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
+ // Função genérica de bounce
69
+ const bounce = el=>{
70
+ if(!el || el.hasAttribute("data-bounce-added")) return;
71
+ el.setAttribute("data-bounce-added","true");
72
+ el.addEventListener("click",()=>{el.style.transition="transform 0.5s cubic-bezier(0.68,-0.55,0.27,1.55)"; el.style.transform="scale(0.95)"; setTimeout(()=>el.style.transform="scale(1)",500);});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  };
74
+ document.querySelectorAll("button, .chat-message, textarea, .gr-button.gr-login, .chat-title, .chat-subtitle, .startup-message, .gr-chatbot").forEach(bounce);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  });
76
  </script>
77
  """
78
 
79
+ # Gradio interface
80
  with gr.Blocks(css="""
81
+ body{background:#000;margin:0;padding:0;font-family:'Inter','Manrope','Outfit',sans-serif;}
82
+ .gradio-container{border-radius:20px;padding:20px;max-width:700px;margin:30px auto;background:linear-gradient(145deg,#0f0f0f,#1a1a1a);box-shadow:0 10px 30px rgba(0,0,0,0.4);transition:transform 0.3s;}
83
+ .title-container{opacity:0;transform:translateY(-20px);transition:0.5s;}
84
+ .chat-title{font-size:32px;color:#fff;margin-bottom:10px;cursor:pointer;transition:0.3s;}
85
+ .chat-subtitle{font-size:14px;color:#aaa;cursor:pointer;transition:0.3s;}
86
+ textarea{border:none;border-radius:25px;padding:14px 20px 14px 20px;background:#1a1a1a;color:#fff;font-size:16px;width:100%;height:56px;transition:0.3s;}
87
+ .send-btn{border:none;border-radius:20px;background:linear-gradient(145deg,#555,#444);color:#fff;width:40px;height:40px;position:absolute;right:8px;top:8px;cursor:pointer;transition:0.3s;}
88
+ .chat-message{border-radius:20px;padding:16px;margin:12px 0;opacity:0;transition:0.5s;box-shadow:0 4px 10px rgba(0,0,0,0.15);}
89
+ .chat-message.user{background:linear-gradient(145deg,#252525,#1f1f1f);color:#fff;align-items:flex-end;margin-left:40px;}
90
+ .chat-message.bot{background:linear-gradient(145deg,#2e2e2e,#252525);color:#fff;align-items:flex-start;margin-right:40px;}
91
+ .startup-message{opacity:0;transform:translateY(20px);transition:0.5s;margin:20px 0;display:flex;justify-content:center;cursor:pointer;}
92
+ .startup-content{display:flex;align-items:center;background:linear-gradient(145deg,#2e2e2e,#252525);padding:20px;border-radius:20px;box-shadow:0 4px 15px rgba(0,0,0,0.2);}
93
+ .startup-icon{font-size:32px;margin-right:15px;}
94
+ .startup-title{font-weight:600;font-size:18px;color:#fff;}
95
+ .startup-subtitle{font-size:16px;color:#eee;}
96
+ .startup-note{font-size:12px;color:#aaa;font-style:italic;}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  """) as demo:
98
 
 
99
  gr.LoginButton()
100
+ gr.ChatInterface(respond, type="messages")
 
 
101
  gr.HTML(fade_js)
102
 
103
  if __name__ == "__main__":