
    h;jbP                     "   d Z ddlZddlZddlmZ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mZ  ej(                  e      Zd	Zd
edeeeeef   f   fdZ	 	 ddeeef   d
eeef   deeef   deeef   deeef   deeef   deeeef      dee   deeef   fdZdededeeef   fdZdedeeee   f   fdZdedeeef   fdZdedeeef   dedee   dee   f
dZ d
edeeee   f   deeef   dededee   dee   fdZ!y) uu  T2I 프롬프트 검수 — 감지 only (mutation=0, signal-only).

entity_t2i: 한국어 설명과 비교하여 T2I 검증 (배치 1회)
scene_detail: shot 원본과 비교하여 T2I 검증 (배치 N회, BATCH_SIZE개씩)

v1 (Area #6, 2026-05-18+): blind substring mutation 폐기 + 5 core fields
structured diagnostic emit. 외부 force signal only — in-step regen 0.
    N)AnyDictListOptionalTuple)AppError)_normalize_scene_detail_result)call_structured)SchemaValidationError)load_promptload_schema
   scene_detail_datareturnc                     i }t        | j                  dg             D ]K  \  }}|j                  d      }t        |j                  dg             D ]  \  }}d| d| d| }||f||<    M |S )u  t2i_variations 모두 순회 — item_id (deterministic) → (scene_list_idx, variation_idx) map 생성.

    item_id format: f"S{scene_index}_L{scene_list_idx}_V{variation_idx}"
    LLM 이 prompt 의 item_id 를 echo 하면 application 이 map 으로 정확 위치 찾음.

    AC-A6 (V3 patch I1, spec §3.3): fan-out 시나리오 (같은 scene_index 다수) 모호성 차단.
    scenesscene_indext2i_variationsS_L_V)	enumerateget)r   m
s_list_idxscener   v_idx
_variationitem_ids           U/Users/manta/Documents/Projects/TheRoad-I1/backend/app/modules/pipeline/t2i_review.py_build_item_id_mapr!      s     %'A&'8'<'<Xr'JK
Eii.!*5995Er+J!KE:+bBug>G$e,AgJ "L L
 H    entity_t2i_dataentity_merge_dataentity_detail_datashot_extract_datavwr_datashot_staging_dataopik_metadatac                 x   |j                  dd      }|j                  dg       D 	cg c]  }	|	d   	 }
}	dj                  |
      }t        ||      }t        |      }t	        |xs i       }t        | |||      }ddlm} t        |dd	      d
k(  xr t        |dd      }|rg }t        j                  d       nt        ||||||      }t        |       t        |      t        |      z   }t        j                  dt        |      t        |             t        |      t        |      ddg |rd|dS d|dS c c}	w )u  T2I 검수 실행 — 감지 only, mutation 0.

    Area #6 v1: target/suggestion blind substring replacement 폐기.
    LLM 이 5 core fields ({id, scope, issue_code, action, hint_diagnostic})
    structured diagnostic 만 emit. 코드는 emit 누적 → 외부 force signal only.

    Returns:
        {
          "entity_fixes": int (detected count, entity scope),
          "scene_fixes":  int (detected count, scene scope),
          "entity_applied": 0  (mutation=0 invariant, canary),
          "scene_applied":  0  (mutation=0 invariant, canary),
          "scene_applied_indices": []  (always empty, canary),
          "diagnostics": list[dict]  (entity + scene 통합 5 core fields list),
        }
    t2i_context 
charactersnamez, r   )settingsstill_recipe_modeoffv1t2i_review_skip_scene_on_v1Tu[   t2i_review: v1 이라 씬 갈래를 건너뛴다 (그 산문은 이미지에 안 쓰인다)zGt2i_review v1: entity %d diagnostics, scene %d diagnostics (mutation=0)skipped_v1_typed_sotran)entity_fixesscene_fixesentity_appliedscene_appliedscene_applied_indicesscene_review_statusdiagnostics)r   join_build_entity_desc_map_build_shot_map_build_staging_map_review_entity_t2iapp.core.configr/   getattrloggerinfo_review_scene_detailr!   listlen)r#   r   r$   r%   r&   r'   r(   r)   r+   c
char_nameschar_names_strentity_desc_mapshot_mapstaging_mapentity_diagnostics_st_scene_skippedscene_diagnosticsr<   s                       r    run_t2i_reviewrS   )   s   6 ,,}b1K%6%:%:<%LM%L!F)%LJMYYz*N --?ARSO 01H %%6%<"=K ,+}  0 	(%0D8 	>C6=  249	: 1xkM
 ())*T2C-DDK
KKQ%6!7 ./-.!# '5""
 
 ;@"
 
