
    `ji                         d Z ddlZddlZddlmZ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mZ  ej$                  e      ZdZd	Zd
ZdZ G d d      Z G d dee      Z G d dee      Zy)uf   Beat 추출 + Shot 추출 단계.

v4: 원본 씬 → beat(상태 변화) → shot(스틸컷) 추출.
    N)ThreadPoolExecutoras_completed)AnyDictListOptional)
StepRunner)call_structuredload_promptload_schemai  i     c                   V    e Zd ZdZdedee   fdZdefdZde	e   fdZ
de	e   fdZy)	_BeatShotMixinu7   Beat/Shot 공통 — segments, 인물 리스트 로드.step_idreturnc                     dd l }ddlm} ddlm}  ||j
                        | j                  z  dz  dz  | j                  z  |z  dz  }|j                         r!|j                  |j                  d            S y )	Nr   )settings)Pathcheckpointsepisodeszmanifest.jsonutf-8)encoding)jsonapp.core.configr   pathlibr   projects_dir
project_id
episode_idexistsloads	read_text)selfr   _jsonr   _Pathcps         T/Users/manta/Documents/Projects/TheRoad-I1/backend/app/core/steps/beat_shot_steps.py_load_prev_checkpointz$_BeatShotMixin._load_prev_checkpoint   s    ,) (''(oo  oo	
   	 99;;;r||W|=>>    c                 L   ddl m} ddlm} | j                  j                  |      j                   ||j                              j                  |j                  | j                  k(        j                         }|r|j                  sddlm}  |ddd      |j                  S )	Nr   )Episode)undeferAppErrorzstep.no_fulltextu'   시나리오 텍스트가 없습니다.  codemessagestatus_code)app.models.projectr+   sqlalchemy.ormr,   dbqueryoptionsfulltextfilteridr   firstapp.core.errorsr.   )r#   r+   r,   epr.   s        r'   _load_fulltextz_BeatShotMixin._load_fulltext+   s|    .* GGMM'"WWW--./VGJJ$//12UW	 	 0 2<esvww{{r)   c                 :   | j                  d      }|r!|j                  di       j                  d      sddlm}  |ddd	      |d   d   }d
}t	        d |D              r6| j                         }t        j                  dt        d |D                     g }|D ]|  }|j                  d      xs% ||j                  dd      |j                  dd       }|j                  |d   |j                  dd
      ||j                  dt        |            d       ~ |S )uF   scene_save 체크포인트에서 segments → 씬 텍스트 리스트.
scene_savedatasegmentsr   r-   zstep.no_scenesu   scene_save 결과 없음r/   r0    c              3   @   K   | ]  }|j                  d          yw)textNget).0segs     r'   	<genexpr>z3_BeatShotMixin._load_scene_texts.<locals>.<genexpr>E   s     7hs3776?"hs   z<beat_shot: %d segments missing text, using fulltext fallbackc              3   D   K   | ]  }|j                  d       rd  yw)rF      NrG   rI   ss     r'   rK   z3_BeatShotMixin._load_scene_texts.<locals>.<genexpr>H   s     H(Q!%%-q(s     rF   
start_charend_charscene_indexheadinglength)idxrS   rF   rT   )r(   rH   r=   r.   anyr?   loggerwarningsumappendlen)r#   save_cpr.   rC   r9   scene_textsrJ   rF   s           r'   _load_scene_textsz _BeatShotMixin._load_scene_texts:   s   ,,\:gkk&"599*E0 0:Tbeff6?:. 7h77**,HNNYH(HHJ C776?_hsww|Q/GPZ\]H^&_D=)779b1''(CI6	    r)   c                     | j                  d      }|r!|j                  di       j                  d      sg S |d   d   D cg c]  }|d   	 c}S c c}w )uH   entity_character_list 체크포인트에서 인물 이름 목록 로드.entity_character_listrB   
charactersname)r(   rH   )r#   r&   cs      r'   _load_character_listz#_BeatShotMixin._load_character_listU   sZ    ''(?@+//=I#%f:l#;<#;a&	#;<<<s   AN)__name__
__module____qualname____doc__strr   r   r(   r?   r   r^   rd    r)   r'   r   r      sH    AS Xd^ $ 4: 6=d3i =r)   r   c                   L    e Zd ZdZddeeef   fdZdee   dee   fdZ	d	dZ
y)
BeatExtractStepuK   Beat 추출 — 원본 씬에서 인물 상태 변화 최소 단위 추출.r   c                 $   | j                         }| j                  d      }d}|r|j                  d      r|d   }|j                  dg       }|rddj                  d |D              z   }ng }|j                  dg       D ]M  }|j                  d	      d
v s|j	                  d|j                  d	d       d|j                  dd              O |rddj                  d |D              z   }|st
        j                  d       | j                         }	|	rJddj                  d |	D              z   dz   }
|r	|dz   |
z   }n|
}t
        j                  dt        |	             t        dd| j                        }t        dd| j                        }t        dd| j                        }| j                  |      }t
        j                  dt        |      t        |             i }t        t              5 }t        |      D ci c]-  \  }}|j!                  | j"                  ||dz   ||||      |dz   / }}}t%        |      D ]  }|j'                         \  }}}|||<    	 d d d        g }t)        |      D ]  }|j+                  ||           t-        d |D              }t/        t        |      t        |            }t
        j                  d||       |t        |      t1        dt        |      |z
        ||dd S c c}}w # 1 sw Y   xY w)!Nvisual_world_rulesrD   rB   director_notesuj   
[물리적 존재 판단 기준 — 인물 언급 시 카메라에 보이는 바디 기준으로 기술]

c              3   &   K   | ]	  }d |   ywz- Nrj   rI   ns     r'   rK   z+BeatExtractStep._execute.<locals>.<genexpr>n   s>       Zs  mr  hi  ]_  `a  _b  [c  mr   rules	rule_type
possession
projectionghost[] visual_guideline"   
[물리적 존재 판단 기준]
c              3   &   K   | ]	  }d |   ywrr   rj   rI   ls     r'   rK   z+BeatExtractStep._execute.<locals>.<genexpr>u        UthscdXZ[\Z]V^hsru   u_   beat_extract: visual_world_rules에 director_notes 없음 — 물리적 존재 기준 미적용uF   
[인물 목록 — 인물 언급 시 이 목록의 이름을 사용]
c              3   &   K   | ]	  }d |   ywrr   rj   rs   s     r'   rK   z+BeatExtractStep._execute.<locals>.<genexpr>|   s*       pS  CR}~rtuvtwpx  CRru   z$beat_extract: %d characters injectedbeat_extractsystemr6   userbeat_schemau&   beat_extract: %d scenes → %d bundles)max_workersrM   c              3   R   K   | ]  }t        |j                  d g              ! ywbeatsNr[   rH   rN   s     r'   rK   z+BeatExtractStep._execute.<locals>.<genexpr>   !     F:a#aeeGR01:   %'z!beat_extract: %d scenes, %d beatsr   )scenestotal_beats)completed_countapplicable_countfailed_countrB   )r^   r(   rH   joinrZ   rW   inford   r[   r   r6   r   _build_bundlesr   MAX_WORKERS	enumeratesubmit_call_bundler   resultsortedextendrY   minmax)r#   moder]   rules_cpvisual_rules
rules_datanotesrules_linesrcharacter_names
char_blockr   user_templateschemabundlesresults_by_idxpoolibfuturesfutrU   r   err
all_scenesr   	completeds                              r'   _executezBeatExtractStep._executed   sB   ,,. --.BCV,!&)JNN#3R8E  N  QU  QZ  QZ  Zs  mr  Zs  Qs   s #4Auu[)-RR#**Qquu["/E.FbOaceIfHg+hi 5 #IDIIUthsUtLt#tLKKyz 335cfjfofo  pS  CR  pS  gS  S  VZ  ZJ+d2Z?)KK>O@TU^X$''B#NFtwwG^]twwG%%k2<c+>NPST[P\]K8D
 &g.	 /DAq %%q!a%P\q5 /	   $G,#&::< VS&,s# - 9 
