OpceanAI commited on
Commit
1c634c9
·
verified ·
1 Parent(s): 1144d6f

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +157 -273
app.py CHANGED
@@ -1,6 +1,61 @@
1
  import gradio as gr
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
- # ─── Custom CSS ───────────────────────────────────────────────────────────────
4
  custom_css = """
5
  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600&display=swap');
6
 
@@ -24,8 +79,6 @@ custom_css = """
24
  --accent-soft: rgba(34, 197, 94, 0.12);
25
  --accent-glow: rgba(34, 197, 94, 0.25);
26
  --purple: #a855f7;
27
- --purple-soft: rgba(168, 85, 247, 0.12);
28
- --blue: #3b82f6;
29
  --blur-sm: 8px;
30
  --blur-md: 16px;
31
  --blur-lg: 24px;
@@ -67,7 +120,6 @@ custom_css = """
67
  }
68
 
69
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
70
-
71
  html { scroll-behavior: smooth; overflow-y: auto !important; overflow-x: hidden !important; }
72
 
73
  body {
@@ -84,60 +136,38 @@ body {
84
 
85
  body::before {
86
  content: '';
87
- position: fixed;
88
- inset: 0;
89
- pointer-events: none;
90
- z-index: 9999;
91
  opacity: 0.015;
92
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
93
- background-repeat: repeat;
94
- background-size: 128px 128px;
95
  }
96
 
97
  body::after {
98
  content: '';
99
- position: fixed;
100
- top: -30%;
101
- left: 50%;
102
- transform: translateX(-50%);
103
- width: 100vw;
104
- height: 60vh;
105
  background: radial-gradient(ellipse at center, var(--accent-soft) 0%, transparent 70%);
106
- pointer-events: none;
107
- z-index: -1;
108
- opacity: 0.4;
109
  }
110
 
111
- .gradio-container,
112
- .gradio-container > .main,
113
- .gradio-container > .main > .wrap {
114
- background: transparent !important;
115
- padding: 0 !important;
116
- max-width: 100% !important;
117
- margin: 0 !important;
118
- height: auto !important;
119
- min-height: auto !important;
120
  }
121
 
122
  /* Navbar */
123
  .navbar {
124
- position: fixed;
125
- top: 0; left: 0; right: 0;
126
- z-index: 1000;
127
- display: flex;
128
- align-items: center;
129
- justify-content: space-between;
130
  padding: 12px 24px;
131
  background: var(--bg-glass-strong);
132
- backdrop-filter: blur(var(--blur-lg));
133
- -webkit-backdrop-filter: blur(var(--blur-lg));
134
  border-bottom: 1px solid var(--border-primary);
135
  }
136
-
137
  .navbar-brand { display: flex; align-items: center; gap: 10px; text-decoration: none; }
138
  .navbar-logo {
139
- width: 28px; height: 28px;
140
- border-radius: var(--radius-md);
141
  background: linear-gradient(135deg, var(--accent), var(--purple));
142
  display: flex; align-items: center; justify-content: center;
143
  font-weight: 800; font-size: 14px; color: var(--text-inverse);
@@ -145,14 +175,10 @@ body::after {
145
  }
146
  .navbar-title { font-size: 15px; font-weight: 700; letter-spacing: -0.03em; color: var(--text-primary); }
147
  .navbar-actions { display: flex; align-items: center; gap: 8px; }
148
-
149
  .theme-toggle {
150
- width: 36px; height: 36px;
151
- border-radius: var(--radius-full);
152
- background: var(--bg-card);
153
- border: 1px solid var(--border-primary);
154
- color: var(--text-secondary);
155
- cursor: pointer;
156
  display: flex; align-items: center; justify-content: center;
157
  transition: all var(--transition-fast);
158
  }
@@ -160,87 +186,43 @@ body::after {
160
  .theme-toggle svg { width: 16px; height: 16px; }
161
 
162
  /* Hero */
163
- .hero {
164
- padding: 120px 24px 60px;
165
- text-align: center;
166
- max-width: 900px;
167
- margin: 0 auto;
168
- position: relative;
169
- }
170
-
171
  .hero-badge {
172
  display: inline-flex; align-items: center; gap: 6px;
173
- padding: 6px 14px;
174
- border-radius: var(--radius-full);
175
- background: var(--bg-glass);
176
- border: 1px solid var(--border-primary);
177
  font-size: 12px; font-weight: 500; color: var(--text-secondary);
178
- margin-bottom: 24px;
179
- backdrop-filter: blur(var(--blur-sm));
180
- -webkit-backdrop-filter: blur(var(--blur-sm));
181
  }
182
-
183
- .hero-badge-dot {
184
- width: 6px; height: 6px;
185
- border-radius: 50%;
186
- background: var(--accent);
187
- box-shadow: 0 0 8px var(--accent-glow);
188
- }
189
-
190
  .hero-title-container { position: relative; display: inline-block; margin-bottom: 24px; }
191
-
192
  .hero-title {
193
- font-size: clamp(3.5rem, 10vw, 7rem) !important;
194
- font-weight: 900 !important;
195
- letter-spacing: -0.02em !important;
196
- line-height: 1 !important;
197
- margin: 0 !important;
198
- position: relative;
199
- z-index: 2;
200
- display: flex;
201
- justify-content: center;
202
- flex-wrap: wrap;
203
  }
204
-
205
  .hero-letter {
206
  display: inline-block;
207
  background: linear-gradient(135deg, #22c55e 0%, #a855f7 50%, #3b82f6 100%);
208
- -webkit-background-clip: text;
209
- -webkit-text-fill-color: transparent;
210
- background-clip: text;
211
  filter: drop-shadow(0 0 20px rgba(34, 197, 94, 0.3));
212
- transition: filter 0.3s ease, transform 0.3s ease;
213
- cursor: default;
214
  }
215
  .hero-letter:hover { filter: drop-shadow(0 0 40px rgba(168, 85, 247, 0.6)); transform: translateY(-5px) scale(1.1); }
216
  .hero-space { display: inline-block; width: 0.3em; }
217
-
218
  .hero-glow-bg {
219
- position: absolute;
220
- top: 50%; left: 50%;
221
- transform: translate(-50%, -50%);
222
  width: 120%; height: 120%;
223
  background: radial-gradient(ellipse at center, rgba(34, 197, 94, 0.15) 0%, rgba(168, 85, 247, 0.08) 40%, transparent 70%);
224
- z-index: 1;
225
- pointer-events: none;
226
- opacity: 0;
227
- filter: blur(40px);
228
  }
229
-
230
  .hero p { font-size: 18px; color: var(--text-secondary); max-width: 560px; margin: 0 auto 32px; line-height: 1.7; }
231
-
232
  .hero-cta { display: flex; align-items: center; justify-content: center; gap: 12px; flex-wrap: wrap; }
233
-
234
  .btn {
235
- display: inline-flex; align-items: center; gap: 8px;
236
- padding: 10px 20px;
237
- border-radius: var(--radius-md);
238
- font-family: var(--font-sans);
239
  font-size: 14px; font-weight: 600; letter-spacing: -0.01em;
240
- cursor: pointer;
241
- transition: all var(--transition-fast);
242
- text-decoration: none;
243
- border: none;
244
  }
245
  .btn-primary { background: var(--text-primary); color: var(--text-inverse); }
246
  .btn-primary:hover { opacity: 0.85; transform: translateY(-1px); box-shadow: var(--shadow-md); }
@@ -250,181 +232,108 @@ body::after {
250
  /* Features */
251
  .features { padding: 40px 24px 60px; max-width: 1100px; margin: 0 auto; }
252
  .features-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; }
253
-
254
  .feature-card {
255
- padding: 24px;
256
- border-radius: var(--radius-lg);
257
- background: var(--bg-glass);
258
- border: 1px solid var(--border-primary);
259
- backdrop-filter: blur(var(--blur-md));
260
  -webkit-backdrop-filter: blur(var(--blur-md));
261
- transition: all var(--transition-base);
262
- position: relative;
263
- overflow: hidden;
264
  }
265
  .feature-card::before {
266
- content: '';
267
- position: absolute; inset: 0;
268
  background: linear-gradient(135deg, transparent 0%, var(--bg-card-hover) 100%);
269
- opacity: 0;
270
- transition: opacity var(--transition-base);
271
  }
272
  .feature-card:hover { border-color: var(--border-secondary); transform: translateY(-2px); box-shadow: var(--shadow-lg); }
273
  .feature-card:hover::before { opacity: 1; }
274
-
275
  .feature-icon {
276
- width: 40px; height: 40px;
277
- border-radius: var(--radius-md);
278
- background: var(--bg-card);
279
- border: 1px solid var(--border-primary);
280
- display: flex; align-items: center; justify-content: center;
281
- margin-bottom: 16px;
282
- color: var(--accent);
283
  }
284
  .feature-card h3 { font-size: 15px; font-weight: 600; letter-spacing: -0.02em; margin-bottom: 8px; color: var(--text-primary); }
285
  .feature-card p { font-size: 13px; color: var(--text-secondary); line-height: 1.6; }
286
 
287
- /* Chat Section */
288
- .chat-section {
289
- padding: 40px 24px 80px;
290
- max-width: 900px;
291
- margin: 0 auto;
292
- position: relative;
293
- }
294
-
295
  .chat-container {
296
- border-radius: var(--radius-xl);
297
- background: var(--bg-glass);
298
- border: 1px solid var(--border-primary);
299
- backdrop-filter: blur(var(--blur-lg));
300
  -webkit-backdrop-filter: blur(var(--blur-lg));
301
- overflow: hidden;
302
- box-shadow: var(--shadow-lg);
303
- margin-bottom: 20px;
304
  }
305
-
306
  .chat-header {
307
- padding: 16px 20px;
308
- border-bottom: 1px solid var(--border-primary);
309
- display: flex; align-items: center; gap: 12px;
310
- background: var(--bg-glass-strong);
311
  }
312
  .chat-header-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 12px var(--accent-glow); }
313
  .chat-header h3 { font-size: 13px; font-weight: 600; letter-spacing: -0.01em; color: var(--text-primary); }
314
  .chat-header span { font-size: 12px; color: var(--text-tertiary); margin-left: auto; }
315
 
316
  /* Auth */
317
- .auth-box {
318
- background: var(--bg-glass);
319
- border: 1px solid var(--border-primary);
320
- border-radius: var(--radius-lg);
321
- padding: 20px;
322
- margin-bottom: 20px;
323
- backdrop-filter: blur(var(--blur-md));
324
- -webkit-backdrop-filter: blur(var(--blur-md));
325
- }
326
- .auth-box p { font-size: 13px; color: var(--text-secondary); margin-bottom: 12px; }
327
- .auth-box button {
328
- width: 100%;
329
- padding: 10px 16px;
330
- height: 42px;
331
- background: var(--text-primary);
332
- color: var(--text-inverse);
333
- border: none;
334
- border-radius: var(--radius-md);
335
- font-family: var(--font-sans);
336
- font-size: 13px;
337
- font-weight: 600;
338
- cursor: pointer;
339
- transition: all var(--transition-fast);
340
  }
341
- .auth-box button:hover { opacity: 0.85; transform: translateY(-1px); }
342
 
343
  /* Gradio Overrides */
344
  .chatbot, div[data-testid="chatbot"] {
345
- background: transparent !important;
346
- border: none !important;
347
- border-radius: 0 !important;
348
- box-shadow: none !important;
349
- height: 480px !important;
350
- max-height: 480px !important;
351
  }
352
  .chatbot .message-wrap, div[data-testid="chatbot"] .message-wrap { padding: 16px !important; background: transparent !important; }
353
-
354
  .message { max-width: 80% !important; padding: 10px 14px !important; border-radius: var(--radius-md) !important; font-family: var(--font-sans) !important; font-size: 13px !important; line-height: 1.6 !important; }
355
- .message.user, .user.message { background: var(--bg-glass-strong) !important; color: var(--text-primary) !important; align-self: flex-end !important; border: 1px solid var(--border-primary) !important; border-bottom-right-radius: var(--radius-sm) !important; backdrop-filter: blur(var(--blur-sm)) !important; -webkit-backdrop-filter: blur(var(--blur-sm)) !important; }
356
- .message.bot, .bot.message { background: var(--bg-card) !important; color: var(--text-secondary) !important; align-self: flex-start !important; border: 1px solid var(--border-primary) !important; border-bottom-left-radius: var(--radius-sm) !important; }
357
-
 
 
 
 
 
 
 
 
358
  .message code { font-family: var(--font-mono) !important; font-size: 12px !important; background: var(--bg-tertiary) !important; border: 1px solid var(--border-primary) !important; border-radius: var(--radius-sm) !important; padding: 2px 6px !important; color: var(--accent) !important; }
359
  .message pre { font-family: var(--font-mono) !important; font-size: 12px !important; background: var(--bg-secondary) !important; border: 1px solid var(--border-primary) !important; border-radius: var(--radius-md) !important; padding: 12px !important; color: var(--text-secondary) !important; overflow-x: auto !important; margin-top: 8px !important; }
360
 
361
  textarea, input[type="text"], .scroll-hide {
362
- background: var(--bg-input) !important;
363
- border: 1px solid var(--border-primary) !important;
364
- border-radius: var(--radius-md) !important;
365
- color: var(--text-primary) !important;
366
- font-family: var(--font-sans) !important;
367
- font-size: 13px !important;
368
- padding: 10px 14px !important;
369
- resize: none !important;
370
- transition: border-color var(--transition-fast) !important;
371
  caret-color: var(--accent) !important;
372
  }
373
  textarea:focus, input[type="text"]:focus { border-color: var(--border-focus) !important; outline: none !important; box-shadow: 0 0 0 3px var(--accent-soft) !important; }
374
  textarea::placeholder, input[type="text"]::placeholder { color: var(--text-tertiary) !important; }
375
 
376
  button[variant="primary"], .submit-btn {
377
- background: var(--text-primary) !important;
378
- color: var(--text-inverse) !important;
379
- border: none !important;
380
- border-radius: var(--radius-md) !important;
381
- font-family: var(--font-sans) !important;
382
- font-size: 13px !important;
383
- font-weight: 600 !important;
384
- height: 38px !important;
385
- padding: 0 18px !important;
386
- cursor: pointer !important;
387
  transition: all var(--transition-fast) !important;
388
  }
389
  button[variant="primary"]:hover, .submit-btn:hover { opacity: 0.85; transform: translateY(-1px); }
390
-
391
  button[variant="secondary"] {
392
- background: transparent !important;
393
- color: var(--text-secondary) !important;
394
- border: 1px solid var(--border-primary) !important;
395
- border-radius: var(--radius-md) !important;
396
- font-family: var(--font-sans) !important;
397
- font-size: 12px !important;
398
- height: 34px !important;
399
- padding: 0 14px !important;
400
- transition: all var(--transition-fast) !important;
401
  }
402
  button[variant="secondary"]:hover { border-color: var(--border-secondary) !important; color: var(--text-primary) !important; background: var(--bg-card) !important; }
403
 
404
  label span, .label-wrap span {
405
- font-family: var(--font-mono) !important;
406
- font-size: 10px !important;
407
- font-weight: 500 !important;
408
- letter-spacing: 0.08em !important;
409
- color: var(--text-tertiary) !important;
410
- text-transform: uppercase !important;
411
  }
412
-
413
  .block, .gr-block { background: transparent !important; border-color: var(--border-primary) !important; border-radius: var(--radius-lg) !important; box-shadow: none !important; }
414
 
415
- .examples td {
416
- background: var(--bg-card) !important;
417
- border: 1px solid var(--border-primary) !important;
418
- border-radius: var(--radius-sm) !important;
419
- font-family: var(--font-sans) !important;
420
- font-size: 12px !important;
421
- color: var(--text-secondary) !important;
422
- padding: 8px 12px !important;
423
- cursor: pointer !important;
424
- transition: all var(--transition-fast) !important;
425
- }
426
- .examples td:hover { border-color: var(--border-secondary) !important; color: var(--text-primary) !important; background: var(--bg-card-hover) !important; }
427
-
428
  ::-webkit-scrollbar { width: 4px; height: 4px; }
429
  ::-webkit-scrollbar-track { background: transparent; }
430
  ::-webkit-scrollbar-thumb { background: var(--border-secondary); border-radius: 99px; }
@@ -434,7 +343,6 @@ label span, .label-wrap span {
434
  .footer { padding: 24px; text-align: center; border-top: 1px solid var(--border-primary); color: var(--text-tertiary); font-size: 12px; }
435
  .footer a { color: var(--text-secondary); text-decoration: none; transition: color var(--transition-fast); }
436
  .footer a:hover { color: var(--text-primary); }
437
-
438
  footer, .footer, .built-with { display: none !important; }
439
 
440
  /* Animation states */
@@ -459,13 +367,11 @@ footer, .footer, .built-with { display: none !important; }
459
  .chat-section { padding: 24px 16px 60px; }
460
  .message { max-width: 90% !important; }
461
  }
462
-
463
  @media (prefers-reduced-motion: reduce) {
464
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
465
  }
466
  """