s Ns   D7c           	      @   i }| j                  di       }|j                         D ]v  \  }}|j                  d      }|d   }dD ]V  }|j                  |g       D ]?  }	|	j                  d      |k(  s||j                  dd      d||	j                  d	d      <   A X x |S )
u!   short_id → {name, description}.entity_details:r   r-   	locationspropsr.   descriptionr,   )r.   rZ   short_id)r   itemssplit)
r%   r$   desc_mapdetailskeyvalpartsr.   cates
             r    r>   r>      s     H $$%5r:GMMOS		#Qx7C&**3355=D( $'*ww}b'A7HQUU:r23 4 8 $ Or"   c           	          i }| j                  dg       D ]e  }|j                  d      }g }|j                  dg       D ]6  }|j                  |j                  dd      |j                  dd      d       8 |||<   g |S )	u,   scene_index → [{shot_index, description}].r   r   shots
shot_indexr   rZ   r,   )rg   rZ   )r   append)r&   rM   ssirf   shs         r    r?   r?      s    H""8R0UU=!%%$BLL ff\15!vvmR8  %
  1 Or"   c                     i }| j                  dg       xs g D ]H  }|j                  d      }|j                  d      }||*|j                  d      xs d}|sB||||f<   J |S )u+  (scene_index, shot_index) → camera_direction string.

    Phase 9.2: 신규 close_framing_existing_ref / physical_inconsistency 검증 룰이
    camera_direction을 비교 대상으로 요구. shot_staging cp의 shots[] 배열에서
    각 (si, shi)별 camera_direction 자연어를 추출.
    rf   r   rg   camera_directionr,   r   )r(   resultrk   rj   shicams         r    r@   r@      s|     F##GR06B6VVM"ff\":ff'(.B #FB9 7 Mr"   rL   r+   c                    t        dd      }t        dd      }|j                  |      }g }dD ]  }| j                  |g       D ]q  }|j                  dd      }	|j                  dd      }
|
s*|j                  |	i       }|j	                  |	|j                  d	d      |j                  d
d      |
d       s  |sg S g }|D ]+  }|j	                  d|d    d|d	    d|d    d|d           - ddj                  |      z   }	 t        d||||      }g }|j                  dg       D ]  }|j                  d      s|j                  d      s'|j                  dd      }|d   D ]|  }|d   }|d   |cxk(  r|k(  sn t        dd|d   d |d!|d"      |j	                  |d   |d#   |d$   |d%   |d&   |d'       t        j                  d(|d   |d$   |d&   dd)        ~  |S # t        t        f$ r  t        $ rB}t        j                  d|       t        ddt        |      j                   d|       |d}~ww xY w)*uX   entity_t2i 배치 검증 — 한국어 설명과 비교. diagnostic 누적 (mutation=0).
t2i_reviewentity_systementity_schema)r+   rW   r[   r,   
t2i_promptr.   rZ   )r[   r.   korean_descrv   [z] u   
  한국어 설명: rw   z
  T2I: u=   아래 엔티티들의 T2I 프롬프트를 검수하세요:



stepsystem_promptuser_promptresponse_schemar)   z"t2i_review entity batch failed: %szt2i_review.entity_batch_faileduh   t2i_review entity batch transient failure — partial success 금지 (silent fallback 정책). original=: codemessageNresults
has_issuesissuesid$t2i_review.diagnostic_alias_mismatchuE   entity issue id/short_id alias mismatch — schema 위반. iss['id']=z iss['short_id']=z result short_id=    (spec §3 Q8 alias=id strict)scope
issue_codeactionhint_diagnostic)r   r   r   r   r   r[   zt2i_review entity %s [%s]: %sP   )r   r   formatr   rh   r=   r
   r   r   	ExceptionrD   errortype__name__rE   )r#   rL   r+   r)   systemschemar\   rc   rI   sidt2i	desc_info
user_lineseir}   ro   rd   r<   rr[   ississ_short_ids                         r    rA   rA      s    7F7F]]{]3F E3 $$S"-A%%
B'C%%b)C'++C4ILLfb)(}}]B?!	  . 4 	J:r"V* .##%m#4"5 6&')	
  TV\VaVablVmmK  #"'
4 !KZZ	2&55155?uuZ,H{  #:D	X=="C)),T 6//;.> ?//7l ;<=	 	 ""d) \"%l"3!(m'*+<'= ,$  3Is<0#6G2H"2M1 # '@ i +, 
 	  	91=166:1g6F6F5Gr!N
 	s   G* *I=H??IrM   rN   rK   c                 x  # t        dd      }t        dd      }|j                  ||      }g }t        | j	                  dg             D ]  \  }	}
t        |
d       |
j	                  d      }|
j	                  d	      #|j	                  |g       }#"t        #fd|D        d      }|rd# d| nd}n|rdj                  d |D              nd}#|j	                  |#fd      nd}t        |
j	                  dg             D ];  \  }}|j	                  dd      }|s|j                  d| d|	 d| |||||d       =  |sg S g }d}t        dt        |      t              D ]  }|||t        z    }|t        z  dz   }t        |      dz
  t        z  dz   }g }|D ]D  }|d   r	d|d    dnd}|j                  d|d    d|d    d|d     d!|d"    d| d#|d           F d$d%j                  |      z   }	 t        d||||&      }|j	                  d'g       D ]  }|j	                  d(      s|j	                  d)      s'|j	                  d      }|sMt        d*d+|j	                  d       d,|j	                  d        d-t        |j	                  d)g              .      |d)   D ]X  } | d   }!| d/   |cxk(  r|!k(  sn t        d0d1| d/   d2|!d3|d4.      |j                  | d/   | d5   | d6   | d7   | d8   |!d9       Z  t        j                  d:||t        |      t!        d; |j	                  d'g       D                      |r+t        j'                  d=|       t        d>d?| d@| dA.      |S # t        t"        f$ r  t$        $ r(}"|dz  }t        j'                  d<|||"       Y d
}"~"Nd
}"~"ww xY w)Bug  scene_detail 배치 검증 — shot 원본 + camera_direction과 비교 (Phase 9.2).

    각 t2i_variation 별로 `_shot_index`(scene_detail v3+)가 있으면 그 단일 shot의
    description + camera_direction을 inject. 없으면 (legacy) scene 내 모든 shot
    description fallback.

    Area #6 v1: 5 core fields diagnostic 누적 (mutation=0).
    rs   scene_systemscene_schema)r+   rJ   r   zt2i_review._review_scene_detail)wherer   _shot_indexNc              3   :   K   | ]  }|d    k(  s|d     yw)rg   rZ   N ).0rk   rp   s     r    	<genexpr>z'_review_scene_detail.<locals>.<genexpr>P  s#     NUrb6F#6MM"Us   
