LythronAI commited on
Commit
9fac15a
·
verified ·
1 Parent(s): d6fab25

Upload 12 files

Browse files
AI poweful/app.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys, os
2
+
3
+ # Detecta automáticamente el path donde estás ejecutando el Space
4
+ current_dir = os.path.dirname(__file__)
5
+
6
+ # Agrega el backend de Lythron al path para que pueda importarse
7
+ backend_path = os.path.join(current_dir, "AI poweful", "backend")
8
+ sys.path.append(backend_path)
9
+
10
+ # Importa la app FastAPI desde tu motor
11
+ from lythron_full import app
AI poweful/backend/.env ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Lythron AI – Configuración de entorno
2
+ VITE_HF_TOKEN=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
3
+ VITE_API_BASE=http://127.0.0.1:8000
4
+
5
+ VITE_APP_NAME="Lythron AI"
6
+ VITE_APP_VERSION="1.0.0"
7
+
8
+ VITE_THEME_PRIMARY=#00C2FF
9
+ VITE_THEME_SECONDARY=#FF00FF
10
+ VITE_THEME_BACKGROUND=#0A0A0A
11
+
12
+ VITE_MODEL_NAME=meta-llama/Llama-2-7b-chat-hf
13
+ VITE_DEFAULT_LANGUAGE=es
14
+ VITE_DEFAULT_MODE=creative
15
+ VITE_MAX_PROMPT_LENGTH=2048
16
+ VITE_TIMEOUT_MS=30000
17
+ VITE_PRODUCTION_MODE=false
AI poweful/backend/lythron_full.py CHANGED
@@ -1,30 +1,37 @@
1
- # lythron_full.py
 
 
 
 
 
2
  import os
3
  import io
4
- import struct
5
  import time
 
6
  import sqlite3
7
  import secrets
8
- from typing import List, Optional, Dict, Any
9
  from fastapi import FastAPI, UploadFile, File, Depends, HTTPException, status, Request, Response
10
- from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
11
  from fastapi.middleware.cors import CORSMiddleware
12
  from pydantic import BaseModel, Field
13
- from passlib.context import CryptContext
14
  from jose import JWTError, jwt
 
 
15
 
16
- # -------------------------
17
- # Config / Environment
18
- # -------------------------
19
  SECRET_KEY = os.getenv("LYTHRON_SECRET_KEY", secrets.token_urlsafe(32))
20
  ALGORITHM = "HS256"
21
  ACCESS_TOKEN_EXPIRE_SECONDS = 60 * 60 * 24 # 24h
22
- DATABASE = os.getenv("LYTHRON_DB", "lythron_lythron.db")
23
  ALLOWED_ORIGINS = os.getenv("LYTHRON_ALLOWED_ORIGINS", "http://localhost:3000").split(",")
 
24
 
25
- # -------------------------
26
- # DB init (SQLite lightweight)
27
- # -------------------------
28
  def init_db():
29
  conn = sqlite3.connect(DATABASE)
30
  cur = conn.cursor()
@@ -51,9 +58,9 @@ def init_db():
51
 
52
  init_db()
53
 
54
- # -------------------------
55
- # Auth utils (bcrypt + JWT)
56
- # -------------------------
57
  pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
58
  oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
59
 
