Ë
    ¥©	j½k  ã                   ó^  — d Z ddlZddlZddlmZ ddlmZ ddl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mZ ddlmZmZmZ ddlmZ ddlmZ ddlmZ  e«         ee«      Z eddd¬«      Z e jC                  e
ejD                  ddgdg¬«       e jG                  d«      d„ «       Z$e jG                  d«      d„ «       Z%e jM                  d«      d„ «       Z'e jM                  d«      d„ «       Z(e jM                  d«      d„ «       Z)d ed!ee*df   fd"„Z+e jY                  d#«      d efd$„«       Z-d ed!e.fd%„Z/d!e*fd&„Z0d'e.d!ee*df   fd(„Z1d ed!ee*df   fd)„Z2e jY                  d*«      d efd+„«       Z3e jY                  d,«      d ed!efd-„«       Z4ed.k(  rddl5Z5 e5jl                  e d/d0¬1«       yy)2zc
FastAPI main application for PR Party.
Provides SSE streaming endpoint for real-time PR analysis.
é    N)Údatetime)ÚAsyncGenerator)ÚFastAPIÚHTTPException)ÚCORSMiddleware)ÚStreamingResponse)ÚEventSourceResponse)Úsettings)Úconfigure_loggingÚ
get_logger)ÚAnalyzeRequestÚEncounterResultÚSSEEvent)Úget_github_client)Úget_fixture_loader)Úget_orchestratorúPR Party APIz8Multi-agent PR review system with IBM Bob and watsonx.aiú1.0.0)ÚtitleÚdescriptionÚversionTÚ*)Úallow_originsÚallow_credentialsÚallow_methodsÚallow_headersÚstartupc               ƒ   ó:   K  — t         j                  dd¬«       y­w)zInitialize services on startup.Úapplication_startupr   )r   N©ÚloggerÚinfo© ó    ú)/var/www/html/prparty/backend/app/main.pyÚstartup_eventr&   +   s   è ø€ ô ‡K�KÐ%¨w€KÕ7ùs   ‚Úshutdownc               ƒ   ó6   K  — t         j                  d«       y­w)zCleanup on shutdown.Úapplication_shutdownNr    r#   r$   r%   Úshutdown_eventr*   1   s   è ø€ ô ‡K�KÐ&Õ'ùs   ‚ú/c               ƒ   ó   K  — ddddœS ­w)zHealth check endpoint.r   Úoperationalr   )ÚserviceÚstatusr   r#   r#   r$   r%   Úrootr0   7   s   è ø€ ð "ØØñð ùs   ‚	z/debug/last-responsec               ƒ   ó@   K  — ddl m} m} t        | «      |xs d| dœS ­w)z:Return the last raw model response from the searcher pass.r   ©Ú_last_searcher_responseÚ_last_searcher_errorN)Úresponse_lengthÚparse_errorÚraw_response)Úapp.clients.bob_clientr3   r4   Úlenr2   s     r%   Údebug_last_responser:   A   s*   è ø€ ÷ UäÐ6Ó7Ø+Ò3¨tØ/ñð ùó   ‚z	/fixturesc               ƒ   óH   K  — t        «       } | j                  «       }|ddœS ­w)z'List available PR fixtures for testing.z6Use these fixture names in the 'use_fixture' parameter)Úfixturesr   )r   Úlist_fixtures)Úloaderr=   s     r%   r>   r>   L   s.   è ø€ ô  Ó!€FØ×#Ñ#Ó%€HàØOñð ùs   ‚ "ÚrequestÚreturnc                ó  K  — 	 t         j                  d| j                  | j                  ¬«       | j                  rDt	        «       }|j                  | j                  «      }|d   }|d   }|d   }|d   }|d   }|d   }nÔt        «       }		 | j                  r4|	j                  | j                  «      \  }
}}|
| _	        || _
        || _        | j                  r| j                  r| j                  st        d	d
