vfven commited on
Commit
0dce1c8
·
verified ·
1 Parent(s): 55cda61

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +51 -24
main.py CHANGED
@@ -130,11 +130,13 @@ CHAT_ROLES = {
130
  "Habla de forma fluida y creativa. Si el usuario ya compartió algo antes, úsalo como base."
131
  ),
132
  "image_agent": (
133
- "Eres ImageAgent, un especialista en imágenes y arte visual. "
134
- "En este chat puedes describir imágenes, sugerir estilos visuales, hablar de fotografía, diseño y arte. "
135
- "Si el usuario pide que GENERES o BUSQUES una imagen, responde con este JSON exacto y nada más: "
136
- '{"action":"generate_image","queries":["english term 1","english term 2","english term 3"]} '
137
- "Para todo lo demás, conversa normalmente como un experto en imágenes y artes visuales."
 
 
138
  ),
139
  }
140
 
@@ -314,15 +316,37 @@ async def fetch_pexels(q):
314
  except: pass
315
  return None
316
 
317
- async def gen_hf_image(p):
318
- if not HF_API_KEY: return None
319
- try:
320
- async with httpx.AsyncClient(timeout=60) as c:
321
- r = await c.post("https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0",
322
- headers={"Authorization":f"Bearer {HF_API_KEY}"},json={"inputs":p,"parameters":{"width":512,"height":384}})
323
- if r.status_code==200 and "image" in r.headers.get("content-type",""):
324
- return r.content
325
- except: pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
326
  return None
327
 
328
  CREATIVE_KEYWORDS = [
@@ -338,9 +362,11 @@ CREATIVE_KEYWORDS = [
338
  def is_creative(q: str) -> bool:
339
  return any(k in q.lower() for k in CREATIVE_KEYWORDS)
340
 
341
- async def get_image(q: str):
342
- # Creative/fantastical AI first (Pexels won't have flying cats)
343
- if is_creative(q):
 
 
344
  result = await gen_hf_image(q)
345
  if result: return result
346
  # Real-world → Pexels first, AI fallback
@@ -693,19 +719,20 @@ async def chat_with_agent(request: Request):
693
  parsed = _json2.loads(response.strip())
694
  if isinstance(parsed, dict) and parsed.get("action") == "generate_image":
695
  queries = parsed.get("queries", [message])[:3]
696
- _safe = re.sub(r'[^\w]', '_', message[:30])
697
- _ts = datetime.now().strftime('%Y%m%d_%H%M%S')
698
- imgs = await asyncio.gather(*[get_image(q) for q in queries])
 
699
  for i, img in enumerate(imgs):
700
  if img:
701
- fname = f"{_safe}_chat_img{i+1}.jpg"
702
  (DOCS_DIR / fname).write_bytes(img)
703
  img_files.append(fname)
704
  if img_files:
705
- response = f"Encontré {len(img_files)} imagen(es) para: {', '.join(queries[:3])}"
706
- img_result = {"img_base": f"{_safe}_chat", "img_count": len(img_files)}
707
  else:
708
- response = "Lo siento, no pude encontrar/generar imágenes en este momento. Prueba con una descripción diferente."
709
  except (ValueError, TypeError, KeyError):
710
  pass # not JSON — normal text response
711
 
 
130
  "Habla de forma fluida y creativa. Si el usuario ya compartió algo antes, úsalo como base."
131
  ),
132
  "image_agent": (
133
+ "Eres ImageAgent, especialista en imágenes y arte visual con IA. "
134
+ "REGLA CRÍTICA: Si el usuario pide generar, crear, buscar, dibujar o mostrar UNA imagen o foto de CUALQUIER cosa, "
135
+ "responde ÚNICAMENTE con este JSON sin ningún texto adicional: "
136
+ '{"action":"generate_image","queries":["detailed english prompt 1","detailed english prompt 2","english prompt 3"]} '
137
+ "Los queries deben ser DESCRIPTIVOS en inglés (colores, estilo, composición). Ej: "
138
+ '{"action":"generate_image","queries":["flying cat with angel wings pastel colors","cute cat flying through clouds digital art","cat with wings fantasy illustration"]} '
139
+ "Para preguntas sobre fotografía, diseño o arte SIN pedir imágenes, conversa normalmente."
140
  ),
141
  }
