
    i0                       U d Z ddlmZ ddlZddlZddlZddlmZ ddlm	Z	  ee
      j                         j                  d   Zedz  Zej                  j!                  d ee             ddlmZ dd	lmZmZmZ dd
ZddZd dZd!dZd"dZd"dZd#dZd$dZd%dZ d&dZ!dddddZ"de#d<   	 	 	 	 	 	 	 	 	 	 	 	 d'dZ$	 	 	 	 	 	 	 	 	 	 d(dZ%d)dZ&e'dk(  r e&        yy)*uR  Generic raw-failure fixture capture (spec phase fixture extractor).

config JSON 으로 fixture 명세를 받고 그에 따라 PID/EID 의 step manifest +
DB row 를 immutable JSON 으로 추출. 스크립트 본문에는 시나리오 의존
(scene/shot index, short_id 등) 일체 없음.

사용 (G4.6 예):

    backend/.venv/bin/python scripts/g4_6_capture_fixtures.py       --pid 298d86d9-615b-4b87-8040-21144c0731c1       --eid b6544514-babb-4781-95a2-6a0ff1da342f       --config scripts/configs/g4_6_fixtures.json       --out backend/tests/fixtures/g4_6/

config 형식 (JSON):

    {
      "fixtures": [
        {"name": "<file>.json", "type": "dependency_single", "scene": <int>, "shot": <int>},
        {"name": "<file>.json", "type": "dependency_pair", "scene": <int>, "shots": [<int>, <int>]},
        {"name": "<file>.json", "type": "image_asset", "scene": <int>, "shot": <int>},
        {"name": "<file>.json", "type": "scene_detail_shot", "scene": <int>, "shot": <int>},
        {"name": "<file>.json", "type": "shot_validator_shot", "scene": <int>, "shot": <int>},
        {"name": "<file>.json", "type": "entity_canon", "short_id": "<id>"}
      ],
      "low_freq_skip": {
        "pre_filename": "<file>.json",
        "post_filename": "<file>.json",
        "protected_short_ids": ["<id>", ...],
        "post_note": "<설명>"
      }
    }
    )annotationsN)Path)Any   backend)SessionLocal)EntityCanon
ImageAsset
SceneStillc                8    t         dz  | z  dz  dz  |z  |z  dz  S )Nprojectscheckpointsepisodeszmanifest.json)	REPO_ROOT)pideidsteps       scripts/g4_6_capture_fixtures.pymanifest_pathr   2   s,    z!C'-7*DsJTQTccc    c                    t        | ||      }|j                         st        d|       t        j                  |j                  d            S )Nzmanifest missing: utf-8encoding)r   existsFileNotFoundErrorjsonloads	read_text)r   r   r   paths       r   load_step_manifestr!   6   sF    c4(D;;="4TF ;<<::dnngn677r   c                    | |z  }|j                  t        j                  |dd      d       t        d|j	                  t
               d|j                         j                   d       y )	NF   )ensure_asciiindentr   r   z  wrote z (z bytes))
write_textr   dumpsprintrelative_tor   statst_size)out_dirnamepayloadtargets       r   
write_jsonr0   =   s\    t^F
djjuQGRYZ	HV''	232fkkm6K6K5LG
TUr   c                l    | D ]/  }|j                  d      |k(  s|j                  d      |k(  s-|c S  y )Nscene_index
shot_indexget)depssceneshotds       r   find_dependencyr:   C   s7    555(QUU<-@D-HH  r   c                l    | D ]/  }|j                  d      |k(  s|j                  d      |k(  s-|c S  y )Nr2   _shot_indexr4   )scenesr7   r8   entrys       r   find_scene_detail_shotr?   J   s7    99]#u,=1IT1QL  r   c                    | D ][  }|j                  d      |k7  r|j                  dg       D ]/  }|j                  d      |k(  s||j                  d      |dc c S  ] y )Nr2   shotsr3   scene_heading)r2   rB   r8   r4   )r=   r7   r8   scshs        r   find_validator_shotrE   Q   sb    66- E)&&"%Bvvl#t+',rvvo?V`bcc &  r   c           	         | j                   | j                  | j                  | j                  | j                  | j
                  | j                  | j                  dS )Nidshort_identity_typer-   descriptionstable_traits
t2i_promptstatusrG   rows    r   entity_canon_to_dictrQ   [   sF    ffLL**nn**	 	r   c                &   | j                   | j                  | j                  | j                  | j                  | j
                  | j                  | j                  | j                  | j                  | j                  | j                  | j                  dS )NrH   