¬«      ‚|	j                  | j                  | j                  | j                  ¬«      ƒ d{  –—† }|d   }|d   }|d   }|d   }|d   }|d   }t#        «       }|j%                  ||||||¬«      ƒ d{  –—† }|j&                  D ]`  }t)        d|j+                  «       ¬«      }dt-        j.                  |j0                  «      › d�­–— t3        j4                  d«      ƒ d{  –—†  Œb |j6                  D ]`  }t)        d|j+                  «       ¬«      }dt-        j.                  |j0                  «      › d�­–— t3        j4                  d«      ƒ d{  –—†  Œb t)        d|j+                  «       ¬«      }dt-        j.                  |j0                  «      › d�­–— t         j                  d||j8                  t;        |j&                  «      ¬«       y7 �Œ¢# t        $ r;}t         j                  dt        |«      ¬«       t        d	t        |«      ¬«      ‚d}~wt         $ r>}t         j                  dt        |«      ¬«       t        ddt        |«      › �¬«      ‚d}~ww xY w7 �Œê7 �Œ€7 �Œ# t         $ r�}t         j                  dt        |«      t=        |«      j>                  ¬ «       t)        d!t        |«      t=        |«      j>                  d œ¬«      }d"t-        j.                  |j0                  «      › d�­–— Y d}~yd}~ww xY w­w)#zð
    Stream PR analysis results as Server-Sent Events.
    
    Event types:
    - finding: Individual finding discovered
    - dialogue: Character dialogue
    - complete: Analysis complete with full result
    - error: Error occurred
    Úanalysis_stream_start©Ú	pr_numberÚuse_fixturerE   Úpr_titleÚ	pr_authorÚdiffÚpackage_jsonÚcontext_filesé�  úREither 'github_url' or 'repo_owner', 'repo_name', and 'pr_number' must be provided©Ústatus_codeÚdetail©ÚownerÚreporE   NÚinvalid_github_url©ÚerrorÚgithub_fetch_erroréô  ú Failed to fetch PR from GitHub: ©rE   rG   rH   rI   rJ   rK   Úfinding©ÚeventÚdatazevent: finding
data: ú