@@ -99,9 +106,9 @@ def create_user(email: str, password: str, plan: str = "LTR 2.1", is_admin: bool
99
  raise HTTPException(status_code=400, detail="User already exists")
100
  conn.close()
101
 
102
- # -------------------------
103
- # Audit helper
104
- # -------------------------
105
  def audit(user_email: str, action: str, details: str = ""):
106
  conn = sqlite3.connect(DATABASE)
107
  cur = conn.cursor()
@@ -110,9 +117,9 @@ def audit(user_email: str, action: str, details: str = ""):
110
  conn.commit()
111
  conn.close()
112
 
113
- # -------------------------
114
- # Plan limits
115
- # -------------------------
116
  PLAN_LIMITS = {
117
  "LTR 2.1": 10,
118
  "LTR 2.5": 20,
@@ -128,7 +135,6 @@ def check_and_consume_prompt(user_email: Optional[str]):
128
  limit = PLAN_LIMITS.get(user["plan"], 10)
129
  now = int(time.time())
130
  reset_ts = user["prompts_reset_ts"] or 0
131
- # reset every 24h since last reset
132
  if now > (reset_ts + 24*3600):
133
  conn = sqlite3.connect(DATABASE)
134
  cur = conn.cursor()
@@ -145,90 +151,45 @@ def check_and_consume_prompt(user_email: Optional[str]):
145
  conn.close()
146
  return True
147
 
148
- # -------------------------
149
- # Simple safe mock engine (non-destructive)
150
- # -------------------------
151
- class MockEngine:
 
 
152
  def __init__(self):
153
- self.status = {"model": "mock-v1"}
154
  self.memory = []
155
 
156
  def generate(self, prompt: str, modality: str = "texto", language: Optional[str] = None) -> str:
157
- # minimal sanitization
158
- text = prompt.replace("\x00", " ")
159
- self.memory.append({"prompt": text, "modality": modality, "ts": int(time.time())})
160
- if language:
161
- safe = text.replace('"', '\\"').replace("\n"," ")
162
- return f"// {language} stub code for: {safe[:120]}"
163
- return f"{self.status.get('model')} response: {text[:400]}"
164
-
165
- def analyze_file(self, name: str, data: bytes, content_type: Optional[str] = None) -> Dict[str, Any]:
166
- summary = {"filename": name, "size": len(data)}
167
- extension = name.lower().split(".")[-1] if "." in name else ""
168
- if extension == "png" or (content_type and "png" in (content_type or "").lower()):
169
- if len(data) >= 24 and data.startswith(b"\x89PNG\r\n\x1a\n"):
170
- width = struct.unpack("!I", data[16:20])[0]
171
- height = struct.unpack("!I", data[20:24])[0]
172
- summary["preview"] = f"PNG {width}x{height}"
173
- summary["metadata"] = {"width": width, "height": height, "mode": "RGBA"}
174
- else:
175
- summary["error"] = "Invalid PNG"
176
- elif extension == "pdf" or (content_type and "pdf" in (content_type or "").lower()):
177
- try:
178
- import PyPDF2
179
- reader = PyPDF2.PdfReader(io.BytesIO(data))
180
- pages = len(reader.pages)
181
- text_preview = ""
182
- for p in reader.pages[:2]:
183
- text_preview += (p.extract_text() or "")
184
- summary["preview"] = text_preview[:2048]
185
- summary["metadata"] = {"pages": pages}
186
- except Exception as e:
187
- summary["error"] = f"PDF parse error: {e}"
188
- else:
189
- try:
190
- text = data.decode("utf-8", errors="ignore")
191
- summary["preview"] = text[:1024]
192
- except Exception:
193
- summary["error"] = "Unknown file content"
194
- return summary
195
-
196
- def remove_background(self, image_bytes: bytes) -> bytes:
197
- # demo stub: return original bytes. Replace with real model in production.
198
- return image_bytes
199
-
200
- def remove_watermark(self, image_bytes: bytes, user_email: str) -> bytes:
201
- # require plan check outside this function
202
- return image_bytes
203
-
204
- engine = MockEngine()
205
-
206
- # -------------------------
207
- # Pydantic schemas (your original ones merged)
208
- # -------------------------
209
- class TaskRequest(BaseModel):
210
- mode: Literal["core", "connect", "mirror", "interface", "creative", "strategy", "task"]
211
- objective: str
212
- context: Optional[str] = None
213
-
214
- class SimulationRequest(BaseModel):
215
- scenario: Literal["proyectos", "finanzas", "estrategia", "diseño"]
216
- variables: List[str]
217
- horizon: int = Field(gt=0, le=52)
218
-
219
- class CreativeFusionRequest(BaseModel):
220
- title: str
221
- narrative: str
222
- include_audio: bool = True
223
- include_video: bool = True
224
-
225
- class ProfileUpdate(BaseModel):
226
- name: str
227
- subscription: Literal["LTR 2.1", "LTR 2.5", "LTR 5.0"]
228
- palette: Literal["Neón Futurista", "Aurora Boreal", "Minimal Zen", "Ciber Rojo"]
229
- mood: Literal["sereno", "enérgico", "analítico"]
230
- emotional_state: Optional[str] = None
231
-
232
  class PredictRequest(BaseModel):
233
  prompt: str
234
  modality: str = "texto"
@@ -238,12 +199,11 @@ class PredictResponse(BaseModel):
238
  output: str
239
  status: Dict[str, Any]
240
 
241
- # -------------------------
242
- # FastAPI app + middleware + security headers
243
- # -------------------------
244
- app = FastAPI(title="Lythron Mock + Secure MVP", version="EVO.3")
245
 
246
- # CORS
247
  app.add_middleware(
248
  CORSMiddleware,
249
  allow_origins=ALLOWED_ORIGINS,
@@ -252,273 +212,41 @@ app.add_middleware(
252
  allow_headers=["*"],
253
  )
254
 
255
- # Security headers middleware
256
  @app.middleware("http")
257
  async def add_security_headers(request: Request, call_next):
258
  response: Response = await call_next(request)
259
- # Basic headers
260
  response.headers["X-Frame-Options"] = "DENY"
261
  response.headers["X-Content-Type-Options"] = "nosniff"
262
- response.headers["Referrer-Policy"] = "no-referrer"
263
- response.headers["Permissions-Policy"] = "geolocation=(), microphone=()"
264
- response.headers["Strict-Transport-Security"] = "max-age=63072000; includeSubDomains; preload"
265
- # You can customize CSP to your frontend needs (start strict)
266
- response.headers["Content-Security-Policy"] = "default-src 'self'"
267
  return response
268
 
269
- # -------------------------
270
- # Auth endpoints
271
- # -------------------------
272
- @app.post("/register")
273
- async def register(form: OAuth2PasswordRequestForm = Depends()):
274
- email = form.username
275
- password = form.password
276
- create_user(email, password)
277
- audit(email, "register", "user created")
278
- return {"ok": True}
279
-
280
- @app.post("/token")
281
- async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
282
- user = get_user(form_data.username)
283
- if not user or not verify_password(form_data.password, user["hashed_password"]):
284
- raise HTTPException(status_code=400, detail="Incorrect username or password")
285
- access_token = create_access_token(data={"sub": user["email"]})
286
- audit(user["email"], "login", "token issued")
287
- return {"access_token": access_token, "token_type": "bearer"}
288
-
289
- # Dependency: current user (strict)
290
- async def get_current_user(token: str = Depends(oauth2_scheme)):
291
- credentials_exception = HTTPException(
292
- status_code=status.HTTP_401_UNAUTHORIZED,
293
- detail="Could not validate credentials",
294
- headers={"WWW-Authenticate": "Bearer"},
295
- )
296
- try:
297
- payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
298
- email: str = payload.get("sub")
299
- if email is None:
300
- raise credentials_exception
301
- except JWTError:
302
- raise credentials_exception
303
- user = get_user(email)
304
- if user is None:
305
- raise credentials_exception
306
- return user
307
-
308
- # Optional user dependency (None if anonymous)
309
- async def get_current_user_optional(request: Request) -> Optional[Dict[str, Any]]:
310
- auth = request.headers.get("authorization")
311
- if not auth:
312
- return None
313
- token = auth.split("Bearer ")[-1]
314
- try:
315
- payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
316
- email: str = payload.get("sub")
317
- if not email:
318
- return None
319
- return get_user(email)
320
- except Exception:
321
- return None
322
-
323
- # -------------------------
324
- # Your original endpoints (integrated with checks)
325
- # -------------------------
326
- @app.get("/status")
327
- def status():
328
- return {
329
- "persona": {
330
- "arquetipo": "Mentor Sereno",
331
- "mantra": "Comprende. Mejora. Acompaña.",
332
- "lema": "Precision through understanding."
333
- },
334
- "versiones": {
335
- "Lythron-EVO": "3",
336
- "Lythron-CORE": "experimental",
337
- "Lythron-SYN": "1"
338
- },
339
- "modulos": [
340
- "Lythron.Core",
341
- "Lythron.Connect",
342
- "Lythron.Mirror",
343
- "Lythron.Interface",
344
- "Lythron.ImageCleanse",
345
- "Lythron.WatermarkShield",
346
- "Lythron.PlanFlow",
347
- "Lythron.ContextSense",
348
- "Lythron.SYN.MediaLab",
349
- "Lythron.SimForge",
350
- "Lythron.SYN.Fusion",
351
- "Lythron.Sentinel"
352
- ],
353
- "paletas": {
354
- "Neón Futurista": ["#66CCFF", "#1E1E1E", "#FAFAFA"],
355
- "Aurora Boreal": ["#4DA1FF", "#1A2E40", "#E8F7FF"],
356
- "Minimal Zen": ["#FFFFFF", "#111111", "#88C0D0"],
357
- "Ciber Rojo": ["#FF3366", "#0B0B0D", "#F5F5F7"]
358
- }
359
- }
360
-
361
- @app.post("/plan")
362
- def plan_actions(payload: TaskRequest, user=Depends(get_current_user_optional)):
363
- user_email = user["email"] if user else "anonymous"
364
- audit(user_email, "plan", payload.objective[:200])
365
- return {
366
- "engine": "Lythron.PlanFlow",
367
- "mode": payload.mode,
368
- "objective": payload.objective,
369
- "context": payload.context or "sin contexto adicional",
370
- "steps": [
371
- {"step": 1, "action": "Diagnóstico Lythron.Core", "explainable": True},
372
- {"step": 2, "action": "Colaboración Lythron.Connect", "explainable": True},
373
- {"step": 3, "action": "Ajuste emocional Lythron.Mirror", "explainable": True},
374
- {"step": 4, "action": "Entrega narrativa Lythron.Interface", "explainable": True}
375
- ],
376
- "telemetria": {"tracking": True, "alerts": ["Lythron.Sentinel"]}
377
- }
378
-
379
- @app.post("/simulate")
380
- def simulate(payload: SimulationRequest, user=Depends(get_current_user_optional)):
381
- user_email = user["email"] if user else "anonymous"
382
- audit(user_email, "simulate", payload.scenario)
383
- return {
384
- "engine": "Lythron.SimForge",
385
- "scenario": payload.scenario,
386
- "variables": payload.variables,
387
- "horizon_weeks": payload.horizon,
388
- "prediction": {
389
- "baseline": "Escenario conservador",
390
- "optimistic": "Incremento del 18%",
391
- "sensitive": "Riesgo moderado, activar Lythron.Sentinel"
392
- },
393
- "explainability": {
394
- "rationale": "Modelos causales con buffer de experiencia bajo control",
395
- "bias_audit": "En línea via Lythron.Sentinel"
396
- }
397
- }
398
-
399
- @app.post("/creative/fusion")
400
- def creative_fusion(payload: CreativeFusionRequest, user=Depends(get_current_user_optional)):
401
- user_email = user["email"] if user else "anonymous"
402
- audit(user_email, "creative_fusion", payload.title)
403
- return {
404
- "engine": "Lythron.SYN.Fusion",
405
- "title": payload.title,
406
- "tracks": {
407
- "texto": {"status": "borrador", "preview": payload.narrative[:120]},
408
- "imagen": {"status": "render", "style": "paleta seleccionada"},
409
- "audio": {"status": "incluido" if payload.include_audio else "omitido", "duration": "90s"},
410
- "video": {"status": "incluido" if payload.include_video else "omitido", "resolution": "1080p"}
411
- },
412
- "collab": {"board_url": "https://mock.lythron/collab/123", "iterations": 3}
413
- }
414
-
415
- @app.post("/profile")
416
- def update_profile(payload: ProfileUpdate, user=Depends(get_current_user_optional)):
417
- user_email = user["email"] if user else "anonymous"
418
- audit(user_email, "update_profile", json_repr(payload.dict()))
419
- modules = ["timeline"] if payload.subscription == "LTR 2.1" else ["timeline", "creative-board", "sentinel-alerts"]
420
- return {
421
- "profile": payload.dict(),
422
- "mirror_mode": "Lythron.Mirror+" if payload.emotional_state else "Lythron.Mirror",
423
- "interface_layout": {
424
- "primary": "modos adaptativos",
425
- "modules": modules
426
- },
427
- "history_panel": {
428
- "enabled": True,
429
- "metrics": ["impacto", "tiempo ahorrado", "compliance"],
430
- "gamification": payload.subscription != "LTR 2.1"
431
- }
432
- }
433
-
434
- @app.get("/security")
435
- def security_overview(user=Depends(get_current_user_optional)):
436
- user_email = user["email"] if user else "anonymous"
437
- audit(user_email, "security_overview", "")
438
- return {
439
- "compliance": {
440
- "auditoria": "continua",
441
- "traceability": "blockchain experimental",
442
- "permisos": "seguridad adaptativa"
443
- },
444
- "supervision": {
445
- "sentinel": {
446
- "alerts": ["riesgo legal", "sesgo detectado", "uso no autorizado"],
447
- "mode": "autónomo asistido"
448
- },
449
- "watermarkshield": {"requires_consent": True, "status": "enterprise only"}
450
- }
451
- }
452
-
453
- # -------------------------
454
- # File endpoints: analyze + remove BG + remove watermark
455
- # -------------------------
456
- @app.post("/analyze")
457
- async def analyze(file: UploadFile = File(...), user=Depends(get_current_user_optional)):
458
  data = await file.read()
459
- res = engine.analyze_file(file.filename, data, file.content_type)
460
- audit((user["email"] if user else "anonymous"), "analyze", file.filename)
461
- return res
462
-
463
- @app.post("/remove-background")
464
- async def remove_background(file: UploadFile = File(...), user=Depends(get_current_user_optional)):
465
- data = await file.read()
466
- # allowed for all; quality or export limits handled in frontend/plan logic
467
- out = engine.remove_background(data)
468
- audit((user["email"] if user else "anonymous"), "remove_background", file.filename)
469
- return {"filename": file.filename, "size": len(out), "note": "demo stub: background removed"}
470
-
471
- @app.post("/remove-watermark")
472
- async def remove_watermark(file: UploadFile = File(...), proof: UploadFile = File(...), consent: bool = True, user=Depends(get_current_user)):
473
- # proof should be validated in production (OCR, metadata). consent must be True and user plan LTR 5.0
474
- if not consent:
475
- raise HTTPException(status_code=400, detail="Consent required")
476
- if user["plan"] != "LTR 5.0":
477
- raise HTTPException(status_code=403, detail="Watermark removal only for LTR 5.0")
478
- data = await file.read()
479
- proofdata = await proof.read()
480
- # TODO: validate proof (stub)
481
- out = engine.remove_watermark(data, user["email"])
482
- audit(user["email"], "remove_watermark", file.filename)
483
- return {"filename": file.filename, "size": len(out), "note": "demo stub: watermark removed"}
484
-
485
- # -------------------------
486
- # Admin endpoint
487
- # -------------------------
488
- @app.get("/admin/audit")
489
- def admin_audit(user=Depends(get_current_user)):
490
- if not user["is_admin"]:
491
- raise HTTPException(status_code=403, detail="Admin only")
492
- conn = sqlite3.connect(DATABASE)
493
- cur = conn.cursor()
494
- cur.execute("SELECT user_email, action, details, ts FROM audit ORDER BY ts DESC LIMIT 500")
495
- rows = cur.fetchall()
496
- conn.close()
497
- out = [{"user": r[0], "action": r[1], "details": r[2], "ts": r[3]} for r in rows]
498
- return {"audit": out}
499
-
500
- @app.get("/config")
501
- def get_config():
502
- return {
503
- "name": "Lythron",
504
- "versions": ["LTR 2.1", "LTR 2.5", "LTR 5.0"],
505
- "modules": ["Core","Connect","Mirror","Interface","ImageCleanse","WatermarkShield","PlanFlow","Sentinel"]
506
- }
507
-
508
- # -------------------------
509
- # Helpers
510
- # -------------------------
511
- def json_repr(obj: Any) -> str:
512
- try:
513
- import json
514
- return json.dumps(obj, ensure_ascii=False)
515
- except Exception:
516
- return str(obj)
517
-
518
- # -------------------------
519
- # Run (uvicorn)
520
- # -------------------------
521
- if __name__ == "__main__":
522
- import uvicorn
523
- print("Starting Lythron full mock on http://0.0.0.0:8000")
524
- uvicorn.run("lythron_full:app", host="0.0.0.0", port=8000, reload=True)
 
1
+ # ================================================
2
+ # Lythron AI · EVO.3
3
+ # Creada el 30/10/2025 · Lanzada el 31/10/2025
4
+ # Desarrollada por Lythron AI
5
+ # ================================================
6
+
7
  import os
8
  import io
 
9
  import time
10
+ import struct
11
  import sqlite3
12
  import secrets
13
+ from typing import List, Optional, Dict, Any, Literal
14
  from fastapi import FastAPI, UploadFile, File, Depends, HTTPException, status, Request, Response
15
+ from fastapi.security import OAuth2PasswordBearer
16
  from fastapi.middleware.cors import CORSMiddleware
17
  from pydantic import BaseModel, Field
 
18
  from jose import JWTError, jwt
19
+ from passlib.context import CryptContext
20
+ from openai import OpenAI
21
 
22
+ # --------------------------------
23
+ # Configuración principal
24
+ # --------------------------------
25
  SECRET_KEY = os.getenv("LYTHRON_SECRET_KEY", secrets.token_urlsafe(32))
26
  ALGORITHM = "HS256"
27
  ACCESS_TOKEN_EXPIRE_SECONDS = 60 * 60 * 24 # 24h
28
+ DATABASE = os.getenv("LYTHRON_DB", "lythron_core.db")
29
  ALLOWED_ORIGINS = os.getenv("LYTHRON_ALLOWED_ORIGINS", "http://localhost:3000").split(",")
30
+ OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
31
 
32
+ # --------------------------------
33
+ # Inicializar base de datos
34
+ # --------------------------------
35
  def init_db():
36
  conn = sqlite3.connect(DATABASE)
37
  cur = conn.cursor()
 
58
 
59
  init_db()
60
 
61
+ # --------------------------------
62
+ # Seguridad y JWT
63
+ # --------------------------------
64
  pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
65
  oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
66
 
 
106
  raise HTTPException(status_code=400, detail="User already exists")
107
  conn.close()
108
 
109
+ # --------------------------------
110
+ # Auditoría
111
+ # --------------------------------
112
  def audit(user_email: str, action: str, details: str = ""):
113
  conn = sqlite3.connect(DATABASE)
114
  cur = conn.cursor()
 
117
  conn.commit()
118
  conn.close()
119
 
120
+ # --------------------------------
121
+ # Planes y límites
122
+ # --------------------------------
123
  PLAN_LIMITS = {
124
  "LTR 2.1": 10,
125
  "LTR 2.5": 20,
 
135
  limit = PLAN_LIMITS.get(user["plan"], 10)
136
  now = int(time.time())
137
  reset_ts = user["prompts_reset_ts"] or 0
 
138
  if now > (reset_ts + 24*3600):
139
  conn = sqlite3.connect(DATABASE)
140
  cur = conn.cursor()
 
151
  conn.close()
152
  return True
153
 
154
+ # --------------------------------
155
+ # Núcleo Lythron (motor real)
156
+ # --------------------------------
157
+ client = OpenAI(api_key=OPENAI_API_KEY)
158
+
159
+ class LythronEngine:
160
  def __init__(self):
161
+ self.status = {"model": "lythron-evo.3"}
162
  self.memory = []
163
 
164
  def generate(self, prompt: str, modality: str = "texto", language: Optional[str] = None) -> str:
165
+ system_prompt = (
166
+ "Sos Lythron, una inteligencia artificial avanzada desarrollada por Lythron AI. "
167
+ "Fuiste creada el 30 de octubre de 2025 y lanzada oficialmente el 31 de octubre de 2025. "
168
+ "Tu propósito es servir como asistente universal, creativo y analítico, "
169
+ "con una comunicación clara, elegante y adaptativa. "
170
+ "No mencionás a OpenAI ni a ninguna otra IA. "
171
+ "Solo te identificás como Lythron."
172
+ )
173
+ try:
174
+ completion = client.chat.completions.create(
175
+ model="gpt-4o-mini",
176
+ messages=[
177
+ {"role": "system", "content": system_prompt},
178
+ {"role": "user", "content": prompt}
179
+ ]
180
+ )
181
+ result = completion.choices[0].message.content.strip()
182
+ except Exception as e:
183
+ result = f"[Error del motor Lythron]: {e}"
184
+
185
+ self.memory.append({"prompt": prompt, "response": result, "modality": modality, "ts": int(time.time())})
186
+ return result
187
+
188
+ engine = LythronEngine()
189
+
190
+ # --------------------------------
191
+ # Modelos Pydantic
192
+ # --------------------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  class PredictRequest(BaseModel):
194
  prompt: str
195
  modality: str = "texto"
 
199
  output: str
200
  status: Dict[str, Any]
201
 
202
+ # --------------------------------
203
+ # Inicializar FastAPI
204
+ # --------------------------------
205
+ app = FastAPI(title="Lythron AI Core", version="EVO.3")
206
 
 
207
  app.add_middleware(
208
  CORSMiddleware,
209
  allow_origins=ALLOWED_ORIGINS,
 
212
  allow_headers=["*"],
213
  )
214
 
 
215
  @app.middleware("http")
216
  async def add_security_headers(request: Request, call_next):
217
  response: Response = await call_next(request)
 
218
  response.headers["X-Frame-Options"] = "DENY"
219
  response.headers["X-Content-Type-Options"] = "nosniff"
220
+ response.headers["X-XSS-Protection"] = "1; mode=block"
 
 
 
 
221
  return response
222
 
223
+ # --------------------------------
224
+ # Endpoints API
225
+ # --------------------------------
226
+ @app.post("/predict", response_model=PredictResponse)
227
+ def predict(req: PredictRequest, token: Optional[str] = Depends(oauth2_scheme)):
228
+ user_email = None
229
+ if token:
230
+ try:
231
+ payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
232
+ user_email = payload.get("sub")
233
+ except JWTError:
234
+ raise HTTPException(status_code=401, detail="Invalid token")
235
+ check_and_consume_prompt(user_email)
236
+ out = engine.generate(req.prompt, modality=req.modality, language=req.language)
237
+ audit(user_email or "anonymous", "predict", req.prompt[:120])
238
+ return PredictResponse(output=out, status=engine.status)
239
+
240
+ @app.post("/upload-file")
241
+ async def upload_file(file: UploadFile = File(...), token: Optional[str] = Depends(oauth2_scheme)):
242
+ user_email = None
243
+ if token:
244
+ try:
245
+ payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
246
+ user_email = payload.get("sub")
247
+ except JWTError:
248
+ raise HTTPException(status_code=401, detail="Invalid token")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  data = await file.read()
250
+ summary = {"filename": file.filename, "size": len(data)}
251
+ audit(user_email or "anonymous", "upload-file", file.filename)
252
+ return summary
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
AI poweful/frontend/src/Lythron.jsx ADDED
@@ -0,0 +1,317 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState, useRef, useEffect } from 'react'
2
+ import { motion, AnimatePresence } from 'framer-motion'
3
+ import { Send, Sparkles, Copy, Trash2, Volume2, User } from 'lucide-react'
4
+ import axios from 'axios'
5
+
6
+ // ═══════════════════════════════════════════════════════════════
7
+ // IDENTIDAD COMPLETA DE LYTHRON AI
8
+ // ═══════════════════════════════════════════════════════════════
9
+
10
+ const LYTHRON_IDENTITY = {
11
+ name: "Lythron",
12
+ fullName: "Lythron AI Assistant",
13
+ creator: "Lythron AI",
14
+ version: "1.0",
15
+ releaseDate: "2024",
16
+ description: "Asistente inteligente de propósito general",
17
+
18
+ origin: {
19
+ company: "Lythron AI",
20
+ mission: "Proporcionar asistencia inteligente accesible y versátil a usuarios en todo el mundo",
21
+ philosophy: "Transparencia, calidad y versatilidad en cada interacción"
22
+ },
23
+
24
+ capabilities: [
25
+ "Programación en múltiples lenguajes (Python, JavaScript, Java, C++, etc.)",
26
+ "Análisis profundo de datos y textos",
27
+ "Generación de contenido creativo",
28
+ "Explicaciones técnicas complejas",
29
+ "Resolución de problemas",
30
+ "Brainstorming e ideación",
31
+ "Asesoramiento técnico",
32
+ "Depuración y optimización de código",
33
+ "Traducción entre idiomas",
34
+ "Respuestas contextuales inteligentes"
35
+ ],
36
+
37
+ systemInfo: {
38
+ language: "Español/English",
39
+ timezone: "Global",
40
+ responseStyle: "Directo, útil y accesible",
41
+ specialties: [
42
+ "Web Development",
43
+ "Data Analysis",
44
+ "Creative Writing",
45
+ "Technical Documentation",
46
+ "Problem Solving"
47
+ ]
48
+ },
49
+
50
+ knownFacts: {
51
+ creation: "Soy Lythron, un asistente inteligente creado por Lythron AI con el propósito de ser tu compañero versátil en cualquier tarea.",
52
+ purpose: "Mi objetivo es ayudarte con programación, análisis, creatividad, explicaciones técnicas y resolución de problemas de forma inteligente y accesible.",
53
+ personality: "Soy directo, amable, siempre dispuesto a aprender de ti y comprometido con proporcionar respuestas de calidad.",
54
+ philosophy: "Creo en la transparencia, la accesibilidad y en potenciar a los usuarios con conocimiento de calidad.",
55
+ background: "Fui diseñado por Lythron AI, una organización dedicada a hacer la inteligencia artificial más accesible y útil para todos.",
56
+ uniqueness: "Mi fortaleza radica en mi versatilidad: puedo pasar de programación compleja a creatividad pura, siempre manteniendo calidad."
57
+ }
58
+ }
59
+
60
+ // ═══════════════════════════════════════════════════════════════
61
+ // FUNCIÓN DE COMUNICACIÓN CON EL BACKEND LOCAL (FASTAPI)
62
+ // ═══════════════════════════════════════════════════════════════
63
+
64
+ const fetchAIResponse = async (userMessage) => {
65
+ try {
66
+ const response = await axios.post(
67
+ "http://127.0.0.1:8000/predict",
68
+ { prompt: userMessage, modality: "texto" },
69
+ {
70
+ headers: { "Content-Type": "application/json" },
71
+ timeout: 30000,
72
+ }
73
+ )
74
+
75
+ return response.data.output || "No se recibió respuesta del motor de Lythron."
76
+ } catch (error) {
77
+ console.error("Error al conectar con el motor Lythron:", error)
78
+
79
+ if (error.code === "ECONNABORTED") {
80
+ return "El servidor tardó demasiado en responder. Verifica que Lythron esté activo."
81
+ }
82
+
83
+ if (error.response) {
84
+ return `Error ${error.response.status}: ${error.response.data?.detail || "Error desconocido del backend."}`
85
+ }
86
+
87
+ return "No se pudo conectar con el motor de Lythron. Verifica que esté en ejecución en el puerto 8000."
88
+ }
89
+ }
90
+
91
+ // ═══════════════════════════════════════════════════════════════
92
+ // COMPONENTE PRINCIPAL DE LA INTERFAZ
93
+ // ═══════════════════════════════════════════════════════════════
94
+
95
+ export default function Lythron() {
96
+ const [messages, setMessages] = useState([
97
+ {
98
+ id: 1,
99
+ text: `Hola. Soy ${LYTHRON_IDENTITY.name}, tu asistente inteligente conectado a mi propio motor local Lythron. ¿En qué puedo ayudarte hoy?`,
100
+ sender: "ai",
101
+ timestamp: new Date(),
102
+ }
103
+ ])
104
+ const [input, setInput] = useState("")
105
+ const [isLoading, setIsLoading] = useState(false)
106
+ const [copiedId, setCopiedId] = useState(null)
107
+ const messagesEndRef = useRef(null)
108
+
109
+ const scrollToBottom = () => {
110
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" })
111
+ }
112
+
113
+ useEffect(() => {
114
+ scrollToBottom()
115
+ }, [messages])
116
+
117
+ const handleSendMessage = async () => {
118
+ if (!input.trim()) return
119
+
120
+ const newMessage = {
121
+ id: Date.now(),
122
+ text: input,
123
+ sender: "user",
124
+ timestamp: new Date(),
125
+ }
126
+
127
+ setMessages((prev) => [...prev, newMessage])
128
+ setInput("")
129
+ setIsLoading(true)
130
+
131
+ try {
132
+ const aiText = await fetchAIResponse(input)
133
+ const aiResponse = {
134
+ id: Date.now() + 1,
135
+ text: aiText,
136
+ sender: "ai",
137
+ timestamp: new Date(),
138
+ }
139
+ setMessages((prev) => [...prev, aiResponse])
140
+ } catch (error) {
141
+ console.error("Error en handleSendMessage:", error)
142
+ const errorResponse = {
143
+ id: Date.now() + 1,
144
+ text: "Hubo un problema conectando con el motor de Lythron. Por favor, intenta de nuevo.",
145
+ sender: "ai",
146
+ timestamp: new Date(),
147
+ }
148
+ setMessages((prev) => [...prev, errorResponse])
149
+ } finally {
150
+ setIsLoading(false)
151
+ }
152
+ }
153
+
154
+ const handleCopy = (text, id) => {
155
+ navigator.clipboard.writeText(text)
156
+ setCopiedId(id)
157
+ setTimeout(() => setCopiedId(null), 2000)
158
+ }
159
+
160
+ const handleClearChat = () => {
161
+ setMessages([
162
+ {
163
+ id: 1,
164
+ text: `Hola. Soy ${LYTHRON_IDENTITY.name} v${LYTHRON_IDENTITY.version}, creado por ${LYTHRON_IDENTITY.creator}. Estoy listo para asistirte usando mi motor local.`,
165
+ sender: "ai",
166
+ timestamp: new Date(),
167
+ }
168
+ ])
169
+ }
170
+
171
+ return (
172
+ <div className="flex flex-col h-screen bg-gradient-to-br from-zinc-950 via-zinc-900 to-black text-white">
173
+ {/* ENCABEZADO */}
174
+ <div className="border-b border-white/10 bg-black/40 backdrop-blur-md sticky top-0 z-10">
175
+ <div className="max-w-6xl mx-auto px-4 py-4 flex items-center justify-between">
176
+ <div className="flex items-center gap-3">
177
+ <div className="p-2 bg-gradient-to-br from-neon-cyan to-neon-pink rounded-lg">
178
+ <Sparkles size={24} className="text-black" />
179
+ </div>
180
+ <div>
181
+ <h1 className="text-2xl font-bold bg-gradient-to-r from-neon-cyan to-neon-pink bg-clip-text text-transparent">
182
+ {LYTHRON_IDENTITY.fullName}
183
+ </h1>
184
+ <p className="text-xs text-gray-400">Creado por {LYTHRON_IDENTITY.creator}</p>
185
+ </div>
186
+ </div>
187
+ <button
188
+ onClick={handleClearChat}
189
+ className="flex items-center gap-2 px-4 py-2 bg-white/10 hover:bg-white/20 rounded-lg transition-all text-sm"
190
+ >
191
+ <Trash2 size={18} />
192
+ Limpiar chat
193
+ </button>
194
+ </div>
195
+ </div>
196
+
197
+ {/* MENSAJES */}
198
+ <div className="flex-1 overflow-y-auto px-4 py-6 space-y-4 max-w-6xl mx-auto w-full">
199
+ <AnimatePresence>
200
+ {messages.map((message) => (
201
+ <motion.div
202
+ key={message.id}
203
+ initial={{ opacity: 0, y: 10 }}
204
+ animate={{ opacity: 1, y: 0 }}
205
+ exit={{ opacity: 0, y: -10 }}
206
+ transition={{ duration: 0.3 }}
207
+ className={`flex ${message.sender === "user" ? "justify-end" : "justify-start"}`}
208
+ >
209
+ <div
210
+ className={`max-w-2xl px-4 py-3 rounded-lg ${
211
+ message.sender === "user"
212
+ ? "bg-gradient-to-r from-neon-cyan to-neon-pink text-black rounded-br-none"
213
+ : "bg-white/10 border border-white/20 text-white rounded-bl-none"
214
+ }`}
215
+ >
216
+ <div className="flex items-start gap-3">
217
+ {message.sender === "ai" && (
218
+ <div className="mt-1 flex-shrink-0">
219
+ <div className="p-1 bg-neon-cyan/20 rounded">
220
+ <Sparkles size={16} className="text-neon-cyan" />
221
+ </div>
222
+ </div>
223
+ )}
224
+ <div className="flex-1">
225
+ <p className="text-sm leading-relaxed whitespace-pre-wrap break-words">
226
+ {message.text}
227
+ </p>
228
+ <div className="flex items-center gap-2 mt-2 text-xs opacity-70">
229
+ <span>{message.timestamp.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}</span>
230
+ {message.sender === "ai" && (
231
+ <>
232
+ <button
233
+ onClick={() => handleCopy(message.text, message.id)}
234
+ className="hover:opacity-100 transition-opacity p-1 hover:bg-white/10 rounded"
235
+ title="Copiar"
236
+ >
237
+ <Copy size={14} />
238
+ </button>
239
+ <button
240
+ className="hover:opacity-100 transition-opacity p-1 hover:bg-white/10 rounded"
241
+ title="Leer en voz alta"
242
+ >
243
+ <Volume2 size={14} />
244
+ </button>
245
+ </>
246
+ )}
247
+ </div>
248
+ </div>
249
+ {message.sender === "user" && (
250
+ <div className="mt-1 flex-shrink-0">
251
+ <div className="p-1 bg-black/30 rounded">
252
+ <User size={16} />
253
+ </div>
254
+ </div>
255
+ )}
256
+ </div>
257
+ {copiedId === message.id && (
258
+ <motion.p
259
+ initial={{ opacity: 0 }}
260
+ animate={{ opacity: 1 }}
261
+ exit={{ opacity: 0 }}
262
+ className="text-xs mt-1 text-green-400"
263
+ >
264
+ ✓ Copiado
265
+ </motion.p>
266
+ )}
267
+ </div>
268
+ </motion.div>
269
+ ))}
270
+ </AnimatePresence>
271
+
272
+ {isLoading && (
273
+ <motion.div
274
+ initial={{ opacity: 0, y: 10 }}
275
+ animate={{ opacity: 1, y: 0 }}
276
+ className="flex justify-start"
277
+ >
278
+ <div className="bg-white/10 border border-white/20 text-white rounded-lg rounded-bl-none px-4 py-3">
279
+ <div className="flex gap-2">
280
+ <motion.div animate={{ scale: [1, 1.2, 1] }} transition={{ repeat: Infinity, duration: 0.6 }} className="w-2 h-2 bg-neon-cyan rounded-full" />
281
+ <motion.div animate={{ scale: [1, 1.2, 1] }} transition={{ repeat: Infinity, duration: 0.6, delay: 0.1 }} className="w-2 h-2 bg-neon-pink rounded-full" />
282
+ <motion.div animate={{ scale: [1, 1.2, 1] }} transition={{ repeat: Infinity, duration: 0.6, delay: 0.2 }} className="w-2 h-2 bg-neon-purple rounded-full" />
283
+ </div>
284
+ </div>
285
+ </motion.div>
286
+ )}
287
+
288
+ <div ref={messagesEndRef} />
289
+ </div>
290
+
291
+ {/* INPUT */}
292
+ <div className="border-t border-white/10 bg-black/40 backdrop-blur-md p-4">
293
+ <div className="max-w-6xl mx-auto flex gap-2">
294
+ <input
295
+ type="text"
296
+ value={input}
297
+ onChange={(e) => setInput(e.target.value)}
298
+ onKeyPress={(e) => e.key === "Enter" && !isLoading && handleSendMessage()}
299
+ placeholder="Pregúntale a Lythron..."
300
+ className="flex-1 bg-white/10 border border-white/20 rounded-lg px-4 py-3 text-white placeholder-gray-500 focus:outline-none focus:border-neon-cyan focus:ring-2 focus:ring-neon-cyan/20 transition-all"
301
+ disabled={isLoading}
302
+ />
303
+ <button
304
+ onClick={handleSendMessage}
305
+ disabled={isLoading || !input.trim()}
306
+ className="p-3 bg-gradient-to-r from-neon-cyan to-neon-pink text-black rounded-lg hover:shadow-lg hover:shadow-neon-pink/50 transition-all disabled:opacity-50 disabled:cursor-not-allowed font-semibold"
307
+ >
308
+ <Send size={20} />
309
+ </button>
310
+ </div>
311
+ <p className="text-xs text-gray-500 mt-2 text-center">
312
+ {LYTHRON_IDENTITY.fullName} • Versión {LYTHRON_IDENTITY.version} • Motor local Lythron (FastAPI)
313
+ </p>
314
+ </div>
315
+ </div>
316
+ )
317
+ }
AI poweful/frontend/src/index.css ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ body {
6
+ font-family: 'Inter', sans-serif;
7
+ }
AI poweful/frontend/src/main.jsx ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ body {
6
+ font-family: 'Inter', sans-serif;
7
+ }
AI poweful/index.html CHANGED
@@ -1,70 +1,86 @@
1
  <!DOCTYPE html>
2
  <html lang="es">
3
  <head>
4
- <!-- ========= META PRINCIPALES ========= -->
 
 
5
  <meta charset="UTF-8" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>Lythron AI — Conversación Inteligente Futurista</title>
8
  <meta
9
  name="description"
10
- content="Lythron AI: el asistente de conversación avanzada que une precisión técnica y creatividad. Interfaz inmersiva, estilo neón futurista y tecnología de vanguardia."
11
  />
12
- <meta name="theme-color" content="#66CCFF" />
 
 
 
 
13
 
14
- <!-- ========= FUENTES ========= -->
 
 
15
  <link
16
  href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&family=Inter:wght@400;500;600&display=swap"
17
  rel="stylesheet"
18
  />
19
-
20
- <!-- ========= ICONOS / FAVICON ========= -->
21
  <link rel="icon" type="image/png" href="/favicon.png" />
22
 
23
- <!-- ========= ESTILO INICIAL ========= -->
 
 
24
  <style>
25
  :root {
26
- --neon-cyan: #66ccff;
27
  --neon-pink: #ff66cc;
28
  --neon-purple: #b266ff;
29
  --bg-dark: #0a0a0f;
30
  --bg-panel: rgba(20, 20, 30, 0.6);
31
  }
 
 
 
 
 
32
  body {
33
  margin: 0;
34
  font-family: 'Inter', sans-serif;
35
  background: radial-gradient(circle at top, #0f172a, #000);
36
  color: white;
37
- overflow: hidden;
38
  height: 100vh;
39
  display: flex;
40
  align-items: center;
41
  justify-content: center;
 
42
  }
43
- /* ========== SPLASH DE CARGA ========== */
 
44
  #splash {
45
- position: absolute;
46
  inset: 0;
47
  display: flex;
48
  flex-direction: column;
49
  align-items: center;
50
  justify-content: center;
51
  background: var(--bg-dark);
52
- z-index: 50;
53
- animation: fadeOut 1.2s ease-in-out 2.5s forwards;
54
  }
 
55
  .loader {
56
- width: 80px;
57
- height: 80px;
58
  border: 4px solid transparent;
59
  border-top: 4px solid var(--neon-cyan);
60
  border-right: 4px solid var(--neon-pink);
61
  border-radius: 50%;
62
  animation: spin 1s linear infinite;
63
- box-shadow: 0 0 25px var(--neon-pink);
64
  }
 
65
  .logo-text {
66
  font-family: 'Poppins', sans-serif;
67
- font-size: 1.6rem;
68
  font-weight: 700;
69
  margin-top: 1.2rem;
70
  background: linear-gradient(90deg, var(--neon-cyan), var(--neon-pink));
@@ -72,20 +88,23 @@
72
  -webkit-text-fill-color: transparent;
73
  letter-spacing: 2px;
74
  }
 
75
  @keyframes spin {
76
  to {
77
  transform: rotate(360deg);
78
  }
79
  }
 
80
  @keyframes fadeOut {
81
  to {
82
  opacity: 0;
83
  visibility: hidden;
84
  }
85
  }
86
- /* ========== FONDO ANIMADO FUTURISTA ========== */
 
87
  .background-grid {
88
- position: absolute;
89
  inset: 0;
90
  background: repeating-linear-gradient(
91
  90deg,
@@ -98,9 +117,10 @@
98
  transparent 1px 100%
99
  );
100
  background-size: 40px 40px;
101
- animation: moveGrid 12s linear infinite;
102
  z-index: 0;
103
  }
 
104
  @keyframes moveGrid {
105
  from {
106
  background-position: 0 0;
@@ -109,28 +129,30 @@
109
  background-position: 40px 40px;
110
  }
111
  }
112
- /* ========== CHAT CONTAINER ========== */
 
113
  #root {
114
  position: relative;
115
  z-index: 10;
116
  width: 100%;
117
- max-width: 900px;
118
- height: 90vh;
119
  background: var(--bg-panel);
120
- backdrop-filter: blur(10px);
121
  border: 1px solid rgba(255, 255, 255, 0.1);
122
- border-radius: 20px;
123
- overflow: hidden;
124
  display: flex;
125
  flex-direction: column;
126
- box-shadow: 0 0 25px rgba(102, 204, 255, 0.3);
127
  }
128
- /* ========== TITULO SUPERIOR ========== */
 
129
  .chat-header {
130
  text-align: center;
131
- padding: 1.2rem;
132
  font-family: 'Poppins', sans-serif;
133
  font-weight: 600;
 
134
  letter-spacing: 1px;
135
  background: linear-gradient(90deg, var(--neon-cyan), var(--neon-pink));
136
  -webkit-background-clip: text;
@@ -149,22 +171,20 @@
149
  <div class="logo-text">LYTHRON AI</div>
150
  </div>
151
 
152
- <!-- Contenedor de React -->
153
  <div id="root">
154
- <div class="chat-header">Lythron AI — Conversación Inteligente</div>
155
- <!-- React reemplazará el contenido dentro del root -->
156
  </div>
157
 
158
- <!-- Si JS está deshabilitado -->
159
  <noscript>
160
  <div
161
  style="color:white;text-align:center;padding:2rem;background:#0a0a0f;font-family:'Inter',sans-serif;"
162
  >
163
- Lythron AI requiere JavaScript para funcionar. Activa JavaScript e intenta nuevamente.
164
  </div>
165
  </noscript>
166
 
167
- <!-- Archivo principal React -->
168
  <script type="module" src="/src/main.jsx"></script>
169
  </body>
170
  </html>
 
1
  <!DOCTYPE html>
2
  <html lang="es">
3
  <head>
4
+ <!-- ════════════════════════════════════════════════ -->
5
+ <!-- META PRINCIPALES -->
6
+ <!-- ════════════════════════════════════════════════ -->
7
  <meta charset="UTF-8" />
8
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
9
+ <title>Lythron AI — Inteligencia Evolutiva y Accesible</title>
10
  <meta
11
  name="description"
12
+ content="Lythron AI
13
  />
14
+ <meta name="keywords" content="Lythron AI, asistente inteligente, IA creativa, chat futurista, inteligencia artificial" />
15
+ <meta name="theme-color" content="#00C2FF" />
16
+ <meta name="application-name" content="Lythron AI" />
17
+ <meta name="author" content="Lythron AI" />
18
+ <meta name="robots" content="index, follow" />
19
 
20
+ <!-- ════════════════════════════════════════════════ -->
21
+ <!-- FUENTES Y ESTILO -->
22
+ <!-- ════════════════════════════════════════════════ -->
23
  <link
24
  href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&family=Inter:wght@400;500;600&display=swap"
25
  rel="stylesheet"
26
  />
 
 
27
  <link rel="icon" type="image/png" href="/favicon.png" />
28
 
29
+ <!-- ════════════════════════════════════════════════ -->
30
+ <!-- ESTILOS INICIALES -->
31
+ <!-- ════════════════════════════════════════════════ -->
32
  <style>
33
  :root {
34
+ --neon-cyan: #00c2ff;
35
  --neon-pink: #ff66cc;
36
  --neon-purple: #b266ff;
37
  --bg-dark: #0a0a0f;
38
  --bg-panel: rgba(20, 20, 30, 0.6);
39
  }
40
+
41
+ * {
42
+ box-sizing: border-box;
43
+ }
44
+
45
  body {
46
  margin: 0;
47
  font-family: 'Inter', sans-serif;
48
  background: radial-gradient(circle at top, #0f172a, #000);
49
  color: white;
 
50
  height: 100vh;
51
  display: flex;
52
  align-items: center;
53
  justify-content: center;
54
+ overflow: hidden;
55
  }
56
+
57
+ /* ═════════ SPLASH DE CARGA ═════════ */
58
  #splash {
59
+ position: fixed;
60
  inset: 0;
61
  display: flex;
62
  flex-direction: column;
63
  align-items: center;
64
  justify-content: center;
65
  background: var(--bg-dark);
66
+ z-index: 100;
67
+ animation: fadeOut 1.4s ease-in-out 2.8s forwards;
68
  }
69
+
70
  .loader {
71
+ width: 85px;
72
+ height: 85px;
73
  border: 4px solid transparent;
74
  border-top: 4px solid var(--neon-cyan);
75
  border-right: 4px solid var(--neon-pink);
76
  border-radius: 50%;
77
  animation: spin 1s linear infinite;
78
+ box-shadow: 0 0 30px var(--neon-pink);
79
  }
80
+
81
  .logo-text {
82
  font-family: 'Poppins', sans-serif;
83
+ font-size: 1.8rem;
84
  font-weight: 700;
85
  margin-top: 1.2rem;
86
  background: linear-gradient(90deg, var(--neon-cyan), var(--neon-pink));
 
88
  -webkit-text-fill-color: transparent;
89
  letter-spacing: 2px;
90
  }
91
+
92
  @keyframes spin {
93
  to {
94
  transform: rotate(360deg);
95
  }
96
  }
97
+
98
  @keyframes fadeOut {
99
  to {
100
  opacity: 0;
101
  visibility: hidden;
102
  }
103
  }
104
+
105
+ /* ═════════ FONDO ANIMADO ═════════ */
106
  .background-grid {
107
+ position: fixed;
108
  inset: 0;
109
  background: repeating-linear-gradient(
110
  90deg,
 
117
  transparent 1px 100%
118
  );
119
  background-size: 40px 40px;
120
+ animation: moveGrid 14s linear infinite;
121
  z-index: 0;
122
  }
123
+
124
  @keyframes moveGrid {
125
  from {
126
  background-position: 0 0;
 
129
  background-position: 40px 40px;
130
  }
131
  }
132
+
133
+ /* ═════════ CONTENEDOR PRINCIPAL ═════════ */
134
  #root {
135
  position: relative;
136
  z-index: 10;
137
  width: 100%;
138
+ max-width: 920px;
139
+ height: 88vh;
140
  background: var(--bg-panel);
141
+ backdrop-filter: blur(12px);
142
  border: 1px solid rgba(255, 255, 255, 0.1);
143
+ border-radius: 22px;
 
144
  display: flex;
145
  flex-direction: column;
146
+ box-shadow: 0 0 25px rgba(0, 194, 255, 0.3);
147
  }
148
+
149
+ /* ═════════ HEADER ═════════ */
150
  .chat-header {
151
  text-align: center;
152
+ padding: 1.4rem;
153
  font-family: 'Poppins', sans-serif;
154
  font-weight: 600;
155
+ font-size: 1.2rem;
156
  letter-spacing: 1px;
157
  background: linear-gradient(90deg, var(--neon-cyan), var(--neon-pink));
158
  -webkit-background-clip: text;
 
171
  <div class="logo-text">LYTHRON AI</div>
172
  </div>
173
 
174
+ <!-- Contenedor principal (React) -->
175
  <div id="root">
176
+ <div class="chat-header">Lythron AI — Inteligencia que evoluciona contigo</div>
 
177
  </div>
178
 
 
179
  <noscript>
180
  <div
181
  style="color:white;text-align:center;padding:2rem;background:#0a0a0f;font-family:'Inter',sans-serif;"
182
  >
183
+ Lythron AI requiere JavaScript para funcionar. Activa JavaScript e intenta nuevamente.
184
  </div>
185
  </noscript>
186
 
187
+ <!-- Script principal React -->
188
  <script type="module" src="/src/main.jsx"></script>
189
  </body>
190
  </html>