Ë
    H¨j>  ã                  óB  — d Z ddlmZ ddlZddlmZmZmZ ddlm	Z	 ddl
mZmZ ddlmZmZmZ dd	lmZ dd
lmZmZmZmZ ddlmZ ddlmZ ddlmZ ddlmZ ddl m!Z!  edg¬«      Z" G d„ de«      Z# G d„ de«      Z$d d„Z%e"jM                  d«      d ee«       ee«      fd!d„«       Z'e"jQ                  d«       ee«       ee«      fd"d„«       Z)e"jM                  d«       ee«       ee«      fd#d„«       Z*e"jQ                  d«       ee«       ee«      fd$d„«       Z+y)%z'Optional Claude reviews of a draft run.é    )ÚannotationsN)Ú	APIRouterÚDependsÚHTTPException)Ú
Connection)Ú	BaseModelÚFieldé   )ÚUserÚcurrent_userÚrequire_center)Úconfig_by_id)ÚJsonbÚfetchallÚfetchoneÚget_conn)Úfind_analogs)Úclaude)Úget_settingsé   )Ú_query_from_inputs)Ú	_load_runÚai)Útagsc                  óB   — e Zd ZU ded<    ed¬«      Zded<   dZded	<   y)
ÚReviewInÚintÚrun_idz/^(review_draft|draft_bottom_line|sanity_check)$)ÚpatternÚstrÚmodeNú
str | NoneÚmodel)Ú__name__Ú
__module__Ú__qualname__Ú__annotations__r	   r!   r#   © ó    ú+/var/www/avy-guidance/api/app/routers/ai.pyr   r      s!   … ØƒKÙÐOÔP€Dˆ#ÓPØ€Eˆ:Ôr)   r   c                  ó:   — e Zd ZU  edd¬«      Zded<   dZded<   y)	Ú
FeedbackInéÿÿÿÿr   )ÚgeÚler   ÚfeedbackNr"   Únote)r$   r%   r&   r	   r0   r'   r1   r(   r)   r*   r,   r,      s   … Ù˜R AÔ&€HˆcÓ&Ø€Dˆ*Ôr)   r,   c                ó:   — t        | d|f«      }t        |d   «      S )NzxSELECT coalesce(sum(cost_usd), 0) AS s FROM ai_reviews WHERE center_id = %s AND created_at >= date_trunc('month', now())Ús)r   Úfloat)ÚconnÚ	center_idÚrows      r*   Ú_month_spendr8   !   s*   € Ü
Øð 	CØ	ˆó€Cô
 ��S‘‹?Ðr)   z
/ai/statusc                óÂ   — t        «       }t        j                  «       |j                  |j                  |j
                  dœ}| �t        || «       t        || «      |d<   |S )N)ÚenabledÚmodelsÚdefault_modelÚmonthly_cap_usdÚmonth_spend_usd)r   r   r:   Úai_allowed_modelsÚai_default_modelÚai_monthly_cap_usdr   r8   )r6   r5   Úuserr3   Úouts        r*   ÚstatusrD   *   s[   € ä‹€AÜ—n‘nÓ&°!×2EÑ2EÐXY×XjÑXjØ×2Ñ2ñ4€CàÐÜ�t˜YÔ'Ü!-¨d°IÓ!>ˆÐÑØ€Jr)   z
/ai/reviewc                ó¤  — t        «       }t        j                  «       st        dd«      ‚| j                  xs |j
                  }||j                  vrt        dd|j                  › �«      ‚t        || j                  |«      }t        ||d   «      |j                  k\  rt        dd«      ‚t        ||d   «      d	   }t        ||d   t        |d
   |«      |d   |d   d¬«      d   }t        j                  |||d   || j                  |«      }	 t        j                   |«      }	t1        |d|d   |d   |j2                  | j                  |t        j4                  |D �cg c]  }|d   ‘Œ	 c}|	d   �t7        |	d   «      nd |	d   |	d   |	d   |	d   |	d   |	d   |	d   |	d    f«      S # t        j"                  $ r}
t        dt%        |
«      «      |
‚d }
~
wt&        j(                  $ r}
t        dd«      |
‚d }
~
wt&        j*                  $ r }
t        dd|
j,                  › d�«      |
‚d }
~
wt&        j.                  $ r}
t        dd«      |
‚d }
~
ww xY wc c}w )!Ni÷  z+AI review is not configured on this server.i¦  zModel must be one of r6   i­  z5This center has reached its monthly AI review budget.Ú	config_idÚconfigÚinputsÚ
valid_dateÚzone_idé   )ÚkÚitemsÚcenter_namez4Claude is rate limited right now; try again shortly.iö  zClaude API error (z).zCould not reach the Claude API.ad  INSERT INTO ai_reviews (center_id, tool_run_id, user_id, mode, model, prompt_version, retrieved_forecast_ids,
               output, stop_reason, fallback_model, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens,
               cost_usd, error)
           VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) RETURNING *ÚidÚoutputÚstop_reasonÚfallback_modelÚinput_tokensÚoutput_tokensÚcache_read_tokensÚcache_write_tokensÚcost_usdÚerror)r   r   r:   r   r#   r@   r?   r   r   r8   rA   r   r   r   Úbuild_requestr!   Ú
