
    #jk                        d Z ddlZddl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  ej                  e      Z G d d      Z G d	 d
ee	      Z G d dee	      Z G d dee	      Z G d dee	      Z G d dee	      Zy)uJ   아웃룩 Phase StepRunner — outlook_phase1/2/3 (분할), outlook_dedup.    N)AnyDictListOptional)
StepRunner)NULL_OUTLOOK_SHORT_ID)episode_carryc                   J    e Zd ZdZdefdZdedee   fdZd Z	d Z
defdZy	)
_OutlookStepMixinuI   아웃룩 단계 공통 — fulltext 로드, 이전 단계 결과 로드.returnc                 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id
episode_idfirstapp.core.errorsr   )selfr   r   epr   s        R/Users/manta/Documents/Projects/TheRoad-I1/backend/app/core/steps/outlook_steps.py_load_fulltextz _OutlookStepMixin._load_fulltext   s    .* GGMM'"WWW--./VGJJ$//12UW	 	 0'A 
 {{    step_idc                     ddl m} ddlm}  ||j                        | j
                  z  dz  dz  | j                  z  |z  dz  }|j                         r%t        j                  |j                  d            S y )	Nr   Pathsettingscheckpointsepisodesmanifest.jsonutf-8encoding)pathlibr*   app.core.configr,   projects_dir
project_idr   existsjsonloads	read_text)r"   r'   r*   r,   cps        r$   _load_prev_checkpointz'_OutlookStepMixin._load_prev_checkpoint$   s{     , &&'$//9()+/??;=DE 	
 99;::bllGl<==r&   c                    | j                  d      }g }g }|r|j                  d      r|d   j                  dg       }ddlm}  || j                  | j
                  | j                        }t        |j                               D ]%  \  }}|d   dk(  s|j                  ||d   d	       ' |sh| j                  d
      }|rU|j                  d      rD|d   j                  dg       D ],  }	|j                  |	j                  d|	d         |	d   d	       . i }
|D ]I  }|j                  d      }|j                  dg       D cg c]  }|j                  d      s| }}||
|<   K ||
|fS c c}w )uE   scene_director 기반 캐릭터 목록 + 씬별 캐릭터 맵 로드.scene_directordatascenesr   )build_short_id_infotype	charactername)short_idrD   
entity_t2i
charactersrE   scene_indexpresent_entity_idsC)r<   getapp.modules.short_idrA   r   r6   r   sorteditemsappend
startswith)r"   director_prevdirector_scenesrG   rA   sid_infosidinfoentity_prevcscene_char_mapdssicharss                 r$   _load_characters_and_scene_mapz0_OutlookStepMixin._load_characters_and_scene_map1   ss   223CD
]..v6+F377"EO@*477DOOT__UH#HNN$45	T<;.%%3V&MN 6 44\BK{v6$V,00rBA%%155QvY3OYZ[aYb&cd C +-!B&B$&FF+?$D\$DSWZH[S$DE\!&N2 "
 >?:: ]s   E,E,c                    | j                  d      }|r!|j                  di       j                  d      s| j                  d      }|r!|j                  di       j                  d      sddlm}  |ddd	
      |d   d   S )N
scene_saver?   segmentsscene_segmentationr   r   step.no_inputu$   씬 세그먼테이션 결과 없음r   r   )r<   rK   r!   r   )r"   seg_prevr   s      r$   _load_segmentsz _OutlookStepMixin._load_segmentsL   s}    --l;x||FB7;;JG112FGHx||FB7;;JG09_mpqq
++r&   c                    | j                  d      }|r|j                  di       ni }d}|j                  d      s|j                  d      rld|j                  dd       d|j                  dd       }|j                  dg       D ]/  }|j                  d	      d
k(  s|d|j                  dd       z  }1 |j                  dd      }|r|d| z  }|S )Nvisual_world_rulesr?    eraregionu   시대: u	   
지역: rules	rule_typecostumeu	   
의상: descriptiont2i_contextu   

