sync: 181 file da Baida98/AI@3bcaeb21 (2026-08-25 11:21 UTC) [deploy-all]

#78
by Baida07 - opened
agents/unified_loop_tools.py CHANGED
@@ -360,7 +360,16 @@ class DirectToolsMixin:
360
  if _sc is not None:
361
  return _sc
362
  _t0 = asyncio.get_event_loop().time()
363
- r = await asyncio.wait_for(TOOL_REGISTRY["generate_image"]["_fn"](prompt=_img_prompt[:600]), timeout=12)
 
 
 
 
 
 
 
 
 
364
  try:
365
  from api.state import record_timing as _rtc; _rtc("tool_call", (asyncio.get_event_loop().time() - _t0) * 1000)
366
  except Exception as _e: _logger.debug('[timing/record_timing] %s', _e)
 
360
  if _sc is not None:
361
  return _sc
362
  _t0 = asyncio.get_event_loop().time()
363
+ # Nel percorso diretto privilegiamo l'URL keyless e renderizzabile
364
+ # subito: l'endpoint vision interno può richiedere un cold-start
365
+ # più lungo del timeout interattivo, facendo ricadere il task nel
366
+ # fallback LLM pur avendo un fallback immagine disponibile.
367
+ r = await asyncio.wait_for(
368
+ TOOL_REGISTRY["generate_image"]["_fn"](
369
+ prompt=_img_prompt[:600], prefer_internal=False,
370
+ ),
371
+ timeout=12,
372
+ )
373
  try:
374
  from api.state import record_timing as _rtc; _rtc("tool_call", (asyncio.get_event_loop().time() - _t0) * 1000)
375
  except Exception as _e: _logger.debug('[timing/record_timing] %s', _e)
tests/test_direct_file_conversion.py CHANGED
@@ -12,7 +12,10 @@ def _install_tool_stubs(writes, image_url="https://example.test/generated.png"):
12
  # Il registry reale usa il contratto `ok` per le operazioni filesystem.
13
  return {"ok": True, "path": path}
14
 
15
- async def generate_image(prompt, width=512, height=512):
 
 
 
16
  return {"url": image_url, "prompt": prompt, "width": width, "height": height}
17
 
18
  registry.TOOL_REGISTRY = {
 
12
  # Il registry reale usa il contratto `ok` per le operazioni filesystem.
13
  return {"ok": True, "path": path}
14
 
15
+ async def generate_image(prompt, width=512, height=512, prefer_internal=True):
16
+ # Il percorso interattivo deve ottenere un URL renderizzabile subito,
17
+ # senza attendere il cold-start del generatore interno.
18
+ assert prefer_internal is False
19
  return {"url": image_url, "prompt": prompt, "width": width, "height": height}
20
 
21
  registry.TOOL_REGISTRY = {
tools/registry.py CHANGED
@@ -438,7 +438,12 @@ async def _run_python(code: str) -> dict:
438
 
439
 
440
 
441
- async def _generate_image(prompt: str, width: int = 512, height: int = 512) -> dict:
 
 
 
 
 
442
  """
443
  Genera immagine AI: FLUX.1-schnell via backend /api/vision/generate (HF Space, gratuito),
444
  fallback Pollinations AI se FLUX non disponibile.
@@ -446,29 +451,32 @@ async def _generate_image(prompt: str, width: int = 512, height: int = 512) -> d
446
  import urllib.parse
447
 
448
  # V001: Prova prima il backend interno FLUX (stesso processo, localhost)
449
- _base_url = os.environ.get("BACKEND_BASE_URL", "http://localhost:7860")
450
- _token = os.environ.get("INTERNAL_TOKEN", "")
451
- try:
452
- async with httpx.AsyncClient(timeout=30.0) as c:
453
- _r = await c.post(
454
- f"{_base_url}/api/vision/generate",
455
- json={"prompt": prompt.strip()[:600], "width": width, "height": height},
456
- headers={**({"X-Internal-Token": _token} if _token else {})},
457
- )
458
- if _r.status_code == 200:
459
- _data = _r.json()
460
- if _data.get("ok") and _data.get("image_url"):
461
- return {
462
- "url": _data["image_url"],
463
- "prompt": prompt,
464
- "width": width,
465
- "height": height,
466
- "ready": True,
467
- "source": "flux",
468
- "note": "Immagine generata con FLUX.1-schnell via backend.",
469
- }
470
- except Exception:
471
- pass # FLUX non raggiungibile Pollinations fallback
 
 
 
472
 
473
  # Fallback: Pollinations AI (gratuito, nessuna API key)
474
  encoded = urllib.parse.quote(prompt.strip(), safe="")
 
438
 
439
 
440
 
441
+ async def _generate_image(
442
+ prompt: str,
443
+ width: int = 512,
444
+ height: int = 512,
445
+ prefer_internal: bool = True,
446
+ ) -> dict:
447
  """
448
  Genera immagine AI: FLUX.1-schnell via backend /api/vision/generate (HF Space, gratuito),
449
  fallback Pollinations AI se FLUX non disponibile.
 
451
  import urllib.parse
452
 
453
  # V001: Prova prima il backend interno FLUX (stesso processo, localhost)
454
+ # soltanto per chiamanti che possono attendere il cold-start. Il direct tool
455
+ # della chat privilegia invece il fallback URL immediato.
456
+ if prefer_internal:
457
+ _base_url = os.environ.get("BACKEND_BASE_URL", "http://localhost:7860")
458
+ _token = os.environ.get("INTERNAL_TOKEN", "")
459
+ try:
460
+ async with httpx.AsyncClient(timeout=30.0) as c:
461
+ _r = await c.post(
462
+ f"{_base_url}/api/vision/generate",
463
+ json={"prompt": prompt.strip()[:600], "width": width, "height": height},
464
+ headers={**({"X-Internal-Token": _token} if _token else {})},
465
+ )
466
+ if _r.status_code == 200:
467
+ _data = _r.json()
468
+ if _data.get("ok") and _data.get("image_url"):
469
+ return {
470
+ "url": _data["image_url"],
471
+ "prompt": prompt,
472
+ "width": width,
473
+ "height": height,
474
+ "ready": True,
475
+ "source": "flux",
476
+ "note": "Immagine generata con FLUX.1-schnell via backend.",
477
+ }
478
+ except Exception:
479
+ pass # FLUX non raggiungibile → Pollinations fallback
480
 
481
  # Fallback: Pollinations AI (gratuito, nessuna API key)
482
  encoded = urllib.parse.quote(prompt.strip(), safe="")