467
 
468
- # ─── Custom JS ────────────────────────────────────────────────────────────────
469
  custom_js = """
470
  (function() {
471
  const script = document.createElement('script');
@@ -524,10 +430,8 @@ function initAnimations() {
524
  return;
525
  }
526
 
527
- // Navbar slide down
528
  anime({ targets: '.navbar', translateY: [-60, 0], opacity: [0, 1], duration: 600, easing: 'easeOutExpo' });
529
 
530
- // Hero timeline
531
  const heroTL = anime.timeline({ easing: 'easeOutExpo' });
532
  heroTL
533
  .add({ targets: '.hero-badge', opacity: [0, 1], translateY: [15, 0], scale: [0.95, 1], duration: 500 })
@@ -536,25 +440,20 @@ function initAnimations() {
536
  .add({ targets: '.hero p', opacity: [0, 1], translateY: [20, 0], duration: 600 }, '-=400')
537
  .add({ targets: '.hero-cta', opacity: [0, 1], translateY: [20, 0], duration: 600 }, '-=350');
538
 
539
- // Floating orbs
540
  anime({ targets: 'body::after', translateX: ['-52%', '-48%'], translateY: ['-2%', '2%'], duration: 8000, loop: true, direction: 'alternate', easing: 'easeInOutSine' });
541
 
542
- // Features scroll
543
  anime.scroll('.features', { repeat: false, threshold: 0.2, onEnter: () => {
544
  anime({ targets: '.feature-card', opacity: [0, 1], translateY: [30, 0], delay: anime.stagger(120, { start: 100 }), duration: 700, easing: 'easeOutExpo' });
545
  }});
546
 
547
- // Chat scroll
548
  anime.scroll('.chat-section', { repeat: false, threshold: 0.15, onEnter: () => {
549
  anime({ targets: '.chat-container', opacity: [0, 1], translateY: [25, 0], scale: [0.98, 1], duration: 600, easing: 'easeOutExpo' });
550
  }});
551
 
552
- // Footer scroll
553
  anime.scroll('.footer', { repeat: false, threshold: 0.5, onEnter: () => {
554
  anime({ targets: '.footer', opacity: [0, 1], translateY: [15, 0], duration: 500, easing: 'easeOutExpo' });
555
  }});
556
 
557
- // Button hover
558
  document.querySelectorAll('.btn-primary').forEach(btn => {
559
  btn.addEventListener('mouseenter', () => anime({ targets: btn, scale: 1.03, duration: 200, easing: 'easeOutQuad' }));
560
  btn.addEventListener('mouseleave', () => anime({ targets: btn, scale: 1, duration: 200, easing: 'easeOutQuad' }));
@@ -564,19 +463,13 @@ function initAnimations() {
564
  btn.addEventListener('mouseleave', () => anime({ targets: btn, scale: 1, duration: 200, easing: 'easeOutQuad' }));
565
  });
566
 
567
- // Card hover
568
  document.querySelectorAll('.feature-card').forEach(card => {
569
  card.addEventListener('mouseenter', () => anime({ targets: card.querySelector('.feature-icon'), scale: 1.1, rotate: '5deg', duration: 300, easing: 'easeOutQuad' }));
570
  card.addEventListener('mouseleave', () => anime({ targets: card.querySelector('.feature-icon'), scale: 1, rotate: '0deg', duration: 300, easing: 'easeOutQuad' }));
571
  });
572
 
573
- // Logo pulse
574
  anime({ targets: '.navbar-logo', boxShadow: ['0 0 20px rgba(34,197,94,0.15)', '0 0 35px rgba(34,197,94,0.3)', '0 0 20px rgba(34,197,94,0.15)'], duration: 3000, loop: true, easing: 'easeInOutSine' });
575
-
576
- // Badge dot pulse
577
  anime({ targets: '.hero-badge-dot', scale: [1, 1.3, 1], opacity: [1, 0.6, 1], duration: 2000, loop: true, easing: 'easeInOutSine' });
578
-
579
- // Chat dot pulse
580
  anime({ targets: '.chat-header-dot', scale: [1, 1.4, 1], opacity: [1, 0.5, 1], duration: 2500, loop: true, easing: 'easeInOutSine' });
581
  }
582
 
@@ -590,35 +483,24 @@ with gr.Blocks(
590
  js=custom_js,
591
  title="Yuuki-RxG",
592
  theme=gr.themes.Base(
593
- primary_hue="zinc",
594
- neutral_hue="zinc",
595
- font=gr.themes.GoogleFont("Inter"),
596
- font_mono=gr.themes.GoogleFont("JetBrains Mono"),
597
- radius_size=gr.themes.sizes.radius_sm,
598
- spacing_size=gr.themes.sizes.spacing_sm,
599
  ).set(
600
- body_background_fill="#09090b",
601
- body_text_color="#fafafa",
602
- background_fill_primary="#09090b",
603
- background_fill_secondary="#111113",
604
- border_color_primary="rgba(255,255,255,0.08)",
605
- color_accent="#22c55e",
606
  color_accent_soft="rgba(34,197,94,0.12)",
607
- button_primary_background_fill="#fafafa",
608
- button_primary_text_color="#09090b",
609
  button_primary_background_fill_hover="#e4e4e7",
610
  button_secondary_background_fill="transparent",
611
  button_secondary_border_color="rgba(255,255,255,0.08)",
612
  button_secondary_text_color="#a1a1aa",
613
- block_border_color="rgba(255,255,255,0.08)",
614
- block_background_fill="transparent",
615
- block_shadow="none",
616
- input_background_fill="rgba(255,255,255,0.04)",
617
  input_border_color="rgba(255,255,255,0.08)",
618
- input_border_color_focus="rgba(255,255,255,0.25)",
619
- input_shadow_focus="none",
620
- shadow_drop="none",
621
- shadow_drop_lg="none",
622
  )
623
  ) as demo:
624
  # ─── Hero ─────────────────────────────────────────────────────────────
@@ -693,13 +575,15 @@ with gr.Blocks(
693
  </div>
694
  """)