asset_typestill_id	entity_idvariant_indexvariant_labelr3   prompt_usedreference_image_idsgeneration_modelcode_versionprompt_file_versionrN   rS   rO   s    r   image_asset_to_dictr^   h   ss    ffnnLL]]****nn"6600(("66** r   c                    | j                  t              j                  t        j                  |k(  t        j                  |k(  t        j
                  |k(  t        j                  |k(        j                         }|t        d| d| d| d|       | j                  t              j                  t        j                  |k(  t        j                  |k(  t        j                  |j                  k(        j                  t        j                        j                         }|s%t        d| d| d| d| d|j                   d      |||j                  |j                  |D cg c]  }t!        |       c}dS c c}w )	NzSceneStill missing for scene= shot=z pid=z eid=zImageAsset missing for scene=z (still_id=u(   ) — fail-fast (silent fixture 차단).)r2   r3   rU   still_frame_promptimage_assets)queryr   filter
project_id
episode_idr2   r3   firstRuntimeErrorr
   rU   rH   order_byrW   allra   r^   )dbr   r   r7   r8   stillassetsas           r   fetch_image_asset_for_shotro   z   st   
	!!S(!!S(""e+!!T)	

 
 
 }:5'vUSVRWW\]`\abcc
	!!S(!!S(588+


 
***	+	  +E7&eC5cU S
"JL
 	

 HH#669?@A,Q/@ 
 As   $E;c                    | j                  t              j                  t        j                  |k(  t        j                  |k(        j                         }|t        d|d|       t        |      S )NzEntityCanon short_id=z missing for pid=)rc   r	   rd   re   rI   rg   rh   rQ   )rk   r   rI   rP   s       r   fetch_entity_canonrq      si    
	&&#-{/C/Cx/O	P	 
 {28,>OPSuUVV$$r   shot_dependency_t2iscene_detailshot_validator)dependency_singledependency_pairscene_detail_shotshot_validator_shotzdict[str, str]CAPTURE_HANDLERSc                   | d   }| d   }|t         v r"t         |   }||vrt        |||      ||<   ||   }	|dk(  ra	j                  di       j                  dg       }
t        |
| d   | d         }|t	        | d| d    d	| d          t        ||d
|d       y |dk(  r	j                  di       j                  dg       }
| d   }| d   }t        |      dk7  rt        | d|       |D ci c]  }d| t        |
||       }}|j                         D cg c]
  \  }}|	| }}}|rt	        | d|       t        ||dd
i|       y |dk(  ra	j                  di       j                  dg       }t        || d   | d         }|t	        | d| d    d	| d          t        ||d|d       y |dk(  rb	j                  di       j                  dg       }t        || d   | d         }|t	        | d| d    d	| d          t        ||ddi|       y |dk(  r!t        ||t        |||| d   | d                y |dk(  rt        ||t        ||| d                y t        | d|      c c}w c c}}w )Nr-   typeru   datadependenciesr7   r8   z: dependency missing scene=r`   z!shot_dependency_t2i.manifest.json)source
dependencyrv   rA   r#   z0: dependency_pair requires exactly 2 shots, got z: missing entries r~   rw   r=   z#: scene_detail entry missing scene=zscene_detail.manifest.json)r~   r8   rx   z%: shot_validator entry missing scene=zshot_validator.manifest.jsonimage_assetentity_canonrI   z: unknown fixture type )ry   r!   r5   r:   rh   r0   len
ValueErroritemsr?   rE   ro   rq   )specr   r   rk   r,   manifest_cacher-   ftyper   manifestr6   r>   r7   rA   sentrieskvmissingr=   s                       r   dispatch_fixturer      s    <DLE  &~%#5c3#EN4 !$'##||FB'++NB?d7mT&\B=$'B4=/QWX\]cXdWefgg7D-P`e"fg	#	#||FB'++NB?WWu:?v%UV[U\]^^HMN1T!:tUA>>N!(>AAI1>$'9'CDD7D8-P"\T["\]	%	%fb)--h;&vtG}d6lK=$'J4PW=/Y_`dek`l_mnoo7D-ISX"YZ	'	'fb)--h;#FDM4<H=$'LTRY]O[abfgmbnaopqq7D8-K"Uu"UV	-	7D"<Rc4PW=Z^_eZf"gh	.	 7D"4Rd:>N"OP D6!8	BCC7 O>s   .I5
I:&I:c          	        t         dz  |z  dz  dz  |z  dz  }|j                         st        d|       t        j                  |j                  d            }t        |t              st        d      |j                  t        j                  t        j                  t        j                  t        j                        j                  t        j                  |k(  t        j                  j!                  |            j#                         }|D ci c]<  }|j                  |j                  |j                  |j                  |j                  d	> }	}|D 
cg c]	  }
|
|	vs|
 }}
|rt        d
t%        |       d| d|d      |D 
cg c]  }
|	|
   	 }}