'AnQ/0 ( F:FFJ[)9:	7KP  ) #K 03{#3i#?@)+F	
 	
% 98s   4L2L 5,L LLr]   c                    g }d}|t        |      k  rDg }d}|t        |      k  rW|||   d   z   t        k  rE|j                  ||          |||   d   z  }|dz  }|t        |      k  r|||   d   z   t        k  rE|s/|t        |      k  r!|j                  ||          ||   d   }|dz  }g }d}|D ci c]  }|d   |
 }	}|d   d   dz
  }
|
dk\  rK|	j                  |
      }|r||d   z   t        kD  rn(|j                  d|d          ||d   z  }|
dz  }
|
dk\  rK|j                  |||rdj                  |      ndd       |t        |      k  rD|S c c}w )Nr   rT   rM   rU   rF   rD   )r   
bundle_lenref_text)r[   BUNDLE_TARGETrZ   rH   REF_MAXinsertr   )r#   r]   r   r   bundler   	ref_partsref_lenrO   scene_by_idxj	ref_scenes               r'   r   zBeatExtractStep._build_bundles   s   #k""FJc+&&:Ax8P+PTa+ak!n-k!nX66
Q c+&&:Ax8P+PTa+a a#k"22k!n-(^H5
Q IG1<=AAeHaKL=q	% 1$Aq&(,,Q/	 Gi.A$AG$K  If$569X..Q q& NN (2;BGGI. 3 #k""<  >s   6Ec                    dd l }|d   }|d   }	|D 
cg c]  }
|
d   	 }}
d}|	rd|	 d}dj                  d	 |D              }|r|dz   |z   }|j                  ||
      }|j                  |      }d|d|d   d   d   d   d<   |d   d    d|d   d    }d}t	        |dz         D ]  }	 t        d|||| j                  d| | j                               }|j                  dg       }|D 