695
 
696
- login_btn = gr.LoginButton("Iniciar sesión con Hugging Face", elem_classes="auth-box")
 
 
 
 
697
 
698
- gr.load(
699
- "models/OpceanAI/Yuuki-RxG",
700
- accept_token=login_btn,
701
- provider="featherless-ai",
702
- )
703
 
704
  # ─── Footer ───────────────────────────────────────────────────────────
705
  gr.HTML("""
 
1
  import gradio as gr
2
+ import os
3
+ import httpx
4
+ import json
5
+
6
+ API_URL = "https://api.featherless.ai/v1/chat/completions"
7
+ MODEL = "OpceanAI/Yuuki-RxG"
8
+
9
+ def get_token(request: gr.Request):
10
+ if request and hasattr(request, "oauth_token") and request.oauth_token:
11
+ return request.oauth_token
12
+ return os.environ.get("HF_TOKEN")
13
+
14
+ def chat_stream(message, history, request: gr.Request):
15
+ token = get_token(request)
16
+ if not token:
17
+ yield history + [{"role": "assistant", "content": "⚠️ Por favor, inicia sesión con tu cuenta de Hugging Face para usar el chat."}]
18
+ return
19
+
20
+ messages = []
21
+ for msg in history:
22
+ if msg["role"] == "user":
23
+ messages.append({"role": "user", "content": msg["content"]})
24
+ elif msg["role"] == "assistant":
25
+ messages.append({"role": "assistant", "content": msg["content"]})
26
+ messages.append({"role": "user", "content": message})
27
+
28
+ headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
29
+ payload = {"model": MODEL, "messages": messages, "stream": True, "max_tokens": 2048}
30
+
31
+ chat_history = history + [{"role": "user", "content": message}]
32
+ yield chat_history
33
+
34
+ full_response = ""
35
+ try:
36
+ with httpx.Client(timeout=60.0) as client:
37
+ with client.stream("POST", API_URL, json=payload, headers=headers) as response:
38
+ if response.status_code != 200:
39
+ yield chat_history + [{"role": "assistant", "content": f"❌ Error {response.status_code}"}]
40
+ return
41
+ for line in response.iter_lines():
42
+ if not line.startswith("data: "):
43
+ continue
44
+ data = line[6:]
45
+ if data.strip() == "[DONE]":
46
+ break
47
+ try:
48
+ chunk = json.loads(data)
49
+ delta = chunk.get("choices", [{}])[0].get("delta", {})
50
+ content = delta.get("content", "")
51
+ if content:
52
+ full_response += content
53
+ yield chat_history + [{"role": "assistant", "content": full_response}]
54
+ except (json.JSONDecodeError, IndexError, KeyError):
55
+ continue
56
+ except Exception as e:
57
+ yield chat_history + [{"role": "assistant", "content": f"❌ Error: {str(e)}"}]
58
 
 
59
  custom_css = """
60
  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600&display=swap');
61
 
 
79
  --accent-soft: rgba(34, 197, 94, 0.12);
80
  --accent-glow: rgba(34, 197, 94, 0.25);
81
  --purple: #a855f7;
 
 
82
  --blur-sm: 8px;
83
  --blur-md: 16px;
84
  --blur-lg: 24px;
 
120
  }
