
    ~j                        d Z ddlmZ ddlZddlZddlmZ ddlmZ ddl	Z	ddl
mZ ddlmZmZ ddlmZmZmZmZ  ej        e          Zd	Zd
Z G d d          ZdS )uF  Anthropic Claude client — the Top-10 ranking stage (stage 9).

Takes the 20 GPT-4o ideas + voice profile + verified facts and returns a
ranked, filtered top-10 ranked topic list with reasoning + safety notes.

Uses Anthropic's Messages API: POST https://api.anthropic.com/v1/messages
with the x-api-key header (NOT Bearer).
    )annotationsN)date)Any)settings)
RankedIdeaVoiceProfile)JsonExtractionError_build_semaphorehttp_post_jsonextract_jsonz%https://api.anthropic.com/v1/messagesz
2023-06-01c                  .    e Zd ZddZddZddZddZdS )AnthropicClientreturnNonec                    t          j        t          j                  | _        t          t          j                  | _        d S )N)timeout)httpxAsyncClientr   ANTHROPIC_TIMEOUT_clientr
   ANTHROPIC_MAX_CONCURRENCY_semselfs    w/Users/abstractioneditor2/ai-workstation/projects/automation/show-city-briefing-agent/app/providers/anthropic_client.py__init__zAnthropicClient.__init__#   s0    (1KLLL$X%GHH			    c                H   K   | j                                          d {V  d S N)r   acloser   s    r   closezAnthropicClient.close'   s2      l!!###########r   dict[str, str]c                ,    t           j        t          ddS )Nzapplication/json)z	x-api-keyzanthropic-versionzContent-Type)r   ANTHROPIC_API_KEY_ANTHROPIC_VERSIONr   s    r   _headerszAnthropicClient._headers*   s    !3!3.
 
 	
r   citystr	show_dater   voicer   verified_factslist[dict[str, Any]]ideaslist[RankedIdea]c                 K   d}t          j        |j        |j        |j        |j        |j        |j        dd          }d| d|                                 d| dt          j        |dt          	           d
t          j        |dt          	           d}t          j        d|d|dgdd}	| j        4 d {V  t          | j        t          |                                 |	t#          t          j                  d           d {V }
d d d           d {V  n# 1 d {V swxY w Y   	 |
                    dg           }d                    d |D                       }n-# t*          t,          f$ r}t/          d| d          |d }~ww xY w	 t1          |          n,# t.          $ r t2                              d           g cY S w xY wt7          t8                    rt;          fddD             g           }nt7          t<                    r}ng }g }d}t?          |d d         d           D ]}t7          |t8                    s|                     tC          t          |                    d          pd          "                                d d          t          |                    d!          pd          "                                d d"         t          |                    d#          pd          "                                d d$         |                    d%          r<t          |                    d%                    "                                d d$         nd tG          |                    d&          p|          |                    d'          r<t          |                    d'                    "                                d d$         nd |                    d(          r<t          |                    d(                    "                                d d$         nd )                     |dz  }|S )*NaK  You are a head writer for a touring comedian's road team. Given 20 candidate crowd-work ideas, you filter and rank them to the top 10 best fit for the host city. Ranking criteria: fit with the comedian's voice, ground in verified facts, on-stage safety, and audience engagement. DROP unsafe or unveriable ideas. Return STRICT JSON.)display_namepersonatonesignature_bitstopics_to_lean_intosensitivities_to_avoidF)ensure_asciizShow: z on z.
Voice profile JSON:
z
Verified facts JSON:
)r6   defaultz
Candidate ideas JSON:
a
  
Return STRICT JSON: an array of up to 10 objects with keys "title", "angle", "city_specificity", "risk_note" (nullable string), "rank" (integer 1..10, 1=best), "reasoning" (one sentence), "safety_notes" (nullable string). Do NOT include dropped ideas in the output.i   user)rolecontentg?)model
max_tokenssystemmessagestemperature	anthropic)clienturlheaderspayloadr   provider_namer:    c              3  t   K   | ]3}|                     d           dk    |                     dd          V  4dS )typetextrF   N)get).0bs     r   	<genexpr>z/AnthropicClient.rank_top_ten.<locals>.<genexpr>g   sM        &'!%%--6:Q:Qfb!!:Q:Q:Q:Q r   zanthropic: bad content shape ()z4anthropic returned non-JSON; returning empty rankingc              3  x   K   | ]4}t                              |          t                    *|         V  5d S r   )
isinstancerJ   list)rK   kparseds     r   rM   z/AnthropicClient.rank_top_ten.<locals>.<genexpr>s   sS       5 5qvzz!}}d335 5 5 5 5 5 5r   )rankedr-   top_tentopics   
   c                v    t          | t                    r#t          |                     dd                    ndS )NrankrX   )rP   dictintrJ   )xs    r   <lambda>z.AnthropicClient.rank_top_ten.<locals>.<lambda>}   s4    V`abdhViVi<qCfb@Q@Q<R<R<Roq r   )keytitlei,  anglei  city_specificityi  	risk_noterZ   	reasoningsafety_notes)r`   ra   rb   rc   rZ   rd   re   )$jsondumpsr0   r1   r2   r3   r4   r5   	isoformatr(   r   ANTHROPIC_RANKING_MODELr   r   r   _ANTHROPIC_URLr&   floatr   rJ   join	TypeErrorAttributeErrorr	   r   loggerwarningrP   r[   nextrQ   sortedappendr   stripr\   )r   r'   r)   r*   r+   r-   r=   voice_blockr8   rD   datatext_blocksrI   excarray_sourceresultsrZ   itemrS   s                     @r   rank_top_tenzAnthropicClient.rank_top_ten1   sf     X 	 j!.}J#2#(#<&+&B"
 "
   :T : :y2244 : :$/: :%)ZU\_%`%`%`: : '+jUTW&X&X&X: : : 	 5"(T::;
 
 9 	 	 	 	 	 	 	 	'|"h899)        D	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 		X((9b11K77  +6    DD >* 	X 	X 	X%&Ms&M&M&MNNTWW	X	!$''FF" 	 	 	NNQRRRIII	 fd## 		5 5 5 5$L 5 5 5 LL
 %% 	!LLL$&<,2q2qrrr 	 	DdD)) NN:$((7++1r2288::4C4@$((7++1r2288::5D5A!$TXX.@%A%A%GR!H!H!N!N!P!PQURUQU!V"hh{33>3txx4455;;==dsdCC9=&))1T22"hh{33>3txx4455;;==dsdCC9=!%.!9!9Dc$((>":":;;AACCDSDII?C      AIDDs=   <AD
D'*D'/5E% %F6F

FF# #&GGN)r   r   )r   r"   )r'   r(   r)   r   r*   r   r+   r,   r-   r,   r   r.   )__name__
__module____qualname__r   r!   r&   r|    r   r   r   r   "   sn        I I I I$ $ $ $
 
 
 
\ \ \ \ \ \r   r   )__doc__
__future__r   rf   loggingdatetimer   typingr   r   
app.configr   
app.modelsr   r   app.providers._commonr	   r
   r   r   	getLoggerr}   ro   rj   r%   r   r   r   r   <module>r      s#    # " " " " "                      / / / / / / / /            
	8	$	$8! k k k k k k k k k kr   