g      à?Údialoguezevent: dialogue
data: Úcompleteúevent: complete
data: Úanalysis_stream_complete©rE   ÚverdictÚfindings_countÚanalysis_stream_error©rV   Ú
error_typerV   úevent: error
data: ) r!   r"   rE   rF   r   Úload_fixturer   Ú
github_urlÚparse_pr_urlÚ
repo_ownerÚ	repo_namer   Úfetch_prÚ
ValueErrorrV   ÚstrÚ	Exceptionr   Ú
analyze_prÚfindingsr   Ú
model_dumpÚjsonÚdumpsr^   ÚasyncioÚsleepÚ	dialoguesre   r9   ÚtypeÚ__name__)r@   r?   Úfixture_datarE   rG   rH   rI   rJ   rK   ÚgithubrR   rS   Úpr_numÚgithub_dataÚeÚorchestratorÚresultr[   r]   r`   Úerror_events                        r%   Úanalyze_pr_streamr†   W   sú  è ø€ ð|HÜ�‰Ø#Ø×'Ñ'Ø×+Ñ+ð 	ô 	
ð ×Òä'Ó)ˆFØ!×.Ñ.¨w×/BÑ/BÓCˆLà$ [Ñ1ˆIØ# JÑ/ˆHØ$ [Ñ1ˆIØ Ñ'ˆDØ'¨Ñ7ˆLØ(¨Ñ9‰Mô 'Ó(ˆFð*à×%Ò%Ø*0×*=Ñ*=¸g×>PÑ>PÓ*QÑ'�E˜4 Ø).�GÔ&Ø(,�GÔ%Ø(.�GÔ%ð ×)Ò)°×1BÒ1BÈ'×J[ÒJ[Ü'Ø$'Øsôð ð %+§O¡OØ!×,Ñ,Ø ×*Ñ*Ø%×/Ñ/ð %4ó %÷ �ð (¨Ñ4�	Ø& zÑ2�Ø'¨Ñ4�	Ø" 6Ñ*�Ø*¨>Ñ:�Ø +¨OÑ <�ô$ (Ó)ˆØ#×.Ñ.ØØØØØ%Ø'ð /ó 
÷ 
ˆð —‘ò 	%ˆGÜØØ×'Ñ'Ó)ôˆEð +¬4¯:©:°e·j±jÓ+AÐ*BÀ$ÐGÓGÜ—-‘- Ó$×$Ñ$ð	%ð ×(Ñ(ò 	%ˆHÜØ Ø×(Ñ(Ó*ôˆEð ,¬D¯J©J°u·z±zÓ,BÐ+CÀ4ÐHÓHÜ—-‘- Ó$×$Ñ$ð	%ô ØØ×"Ñ"Ó$ô
ˆð (¬¯
©
°5·:±:Ó(>Ð'?¸tÐDÓDä�‰Ø&ØØ—N‘NÜ˜vŸ™Ó/ð	 	õ 	
ðAúô ò ä—‘Ð1¼¸Q»�Ô@Ü#Ø #Ü˜q›6ôð ûô ò ä—‘Ð1¼¸Q»�Ô@Ü#Ø #Ø=¼cÀ!»f¸XÐFôð ûðúð
ùð  %ùð %úô  ò HÜ�‰Ø#Ü�a“&Ü˜A“w×'Ñ'ð 	ô 	
ô Øä˜Q›Ü" 1›g×.Ñ.ñô
ˆð %¤T§Z¡Z°×0@Ñ0@Ó%AÐ$BÀ$ÐG×GÐGûðHüs¦   ‚P„BM+ ÂB&K Ä1KÄ2"K Å$M+ Å8M"Å9A,M+ Ç%M%Ç&A.M+ ÉM(ÉA=M+ ËPËK Ë	MË6LÌMÌ!9MÍMÍM+ Í%M+ Í(M+ Í+	PÍ4BO?Ï:PÏ?PÐPz/analyzec              ƒ   ó2   K  — t        t        | «      «      S ­w)z•
    Analyze a PR and stream results via Server-Sent Events.

    Use 'use_fixture' parameter for offline testing with fixtures (pr1, pr2, pr3).
    )r	   r†   ©r@   s    r%   rt   rt   à   s   è ø€ ô Ô0°Ó9Ó:Ð:ùs   ‚c              ƒ   óF  K  — | j                   r§t        «       }|j                  | j                   «      }|d   |d   |d   |d   |d   |d   |j                  d«      |j                  di «      j                  d	g «      |j                  d«      r$|j                  di «      j                  d	g «      d
œ	S g d
œ	S t	        «       }	 | j
                  r4|j                  | j
                  «      \  }}}|| _        || _        || _	        | j                  r| j                  r| j                  st        dd¬«      ‚|j                  | j                  | j                  | j                  ¬«      ƒ d{  –—† }|d   |d   |d   |d   |d   |d   dg g d
œ	S 7 Œ"# t        $ r;}t        j                  dt        |«      ¬«       t        dt        |«      ¬«      ‚d}~wt        $ r ‚ t         $ r>}t        j                  dt        |«      ¬«       t        ddt        |«      › �¬«      ‚d}~ww xY w­w)z„
    Resolve a request to PR metadata + content. Shared by streaming and sync
    endpoints. Raises HTTPException on bad input.
    rE   rG   rH   rI   rJ   rK   Úexpected_findings_validatedÚexpected_findings_rawru   )	rE   rG   rH   rI   rJ   rK   ÚpregeneratedÚexpected_rawÚexpected_validatedrL   rM   rN   rQ   NrT   rU   rW   rX   rY   )rF   r   rk   Úgetr   rl   rm   rn   ro   rE   r   rp   rq   r!   rV   rr   rs   )	r@   r?   r~   r   rR   rS   r€   r�   r‚   s	            r%   Ú_load_pr_payloadr�   ê   sN  è ø€ ð
 ×ÒÜ#Ó%ˆØ×*Ñ*¨7×+>Ñ+>Ó?ˆà% kÑ2Ø$ ZÑ0Ø% kÑ2Ø  Ñ(Ø(¨Ñ8Ø)¨/Ñ:Ø(×,Ñ,Ð-JÓKØ(×,Ñ,Ð-DÀbÓI×MÑMÈjÐZ\Ó]ð  ×#Ñ#Ð$AÔBð × Ñ Ð!>ÀÓC×GÑGÈ
ÐTVÓWñ
ð 	
ð ñ
ð 	
ô  Ó €Fð'
Ø×ÒØ"(×"5Ñ"5°g×6HÑ6HÓ"IÑˆE�4˜Ø!&ˆGÔØ $ˆGÔØ &ˆGÔà×!Ò!¨×):Ò):À'×BSÒBSÜØØkôð ð
 #ŸO™OØ×$Ñ$Ø×"Ñ"Ø×'Ñ'ð ,ó 
÷ 
ˆð % [Ñ1Ø# JÑ/Ø$ [Ñ1Ø Ñ'Ø'¨Ñ7Ø(¨Ñ9Ø ØØ"$ñ

ð 
	
ð
ùô  ò <Ü�‰Ð)´°Q³ˆÔ8Ü¨´C¸³FÔ;Ð;ûÜò ØÜò 
Ü�‰Ð)´°Q³ˆÔ8ÜØØ5´c¸!³f°XÐ>ô
ð 	
ûð
üsI   ‚B>H!ÃB&F Å'F
Å(!F Æ	H!Æ
F Æ	HÆ6GÇHÇ 9HÈHÈH!c                   ó   — y)zBComment line keeps proxies/CDNs from closing idle SSE connections.z: keep-alive

r#   r#   r$   r%   Ú_heartbeat_eventr’   -  s   € àr$   Úpayloadc                óV	  ‡%‡&K  — ddl m}m} ddlm} ddlm} ddlm}m	} | d   }| d   }| d   }	| d	   }
| d
   }|D �cg c]  }|d   ‘Œ	 }}d|||	|dœdœ}dt        j                  |d   «      › d�­–— |D ]   Š%dt        j                  d‰%i«      › d�­–— Œ" g }t        |«      D �]7  \  }}|t        |
«      k  r|
|   ni }|j                  dd«      }dddddœ}dddddœ}	 |j                   ||j                  dd |d!›�«      |j                  d"d#«      |j                  d$|j                  d%d#«      «      ||j                  |d«      |j                  |d«      |j                  d&|j                  d'd(«      «      |j                  d)d*«      |j                  d+d*«      |j                  d,d#«      |j                  d-d.«      |xs i j                  d/d#«      ¬0«      «       �Œ:  |«       }|j)                  |«      } |«       Š&g }|D �]t  Š%|j                  ‰%g «      }	 |r(t+        j,                  ˆ%ˆ&fd4„|D «       d5d6iŽƒ d3{  –—† }ng }g }t/        ||«      D ]¸  \  }}|j                   ||j0                  |j2                  |j4                  |j6                  |j8                  |j:                  |j<                  |j>                  |j@                  |jB                  ‰%tE        |t&        «      r|jG                  «       r|n|j4                  ¬7«      «       Œº |jI                  |«       d8t        j                  ‰%|D �cg c]  }|jK                  «       ‘Œ c}d9œ«      › d�­–— t+        jL                  d:«      ƒ d3{  –—†  �Œw  |«       } tO        d=„ |D «       «      }!tQ        dd>|!z
  «      }"| jS                  |!«      }#tU        |||	|#|!|"|| jW                  |«      tY        jZ                  «       j]                  «       ¬?«	      }$d@t        j                  |$jK                  «       «      › d�­–— y3c c}w # t         $ r+}t"        j%                  d1t'        |«      ¬2«       Y d3}~�Œ±d3}~ww xY w7 �Œ c c}w 7 Œò# t         $ r3}d;t        j                  ‰%t'        |«      d<œ«      › d�­–— Y d3}~�Œœd3}~ww xY w­w)Aa  
    Stream a fixture's pre-generated findings as if they were coming from
    the real pipeline. Groups findings by character and emits one
    character_complete event per character, with realistic spacing so the
    UI animation has room to breathe.
    r   )ÚFindingValidatedÚFinding©Úget_classifier©Úget_voice_rewriter)ÚCHARACTER_PIPELINEÚPRAnalysisOrchestratorrE   rG   rH   r�   rŽ   é   Ústarted)rE   rG   rH   Ú
charactersr\   zevent: started
data: r^   r_   zevent: character_started
data: Úcharacter_idÚseverityÚlowéZ   é<   é   é
   )ÚcriticalÚhighÚmediumr¢   Úcrit_hitÚhitÚgrazeÚwhisperÚidÚFÚ03dr   Ú Úexplanationr   ÚfileÚ	file_pathÚunknownÚ
line_starté   Úline_endÚcode_snippetÚcategoryÚgeneralÚvalidation_notes©r®   r   r   r¡   ÚdamageÚdamage_typer´   r¶   r¸   r¹   rº   r¼   Úfixture_finding_skiprU   Nc              3   óB   •K  — | ]  }‰j                  ‰|«      –— Œ y ­w©N)Úrewrite_finding)Ú.0ÚfvÚchar_idÚvoices     €€r%   ú	<genexpr>z/_stream_pregenerated_fixture.<locals>.<genexpr>ˆ  s   øè ø€ Ò[¸R�e×+Ñ+¨G°R×8Ñ[ùs   ƒÚreturn_exceptionsT)r®   r   r   r¡   r¾   r¿   r´   r¶   r¸   r¹   r    Úcharacter_dialoguez event: character_complete
data: )r    ru   g333333ã?zevent: character_error
data: )r    rV   c              3   ó4   K  — | ]  }|j                   –— Œ y ­wrÂ   ©r¾   ©rÄ   Úfs     r%   rÈ   z/_stream_pregenerated_fixture.<locals>.<genexpr>´  s   è ø€ Ò6 A�q—x•xÑ6ùó   ‚éd   ©	rE   rG   rH   re   Útotal_damageÚremaining_hpru   r{   Úanalysis_timestamprb   )/Ú
app.modelsr•   r–   Úapp.services.classifierr˜   Úapp.services.voice_rewriterrš   Úapp.services.orchestratorr›   rœ   rw   rx   Ú	enumerater9   r�   Úappendrs   r!   Úwarningrr   Úclassify_findingsry   ÚgatherÚzipr®   r   r   r¡   r¾   r¿   r´   r¶   r¸   r¹   Ú
isinstanceÚstripÚextendrv   rz   ÚsumÚmaxÚ_calculate_verdictr   Ú_generate_dialoguesr   ÚutcnowÚ	isoformat)'r“   r•   r–   r˜   rš   r›   rœ   rE   rG   rH   r�   rŽ   ÚcÚall_character_idsrž   Úfindings_validatedÚiÚvalidated_dataÚrawr¡   Ú
damage_mapÚdamage_type_mapÚexcÚ
classifierÚ
classifiedÚall_findingsÚchar_findings_validatedr{   ÚvoicedrÅ   r`   rÎ   rƒ   rÒ   rÓ   re   r„   rÆ   rÇ   s'                                        @@r%   Ú_stream_pregenerated_fixturerö   2  sÂ  ùè ø€ ÷ 5Ý6Ý>÷ð
 ˜Ñ$€IØ�zÑ"€HØ˜Ñ$€IØ˜>Ñ*€LØ Ð!5Ñ6Ðà'9Ö: !˜˜1›Ð:ÐÐ:ð à"Ø Ø"Ø+ñ	