121
 
122
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
 
123
  html { scroll-behavior: smooth; overflow-y: auto !important; overflow-x: hidden !important; }
124
 
125
  body {
 
136
 
137
  body::before {
138
  content: '';
139
+ position: fixed; inset: 0;
140
+ pointer-events: none; z-index: 9999;
 
 
141
  opacity: 0.015;
142
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
143
+ background-repeat: repeat; background-size: 128px 128px;
 
144
  }
145
 
146
  body::after {
147
  content: '';
148
+ position: fixed; top: -30%; left: 50%; transform: translateX(-50%);
149
+ width: 100vw; height: 60vh;
 
 
 
 
150
  background: radial-gradient(ellipse at center, var(--accent-soft) 0%, transparent 70%);
151
+ pointer-events: none; z-index: -1; opacity: 0.4;
 
 
152
  }
153
 
154
+ .gradio-container, .gradio-container > .main, .gradio-container > .main > .wrap {
155
+ background: transparent !important; padding: 0 !important; max-width: 100% !important;
156
+ margin: 0 !important; height: auto !important; min-height: auto !important;
 
 
 
 
 
 
157
  }
158
 
159
  /* Navbar */
160
  .navbar {
161
+ position: fixed; top: 0; left: 0; right: 0; z-index: 1000;
162
+ display: flex; align-items: center; justify-content: space-between;
 
 
 
 
163
  padding: 12px 24px;
164
  background: var(--bg-glass-strong);
165
+ backdrop-filter: blur(var(--blur-lg)); -webkit-backdrop-filter: blur(var(--blur-lg));
 
166
  border-bottom: 1px solid var(--border-primary);
167
  }
 
168
  .navbar-brand { display: flex; align-items: center; gap: 10px; text-decoration: none; }
169
  .navbar-logo {
170
+ width: 28px; height: 28px; border-radius: var(--radius-md);
 
171
  background: linear-gradient(135deg, var(--accent), var(--purple));
172
  display: flex; align-items: center; justify-content: center;
173
  font-weight: 800; font-size: 14px; color: var(--text-inverse);
 
175
  }
176
  .navbar-title { font-size: 15px; font-weight: 700; letter-spacing: -0.03em; color: var(--text-primary); }
177
  .navbar-actions { display: flex; align-items: center; gap: 8px; }
 
178
  .theme-toggle {
179
+ width: 36px; height: 36px; border-radius: var(--radius-full);
180
+ background: var(--bg-card); border: 1px solid var(--border-primary);
181
+ color: var(--text-secondary); cursor: pointer;
 
 
 
182
  display: flex; align-items: center; justify-content: center;
183
  transition: all var(--transition-fast);
184
  }
 
186
  .theme-toggle svg { width: 16px; height: 16px; }
187
 
188
  /* Hero */
189
+ .hero { padding: 120px 24px 60px; text-align: center; max-width: 900px; margin: 0 auto; position: relative; }
 
 
 
 
 
 
 
190
  .hero-badge {
191
  display: inline-flex; align-items: center; gap: 6px;
192
+ padding: 6px 14px; border-radius: var(--radius-full);
193
+ background: var(--bg-glass); border: 1px solid var(--border-primary);
 
 
194
  font-size: 12px; font-weight: 500; color: var(--text-secondary);
195
+ margin-bottom: 24px; backdrop-filter: blur(var(--blur-sm)); -webkit-backdrop-filter: blur(var(--blur-sm));
 
 
196
  }
197
+ .hero-badge-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 8px var(--accent-glow); }
 
 
 
 
 
 
 