t'        || d   t)        |j+                  t                     ||d       t-        | j/                  dg             }|D cg c]  }|d   |vs| }}|D cg c]  }|d   	 }}t'        || d   | j/                  dd      t1        |      ||d       yc c}w c c}
w c c}
w c c}w c c}w )u   ref_low_freq_skip pre + post 쌍 생성.

    pre: 현재 ref_low_freq_skip.json (UUID list) + short_id resolved.
    post: protected_short_ids 가 제거된 expected 결과.
    r   r   imageszref_low_freq_skip.jsonz"ref_low_freq_skip.json missing at r   r   z$ref_low_freq_skip.json is not a list)rH   rI   rJ   r-   u   ref_low_freq_skip 의 u&    UUID 가 EntityCanon 에 없음 (pid=z): u'    — fail-fast (silent fixture 차단).pre_filename)r~   uuidsresolvedprotected_short_idsrI   rH   post_filename	post_note )noter   r   r   N)r   r   rh   r   r   r   
isinstancelistrc   r	   rH   rI   rJ   r-   rd   re   in_rj   r   r0   strr)   setr5   sorted)cfgr   r   rk   r,   	skip_path
skip_uuids
canon_rowsrresolved_indexu
unresolvedordered_resolved	protectedpost_resolved
post_uuidss                   r   write_low_freq_skip_pairr      sY    	J$}4x?#EH``  ?	{KLLI///ABJj$'ABB
!5!5{7N7NP[P`P`a	&&#-{~~/A/A*/M	N	  A 	
QTTqzz!--YZY_Y_``   (CZ1N+B!ZJC$S_$5 65J>)PR
 	
 4>>:aq):>wN+i++I67$.  CGG1267I 0S 01AjM4RQ 0MS#01=a!D'=J1wO,R(%i0!	/ + D ? T1s+   AH?	I$II	+I8IIc                    t        j                  t              } | j                  ddd       | j                  ddd       | j                  ddd	       | j                  d
dd       | j	                         }t        |j                        j                         st        |j                  z  nt        |j                        }t        j                  |j                  d            }|j                  d      }t        |t              r|st        d| d      |j                  d      }t        |t               st        d| d      dD ]  }||vst        d| d| d       t        |j"                        j                         st        |j"                  z  nt        |j"                        }|j%                  dd       t'        d|j(                   d|j*                   d|j-                  t               d|j-                  t                      i }t/               }		 |D ]'  }
t1        |
|j(                  |j*                  |	||       ) t3        ||j(                  |j*                  |	|       |	j5                          t7        |      dz   }t'        d| d|j-                  t                      y # |	j5                          w xY w) N)rK   z--pidTre   )requiredhelpz--eidrf   z--configzfixture config JSON pathz--outz"output dir (relative to repo root)r   r   fixtureszconfig z%: 'fixtures' must be a non-empty listlow_freq_skipz : 'low_freq_skip' must be a dict)r   r   r   z: low_freq_skip.z missing)parentsexist_okzcapture: pid=z, eid=z	, config=z, out=)r   r   rk   r,   r   )r   r   rk   r,   r#   u
   
DONE — z fixtures written to )argparseArgumentParser__doc__add_argument
parse_argsr   configis_absoluter   r   r   r   r5   r   r   r   dictoutmkdirr(   r   r   r)   r   r   r   closer   )parserargsconfig_pathr   r   lfsr   r,   r   rk   r   expecteds               r   mainr   &  sy   $$9F
$\B
$\B

T8RS
$5YZD373D3P3P3R9t{{*X\]a]h]hXiK
**[**G*<
=Cwwz"Hh%X7;-/TUVV
''/
"Cc4 7;-/OPQQL3w{m3CH:XVWW M -1N,F,F,Hy488#dSWS[S[nGMM$M.	M$((6$((9[=T=TU^=_<``fgngzgz  |E  hF  gG  H  I&(N	BDTtxxTXX"gftu  $((RQXY

8}q H	Kz!6w7J7J97U6V
WX 	
s   &AJ9 9K__main__)r   r   r   r   r   r   returnr   )r   r   r   r   r   r   r   r   )r,   r   r-   r   r.   objectr   None)r6   r   r7   intr8   r   r   dict | None)r=   r   r7   r   r8   r   r   r   )rP   r	   r   r   )rP   r
   r   r   )
r   r   r   r   r7   r   r8   r   r   r   )r   r   rI   r   r   r   )r   dict[str, Any]r   r   r   r   r,   r   r   zdict[str, dict]r   r   )
r   r   r   r   r   r   r,   r   r   r   )r   r   )(r   
__future__r   r   r   syspathlibr   typingr   __file__resolver   r   BACKENDr    insertr   app.core.databaser   app.models.projectr	   r
   r   r   r!   r0   r:   r?   rE   rQ   r^   ro   rq   ry   __annotations__r   r   r   __name__ r   r   <module>r      sO   B #   
  N""$,,Q/	
i
 3w<   * B Bd8V
$"J% /,'+	$ . :D
:D 
:D 
	:D :D $:D 
:Dz4	4 
4 
	4 4 
4n#YL zF r   