[T2I 시각 컨텍스트]
)r<   rK   )r"   vwr_cpvwr_datavisual_rulesrt2i_ctxs         r$   _load_visual_rulesz$_OutlookStepMixin._load_visual_rulesU   s    ++,@A-36::fb)<<(,,x"8%hll5"&=%>jV^`bIcHdeL\\'2.55%2 j}b1I0J$KKL / ,,}b1=gYGGLr&   N)__name__
__module____qualname____doc__strr%   r   r   r<   r\   rc   rs    r&   r$   r   r      s>    S &S Xd^ ;6,C r&   r   c                   4    e Zd ZdZdefdZddeeef   fdZy)OutlookPhase1StepuI   아웃룩 Phase1 — 캐릭터별 아웃룩 목록 추출 + orphan retry.r   c                    ddl }ddlm} ddlm}  || j
                        }i }dD ]#  \  }} |d||      }|d    d	|d
    |d| <   % t        j                  | j                  | j                  d| j                        }	d|i|}
|	r'|
j                  d|	it        j                                t        j                  |
dd      }|j                  |j!                  d            j#                         dd S )uk  앞 화 명부가 붙는 판에서는 **이관 팩 지문까지** 접는다.

        ★저장과 비교가 이 함수 하나를 봐야 한다 — `_execute` 가 이 값을
         `data["config_hash"]` 로 안 돌려주면 저장은 project_config 만 보고
         비교는 이것을 봐서 매번 어긋난다.
        ★2026-09-18: 「명부가 없으면 종전 값 그대로」는 **이제 아니다**.
         이 단계가 실제로 부르는 팩을 아래에서 늘 접는다 — 팩 문안을 고치고도
         지문이 안 움직이면 고친 글이 아무 데도 안 닿기 때문이다.
        r   N)compute_config_hash)resolve_effective))phase1prompt)phase1_schemaschemaoutlook_extractor)kindversion:raw_content_hashpack_outlookbasecarry_rosterTF)	sort_keysensure_asciir0      )hashlibapp.core.step_runnerr}   app.modules.prompt_loaderr~   project_config_ecroster_digestr   r6   r   updatepack_fingerprintr8   dumpssha256encode	hexdigest)r"   r   r}   r~   r   _packstemr   effdigestpayloadraws               r$   _config_hashzOutlookPhase1Step._config_hashj   s     	<?"4#6#67 8JD$#$7DIC'*9~&6a<N8O7P$QEE$.!8 ""477DOOY#'??44)5)NNNFMc6J6J6LMNjjDuE~~cjj12<<>sCCr&   c                   () | j                         }| j                         \  }}}| j                         }| j                         }ddlm} t        j                  dt        |      t        |             ddl	m
}	  |	| j                  | j                  d| j                  |dk(        }
i }g }ddlm}  || j                  | j                  | j                        }|j!                  d	d
      } |||||| j"                  ||