cg c]  }
|
j                  d       }}
t        |      t        |      k7  rt        |      t        |      z
  }t        |      t        |      z
  }t        |      t        |      k(  r6|s4t        j                  d|||       t        |      D ]  \  }}
||   |
d<    n||k  rGt        j                  d||t        |      t        |      |dz   |       t        j                  d       At        j                  d|||       t        |      }|D ]  }||vs|j!                  |dg d        t#        d |D              }t        j%                  d||t        |      |       ||d fc S  y c c}
w c c}
w # t&        $ rp}||k  r8t        j                  d|||dz   ||       t        j                  d       Y d }~t        j                  d||||       |g t)        |      fcY d }~c S d }~ww xY w) Nr   r   r   rU   rD   uI   [앞쪽 씬 — 참조만, 이 씬들의 beat는 추출하지 마세요]


rp   c              3   D   K   | ]  }d |d    d|d    d|d      yw)
--- Scene rU   : rS   z ---
rF   Nrj   rN   s     r'   rK   z/BeatExtractStep._call_bundle.<locals>.<genexpr>   s7       
 5
"Qy\N&6Ds    )ref_sectionbundle_textintegertypeenum
propertiesitemsrR   ~   rM   r   beat_extract_stepsystem_promptuser_promptresponse_schemaproject_configschema_nameopik_metadatazPbeat_extract call %d (scenes %s): index mismatch, remapping by order. missing=%suV   beat_extract call %d (scenes %s): count mismatch (got %d, expected %d) — retry %d/%d   zLbeat_extract call %d (scenes %s): filling missing scenes %s with empty beats)rR   scene_headingr   c              3   R   K   | ]  }t        |j                  d g              ! ywr   r   rN   s     r'   rK   z/BeatExtractStep._call_bundle.<locals>.<genexpr>  !     !J6a#aeeGR&8"96r   z5beat_extract call %d (scenes %s): %d scenes, %d beatsz0beat_extract call %d (scenes %s) retry %d/%d: %sz<beat_extract call %d (scenes %s) FAILED after %d retries: %s)copyr   formatdeepcopyranger
   r   build_opik_metadatarH   setr[   rW   rX   r   timesleeprZ   rY   r   	Exceptionri   )r#   bundle_infocall_idxr   r   r   r   r   r   r   rO   expected_indicesr   r   r   call_schemascene_range	max_retryattemptr   r   returned_indicesmissingextrar   returned_setmir   excs                                r'   r   zBeatExtractStep._call_bundle   sV   X&z*.45fAeHf5fgofpptuKii  
 
 
 &/+=K#**## + 
 mmF+$U