ñ€Gð #¤4§:¡:¨g°f©oÓ#>Ð"?¸tÐ
DÓDà$ò 
ˆðÜ—Z‘Z °Ð 9Ó:Ð;¸4ðAô	
ð
ð 24ÐÜ&Ð'9Ó:ó CÑˆˆ>Ø!"¤S¨Ó%6Ò!6ˆl˜1Šo¸BˆØ—7‘7˜: uÓ-ˆØ"$¨b¸BÀrÑJˆ
à"ØØØñ	
ˆð	CØ×%Ñ%Ù Ø—w‘w˜t q¨¨3¨ [Ó1ØŸ'™' '¨2Ó.Ø #§¡¨°s·w±w¸}ÈbÓ7QÓ RØ%Ø%Ÿ>™>¨(°BÓ7Ø /× 3Ñ 3°H¸iÓ HØ!Ÿg™g f¨c¯g©g°kÀ9Ó.MÓNØ"Ÿw™w |°QÓ7Ø ŸW™W Z°Ó3Ø!$§¡¨¸Ó!<Ø ŸW™W Z°Ó;Ø&4Ò&:¸×%?Ñ%?Ð@RÐTVÓ%WôöðCñ<  Ó!€JØ×-Ñ-Ð.@ÓA€JáÓ €EØ"$€Lð %ó -ˆØ",§.¡.°¸"Ó"=Ðð+	Ù&Ü")§.¡.Ü[ÐCZÔ[ð#à&*ñ#÷ ‘	ð
 �	à$&ˆFÜ #Ð$;¸YÓ Gò ‘��HØ—‘ÙØŸ5™5Ø Ÿh™hØ$&§N¡NØ!#§¡Ø!Ÿy™yØ$&§N¡NØ"$§,¡,Ø#%§=¡=Ø!#§¡Ø%'§_¡_Ø%,ô  *¨(´CÔ8¸X¿^¹^Ô=Mñ %à!#§¡ôõðð, ×Ñ Ô'ðÜŸ™°WÐciÖJjÐ^_È1Ï<É<Í>ÒJjÑ$kÓlÐmÐmqðsóô
 —-‘- Ó$×$Ò$ðQ-ñ` *Ó+€LÜÑ6¨Ô6Ó6€LÜ�q˜# Ñ,Ó-€LØ×-Ñ-¨lÓ;€GäØØØØØ!Ø!ØØ×2Ñ2°<Ó@Ü#Ÿ?™?Ó,×6Ñ6Ó8ô
€Fð $¤D§J¡J¨v×/@Ñ/@Ó/BÓ$CÐ#DÀDÐ
IÔIùò{ ;øôd ò 	CÜ�N‰NÐ1¼¸S»ˆN×BÒBûð	CúðûòB Kkð %ùÜò 	ðÜŸ™°WÄsÈ3ÃxÑ$PÓQÐRÐRVðX÷ñ ûð	üs˜   „:R)¾P$Á
BR)Ã$C;P)Ç<R)È$Q*É Q ÉC6Q*Ì7Q#Í'Q*Í5Q(Í6Q*Í:B/R)Ð)	QÐ2 QÑR)ÑQÑR)Ñ Q*Ñ#Q*Ñ*	R&Ñ3(R!ÒR)Ò!R&Ò&R)c           	     óü  K  — 	 t        «       ­–— t        | «      ƒ d{  –—† }|d   rt        |«      2 3 d{  –—† }|­–— Œt        «       }|j	                  |d   |d   |d   |d   |d   |d   ¬	«      2 3 d{  –—† }|d
   }|d   }d|› dt        j                  |«      › d�­–— Œ37 Œ‰7 Œr6 y7 Œ46 y# t        $ r=}dt        j                  |j                  |j                  dœ«      › d�­–— Y d}~yd}~wt        $ ry}t        j                  dt        |«      t        |«      j                  ¬«       dt        j                  t        |«      t        |«      j                  dœ«      › d�­–— Y d}~yd}~ww xY w­w)z²
    Per-character streaming pipeline. Emits one event per character as
    each independent agent finishes, plus a final `complete` event with
    the full EncounterResult.
    NrŒ   rE   rG   rH   rI   rJ   rK   rZ   r]   r^   zevent: z
data: r_   rj   )ÚmessagerO   Ústream_analysis_unhandled_errorrh   )rø   ri   )r’   r�   rö   r   Úanalyze_pr_streamingrw   rx   r   rP   rO   rs   r!   rV   rr   r|   r}   )r@   r“   r]   rƒ   Ú	raw_eventÚnamer^   rð   s           r%   Úanalyze_pr_stream_v2rý   Ç  s¦  è ø€ ð)
ô Ó Ó ä(¨Ó1×1ˆð �>Ò"Ü;¸GÓD÷ ð �eØ”ô (Ó)ˆØ+×@Ñ@Ø˜kÑ*Ø˜ZÑ(Ø˜kÑ*Ø˜‘Ø  Ñ0Ø! /Ñ2ð  Aó  
÷ 
	Að 
	A�)ð ˜WÑ%ˆDØ˜VÑ$ˆDØ˜D˜6 ¬$¯*©*°TÓ*:Ð);¸4Ð@Ô@ð) 2øðøÐDàð
	Aøñ  
øô ò 
ðÜ—Z‘Z¨C¯J©JÀsÇÁÑ WÓXÐYÐY]ð_÷	
ð 	
ûô ò 	
Ü�‰Ø-Ü�c“(Ü˜C“y×)Ñ)ð 	ô 	
ðÜ—Z‘Z¬C°«HÄDÈÃI×DVÑDVÑ WÓXÐYÐY]ð_÷	
ð 	
ûð	
üs•   ‚E<„B3 ŸB) B3 ´B-¸B+¹B-¼:B3 Á6B1Á:B/Á;B1Á>,B3 Â+B-Â-B3 Â.E<Â/B1Â1B3 Â2E<Â3	E9Â<3C4Ã/E<Ã4E9Ä A/E4Å/E<Å4E9Å9E<z/analyze/streamc              ƒ   ó@   K  — t        t        | «      dddddœ¬«      S ­w)aF  
    Per-character streaming endpoint. Each of the six character agents runs
    independently and emits its findings as soon as its own pipeline finishes
    (search + voice rewrite). The frontend uses these events to populate
    each island's panel progressively instead of waiting for the whole
    council to finish.
    ztext/event-streamzno-cacheÚnoz
keep-alive)zCache-ControlzX-Accel-BufferingÚ
Connection)Ú
media_typeÚheaders)r   rý   rˆ   s    r%   Úanalyze_pr_stream_endpointr  ù  s.   è ø€ ô Ü˜WÓ%Ø&à'Ø!%Ø&ñ
ôð ùr;   z/analyze/syncc              ƒ   ó¬  K  — 	 t         j                  d| j                  | j                  ¬«       | j                  �rt	        «       }|j                  | j                  «      }|d   }|d   }|d   }|j                  d«      �r²t         j                  d| j                  ¬«       d	d
lm} d	dl	m
} d	dlm} |d   d   }	|d   d   }
g }t        |
«      D ]~  \  }}|	|   }|d   }|dk(  rd}d}n|dk(  rd}d}n|dk(  rd}d}nd}d} ||d   |d   |d   ||||d   |d   |d    |d!   |j                  d"d#«      |d$   ¬%«      }|j                  |«       Œ€  |«       }|j                  |«      } |«       }|j!                  |«      ƒ d&{  –—† }t#        d'„ |D «       «      }t%        d	d(|z
  «      }|d)k\  rd*}n
|d+k\  rd,}nd-}d	d.lm}  |«       }|j+                  |«      }t-        ||||||||t/        j0                  «       j3                  «       ¬/«	      }t         j                  d0||t5        |«      ¬1«       |S |d2   }|d3   }|d4   } nÔt7        «       }!	 | j8                  r4|!j;                  | j8                  «      \  }"}#}$|"| _        |#| _        |$| _        | j<                  r| j>                  r| j                  stA        d5d6¬7«      ‚|!jC                  | j<                  | j>                  | j                  ¬8«      ƒ d&{  –—† }%|%d   }|%d   }|%d   }|%d2   }|%d3   }|%d4   } tM        «       }|jO                  |||||| ¬>«      ƒ d&{  –—† }t         j                  d0||jP                  ¬?«       |S 7 �Œß7 Œr# tD        $ r;}&t         jG                  d9tI        |&«      ¬:«       tA        d5tI        |&«      ¬7«      ‚d&}&~&wtJ        $ r>}&t         jG                  d;tI        |&«      ¬:«       tA        d<d=tI        |&«      › �¬7«      ‚d&}&~&ww xY w7 Œ¹# tJ        $ rO}&t         jG                  d@tI        |&«      tS        |&«      jT                  ¬A«       tA        d<tI        |&«      ¬7«      ‚d&}&~&ww xY w­w)Bz²
    Analyze a PR and return complete result (non-streaming).
    Useful for testing and debugging.
    
    When using fixtures, loads pre-generated findings for fast demo.
    Úanalysis_sync_startrD   rE   rG   rH   rŠ   Úusing_pregenerated_findings)Úfixturer   )r•   r—   r™   r‹   ru   r¡   r§   r£   rª   r¨   r¤   r«   r©   r¥   r¬   r¦   r­   r®   r   r²   r³   r¶   r¸   r¹   rº   r»   r¼   r½   Nc              3   ó4   K  — | ]  }|j                   –— Œ y ­wrÂ   rÌ   rÍ   s     r%   rÈ   z"analyze_pr_sync.<locals>.<genexpr>^  s   è ø€ Ò"E° 1§8¥8Ñ"EùrÏ   rÐ   éP   Úblockedé2   Úchanges_requiredÚapproved)rœ   rÑ   Úanalysis_sync_completerd   rI   rJ   rK   rL   rM   rN   rQ   rT   rU   rW   rX   rY   rZ   )rE   re   Úanalysis_sync_errorrh   )+r!   r"   rE   rF   r   rk   r�   rÕ   r•   rÖ   r˜   r×   rš   rÙ   rÚ   rÜ   Úrewrite_findingsrâ   rã   rØ   rœ   rå   r   r   ræ   rç   r9   r   rl   rm   rn   ro   r   rp   rq   rV   rr   rs   r   rt   re   r|   r}   )'r@   r?   r~   rE   rG   rH   r•   r˜   rš   r�   Úexpected_validated_datarê   rë   rì   Úraw_findingr¡   r¾   r¿   r[   rñ   Úclassified_findingsÚvoice_rewriterÚvoiced_findingsrÒ   rÓ   re   rœ   rƒ   r{   r„   rI   rJ   rK   r   rR   rS   r€   r�   r‚   s'                                          r%   Úanalyze_pr_syncr    sõ  è ø€ ðx<Ü�‰Ø!Ø×'Ñ'Ø×+Ñ+ð 	ô 	
ð ×ÓÜ'Ó)ˆFØ!×.Ñ.¨w×/BÑ/BÓCˆLà$ [Ñ1ˆIØ# JÑ/ˆHØ$ [Ñ1ˆIð ×ÑÐ =Õ>Ü—‘Ð9À7×CVÑCV�ÔWå7ÝBÝJð  ,Ð,CÑDÀZÑP�Ø*6Ð7TÑ*UÐV`Ñ*aÐ'ð &(Ð"Ü)2Ð3JÓ)Kò  7Ñ%�A�~Ø".¨q¡/�Kð  +¨:Ñ6�HØ :Ò-Ø!#˜Ø&0™Ø! VÒ+Ø!#˜Ø&+™Ø! XÒ-Ø!#˜Ø&-™à!#˜Ø&/˜á.Ø& tÑ,Ø)¨'Ñ2Ø$/°Ñ$>Ø!)Ø%Ø$/Ø"-¨fÑ"5Ø#.¨|Ñ#<Ø!,¨ZÑ!8Ø%0°Ñ%@Ø!,§¡°¸YÓ!GØ)7Ð8JÑ)Kô�Gð '×-Ñ-¨gÕ6ðA 7ñF ,Ó-�
Ø&0×&BÑ&BÐCUÓ&VÐ#á!3Ó!5�Ø(6×(GÑ(GÐH[Ó(\×"\�ô  #Ñ"E°_Ô"EÓE�Ü" 1 c¨LÑ&8Ó9�à 2Ò%Ø'‘GØ! RÒ'Ø0‘Gà(�Gõ MÙ5Ó7�Ø(×<Ñ<¸_ÓM�	ä(Ø'Ø%Ø'Ø#Ø!-Ø!-Ø,Ø'Ü'/§¡Ó'8×'BÑ'BÓ'Dô
�ô —‘Ø,Ø'Ø#Ü#& Ó#7ð	 ô ð �Ø Ñ'ˆDØ'¨Ñ7ˆLØ(¨Ñ9‰Mô 'Ó(ˆFð*à×%Ò%Ø*0×*=Ñ*=¸g×>PÑ>PÓ*QÑ'�E˜4 Ø).�GÔ&Ø(,�GÔ%Ø(.�GÔ%ð ×)Ò)°×1BÒ1BÈ'×J[ÒJ[Ü'Ø$'Øsôð ð %+§O¡OØ!×,Ñ,Ø ×*Ñ*Ø%×/Ñ/ð %4ó %÷ �ð (¨Ñ4�	Ø& zÑ2�Ø'¨Ñ4�	Ø" 6Ñ*�Ø*¨>Ñ:�Ø +¨OÑ <�ô$ (Ó)ˆØ#×.Ñ.ØØØØØ%Ø'ð /ó 
÷ 
ˆô 	�‰Ø$ØØ—N‘Nð 	ô 	
ð ˆðU #]ùðzùô ò ä—‘Ð1¼¸Q»�Ô@Ü#Ø #Ü˜q›6ôð ûô ò ä—‘Ð1¼¸Q»�Ô@Ü#Ø #Ø=¼cÀ!»f¸XÐFôð ûðúð
ùô" ò <Ü�‰Ø!Ü�a“&Ü˜A“w×'Ñ'ð 	ô 	
ô
 ¨´C¸³FÔ;Ð;ûð<üs˜   ‚Q„FO9 ÆM&ÆB,O9 È4QÈ5O9 ÉB&M+ Ë6M)Ë7"M+ Ì$O9 Ì=O7Ì>'O9 Í%QÍ&O9 Í)M+ Í+	O4Í46N*Î*O4Î69O/Ï/O4Ï4O9 Ï9	QÐA
QÑQÑQÚ__main__z0.0.0.0i@  )ÚhostÚport)7Ú__doc__ry   rw   r   Útypingr   Úfastapir   r   Úfastapi.middleware.corsr   Úfastapi.responsesr   Ússe_starlette.sser	   Ú
app.configr
   Úapp.logging_configr   r   rÕ   r   r   r   Úapp.clients.github_clientr   Úapp.services.fixture_loaderr   rØ   r   r}   r!   ÚappÚadd_middlewareÚcors_origins_listÚon_eventr&   r*   r�   r0   r:   r>   rr   r†   Úpostrt   Údictr�   r’   rö   rý   r  r  ÚuvicornÚrunr#   r$   r%   ú<module>r,     sB  ðñó Û Ý Ý !ç *Ý 2Ý /Ý 1å ß <ß @Ñ @Ý 7Ý :Ý 6ñ Ô Ù	�HÓ	€ñ Ø
ØJØô€ð × Ñ ØØ×,Ñ,ØØ�%Ø�%ð ô ð ‡�ˆiÓñ8ó ð8ð
 ‡�ˆjÓñ(ó ð(ð
 ‡�ˆƒñó ðð ‡�Ð	Ó ñó !ðð ‡�ˆÓñó ððFH ^ð FH¸ÀsÈDÀyÑ8Qó FHðR ‡�ˆ*Óð;˜nò ;ó ð;ð@
 Nð @
°tó @
ðF˜#ó ð
RJ°ð RJ¸ÈÈTÈ	Ñ9Ró RJðj/
¨ð /
¸>È#ÈtÈ)Ñ;Tó /
ðd ‡�Ð
Óð¨nò ó ðð& ‡�ˆ/Óð< >ð <°oò <ó ð<ðD ˆzÒÛØ€G‡K�K�˜)¨$Ö/ð r$   