||	      }|j%                  dg       }|D ci c]%  }|j%                  dd      |j%                  dd      ' c}(|D ch c]  }|j%                  dd       c})()fd}ddlm}  || j                  | j                  d|       |D ]"  }|j%                  d      s ||d         |d<   $ t        j                  dt        |      dj+                  d |d d D                     |j-                         D ch c]  }|D ]  }|  }}}t/        dd      D ]$  }|D ch c]  }|j%                  dd       }}|D cg c],  }|j%                  dd      |v r|j%                  dd      |vr|. }}|s nt        j1                  d|t        |      |D cg c]-  }|j%                  dd      dz   |j%                  dd      z   dz   / c}       |j3                         D ci c].  \  }}||D cg c]  }||D ch c]  }|d   	 c}v s| c}}0 }}}}}|j3                         D ci c]  \  }}|s	|| }}} ||D cg c]  }|j%                  d      |v s| c}|||| j"                  ||
||	      }|j5                  |       |j%                  dg       } | st        j1                  d|        n || j                  | j                  d|        | D ]"  }|j%                  d      s ||d         |d<   $ |j7                  |        t        j                  d|t        |       t        |             ' t9               }!|g|xs dD ]7  }"|"xs i j%                  d g       xs g D ]  }||v s|!j;                  |        9 t9               }#|j%                  d!g       D ]  }||v s|#j;                  |        | j=                  d"      }$|$rl|$j%                  d#i       j%                  d$      rK|$d#   d$   D ]@  }%|%j%                  d%d&      r|%j%                  d'd      }&|&s+|&|v s0|#j;                  |&       B |D ch c]  }|j%                  dd       }}|D cg c]P  }|j%                  dd      |v r:|j%                  dd      |vr&|j%                  dd      |#vr|j%                  dd      R }}|r t        j1                  d(t        |      |       |#r|D cg c]'  }|j%                  d      |#v s|j%                  d      ) }'}|D cg c]  }|j%                  d      |#vs| }}|'rt        j                  d)|'       |j5                  t>        d*d+d d&d,       t        j                  d-t        |#      tA        |#             t        |      t        |      d| jC                         |tA        |#      tA        |!      d.|rtD        jF                  |id/S i d/S c c}w c c}w c c}}w c c}w c c}w c c}w c c}w c c}}w c c}}}}w c c}}w c c}w c c}w c c}w c c}w c c}w )0Nr   )extract_outlooks_phase1z(Outlook phase1: %d scenes, %d characters)build_roster_blockr   force)refresh)get_planning_contextcharacters_textu!   ## 기획서 인물 참고 정보)	r_   rG   scene_character_maprp   r   opik_metadataprior_roster	carry_outplanning_blockoutlooksrD   rf   rE   c                 4    | v r| S j                  | |       S NrK   )cid_char_name_to_sid_char_sid_sets    r$   _normalize_char_idz6OutlookPhase1Step._execute.<locals>._normalize_char_id   s#    m#
$((c22r&   )assign_short_idscharacter_idz)Outlook phase1 complete: %d outlooks (%s)z, c              3   @   K   | ]  }|j                  d d        yw)rE   ?Nr   ).0os     r$   	<genexpr>z-OutlookPhase1Step._execute.<locals>.<genexpr>   s     R>QaeeJ4>Q            u6   Outlook phase1 retry %d/2: %d orphan characters — %s()rH   z:Outlook phase1 retry %d: LLM returned 0 outlooks, stoppingz0Outlook phase1 retry %d: +%d outlooks (total %d)ry   body_identity_charactersnon_humanoid_charactersentity_relationr?   	relationsvisual_similarityTvariant_short_idzBOutlook phase1: %d orphan characters without outlook (not O00): %sz:O00: removed LLM-assigned outlooks for non-human chars: %szNull OutlookzBNon-human or non-outfit entity. Uses entity reference image as-is.)rE   rD   rl   r   is_nullz0O00 (Null Outlook) assigned to %d characters: %s)r   null_outlook_charsbody_identity_chars)completed_countapplicable_countfailed_countconfig_hashr?   )$rc   r\   rs   build_opik_metadata)app.modules.pipeline.outlook_extractor_v2r   loggerrU   len"app.modules.pipeline.episode_carryr   r   r6   r   app.core.planning_doc_contextr   inject_if_availabler   rK   app.core.entity_identityr   joinvaluesrangewarningrN   rO   extendsetaddr<   r   rM   r   r   
LEDGER_KEY)*r"   moder_   rG   rX   _rp   	opik_metar   r   _roster_carry_retry_resultsr   _pctx	_planningphase1_resultphase1_outlooksrW   r   r   olr[   r   active_char_sidsp1_retrychars_with_outlookorphan_charsrZ   orphan_char_mapsegretry1_resultnew_outlooksr   _rr   rel_cprelvar_sidremovedr   r   s*                                           @@r$   _executezOutlookPhase1Step._execute   s{   &&((,(K(K(M%
NA..0,,.	U>HsS]_ 	J %TWWdooy%)__.2go@ "$!F$T__dootwwO--BD	/! .%..# $

 (++J; PZZz!QUU62.j"0EEzZ8BC
1z2.
C	3 	>$//9oN!Bvvn%%7>8J%K>" " 	?(IIRobq>QRR	T
 .<-B-B-DV-DEPUCPUC-DVaHGV!W"&&"<!W'1 Pz!eeJ37GG uuZ4<NN zL P  NNH#l+P\]P\1z2&,quuVR/@@3FP\] 1?0D0D0FH0F92u  "5#i5CC[gCh[gVWAjM[gCh<hC5#ii0F  H:I:O:O:Q[:QYRUZr5y:QO[3)1_#SWW]5K5^#_'$3)#22'
 % (M !!-0(,,Z<L[]ef TWWdooy,O"66.));B~<N)OB~& # ""<0KKJ #l"3S5IKW $f "e :N$8b:Bb~~&@"EKK**'++C0 L ; !U !$$%>CC&&"&&s+ D
 ++,=>fjj,00=f~k2ww2D9!gg&8"=G7.>#>*..w7	 3 DSS?Rbff^R8?S+5
+5auuZ$(88j"%-??j"%-?? EE*b!: 	 
 NNTL!<
 4CtObrvvnG]asGsrvvj)OGt,;pObrvvn?U]o?orOOpXZab ""1&c $$  KKB&'0B)C  #?3 #J,,.+&,-?&@'-.A'B 06CNNF+
 	
 <>
 	