L!(+G4\B=Q
  5)*!F2Ju,=+>?	Y]+G8.('"( +$/#'#6#6"/z :"&":":"<  Hb1 CI#I&QAEE-$8& #I'(C0@,AA!"23c:J6KKG 01C8H4IIE 6{c*:&;;En$k7 %.f$5DAq/?/BAm, %6 9,t$k3v;DT@UW^abWbdm 

1  j$k7 (++;'<"2B!5 &bSU`b.c d #3 "!J6!JJS$k3v;M--a ,7 6R $JF  .Y&NN#U#+['A+yRUWJJqM]'iFSX--.sJ   I*-AI40I/CI4),I4AI4/I44	K-=7K(:&K( K-(K-Nresume)rD   )re   rf   rg   rh   r   ri   r   r   r   r   r   rj   r)   r'   rl   rl   a   s>    U@
c3h @
D!$t* !d !FY.r)   rl   c                       e Zd ZdZdefdZddeeef   fdZde	e   dee
e	f   de	e   fdZde	e   defd	Zd
 ZddZy)ShotExtractStepu:   Shot 추출 — beat 기반으로 씬별 스틸컷 추출.r   c           	      >   ddl }ddl}ddlm} ddlm}m} |j                         } |dd| j                         |dd| j                        fD ]3  }|j                  |j                  d	             |j                  d
       5 |j                  |j                   |dd| j                        d      j                  d	             |j                  d
       |j                   || j                        j                  d	             |j                         dd S )u&  E2E13 Codex HIGH-3(재리뷰 HIGH-2): 실제 로드되는 effective
        prompt(system/user/schema — DB active row 우선 포함)의 내용 해시를
        접는다. 디렉터리 이름만 접으면 같은 팩 내 내용 변경·DB winner
        변경이 CP 무효화를 비껴간다.r   N)compute_config_hashr   shot_extractr   r   r   r       shot_schemaT)	sort_keys   )hashlibr   app.core.step_runnerr   app.modules.prompt_loaderr   r   sha256r6   updateencodedumpsr   	hexdigest)r#   r  r$   r   r   r   hrF   s           r'   _config_hashzShotExtractStep._config_hash,  s    
 	<FNNTWW=477;
D HHT[[)*HHW
 	
$''B  
 &/	 	
	$T%8%89@@IJ{{}Sb!!r)   c                    | j                         }| j                  d      }|r!|j                  di       j                  d      sddlm}  |ddd	      |d   d   }| j                  d
      }d}|r|j                  d      r|d   }|j                  dg       }	|	rddj                  d |	D              z   }ng }
|j                  dg       D ]M  }|j                  d      dv s|
j                  d|j                  dd       d|j                  dd              O |
rddj                  d |
D              z   }|st        j                  d       d}|rM|j                  d      r<|d   j                  dd      }|r%d| d}t        j                  dt        |             |r||z   }| j                         }|rt        j                  dt        |             t        dd| j                        }t        dd | j                        }t        dd!| j                        }dd"lm} | || j                         z  }i }|D ]+  }|j                  d#      }||j                  d$g       ||<   - | j#                  ||      }t        j                  d%t        |      t        |             g }d}t%        |      D ]a  \  }}|d&z   }| j'                  ||||||||      \  }}}|rt        j)                  d'||       |j+                  |       | j-                  |      }c |D cg c]  }|j                  d(      r|d#    }}|r t        j)                  d)t        |      |       t/        d* |D              } t1        t        |      t        |            }!t        j                  d+|!|        |!t        |      t3        dt        |      |!z
        || d,| j5                         d-S c c}w ).Nr   rB   r   r   r-   zstep.no_beatsu   beat_extract 결과 없음r/   r0   rn   rD   ro   ug   