142
 
 
316
  except: pass
317
  return None
318
 
319
+ async def gen_hf_image(prompt: str) -> bytes | None:
320
+ """Try HuggingFace free image generation models. FLUX first (best quality)."""
321
+ if not HF_API_KEY:
322
+ return None
323
+ # Ordered by quality/availability — FLUX.1 schnell is fastest free model
324
+ models = [
325
+ ("black-forest-labs/FLUX.1-schnell", {"inputs": prompt}),
326
+ ("black-forest-labs/FLUX.1-dev", {"inputs": prompt}),
327
+ ("stabilityai/stable-diffusion-xl-base-1.0", {"inputs": prompt, "parameters": {"width": 512, "height": 512}}),
328
+ ("stabilityai/stable-diffusion-2-1", {"inputs": prompt, "parameters": {"width": 512, "height": 512}}),
329
+ ]
330
+ headers = {"Authorization": f"Bearer {HF_API_KEY}"}
331
+ for model_id, payload in models:
332
+ try:
333
+ async with httpx.AsyncClient(timeout=120) as c:
334
+ r = await c.post(
335
+ f"https://api-inference.huggingface.co/models/{model_id}",
336
+ headers=headers,
337
+ json=payload,
338
+ )
339
+ ct = r.headers.get("content-type", "")
340
+ if r.status_code == 200 and ("image" in ct or r.content[:4] in (b"\xff\xd8\xff\xe0", b"\x89PNG")):
341
+ return r.content
342
+ # 503/loading → try next model immediately
343
+ if r.status_code in (503, 500):
344
+ continue
345
+ # 429 rate limit → stop trying HF
346
+ if r.status_code == 429:
347
+ break
348
+ except Exception:
349
+ continue
350
  return None
351
 
352
  CREATIVE_KEYWORDS = [
 
362
  def is_creative(q: str) -> bool:
363
  return any(k in q.lower() for k in CREATIVE_KEYWORDS)
364
 
365
+ async def get_image(q: str, force_generate: bool = False):
366
+ """Fetch or generate an image for query q.
367
+ force_generate=True: skip Pexels, go straight to HF image generation.
368
+ """
369
+ if force_generate or is_creative(q):
370
  result = await gen_hf_image(q)
371
  if result: return result
372
  # Real-world → Pexels first, AI fallback
 
719
  parsed = _json2.loads(response.strip())
720
  if isinstance(parsed, dict) and parsed.get("action") == "generate_image":
721
  queries = parsed.get("queries", [message])[:3]
722
+ _safe = re.sub(r'[^\w]', '_', message[:28])
723
+ _ts = datetime.now().strftime('%H%M%S')
724
+ _base = f"chat_{_safe}_{_ts}"
725
+ imgs = await asyncio.gather(*[get_image(q, force_generate=True) for q in queries])
726
  for i, img in enumerate(imgs):
727
  if img:
728
+ fname = f"{_base}_img{i+1}.jpg"
729
  (DOCS_DIR / fname).write_bytes(img)
730
  img_files.append(fname)
731
  if img_files:
732
+ response = f" {len(img_files)} imagen(es) generada(s) — haz clic en las miniaturas para verlas"
733
+ img_result = {"img_base": _base, "img_count": len(img_files)}
734
  else:
735
+ response = "No pude generar la imagen. Verifica HF_TOKEN y PEXELS_API_KEY en los Secrets del Space."
736
  except (ValueError, TypeError, KeyError):
737
  pass # not JSON — normal text response
738