S [C0 W!WP ^Ch#i H[_z T
 ups   *[;\ 
\1\1\'2\5\%
\\\\"\% 
\-\-\3
2\3
\88A\=7]])]]\\%Nresume)	rt   ru   rv   rw   rx   r   r   r   r   ry   r&   r$   r{   r{   g   s*    S#Dc #DJ@
c3h @
r&   r{   c                   (    e Zd ZdZddeeef   fdZy)OutlookPhase2StepuH   아웃룩 Phase2 — 씬별 캐릭터→아웃룩 매핑 + 누락 retry.r   c                 B  ./01 | j                         }| j                         \  }0}| j                         }| j                  d      }|r!|j	                  di       j	                  d      sddlm}  |ddd	      |d   d   }t        |d   j	                  d
g             }	|D 
cg c]+  }
|
j	                  d      dk7  s|
j	                  d      r*|
- }}
|D cg c]  }|j	                  dd      |	vs| }}0j                         D ci c]  \  }}||D cg c]	  }||	vs| c} }}}}|j                         D ci c]  \  }}|s	|| }}}ddl	m
} t        j                  dt        |      t        |      t        |	              |||||| j                  |      }|j	                  dg       /t        j                  dt        /             |D 
ch c](  }
|
j	                  d      r|
j	                  d      xs d* c}
.d}dt        f./0fd}t        d|dz         D ]  }0j                         D ch c]  \  }}t!        .fd|D              r| }}}/D ch c]  }|j	                  d      s|d    }}||z
  }/D ]p  }|d   }0j	                  |g       D ch c]  }|.v r|
 }}|j	                  dg       D ch c]  }|j	                  dd       }}||z
  s`|j#                  |       r |s nt         |             }t        j%                  d||t        |             |D cg c]  }|j	                  d      |v s| } }| s n0j                         D ci c]  \  }}||v s|| }!}}|!j'                         D ch c]  }|D ]  }|  }"}}|D cg c](  }|j	                  d|j	                  d            |"v s'|* }#} || ||#|!| j                  |      }$|$j	                  dg       }%|%D ]  }|j	                  d      s|d   1t)        1fd/D        d       }&|&r|&j	                  d      s+/D 'cg c]  }'|'d   1k7  s|' c}'//j+                  |       m|&d   D ch c]  }|j	                  dd       }(}|d   D ]+  }|j	                  dd      |(vs|&d   j+                  |       -  t         |             })t        j                  d|||)       |)|k\  s n  |       }*|*r)t        j%                  d t        |*      t-        |*             |	r؉/D ci c]  }|d   |
 }+}d},0j                         D ]  \  }}|D cg c]	  }||	v s| }-}|-s|+j	                  |      }|s|g d!}/j+                  |       ||+|<   |-D ]I  }|d   D cg c]  }|j	                  d      |k7  s| c}|d<   |d   j+                  |dd"       |,dz  },K  |,rt        j                  d#|,       t        /      t        |      d|/t-        |	      d$d%S c c}
w c c}w c c}w c c}}}w c c}}w c c}
w c c}}w c c}w c c}w c c}w c c}w c c}}w c c}}w c c}w c c}'w c c}w c c}w c c}w c c}w )&Noutlook_phase1r?   r   r   r   ra   u   outlook_phase1 결과 없음r   r   r   rE   O00r   rf   )extract_outlooks_phase2zIOutlook phase2: mapping %d outlooks to %d scenes (O00: %d chars excluded))r_   r   rG   r   r   r   scene_assignmentsz-Outlook phase2 complete: %d scene assignmentsr   r   r   c                  F   i } D ]E  }| j                  |d   t                     j                  d |j                  dg       D               G j	                         D ch c]0  \  }}|D ]&  }|v r || j                  |t                     vr||f( 2 c}}}S c c}}}w )NrH   c              3   @   K   | ]  }|j                  d d        yw)r   rf   Nr   )r   as     r$   r   zEOutlookPhase2Step._execute.<locals>._missing_pairs.<locals>.<genexpr>  s"      @R7P!AEE."-7Pr   assignments)
setdefaultr   r   rK   rN   )gotsarZ   r[   rW   _chars_with_outlookr  rX   s        r$   _missing_pairsz2OutlookPhase2Step._execute.<locals>._missing_pairs  s    "$C!r-0#%8?? @R79vvmR7P@R R " .<-A-A-C Q-C	EU//ASWWR=O4O GUG-C Q Q Qs   "5Br   c              3   &   K   | ]  }|v  
 y wr   ry   )r   rW   r	  s     r$   r   z-OutlookPhase2Step._execute.<locals>.<genexpr>  s     ?Aq//s   r  rH   u(   Outlook phase2 retry %d/%d: %d씬 누락rD   c              3   4   K   | ]  }|d    k(  s|  yw)rH   Nry   )r   ssi_matchs     r$   r   z-OutlookPhase2Step._execute.<locals>.<genexpr>  s     #[{!a>NRZ>ZA{s   u7   Outlook phase2 retry %d: 빠진 (씬, 인물) %d → %duI   Outlook phase2: 끝내 아웃룩이 안 붙은 (씬, 인물) %d개 — %s)rH   r  )r   
outlook_idz*O00 injected into %d scene-character slots)r   r  r   r   r   r   r?   )rc   r\   r   r<   rK   r!   r   r   rN   r   r   r   rU   r   r   r   anyr   r   r   nextrO   rM   )2r"   r   r_   rG   r   r   p1_cpr   r   r   r   regular_outlooksrW   regular_charsrZ   r[   r   regular_scene_mapr   phase2_result	MAX_RETRYr
  retry_roundscenes_with_charsr  assigned_scenesmissing_scenesexpectedr  assignedbeforer   missing_segmentsmissing_char_mapmissing_char_idsmissing_charactersretry_resultretry_assignmentsexisting_sar  existing_charsafterleftassignments_mapinjected_countnull_in_scener	  r  rX   r  s2                                                 @@@@r$   r   zOutlookPhase2Step._executeX  s=   &&((,(K(K(M%
NA,,.	 **+;<EIIfb155jA09Wehii=, v!2!23G!LM *2k2RVVJ5G55PY[Y_Y_`iYjBk$.bJq!%%
B2GOa2aJb ,113
3	E G4F)FGG3 	 
 9J8O8O8Q[8Q92uUZRY8Q[U_)*CM3?Q;R	T/%$ 1..#
 $''(;R@CSEUV 6F
5Ervvn% VVN#)r)5E
 		Q 	Q !IM2K$2$8$8$:!$:yr5??? $:  ! <G`;R"&&Q^J_r-0;O`.@N!&'5'9'9"b'A 9'A! $77 'A 9?AvvmUW?XY?X!AEE."5?XYh&"&&r* " ")*FNNE{T]_bcq_rs/7dx377=;QUc;cxd#;I;O;O;Qj;Qib%UW[iUiE	;Qj1A1H1H1J\1JV[sV[1J\-7!pZ155QUUSY];[_o;o!Z!p2)!-$4#22'L !- 0 01Db I'vvm,m,"#[{#[]ab"+//-*H.9"ZkQ}=MQY=Y1k"ZK&&r*ITUbIc%dIcAaeeNB&?IcN%d.554NJ'6==a@ / (  ()EKKQS^`fhmnw 3z NNfhklphqsyz~s  A P[/\P["=0A20EP[O/\N+113	E05 S@R9R S$$((,)+B?B&&r**,OB'(C#%m#4)#4an8MQT8T#4)B}% }%,,cQV-WX"a'N ) 4  H.Y  #;/ #H$%0&,-?&@		
 		
K lbG
 \.
 ! a
9Y  e  k\!p$ #[ &e& 0] !T)s   (X<X<X<Y8YY	Y)Y-Y	
YY"-Y Y/Y#Y#2Y(Y-Y2Y2:Y7Y7"Y=9(Z"ZZ(ZZZ-	Z7Z:ZZYNr   rt   ru   rv   rw   r   rx   r   r   ry   r&   r$   r   r   U  s    R\
c3h \
r&   r   c                   (    e Zd ZdZddeeef   fdZy)OutlookPhase3Stepu=   아웃룩 Phase3 — LLM 병합 판별 + 코드에서 정리.r   c           	         | j                  d      }|r|j                  d      sddlm}  |ddd      |d   d	   }|d   d
   }t	        |d   j                  dg             }d }g }|D ];  }	|	j                  d      dk(  s|	j                  d      r|	}+|j                  |	       = | j                         \  }
}}i }|D ]]  }|j                  d      }|j                  dg       D ]5  }|j                  d      s|j                  |g       j                  |       7 _ | j                  d      }i }|rL|j                  di       j                  dg       D ]'  }|j                  dd      ||j                  dd      <   ) ddl	m
} t        j                  dt        |      t        |              |||||| j                  | j                               }|j                  dg       }|j                  dg       }|j                  dg       }|D ci c]  }|j                  d      s|d   |d    }}|rS|D ]8  }|j                  dg       D ]!  }|j                  dd      }||v s||   |d<   # : t        j                  d|       |r&|j                  |       t        j                  d       t        j                  d t        |      t        |             t        |      d!d|||t!        |      d"d#S c c}w )$Noutlook_phase2r?   r   r   ra   u   outlook_phase2 결과 없음r   r   r   r  r   rE   r   r   rH   rI   rJ   scene_summary	summariesrf   )extract_outlooks_phase3zDOutlook phase3: cleaning %d outlooks, %d assignments (O00 protected))r   r  scene_summariescharacter_routesr   r   cleaned_outlookscleaned_assignmentsr   
merge_intor  r  zPhase3 merge applied: %sz-O00 (Null Outlook) preserved in phase3 resultz1Outlook phase3 complete: %d outlooks (removed %d)r   )r   r  r   r   r  )r<   rK   r!   r   r   rO   r\   rP   r  r   r4  r   rU   r   r   r   rM   )r"   r   p2_cpr   r   r  r   o00_outlookr  r   r   rX   rR   r6  rY   rZ   rT   
summary_cpr5  ssr4  phase3_resultr7  r8  r   rq   	merge_mapr  r  oids                                 r$   r   zOutlookPhase3Step._execute  s   **+;<EIIf-09Wehii=,Fm$78 v!2!23G!LM Bvvj!U*bffY.?  ''+	  .2-P-P-R*>?,.!B&Bvv2B7>>#&$//R8??C 8 " //@
*, nnVR044["E<>FF?TV<W}a 89 F 	V 	Z\_`p\qsv  xC  tD  	E/%)+-..224
 ),,-?D+//0ErJ##Ir2 @G^w!!%%P\J]Q|_ao5w	^)r2A%%b1Ci'*3C., 3 *
 KK2I> ##K0KKGHGM]I^`cdk`lm  ##34 !,%8"&,-?&@		

 
	