[물리적 존재 판단 기준 — description에는 카메라에 보이는 인물/바디만 묘사]
rp   c              3   &   K   | ]	  }d |   ywrr   rj   rs   s     r'   rK   z+ShotExtractStep._execute.<locals>.<genexpr>X  s>       Wp  jo  ef  Z\  ]^  \_  X`  joru   rv   rw   rx   r|   r}   r~   r   c              3   &   K   | ]	  }d |   ywrr   rj   r   s     r'   rK   z+ShotExtractStep._execute.<locals>.<genexpr>`  r   ru   u_   shot_extract: visual_world_rules에 director_notes 없음 — 물리적 존재 기준 미적용t2i_contextu   
[시각적 배경 — 시나리오를 이미지화하는 작업입니다. description 묘사 시 아래 맥락을 반영하세요]
z-shot_extract: t2i_context injected (%d chars)z,shot_extract: %d characters injected as enumr   r   r   r   r   )project_corrections_blockrR   r   u3   shot_extract: %d scenes → %d bundles (sequential)rM   u%   shot_extract: bundle %d failed — %sshotsz(shot_extract: %d scenes with 0 shots: %sc              3   R   K   | ]  }t        |j                  d g              ! ywr  Nr   rN   s     r'   rK   z+ShotExtractStep._execute.<locals>.<genexpr>  r   r   z!shot_extract: %d scenes, %d shots)r   total_shots)r   r   r   rB   config_hash)r^   r(   rH   r=   r.   r   rZ   rW   r   r[   rd   r   r6   r   app.core.creator_correctionsr  r   r   r   r   rX   r   _build_prev_shots_contextrY   r   r   r  )"r#   r   r]   beat_cpr.   
beats_datar   r   r   r   r   r   r  _ctxr   r   r   r   r  beats_by_scene_idxbdrU   r   r   prev_shots_ctxr   r   r   r   r   rO   empty_shot_scenesr  r   s"                                     r'   r   zShotExtractStep._executeF  s   ,,. ,,^<gkk&"599(C09UcfggV_X.
 --.BCV,!&)JNN#3R8E  K  NR  NW  NW  Wp  jo  Wp  Np   p !#4Auu[)-RR#**Qquu["/E.FbOaceIfHg+hi 5 #IDIIUthsUtLt#tLKKyz V,F#''r:D !g  hl  gm  mo  pKSQUYW&5L 335KKFOH\]^X$''B#NFtwwG^]twwG 	K+DOO<<  B&&'C*,&&"*="3' 
 %%k3EFI3{K[]`ah]ij 
"7+IAv1uH#00&-~_n C FRUVf%!;;JGN , 8BXz!wQ}-zXNNEsK\G]_pqF:FFJ[)9:	7KP  ) #K 03{#3i#?@)+F  ,,.
 	
 Ys   !O"8O"r]   r  c                    g }d}|t        |      k  rg }d}|t        |      k  ro|||   d   z   t        k  r]||   }|j                  i |d|j                  |d   g       i       ||d   z  }|dz  }|t        |      k  r|||   d   z   t        k  r]|sG|t        |      k  r9||   }|j                  i |d|j                  |d   g       i       |d   }|dz  }|j                  ||d       |t        |      k  r|S )Nr   rT   r   rU   rM   )r   r   )r[   r   rZ   rH   )r#   r]   r  r   r   r   r   sts           r'   r   zShotExtractStep._build_bundles  s6   #k""FJc+&&:Ax8P+PTa+a ^TTW.@.D.DRYPR.STUbl*
Q	 c+&&:Ax8P+PTa+a
 a#k"22 ^TTW.@.D.DRYPR.STU\
QNNfJGH #k"" r)   r   c                 &   g }|D ]g  }|j                  dd      }|j                  dg       D ]>  }|j                  dd      }|j                  d| d|j                  dd       d	|        @ i |syt        d
kD  rg }d
}t        |      D ]9  }	t	        |	      |rdnd
z   }
||
z   t        kD  r n|j                  d
|	       ||
z  }; t	        |      t	        |      k  rddj                  |      z   S dj                  |      S dj                  |      S )uX   처리된 shot 결과 → 다음 번들 컨텍스트 (전체 전달, truncation 없음).rR   ?r  descriptionrD   u     씬z Shot
shot_indexr   r   rM   z  ...
rp   )rH   rZ   PREV_SHOTS_MAXreversedr[   r   r   )r#   r   linesrO   sishdesckepttotallineneededs              r'   r  z)ShotExtractStep._build_prev_shots_context  s   A}c*BeeGR(vvmR0uRDbff\3.G-H4&QR ) 
 ADE T4aQ76>N2At$ ( 4y3u:% 499T?2299T?"yyr)   c                     |syg }|D ]+  }|j                  d|d    d|d    d|d    d|d	           - d
j                  |      S )Nu:     (beat 없음 — 상황 묘사 기반으로 Shot 추출)z  Beat 
beat_indexz: [change_typer}   before_stateu    → after_staterp   )rZ   r   )r#   r   r'  r   s       r'   _format_beatszShotExtractStep._format_beats  sk    OALL71\?"33q7G6Hn-.eAm4D3EG H  yyr)   Nc	                    dd l }	|d   }
|
D cg c]  }|d   	 }}d}|rd|z   dz   }d}|rddj                  d	 |D              z   dz   }g }|
D ]<  }| j                  |d
         }|j                  d|d    d|d    d| d|d           > dj                  |      }|r|dz   |z   }d|v r|j	                  |||      }n|j	                  ||      }|r||z   }|	j                  |      }d|d|d   d   d   d   d<   |rM|d   d   d   d   j                  di       j                  di       j                  di       }d|v rd|d|d   d<   |