198
  .hero-title-container { position: relative; display: inline-block; margin-bottom: 24px; }
 
199
  .hero-title {
200
+ font-size: clamp(3.5rem, 10vw, 7rem) !important; font-weight: 900 !important;
201
+ letter-spacing: -0.02em !important; line-height: 1 !important; margin: 0 !important;
202
+ position: relative; z-index: 2; display: flex; justify-content: center; flex-wrap: wrap;
 
 
 
 
 
 
 
203
  }
 
204
  .hero-letter {
205
  display: inline-block;
206
  background: linear-gradient(135deg, #22c55e 0%, #a855f7 50%, #3b82f6 100%);
207
+ -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
 
 
208
  filter: drop-shadow(0 0 20px rgba(34, 197, 94, 0.3));
209
+ transition: filter 0.3s ease, transform 0.3s ease; cursor: default;
 
210
  }
211
  .hero-letter:hover { filter: drop-shadow(0 0 40px rgba(168, 85, 247, 0.6)); transform: translateY(-5px) scale(1.1); }
212
  .hero-space { display: inline-block; width: 0.3em; }
 
213
  .hero-glow-bg {
214
+ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
 
 
215
  width: 120%; height: 120%;
216
  background: radial-gradient(ellipse at center, rgba(34, 197, 94, 0.15) 0%, rgba(168, 85, 247, 0.08) 40%, transparent 70%);
217
+ z-index: 1; pointer-events: none; opacity: 0; filter: blur(40px);
 
 
 
218
  }
 
219
  .hero p { font-size: 18px; color: var(--text-secondary); max-width: 560px; margin: 0 auto 32px; line-height: 1.7; }
 
220
  .hero-cta { display: flex; align-items: center; justify-content: center; gap: 12px; flex-wrap: wrap; }
 
221
  .btn {
222
+ display: inline-flex; align-items: center; gap: 8px; padding: 10px 20px;
223
+ border-radius: var(--radius-md); font-family: var(--font-sans);
 
 
224
  font-size: 14px; font-weight: 600; letter-spacing: -0.01em;
225
+ cursor: pointer; transition: all var(--transition-fast); text-decoration: none; border: none;
 
 
 
226
  }
227
  .btn-primary { background: var(--text-primary); color: var(--text-inverse); }
228
  .btn-primary:hover { opacity: 0.85; transform: translateY(-1px); box-shadow: var(--shadow-md); }
 
232
  /* Features */
233
  .features { padding: 40px 24px 60px; max-width: 1100px; margin: 0 auto; }
234
  .features-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; }
 