! _s   K8'K8Nr   r-  ry   r&   r$   r/  r/    s    GN
c3h N
r&   r/  c                   (    e Zd ZdZddeeef   fdZy)OutlookExtractionStepu8   Legacy: outlook_extraction → phase1+2+3 순차 실행.r   c                    t         j                  t               }|j                  j                  | j                         |j	                  |      }| j                  d|d   d       ddlm} ddlm	}  ||j                        | j                  z  dz  dz  | j                  z  d	z  }|j                  d
d
       |dz  j                  t        j                   d|d   ddd      d       t"        j                  t"              }|j                  j                  | j                         |j	                  |      } ||j                        | j                  z  dz  dz  | j                  z  dz  }	|	j                  d
d
       |	dz  j                  t        j                   d|d   ddd      d       t$        j                  t$              }
|
j                  j                  | j                         |
j	                  |      }|S )Nrunningr?   )statusr?   r   r)   r+   r-   r.   r   T)parentsexist_okr/   	completedF   )r   indentr0   r1   r1  )r{   __new____dict__r   r   save_checkpointr3   r*   r4   r,   r5   r6   r   mkdir
write_textr8   r   r   r/  )r"   r   p1	p1_resultr*   r,   	p1_cp_dirp2	p2_result	p2_cp_dirp3	p3_results               r$   r   zOutlookExtractionStep._executeT  s   &&'89
4==)KK%		9V;LMN 	!,../$//AMQT^^aeapapp  tD  D	t4	_	$00JJ+y7HIX]fgh 	1 	

 &&'89
