ó
    dÉj=  ã                   óÈ   • % S r SSKrSSKrSSKJr  \R
                  " \5      rSrSr	Sr
Sr0 r\\\4   \S'   S	\S
\4S jrS\S\S	\S
S4S jrS\S
S4S jrS\S
\\   4S jrg)u  
Salud de los servicios de IA por tenant â€” el canal por el que un fallo de fondo
llega a la pantalla.

La generaciÃ³n anticipada y el pre-recorte de fondo los lanza el organizador, sin
nadie delante. El dÃ­a que la cuenta se quedÃ³ sin saldo, el Ãºnico rastro fueron
unas lÃ­neas de log en el servidor: en pantalla no pasaba nada, las fotos se
organizaban con normalidad y simplemente no aparecÃ­an las versiones IA. AquÃ­ se
guarda el Ãºltimo fallo definitivo de cada tenant y `/api/organizer/status` lo
devuelve junto al resto del estado â€” el front ya sondea ese endpoint, asÃ­ que no
hace falta ni un endpoint ni un sondeo mÃ¡s.

Dos reglas que definen lo que se guarda:

- **SÃ³lo fallos definitivos.** Quien registra lo hace DESPUÃ‰S de `with_retries`,
  nunca dentro. Los 5xx esporÃ¡dicos del proveedor bajo carga se resuelven solos
  en el siguiente intento; encender un aviso por cada uno enseÃ±arÃ­a a ignorarlos,
  que es justo lo que no puede pasar con el que sÃ­ importa.
- **Un Ã©xito lo borra.** El estado responde Â«Â¿funciona ahora?Â», no Â«Â¿fallÃ³ alguna
  vez?Â». Y caduca por su cuenta (`_TTL_SECS`): un fallo de hace horas del que
  nadie ha vuelto a saber no debe recibir a quien abre la aplicaciÃ³n por la
  tarde.

`code` distingue el caso que no se arregla reintentando (`no_credits`) del resto
(`error`), porque son dos acciones distintas: recargar la cuenta o mirar el log.
El texto crudo del proveedor se queda en el log y NO viaja al front: nombra al
servicio externo, y eso no tiene por quÃ© acabar en la pantalla de un cliente.
é    N)ÚOptionali  ÚiaÚnobgÚheadsÚ_stateÚexcÚreturnc                 ó^   • [        [        U SU 5      5      R                  5       nSU;   a  S$ S$ )u˜   `no_credits` es el Ãºnico caso que merece su propio mensaje: el proveedor
responde 400 y no hay reintento que lo arregle â€” hay que recargar la cuenta.Údetailzinsufficient creditsÚ
no_creditsÚerror)ÚstrÚgetattrÚlower)r   Úmsgs     ÚUD:\Ingenieria\TRABAJOS ONLINE\Projects\11- Photo School\backend\services\ai_health.pyÚ	_classifyr   /   s2   € ô Œg�c˜8 SÓ)Ó
*×
0Ñ
0Ó
2€CØ1°SÓ8ˆ<ÐE¸gÐEó    Ú
short_codeÚtaskc                 óÊ   • U (       d  g[        U5      n[        R                  U 5      nU(       a  US   U:X  a  US   S-   OSnUUU[        R                  " 5       S.[        U '   g)zFRegistra un fallo YA definitivo (reintentos agotados o no aplicables).NÚcodeÚcounté   )r   r   r   Úat)r   r   ÚgetÚtime)r   r   r   r   Úprevr   s         r   Úrecord_failurer   6   s\   € æØÜ�S‹>€DÜ�:‰:�jÓ!€Dö "&¨$¨v©,¸$Ó*>ˆD�‰M˜AÒÀA€EàØØÜ�iŠi‹kñ	„Fˆ:Òr   c                 óz   • U (       a4  [         R                  U S5      (       a  [        R                  SU SS0S9  ggg)uI   Una llamada que sÃ­ funcionÃ³: el servicio estÃ¡ vivo, se borra el aviso.Nu*   ðŸŸ¢ [%s] servicios IA operativos de nuevoÚauditT)Úextra)r   ÚpopÚloggerÚinfo)r   s    r   Úrecord_successr&   G   s6   € æ”f—j‘j ¨T×2Ñ2ä�‰Ð@À*ÐU\Ð^bÐTcˆÒdð 3€zr   c                 óè   • [         R                  U 5      nU(       d  g[        R                  " 5       US   -
  nU[        :”  a  [         U 	 gUS   US   US   [	        U5      [	        US   S-  5      S.$ )u  Estado para el front, o `None` si no hay nada que contar.

Devuelve `at` en segundos de antigÃ¼edad en vez de una marca de tiempo: el
front sÃ³lo necesita saber si es el mismo episodio del que ya avisÃ³, y una
edad no depende de que el reloj del navegador coincida con el del servidor.
Nr   r   r   r   iè  )r   r   r   Úseconds_agoÚepisode)r   r   r   Ú	_TTL_SECSÚint)r   ÚstÚages      r   Ú
get_statusr.   N   sv   € ô 
�‰�JÓ	€BÞØÜ
�)Š)‹+˜˜4™Ñ
 €CØ
ŒYƒÜ�:ÐØà�6‘
Ø�6‘
Ø�G‘Ü˜3“xô �r˜$‘x $‘Ó'ñð r   )Ú__doc__Úloggingr   Útypingr   Ú	getLoggerÚ__name__r$   r*   ÚTASK_IAÚ	TASK_NOBGÚ
TASK_HEADSr   Údictr   Ú__annotations__ÚBaseExceptionr   r   r&   r.   © r   r   Ú<module>r;      s³   ðòó8 Û Ý à	×	Ò	˜8Ó	$€ð €	ð €Ø€	Ø€
à€ˆˆS�$ˆY‰Ó ðF�=ð F Sô Fð˜sð ¨#ð °Mð Àdô ð"e˜sð e tô eð˜3ð  8¨D¡>õ r   