235
  .feature-card {
236
+ padding: 24px; border-radius: var(--radius-lg); background: var(--bg-glass);
237
+ border: 1px solid var(--border-primary); backdrop-filter: blur(var(--blur-md));
 
 
 
238
  -webkit-backdrop-filter: blur(var(--blur-md));
239
+ transition: all var(--transition-base); position: relative; overflow: hidden;
 
 
240
  }
241
  .feature-card::before {
242
+ content: ''; position: absolute; inset: 0;
 
243
  background: linear-gradient(135deg, transparent 0%, var(--bg-card-hover) 100%);
244
+ opacity: 0; transition: opacity var(--transition-base);
 
245
  }
246
  .feature-card:hover { border-color: var(--border-secondary); transform: translateY(-2px); box-shadow: var(--shadow-lg); }
247
  .feature-card:hover::before { opacity: 1; }
 
248
  .feature-icon {
249
+ width: 40px; height: 40px; border-radius: var(--radius-md); background: var(--bg-card);
250
+ border: 1px solid var(--border-primary); display: flex; align-items: center; justify-content: center;
251
+ margin-bottom: 16px; color: var(--accent);
 
 
 
 
252
  }
253
  .feature-card h3 { font-size: 15px; font-weight: 600; letter-spacing: -0.02em; margin-bottom: 8px; color: var(--text-primary); }
254
  .feature-card p { font-size: 13px; color: var(--text-secondary); line-height: 1.6; }
255
 
256
+ /* Chat */
257
+ .chat-section { padding: 40px 24px 80px; max-width: 900px; margin: 0 auto; }
 
 
 
 
 
 
258
  .chat-container {
259
+ border-radius: var(--radius-xl); background: var(--bg-glass);
260
+ border: 1px solid var(--border-primary); backdrop-filter: blur(var(--blur-lg));
 
 
261
  -webkit-backdrop-filter: blur(var(--blur-lg));
262
+ overflow: hidden; box-shadow: var(--shadow-lg); margin-bottom: 20px;
 
 
263
  }
 
264
  .chat-header {
265
+ padding: 16px 20px; border-bottom: 1px solid var(--border-primary);
266
+ display: flex; align-items: center; gap: 12px; background: var(--bg-glass-strong);
 
 
267
  }
268
  .chat-header-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 12px var(--accent-glow); }
269
  .chat-header h3 { font-size: 13px; font-weight: 600; letter-spacing: -0.01em; color: var(--text-primary); }
270
  .chat-header span { font-size: 12px; color: var(--text-tertiary); margin-left: auto; }
271
 
272
  /* Auth */