4==)KK%	 ../$//AMQT^^aeapapp  tD  D	t4	_	$00JJ+y7HIX]fgh 	1 	

 &&'89
4==)KK%	r&   Nr   r-  ry   r&   r$   rB  rB  Q  s    B"c3h "r&   rB  c                   (    e Zd ZdZddeeef   fdZy)OutlookDedupStepuB   아웃룩 중복 판별 — 기존 outlook_dedup 로직 재사용.r   c                    ddl m}m} | j                  d      }|r|j	                  d      dk7  r| j                  d      }|r|j	                  d      dk7  r	dddddid	S |j	                  d
i       j	                  dg       }|D cg c]+  }|j	                  d      dk7  s|j	                  d      r*|- }}t        |      dk  r	dddddid	S  ||| j                        }t        |t              rt        |      nd}	|	dkD  r5 || j                  | j                  |       t        j                  d|	       nt        j                  d       ddd|	|dd	S c c}w )Nr   )find_duplicate_outlooksapply_outlook_mergeoutlook_phase3rE  rH  outlook_extractionr   z'outlook phase3/extraction not completedr  r?   r   rE   r   r   rI  ztoo few outlooks to dedup)r   zOutlook dedup: merged %d groupsz"Outlook dedup: no duplicates foundr   )merge_groups
duplicates)"app.modules.pipeline.outlook_dedupr[  r\  r<   rK   r   r   
isinstancelistr   r6   r   rU   )
r"   r   r[  r\  ol_cpr   r   r  r`  merge_counts
             r$   r   zOutlookDedupStep._execute  sm   	
 **+;<		(+{:../CDE		(+{:#$$% !"$MN	  99VR(,,Z<)1k2RVVJ5G55PY[Y_Y_`iYjBk 1$#$$% !"$?@	  --=dNaNab
)3J)Ec*o1?*EKK9;GKK<=  ! !%0
K	
 	
% ls   E E2ENr   r-  ry   r&   r$   rY  rY  |  s    L+
c3h +
r&   rY  )rw   r8   loggingtypingr   r   r   r   r   r   r   r   app.modules.pipeliner	   r   	getLoggerrt   r   r   r{   r   r/  rB  rY  ry   r&   r$   <module>rj     s    P   , , + : 5			8	$S Srh
): h
\_
): _
JQ
): Q
n%-z %V.
(* .
r&   