run_reviewÚAIUnavailabler    Ú	anthropicÚRateLimitErrorÚAPIStatusErrorÚstatus_codeÚAPIConnectionErrorr   rO   ÚPROMPT_VERSIONr   )Úbodyr5   rB   r3   r#   ÚrunrG   ÚanalogsÚparamsÚresultÚeÚas               r*   Úreviewri   5   sƒ  € ä‹€AÜ�>‰>ÔÜ˜CÐ!NÓOÐOØ�J‰JÒ,˜!×,Ñ,€EØ�A×'Ñ'Ñ'Ü˜CÐ#8¸×9LÑ9LÐ8MÐ!NÓOÐOÜ
�D˜$Ÿ+™+ tÓ
,€CÜ�D˜#˜kÑ*Ó+¨q×/CÑ/CÒCÜ˜CÐ!XÓYÐYÜ˜$  KÑ 0Ó1°(Ñ;€FÜ˜4  [Ñ!1Ô3EÀcÈ(ÁmÐU[Ó3\Ð^aÐbnÑ^oÐqtÐu~Ñqð  DEô  Fð  GNñ  O€GÜ×!Ñ! # v¨s°=Ñ/AÀ7ÈDÏIÉIÐW\Ó]€Fð	KÜ×"Ñ" 6Ó*ˆô Øð	bð 
ˆ[Ñ	˜3˜t™9 d§g¡g¨t¯y©y¸%Ä×AVÑAVÐjqÖXrÐefÐYZÐ[_ÓY`ÒXrØ$*¨8Ñ$4Ð$@Œˆv�hÑÔ	 ÀdÈFÐS`ÑLaÐciÐjzÑc{Ø	�Ñ	 ¨Ñ!8¸&ÐATÑ:UÐW]Ð^rÑWsØ	�
Ñ	˜V G™_ð	.ó
ð 
øô ×Ñò 0Ü˜C¤ Q£Ó(¨aÐ/ûÜ×#Ñ#ò `Ü˜CÐ!WÓXÐ^_Ð_ûÜ×#Ñ#ò PÜ˜CÐ#5°a·m±m°_ÀBÐ!GÓHÈaÐOûÜ×'Ñ'ò KÜ˜CÐ!BÓCÈÐJûðKüò YssB   ÄF% ÅIÆ%I
Æ8GÇI
Ç$G1Ç1I
ÈH"È"I
È8IÉI
z/runs/{run_id}/reviewsc                ó8   — t        || |«       t        |d| f«      S )NzHSELECT * FROM ai_reviews WHERE tool_run_id = %s ORDER BY created_at DESC)r   r   )r   r5   rB   s      r*   Úlist_reviewsrk   Z   s"   € äˆd�F˜DÔ!Ü�DÐdÐgmÐfoÓpÐpr)   z /ai/reviews/{review_id}/feedbackc                ó²   — t        |d| f«      }|st        dd«      ‚t        ||d   «       |j                  d|j                  |j
                  | f«       ddiS )Nz.SELECT center_id FROM ai_reviews WHERE id = %si”  zReview not foundr6   zEUPDATE ai_reviews SET feedback = %s, feedback_note = %s WHERE id = %sÚokT)r   r   r   Úexecuter0   r1   )Ú	review_idrb   r5   rB   r7   s        r*   r0   r0   `   se   € ä
�4ÐIÈIÈ<Ó
X€CÙÜ˜CÐ!3Ó4Ð4Ü�4˜˜[Ñ)Ô*Ø‡L�LÐXÐ[_×[hÑ[hÐjn×jsÑjsÐu~ÐZô  AØ�$ˆ<Ðr)   )r5   r   r6   r   Úreturnr4   )r6   z
int | Noner5   r   rB   r   )rb   r   r5   r   rB   r   )r   r   r5   r   rB   r   )ro   r   rb   r,   r5   r   rB   r   ),Ú__doc__Ú
__future__r   r\   Úfastapir   r   r   Úpsycopgr   Úpydanticr   r	   Úauthr   r   r   Úconfigsr   Údbr   r   r   r   Ú	retrievalr   Úservicesr   Úsettingsr   Ú	forecastsr   Úrunsr   Úrouterr   r,   r8   ÚgetrD   Úpostri   rk   r0   r(   r)   r*   ú<module>r�      s  ðÙ -å "ã ß 5Ñ 5Ý ß %ç 5Ñ 5Ý "ß 4Ó 4Ý $Ý Ý #Ý )Ý á	˜˜Ô	€ôˆyô ô�ô ó
ð ‡�ˆLÓØ#'¹GÀHÓ<MÑ\cÐdpÓ\qó ó ðð ‡�ˆ\ÓÙ.5°hÓ.?ÉgÐVbÓNcó !ó ð!ðH ‡�Ð$Ó%Ù18¸Ó1BÑQXÐYeÓQfó qó &ðqð
 ‡�Ð/Ó0ÙBIÈ(ÓBSÑbiÐjvÓbwó ó 1ñr)   