273
+ .auth-row { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; }
274
+ .auth-row p { font-size: 13px; color: var(--text-secondary); flex: 1; }
275
+ .auth-login-btn {
276
+ padding: 8px 16px; height: 36px;
277
+ background: var(--text-primary); color: var(--text-inverse);
278
+ border: none; border-radius: var(--radius-md);
279
+ font-family: var(--font-sans); font-size: 12px; font-weight: 600;
280
+ cursor: pointer; transition: all var(--transition-fast);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  }
282
+ .auth-login-btn:hover { opacity: 0.85; transform: translateY(-1px); }
283
 
284
  /* Gradio Overrides */
285
  .chatbot, div[data-testid="chatbot"] {
286
+ background: transparent !important; border: none !important; border-radius: 0 !important;
287
+ box-shadow: none !important; height: 480px !important; max-height: 480px !important;
 
 
 
 
288
  }
289
  .chatbot .message-wrap, div[data-testid="chatbot"] .message-wrap { padding: 16px !important; background: transparent !important; }
 
290
  .message { max-width: 80% !important; padding: 10px 14px !important; border-radius: var(--radius-md) !important; font-family: var(--font-sans) !important; font-size: 13px !important; line-height: 1.6 !important; }
291
+ .message.user, .user.message {
292
+ background: var(--bg-glass-strong) !important; color: var(--text-primary) !important;
293
+ align-self: flex-end !important; border: 1px solid var(--border-primary) !important;
294
+ border-bottom-right-radius: var(--radius-sm) !important;
295
+ backdrop-filter: blur(var(--blur-sm)) !important; -webkit-backdrop-filter: blur(var(--blur-sm)) !important;
296
+ }
297
+ .message.bot, .bot.message {
298
+ background: var(--bg-card) !important; color: var(--text-secondary) !important;
299
+ align-self: flex-start !important; border: 1px solid var(--border-primary) !important;
300
+ border-bottom-left-radius: var(--radius-sm) !important;
301
+ }
302
  .message code { font-family: var(--font-mono) !important; font-size: 12px !important; background: var(--bg-tertiary) !important; border: 1px solid var(--border-primary) !important; border-radius: var(--radius-sm) !important; padding: 2px 6px !important; color: var(--accent) !important; }
303
  .message pre { font-family: var(--font-mono) !important; font-size: 12px !important; background: var(--bg-secondary) !important; border: 1px solid var(--border-primary) !important; border-radius: var(--radius-md) !important; padding: 12px !important; color: var(--text-secondary) !important; overflow-x: auto !important; margin-top: 8px !important; }
304
 
305
  textarea, input[type="text"], .scroll-hide {
306
+ background: var(--bg-input) !important; border: 1px solid var(--border-primary) !important;
307
+ border-radius: var(--radius-md) !important; color: var(--text-primary) !important;
308
+ font-family: var(--font-sans) !important; font-size: 13px !important;
309
+ padding: 10px 14px !important; resize: none !important; transition: border-color var(--transition-fast) !important;
 
 
 
 
 
310
  caret-color: var(--accent) !important;
311
  }
312
  textarea:focus, input[type="text"]:focus { border-color: var(--border-focus) !important; outline: none !important; box-shadow: 0 0 0 3px var(--accent-soft) !important; }
313
  textarea::placeholder, input[type="text"]::placeholder { color: var(--text-tertiary) !important; }
314
 
315
  button[variant="primary"], .submit-btn {
316
+ background: var(--text-primary) !important; color: var(--text-inverse) !important;
317
+ border: none !important; border-radius: var(--radius-md) !important;
318
+ font-family: var(--font-sans) !important; font-size: 13px !important; font-weight: 600 !important;
319
+ height: 38px !important; padding: 0 18px !important; cursor: pointer !important;
 
 
 
 
 
 
320
  transition: all var(--transition-fast) !important;
321
  }
322
  button[variant="primary"]:hover, .submit-btn:hover { opacity: 0.85; transform: translateY(-1px); }
 
323
  button[variant="secondary"] {
324
+ background: transparent !important; color: var(--text-secondary) !important;
325
+ border: 1px solid var(--border-primary) !important; border-radius: var(--radius-md) !important;
326
+ font-family: var(--font-sans) !important; font-size: 12px !important;
327
+ height: 34px !important; padding: 0 14px !important; transition: all var(--transition-fast) !important;
 
 
 
 
 
328
  }
329
  button[variant="secondary"]:hover { border-color: var(--border-secondary) !important; color: var(--text-primary) !important; background: var(--bg-card) !important; }
330
 
331
  label span, .label-wrap span {
332
+ font-family: var(--font-mono) !important; font-size: 10px !important; font-weight: 500 !important;
333
+ letter-spacing: 0.08em !important; color: var(--text-tertiary) !important; text-transform: uppercase !important;
 
 
 
 
334
  }
 
335
  .block, .gr-block { background: transparent !important; border-color: var(--border-primary) !important; border-radius: var(--radius-lg) !important; box-shadow: none !important; }
336
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337
  ::-webkit-scrollbar { width: 4px; height: 4px; }
338
  ::-webkit-scrollbar-track { background: transparent; }
339
  ::-webkit-scrollbar-thumb { background: var(--border-secondary); border-radius: 99px; }
 
343
  .footer { padding: 24px; text-align: center; border-top: 1px solid var(--border-primary); color: var(--text-tertiary); font-size: 12px; }
344
  .footer a { color: var(--text-secondary); text-decoration: none; transition: color var(--transition-fast); }
345
  .footer a:hover { color: var(--text-primary); }
 
346
  footer, .footer, .built-with { display: none !important; }
347
 
348
  /* Animation states */
 
367
  .chat-section { padding: 24px 16px 60px; }
368
  .message { max-width: 90% !important; }
369
  }
 
370
  @media (prefers-reduced-motion: reduce) {
371
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
372
  }
373
  """
374
 
 
375
  custom_js = """