r,     shotr   u   (없음)
c              3   8   K   | ]  }d |d    d|d      yw)r   rg   r   rZ   Nr   )r   rk   s     r    r   z'_review_scene_detail.<locals>.<genexpr>U  s-      "KPR&L)*"R->,?@5s   r   rv   r   r   r   )r   r   	var_index	shot_textrm   rv   r      rm   z  camera_direction: z
[item_id: r   u   ] [씬z varr   u   ]
  shot 원본:
r   z  T2I: u7   아래 씬들의 T2I 프롬프트를 검수하세요:

ry   rz   r   r   r   zt2i_review.missing_item_idu:   LLM result missing item_id — schema 위반. scene_index=z var_index=z issues=r   r   r   uC   scene issue id/item_id alias mismatch — schema 위반. iss['id']=z iss['item_id']=z result item_id=r   r   r   r   r   )r   r   r   r   r   r   z1t2i_review scene batch %d/%d: %d items, %d issuesc              3   d   K   | ](  }|j                  d       r|j                  d      rd * yw)r   r   r   Nrn   )r   r   s     r    r   z'_review_scene_detail.<locals>.<genexpr>  s/      H'@! uu\2quuX '@s   .0z't2i_review scene batch %d/%d failed: %sz&t2i_review: %d/%d scene batches failedzt2i_review.batch_failedzt2i_review /u\    scene batches failed — transient errors. partial success 금지 (silent fallback 정책).)r   r   r   r   r   r	   nextr=   rh   rangerH   
BATCH_SIZEr
   r   rD   rE   sumr   r   warning)$r   rM   rN   r+   rK   r)   r   r   r\   r   ri   rj   rf   	shot_descr   cam_dirvivr   fixesfailed_batchesbatch_startbatch	batch_numtotal_batchesr   bi	cam_blockr}   ro   r   result_item_idr   iss_item_idrd   rp   s$                                      @r    rF   rF   /  s   " ~6F~6F]]{~]NF E"#4#8#82#FG
A&q0QRUU=!eeM"R$ ?NUNI 8A&R	{3jI  		 "KP" & 
 58O+//2s)R0quu%5r:;EB%%b)C!"2$bBrd;#%!#!*(/"%  <- HD 	ENQE
J7k+
":;:-1	UaJ6:
B () 'r*<'=&>bA/1  R	]O6"]2C1DDKHY Z##%k?"32+"\*+-  RTZT_T_`jTkk<	c$!$' &+F ZZ	2.55&155? &'UU9%5N)&!=#//0uu]/C.D E--.UU;-?,@ A**-aeeHb.A*B)C!E   !{
 '*)n #D	^ J{ J"*%K'114T >66A_ E66D5G HD%E	# 	 "%d)%(\*-l*;&)(m/23D/E'2& #  +! /R KKK!=#e* Hvzz)R'@ H HII 8b  	?Q^_*n-Q}o >U V
 	
 L) /0 	  	caNNNDiQ^`abb	cs%   :6M91M9DM99N9N44N9)NN)"__doc__jsonloggingtypingr   r   r   r   r   app.core.errorsr    app.core.steps._evidence_helpersr	   app.modules.llm.llm_clientr
   app.modules.llm.safetyr   app.modules.prompt_loaderr   r   	getLoggerr   rD   r   strintr!   rS   r>   r?   tupler@   rA   rF   r   r"   r    <module>r      s2     3 3 $ K 6 8 >			8	$
$ 4U38_8L3M 0 37$(_#s(^_CH~_ CH~_ S#X	_
 CH~_ 38n_  S#X/_ D>_ 
#s(^_D15	#t)_&t S$t*_0E $ 4s
3C .dd#t)_d d D>	d
 
$ZdVZZ3T
?#Z eSj!Z 	Z
 Z D>Z 
$ZZr"   