d   d    d|
d   d    }d}t        |dz         D ]  }	 t        d |||| j                  d!| | j                         "      }|j                  dg       }|D cg c]  }|j                  d       }}t        |      t        |      k7  rt        |      t        |      z
  }t        |      t        |      k(  r4t        j                  d#|||       t        |      D ]  \  }}||   |d<    nx||k  rGt        j                  d$||t        |      t        |      |dz   |       t!        j"                  d%       't        |      }|D ]  }||vs|j                  |dg d&        t%        d' |D              }t        j'                  d(||t        |      |       ||d fc S  y c c}w c c}w # t(        $ rp} ||k  r8t        j                  d)|||dz   ||        t!        j"                  d%       Y d } ~ t        j                  d*||||        |g t+        |       fcY d } ~ c S d } ~ ww xY w)+Nr   r   rU   rD   uR   [이전 씬의 Shot 결과 — 참조만, 인물 호칭·존재 일관성 유지]
r   uN   [인물 목록 — characters에는 반드시 이 목록의 이름만 사용]
rp   c              3   &   K   | ]	  }d |   ywrr   rj   rs   s     r'   rK   z/ShotExtractStep._call_bundle.<locals>.<genexpr>  s     >obHoru   r   r   r   rS   z ---
[Beats]
u   

[원문]
rF   z{character_list_section})r   scenes_sectioncharacter_list_section)r   r7  r   r   r   r   rR   r  ra   stringr   r   r   rM   r   shot_extract_r   zPshot_extract call %d (scenes %s): index mismatch, remapping by order. missing=%suV   shot_extract call %d (scenes %s): count mismatch (got %d, expected %d) — retry %d/%dr   )rR   r   r  c              3   R   K   | ]  }t        |j                  d g              ! ywr  r   rN   s     r'   rK   z/ShotExtractStep._call_bundle.<locals>.<genexpr>F  r   r   z5shot_extract call %d (scenes %s): %d scenes, %d shotsz0shot_extract call %d (scenes %s) retry %d/%d: %sz<shot_extract call %d (scenes %s) FAILED after %d retries: %s)r   r   r4  rZ   r   r   rH   r   r
   r   r   r   r[   rW   rX   r   r   r   rY   r   r   ri   )!r#   r   r   r   r   r   r   r  r   r   r   rO   r   r   r8  scenes_parts	beat_textr7  r   r   
shot_propsr   r   r   r   r   r   r   r   r   r   r  r   s!                                    r'   r   zShotExtractStep._call_bundle  sW   X&.45fAeHf5 e !#)*  "$a))>o>>? # A**1W:6IQuXJb9 7%; 'vYK)   \2)F2^CN%6'..'-'= / K (..'- / K &4{B mmF+$U
L!(+G4\B=Q $\28<WElSWWX_acdhhiprtuyy  {G  IK  LJz)$+5
<(1
  5)*!F2Ju,=+>?	Y]+G0.('"( +$/#'#6#6"/z :"&":":"<  Hb1 CI#I&QAEE-$8& #I'(C0@,AA!"23c:J6KKG6{c*:&;;n$k7 %.f$5DAq/?/BAm, %6 9,t$k3v;DT@UW^abWbdm 

1 '*+;'<"2B!5 &bSU`b.c d #3 "!J6!JJS$k3v;M--Q ,A 6\ $J6  .Y&NN#U#+['A+yRUWJJqM]'iFSX--.sJ   L7AL:LCLL.ALL	N7N &N 8N Nr   )rD   rD   N)re   rf   rg   rh   ri   r  r   r   r   r   intr   r  r4  r   rj   r)   r'   r   r   )  sx    D"c "4`
c3h `
D$t* $sTXy/ ^bcg^h & T
  s  2 u.r)   r   )rh   loggingr   concurrent.futuresr   r   typingr   r   r   r   r  r	   app.modules.llm.llm_clientr
   r  r   r   	getLoggerre   rW   r   r   r   r%  r   rl   r   rj   r)   r'   <module>rE     sx      ? , , + 6 >			8	$
D= D=VA.nj A.Pi.nj i.r)   