376
  (function() {
377
  const script = document.createElement('script');
 
430
  return;
431
  }
432
 
 
433
  anime({ targets: '.navbar', translateY: [-60, 0], opacity: [0, 1], duration: 600, easing: 'easeOutExpo' });
434
 
 
435
  const heroTL = anime.timeline({ easing: 'easeOutExpo' });
436
  heroTL
437
  .add({ targets: '.hero-badge', opacity: [0, 1], translateY: [15, 0], scale: [0.95, 1], duration: 500 })
 
440
  .add({ targets: '.hero p', opacity: [0, 1], translateY: [20, 0], duration: 600 }, '-=400')
441
  .add({ targets: '.hero-cta', opacity: [0, 1], translateY: [20, 0], duration: 600 }, '-=350');
442
 
 
443
  anime({ targets: 'body::after', translateX: ['-52%', '-48%'], translateY: ['-2%', '2%'], duration: 8000, loop: true, direction: 'alternate', easing: 'easeInOutSine' });
444
 
 
445
  anime.scroll('.features', { repeat: false, threshold: 0.2, onEnter: () => {
446
  anime({ targets: '.feature-card', opacity: [0, 1], translateY: [30, 0], delay: anime.stagger(120, { start: 100 }), duration: 700, easing: 'easeOutExpo' });
447
  }});
448
 
 
449
  anime.scroll('.chat-section', { repeat: false, threshold: 0.15, onEnter: () => {
450
  anime({ targets: '.chat-container', opacity: [0, 1], translateY: [25, 0], scale: [0.98, 1], duration: 600, easing: 'easeOutExpo' });
451
  }});
452
 
 
453
  anime.scroll('.footer', { repeat: false, threshold: 0.5, onEnter: () => {
454
  anime({ targets: '.footer', opacity: [0, 1], translateY: [15, 0], duration: 500, easing: 'easeOutExpo' });
455
  }});
456
 
 
457
  document.querySelectorAll('.btn-primary').forEach(btn => {
458
  btn.addEventListener('mouseenter', () => anime({ targets: btn, scale: 1.03, duration: 200, easing: 'easeOutQuad' }));
459
  btn.addEventListener('mouseleave', () => anime({ targets: btn, scale: 1, duration: 200, easing: 'easeOutQuad' }));
 
463
  btn.addEventListener('mouseleave', () => anime({ targets: btn, scale: 1, duration: 200, easing: 'easeOutQuad' }));
464
  });
465
 
 
466
  document.querySelectorAll('.feature-card').forEach(card => {
467
  card.addEventListener('mouseenter', () => anime({ targets: card.querySelector('.feature-icon'), scale: 1.1, rotate: '5deg', duration: 300, easing: 'easeOutQuad' }));
468
  card.addEventListener('mouseleave', () => anime({ targets: card.querySelector('.feature-icon'), scale: 1, rotate: '0deg', duration: 300, easing: 'easeOutQuad' }));
469
  });
470
 
 
471
  anime({ targets: '.navbar-logo', boxShadow: ['0 0 20px rgba(34,197,94,0.15)', '0 0 35px rgba(34,197,94,0.3)', '0 0 20px rgba(34,197,94,0.15)'], duration: 3000, loop: true, easing: 'easeInOutSine' });
 
 
472
  anime({ targets: '.hero-badge-dot', scale: [1, 1.3, 1], opacity: [1, 0.6, 1], duration: 2000, loop: true, easing: 'easeInOutSine' });
 
 
473
  anime({ targets: '.chat-header-dot', scale: [1, 1.4, 1], opacity: [1, 0.5, 1], duration: 2500, loop: true, easing: 'easeInOutSine' });
474
  }
475
 
 
483
  js=custom_js,
484
  title="Yuuki-RxG",
485
  theme=gr.themes.Base(
486
+ primary_hue="zinc", neutral_hue="zinc",
487
+ font=gr.themes.GoogleFont("Inter"), font_mono=gr.themes.GoogleFont("JetBrains Mono"),
488
+ radius_size=gr.themes.sizes.radius_sm, spacing_size=gr.themes.sizes.spacing_sm,
 
 
 
489
  ).set(
490
+ body_background_fill="#09090b", body_text_color="#fafafa",
491
+ background_fill_primary="#09090b", background_fill_secondary="#111113",
492
+ border_color_primary="rgba(255,255,255,0.08)", color_accent="#22c55e",
 
 
 
493
  color_accent_soft="rgba(34,197,94,0.12)",
494
+ button_primary_background_fill="#fafafa", button_primary_text_color="#09090b",
 
495
  button_primary_background_fill_hover="#e4e4e7",
496
  button_secondary_background_fill="transparent",
497
  button_secondary_border_color="rgba(255,255,255,0.08)",
498
  button_secondary_text_color="#a1a1aa",
499
+ block_border_color="rgba(255,255,255,0.08)", block_background_fill="transparent",
500
+ block_shadow="none", input_background_fill="rgba(255,255,255,0.04)",
 
 
501
  input_border_color="rgba(255,255,255,0.08)",
502
+ input_border_color_focus="rgba(255,255,255,0.25)", input_shadow_focus="none",
503
+ shadow_drop="none", shadow_drop_lg="none",
 
 
504
  )
505
  ) as demo:
506
  # ─── Hero ─────────────────────────────────────────────────────────────
 
575
  </div>
576
  """)
577
 
578
+ login_btn = gr.LoginButton("Iniciar sesión con Hugging Face", elem_classes="auth-login-btn")
579
+
580
+ chatbot = gr.Chatbot(type="messages", height=480)
581
+ msg = gr.Textbox(placeholder="Escribe tu mensaje...", lines=1)
582
+ clear = gr.Button("Limpiar chat", variant="secondary")
583
 
584
+ msg.submit(chat_stream, [msg, chatbot], [chatbot])
585
+ msg.submit(lambda: "", None, [msg])
586
+ clear.click(lambda: [], None, [chatbot], queue=False)
 
 
587
 
588
  # ─── Footer ───────────────────────────────────────────────────────────
589
  gr.HTML("""