
    Sj                        d Z ddlZddlZddlZddlmZ  ee      j                  Z	ej                  j                  d ee	             ddlZddlZddlZddlZe	Zedz  dz  Zedz  Zedz  ZdZd	Zg d
ZdZg dZdZdZd Z d Z!d Z"d Z#d Z$d Z%d Z&d Z'd Z(d Z)d Z*d Z+dZ,d Z-dj]                  g d      Z/d Z0dj]                  g d       Z1d! Z2d" Z3d# Z4d$Z5d%Z6d&Z7d' Z8d( Z9dj]                  g d)      Z:d* Z;d+ Z<d, Z=ed-z  Z>d.Z?d/Z@d0ZAd1 ZBd2 ZCd3 ZDg d4ZEeFd5k(  r ej                         ZHeHj                  d6d7eEd8d9gz   :       eHj                         ZKeED  ci c]  } |  eL       d;|      c} ZMeKj                  d8k(  reEdd< D ]  ZO eMeO            yeKj                  d9k(  reEd<d= D ]  ZO eMeO            y eMeKj                             yyc c} w )>u  s37 — 옥탑 관련 23샷 전면 재구축 (2026-07-12, 실험 전용·커밋 금지).

사용자 설계(하드코딩·하드 프롬프트 절대 금지 — 구조·크기·규모는 LLM 이
씬 원문 전문에서 스스로 추론):

실외(8샷 = 옥탑외부 5 + 철제계단 1 + 골목 2):
  ①ext_prompt  LLM 이 전체 관련 씬 원문으로 건물 전체 실사 마스터 t2i
               프롬프트 저작(근거 목록 포함) → ②ext_photos nb2 3롤
  ③ext_judge  GPT/Gemini VLM 0-10 합산 선택(동점=Gemini — s29 계약 재사용)
  ④ext_fix    양 VLM 결함 취합 → nb2 i2i 수정(0건=생략) = 기본 이미지
  ⑤ext_bg_prompts LLM 이 샷별 배경 플레이트 t2i 프롬프트 저작
  ⑥ext_bgs    nb2, 참조=[기본 이미지] — 샷별 배경 8장
  ⑦ext_sketch i2, 참조=[배경 8장 동시] → 8패널 분할 스케치 1장

실내(15샷):
  ⑧fp_spec    LLM 이 실내 씬 원문에서 공간 구성 추론 → FP 도면 프롬프트
  ⑨fp_img     i2 평면도(재투영 매체 계약)
  ⑩int_plan   LLM 이 그리는 순서 판단: 뿌리 플레이트부터 순서·커버 샷 배정
               (전체 실내 샷 정보 전달)
  ⑪int_plates nb2 체이닝 — 뿌리=[FP], 이후=[FP+뿌리+직전]
  ⑫int_sketch i2, 참조=[모든 플레이트] → ≤8패널 스케치 2장(8+7)
  ⑬crop / ⑭html 갤러리

사용: backend/.venv/bin/python s37_rooftop_rebuild.py --only <stage>
    N)Pathouts37panelszs37_rooftop_rebuild.htmls37_rooftop_v1s35_full_v1)rooftop_room_exteriorexterior_metal_staircaseresidential_alley_courtyardrooftop_room_interior))Azext_master_a.png)Bzext_master_b.png)Czext_master_c.pngzext_master_fixed.pngz
int_fp.pngc                  4    t        j                  t              S N)F	load_planS35_PLAN     W/Users/manta/Documents/Projects/TheRoad-I1/scratchpad/forest_exp/s37_rooftop_rebuild.py_s35r   8   s    ;;x  r   c                 d    | d   D ci c]  }|d   |
 }}g }|D ]  }|||   d   z  } |S c c}w )Ngroupskeyshotsr   )plan35gkeysggmapr   gks         r   	_shots_ofr"   <   sQ    !'!12!1AAeHaK!1D2
CtBx   J	 3s   -c                 b    t         j                  d   t        |          }d|  d|d    d|d    S )Nscenesu   [씬 z] heading
text)RDATAstr)siscs     r   _scene_textr-   D   s:    	
	#b'	"B2$bIr"V*66r   c                     t        | D ch c]  }t        j                  |      d    c}      }dj                  d |D              S c c}w )Nr   

c              3   2   K   | ]  }t        |        y wr   )r-   ).0r+   s     r   	<genexpr>z _scenes_block.<locals>.<genexpr>K   s     62{2   )sortedr(   _keyjoin)tagstsidss      r   _scenes_blockr:   I   sA    .A166!9Q<./D;;6666 /s   Ac                 2    dj                  d | D              S )Nr&   c              3   x   K   | ]2  }| d t         j                  t        j                  |         d     4 yw): descN)r(   SHOTr5   )r1   r8   s     r   r2   z_shots_block.<locals>.<genexpr>O   s3     G$Qs"QVVAFF1I.v678$s   8:)r6   )r7   s    r   _shots_blockr@   N   s    99G$GGGr   c                     i }t         t        gz   D ]3  }|j                  | j                  di       j                  |i              5 |S )Nmovement)
EXT_GROUPS	INT_GROUPupdateget)r   mvr!   s      r   	_movementrH   R   sA    	BI;&
		&**Z,00R89 'Ir   c                 8    | dk  rt        j                  |       S y)N   )   u   8 panels made by THREE vertical cuts at exactly 25%, 50% and 75% of the width and ONE horizontal cut at exactly 50% of the height — a 4-column x 2-row grid, all eight panels exactly equal	1536x102416:9)r   _grid)ns    r   _grid_nrP   Y   s    Avwwqz+r   c                  H   t               } t        | t              }t        | t        g      }||z   }dj	                  g d      }dddddidddiddid	g d	d
}dt        |      z   dz   t        |      z   }t        j                  d|||      }t        dz  t         dz  j                         rt        j                  t              ni }||d<   ||d<   ||d<   t        j                  t        |       t        dt        |d         d       |d   D ]  }	t        d|	        y )Nr&   )u[   당신은 영화 미술감독 겸 로케이션 설계자다. 한 건물(주인공이 사는uS   곳)이 나오는 모든 씬의 원문 전문을 읽고, 그 건물 '전체'가 한u[   프레임에 담기는 실사 로케이션 마스터 스틸 1장을 만들 이미지 생성uY   프롬프트(영어)를 저작하라. 이 마스터는 이후 모든 샷 배경의 기준u   이미지가 된다.   규칙:uV   1) 건물의 층수·크기·규모·공간 구성·고정 지형지물(출입 동선,uX      상하 이동 수단, 지붕 위 구조물, 지상부와의 관계 등)은 오직 씬uW      원문의 근거로만 추론하라. 인물의 이동·행동·시선, 공간 사용uV      방식이 크기·구조의 단서다. 실내 씬의 공간 사용도 건물 외형u!      규모 추론에 반영하라.uX   2) 근거 없는 부분은 그 지역·유형의 전형으로 최소한만 보충하고,u.      원문과 모순되게 발명하지 마라.uY   3) 카메라: 건물 전체와 그 주변 맥락(지상 접근부까지)이 다 보이는u+      하나의 시점을 스스로 정하라.uP   4) 마스터는 중립 상태: 사람 없음, 읽히는 텍스트 없음, 특정uA      사건의 순간 상태물 없음. 시간대는 중립 주간.u0   5) 배경 나라·시대는 원문을 따른다.uU   출력: inferred_facts_ko(추론한 구조·규모 사실 각각에 근거 씬/문장uT   명시), master_prompt_en(완결된 t2i 프롬프트 — 추론한 규모·구조가uS   프롬프트 안에 스스로 서술되게), camera_ko(선택한 시점과 이유).objectFarraytypestringrU   items)inferred_facts_komaster_prompt_en	camera_korU   additionalProperties
propertiesrequiredu"   건물 관련 씬 원문 전문:

u.   

이 건물이 나오는 샷 목록(참고):
s37_ext_promptplansz.json
ext_masterext_tagsint_tagsu   [ext_prompt] 근거rY      건z  -)r   r"   rC   rD   r6   r:   r@   r   llmBASEPLANexistsr   	save_planprintlen)
r   rc   rd   all_tagsSYSSCHEMAuserresplanf_s
             r   stage_ext_promptrt   e   sB   VF,H)-H("H
))  C. &-8JK#X.h'N) K	LF
 3]85LLABDPQYDZ[D
%% #tV
4C!%TF%.!@ H H J1;;t 	DDDKKd	
S)<%=!>F%&eR 'r   c            	      
   t        j                  t              } | d   d   }t        j	                  dd       t
        D ]7  \  }}t        j                  d|j                          |g dt        |z         9 t        d       y )	Nrb   rZ   Tparentsexist_oks37_ext_master_rM   aspect_ratioout_pathu   [ext_photos] nb2 3롤 완료)	r   r   rh   OUTmkdirMASTER_CANDimg_nb2lowerrk   )rr   plabfns       r   stage_ext_photosr      sq    ;;tD\-.AIIdTI*R			OCIIK=11b%b	:  

()r   c            	         t        j                  t              } dd| d   d   z   dg}t        D ]d  \  }}t        |z  }|j                         s
J d|        |j                  dd| dd       |j                  t        j                  |             f i d	D ]U  \  }}t        j                  |t        j                  |t        j                  |
      |<   t        d| d|   d           W t        D ci c]  \  }t        fddD               }	}}t        |	j                               }
|	j!                         D cg c]  \  }}||
k(  s| }}}d   d   t#        |fd      }| j%                  |	|t'        t              |   d       t        j(                  t        |        t        d|	 d|        y c c}}w c c}}w )Nr'   z<THE PROMPT (all three candidates were generated from this):
rb   rZ   rU   r'   u   후보 없음: z
Candidate :))gpts37_ext_judge_gpt)
gemini-pros37_ext_judge_geminimodelzjudge[z
]: winner=winnerc              3   R   K   | ]  }t        fd |   d   D                 yw)c              3   :   K   | ]  }|d    k(  s|d     yw)labelscoreNr   )r1   vr   s     r   r2   z,stage_ext_judge.<locals>.<genexpr>.<genexpr>   s#     K!5A7s9JQwZ!5s   
verdictsN)next)r1   mjudger   s     r   r2   z"stage_ext_judge.<locals>.<genexpr>   s-      (&A 	Kq*!5KK&s   $'r   r   r   rankingc                 2    | v rj                  |       S dS )Nc   )index)r   gem_ranks    r   <lambda>z!stage_ext_judge.<locals>.<lambda>   s%    Xo *2)< *.+-*.r   )r   )	ext_judge
ext_totalsext_selectedext_selected_filez[ext_judge] totals=z
 selected=)r   r   rh   r   r}   ri   appendpng_data_urlrf   TJUDGE_SYSTEMJUDGE_SCHEMArk   summaxvaluesrX   minrE   dictrj   )rr   partsr   r   fr   tagr   _totalsbestr8   tiedselectedr   r   s          `      @@r   stage_ext_judger      s   ;;tD(l+,>?@B CE !	r"Hxxz0_QC00zf
5'.CDEQ^^A&'	 !
 E?
suuS!..%#(*eugZeX(>'?@A	? 7BC6AFC 3 (&( ( (6A  C v}}D$lln:nFCT	CnD:\"9-H4 . /HKKe6!)&*;&7&AC D KKd	xz(
<=C ;s   ? GGGc                     t        j                  t              } t        | d   z  }dd| d   d   z   ddddt        j                  |      g}i }dD ]^  \  }}t        j
                  |t        j                  |t        j                  |	      ||<   t        d
| dt        ||   d                 ` || d<   dD cg c]  \  }}||   d   D ]  }d| d|d      }}}}|s3| d   | d<   d| d<   t        j                  t        |        t        d       y dj                  t        j                  ddj                  |      z   t        j                  g      }	|	| d<   t        | d<   t        j                  t        |        t        j                   d|	t        j"                  |fgdt        t        z         t        d       y c c}}}w )Nr   r'   z5THE PROMPT (the photograph was generated from this):
rb   rZ   r   zPhotograph to examine:))r   s37_ext_critique_gpt)r   s37_ext_critique_geminir   z	critique[z
]: issues=issuesext_critique))r   zGPT VLM)r   z
Gemini VLMz- (z) fix_enext_fixed_fileText_fix_skippedu$   [ext_fix] 결함 0 — 수정 생략r/   zISSUES TO FIX:
r&   ext_fix_prompts37_ext_master_fixedrM   rz   u   [ext_fix] 수정본 완료)r   r   rh   r}   r   rf   r   CRITIQUE_SYSTEMCRITIQUE_SCHEMArk   rl   rj   r6   FIX_HEADPRESERVE_TAILMASTER_FIXEDr   	FIX_LABEL)
rr   srcr   critiquer   r   titlei	fix_linesr   s
             r   stage_ext_fixr      s   ;;tD
()
)C#l+,>?@B &>?^^C "E HB
s%%Q%6%6 ! 1 1@	%
3xx/H+I*JKL	B
 $D&D5&D\UE"5/(3Q ugR(}- 4 .&D  5 !%&9!:"&	D$45QZZ'$))I*>>__& 	'A D	)D	KKdII$a1;;*<)=!C,,>@	
&'%5s   ="Gc            
      R   t        j                  t              } | d   }dj                  g d      }dddddddd	idd	idd	id
g d
ddidgd}d| d   d   z   dz   t	        |      z   dz   t        |      z   }t        j                  d|||      }|d   D ch c]  }|d   	 }}|D cg c]	  }||vs| }	}|	rt        d|	       |d   D ci c]  }|d   |
 c}| d<   t        j                  t        |        t        dt        |d          d       y c c}w c c}w c c}w )Nrc   r&   )uU   당신은 영화 배경(플레이트) 설계자다. 기준이 되는 건물 마스터uY   이미지의 생성 프롬프트와, 씬 원문 전문, 그리고 각 샷의 텍스트를uV   읽고 — 샷마다 그 샷의 카메라에 필요한 '배경 플레이트' 이미지u,   생성 프롬프트(영어)를 저작하라.rR   uX   1) 배경 플레이트 = 그 샷의 카메라 위치·방향에서 본 장소만. 사람uR      없음, 읽히는 텍스트 없음, 사건 순간 상태물 없음(빈 세트).uV   2) 마스터 이미지가 참조로 함께 첨부된다 — 프롬프트는 '첨부된uR      마스터 사진의 그 건물/그 장소'임을 명시하고, 어느 부분을uE      어느 방향에서 보는지 마스터 기준으로 서술하라.uY   3) 샷 텍스트가 요구하는 시간대가 있으면 그 시간대(씬 헤딩 참조),u"      없으면 씬 헤딩 시간대.uU   4) 건물 구조·지형지물은 씬 원문 근거를 벗어나 발명하지 마라.uJ   각 샷마다: shot(태그), bg_prompt_en, view_ko(어느 부분을 어느u   방향에서·한 구절).rS   FrX   rT   rU   rV   )shotbg_prompt_enview_kor\   rW   u)   마스터 이미지 생성 프롬프트:
rb   rZ   u   

관련 씬 원문 전문:

u>   

샷 목록(각각 배경 플레이트 프롬프트 저작):
s37_ext_bg_promptsr   u   배경 프롬프트 누락: ext_bgz[ext_bg_prompts] re   )r   r   rh   r6   r:   r@   rf   
SystemExitrj   rk   rl   )
rr   rc   rn   ro   rp   rq   itgotr8   missings
             r   stage_ext_bg_promptsr      s   ;;tDJH
))  C" 'e*!' 2"H-L/ <-= >N? IF 9< !345124A(4KL RR 8$	%D
 %%$c4
8C #G
-"2f:C
-"3(Qaslq(G37yABB/27|<|bj"n|<DNKKd	c#g,/0
45 .3 =s   D*	D4DD$u   LOCATION MASTER PHOTOGRAPH — the exact building and grounds where this background takes place: its architecture, massing, materials and fixed features are spatial truth; render the requested view OF THIS PLACE. Never copy this photo's camera or crop.c                      t        j                  t              } t        | d   z  }| d   D ]J  }| d   |   }t        j                  d| |d   t
        |fgdt        d| dz  	       t        d
|        L y )Nr   rc   r   s37_ext_bg_r   rM   bg_.pngrz   z
[ext_bgs] )r   r   rh   r}   r   MASTER_REF_LABELrk   )rr   masterr   r   s       r   stage_ext_bgsr     s    ;;tD4())FJ(^C 			Ku%r.'9$f-.V3se40	2 	
3% !  r   r&   )zCBACKGROUND PHOTOGRAPHS (attached in panel order): the N-th attachedz@photograph is the REAL location background of PANEL N. Draw eachuC   panel's environment faithfully FROM its own photograph — the samez@architecture, fixed features and spatial layout, translated intouD   monochrome pencil storyboard linework — then stage the figures perzCthat panel's shot text and movement. If a panel's shot text impliesz@a slightly different framing than its photograph, keep the placez&identical and adjust only the framing.c                  n   t        j                  t              } t               }t	        |      }| d   }|D cg c]  }t        j                  |       }}t        t        |            \  }}}}	g }
t        |d      D ]  \  }\  }}t
        j                  ||f   }d| d|d    }|j                  d| d|       }|r'|d|d	    z  }|j                  d
      r|d|d
    z  }|d| dz  }|
j                  |        t        j                  j                  |      dt        j                   t        j"                  t        j$                  t        j&                  t(        ddj+                  |
      g	}|t        |      kD  r9|j                  t        j,                  j                  t        |      |             |j                  t        j.                  j                  dj+                  d t1        dt        |      dz         D                           dj+                  |      }d|||d| d<   t        j2                  t        |        |D cg c]  }t4        d| dz   }}t        j6                  d|||t4        dz         t9        dt        |       dt        |       d        y c c}w c c}w )!Nrc      PANEL r=   r>   Ssh
  MOVEMENT (follow exactly): rB   figures=   
  FIGURES — apparent size & depth order (follow exactly): $
  BACKGROUND: attached photograph #.layoutzXTHE LOCATION (same building in all panels): the place shown in the attached photographs..PANELS (one shot per panel, Korean shot text):r&   n_shotsslots, c              3   2   K   | ]  }t        |        y wr   r*   r1   r   s     r   r2   z#stage_ext_sketch.<locals>.<genexpr>J  s     B*AQ#a&*Ar3   numbersr/   zsketch_ext.pngfiler   r   prompt
ext_sketchr   r   s37_ext_sketchrefssizer|   z[ext_sketch] u   패널 완료 (refs    장))r   r   rh   r   rH   r(   r5   rP   rl   	enumerater?   rF   r   r   HEADformatPURPOSEREALIZEGEOMETRYCONSISTENCYSKETCH_REF_NOTEr6   BLANKSEALrangerj   r}   img_gptrk   )rr   r   rG   r7   r8   keysr   r   r   _arlinesr   r+   shisliner   r   r   r   s                       r   stage_ext_sketchr  ,  sx   ;;tDVF	6	B
D#$t!AFF1ItD$&s4y1E64E!$*9BFFB9s"QvYK(FFQrd"SE?#5a
m_EEDuuY //0|n> ?7s!<<T + 	
V$	%			199ajj!--8		%E s4yQWW^^CIU^CD	LL		B%3t9q=*ABB  D EEA"2T#(A7DKKd)-.ACCs$-D.II4--/	M#d)$8T4
HIC %< /s   J-J2)zBOUTPUT MEDIUM: a flat 2D architectural FLOOR PLAN DRAWING on plainu<   drawing paper — NOT a photograph, NOT a 3D rendering. TRUEzCORTHOGRAPHIC PLAN seen from DIRECTLY ABOVE (90 degrees). Absolutelyz@NO 3D: no perspective, no axonometric tilt, no wall surfaces, nou>   furniture volumes — walls as clean double lines, openings aszCstandard plan symbols, fixtures and furniture as flat plan symbols,z@uniform flat fills and clean drafting linework. No readable textzlabels anywhere.c            	         t        j                  t              } | d   }dj                  g d      }dddddddiddiddid	g d	d
dddiddidg dd
}dt	        |      z   dz   t        |      z   }t        j                  d|||      }|| d<   t        j                  t        |        t        d|d   D cg c]  }|d   	 c}        t        d|d          y c c}w )Nrd   r&   )uV   당신은 영화 미술팀 도면 작성자다. 한 주거 공간의 실내 씬 원문uP   전문을 읽고, 그 내부의 공간 구성을 추론해 평면도(floor plan)u3   도면 생성 프롬프트(영어)를 저작하라.rR   u[   1) 공간의 개수·종류·연결 관계·고정 설비(문·창·수납·위생 설비·uX      가구 등)와 대략의 크기는 오직 원문 근거로만 추론하라. 인물이uZ      공간 사이를 어떻게 이동하는지, 무엇이 어디에 있는지가 단서다.uU   2) 근거 없는 부분은 그 유형 주거의 전형으로 최소 보충, 원문과u      모순 금지.uN   3) rooms: 추론한 공간 각각 — name_en, evidence_ko(근거 씬/문장),u,      fixtures_en(그 공간의 고정 요소).u@   4) size_estimate_ko: 전체 크기·규모 추정과 그 근거.uN   5) fp_prompt_en: 완결된 평면도 t2i 프롬프트 — 공간 배치 서사uL      (layout narration)를 담되 텍스트 라벨은 도면에 넣지 않게.rS   FrT   rU   rV   )name_enevidence_kofixtures_enr\   rW   )roomssize_estimate_kofp_prompt_en   실내 씬 원문 전문:

u   

실내 샷 목록(참고):
s37_fp_specfp_specz[fp_spec] rooms=r  r   r  )	r   r   rh   r6   r:   r@   rf   rj   rk   )rr   rd   rn   ro   rp   rq   rs          r   stage_fp_specr  c  s"   ;;tDJH
))  C  !e"H- &1 &1L3 B-C D $X.*N, B	CF ,mH.EE013?3IJD
%%sD&
1CDOKKd	CLALqa	lLAB
CD	#s%&' Bs   8C
c                      t        j                  t              } | d   d   dz   t        z   }|| d<   t        j                  t        |        t        j
                  d|d dt        t        z         t        d       y )	Nr  r  r/   fp_prompt_final
s37_fp_img	1024x1024r   u   [fp_img] 완료)	r   r   rh   	FP_MEDIUMrj   r	  r}   FP_FILErk   )rr   r   s     r   stage_fp_imgr$    se    ;;tDY'&09<AD	KKdIIlAD{W}&	
r   c                  n   t        j                  t              } | d   }dj                  g d      }dddddddd	idd	idd	iddd	id
dd	idg ddd
idgd}| d   }dj                  d |d   D              }d|z   dz   |d   z   dz   t	        |      z   dz   t        |      z   }t        j                  d|||      }|d   D 	cg c]  }|d   D ]  }	|	  }
}}	|D 	cg c]	  }	|	|
vs|	 }}	t        |
      D 	cg c]  }	|
j                  |	      dkD  s|	 }}	|s|rt        d| d|       |d   | d<   t        j                  t        |        t        dt        |d          d       |d   D ]0  }t        d|d    d|d     d!|d           t        d"|d#           2 y c c}	}w c c}	w c c}	w )$Nrd   r&   )uR   당신은 영화 배경(플레이트) 설계자다. 한 주거 실내의 평면도uQ   스펙과, 실내 씬 원문 전문, 그리고 그 실내에서 찍는 전체 샷uS   목록을 받는다. 이 실내의 배경 플레이트(사람 없는 실사 배경)uJ   들을 어떤 것부터 어떤 순서로 그릴지 스스로 판단하라.rR   uU   1) 첫 번째 플레이트가 '뿌리(root)': 이후 모든 플레이트의 기준이uT      되므로, 공간의 정체성과 고정 요소가 가장 많이 담기는 뷰를u      골라라.uS   2) 이후 순서는 체이닝을 고려하라: 각 플레이트는 뿌리와 직전uR      플레이트를 참조 이미지로 받아 생성된다 — 앞 플레이트와uC      공간·요소가 겹치는 뷰가 이어지도록 배열하라.uY   3) 플레이트 수는 스스로 정하라(전체 샷의 카메라를 커버하는 최소u3      집합, 서로 다른 뷰·서브공간 단위).uR   4) covers: 각 플레이트가 배경을 담당할 샷 태그들 — 전체 샷이uB      빠짐없이 정확히 한 플레이트에 배정돼야 한다.uM   5) prompt_en: 그 플레이트의 t2i 프롬프트(영어) — 사람 없음,uT      읽히는 텍스트 없음, 사건 순간 상태물 없음(빈 세트), 첨부된uS      평면도(와 뿌리·직전 플레이트)의 그 공간임을 명시, 카메라uL      위치·방향을 평면도 기준으로 서술. 시간대는 씬 헤딩.uU   6) 공간 구성·설비는 평면도 스펙과 원문 근거를 벗어나지 마라.uS   출력: plates 배열(순서=생성 순서, 첫 항목=뿌리) — key(스네이크uK   슬러그), title_ko, why_ko(이 순서·뷰인 이유), covers, prompt_en.rS   FplatesrT   rU   rV   rW   )r   title_kowhy_kocovers	prompt_enr\   r  c              3   F   K   | ]  }d |d    d|d    d|d    d  yw)z- r  r=   r  u
    (근거: r  )Nr   )r1   r  s     r   r2   z!stage_int_plan.<locals>.<genexpr>  s=       A Qy\N"Q}-.j=9I8J!Ls   !r  u!   평면도 스펙(추론 완료):
u   
크기 추정: r  u   

실내 씬 원문 전문:

u8   

전체 실내 샷 목록(빠짐없이 커버 배정):
s37_int_planr)  r   u*   플레이트 커버 검증 실패 missing=z dup=
int_platesz[int_plan] u   플레이트:z  r    (r'  z	) covers=u       이유: r(  )r   r   rh   r6   r:   r@   rf   setcountr   rj   rk   rl   )rr   rd   rn   ro   spec	rooms_txtrp   rq   p_r8   coveredr   dups                r   stage_int_planr7    s?   ;;tDJH
))  C0 7e)#X.!8,#*fh5GH$h/L1&.' (	N) J
 F 	?D		  g   I 19<!"$();$<=124A(4KL LL 8$	%D
 %%T6
2Cx=?=R"X,Qq,q=G?"7(Qaw&6q(G7'l
;lgmmA&6&:1lC
;#EgY ' ( 	(XDKKd	KCM*+=
9:(m2e9+R:/yHGHR\N+,  @7
;s   F'	F-)F-<F2F2u   FLOOR PLAN — the spatial truth of this interior: room layout, openings and fixture positions; never draw the plan itself, render the real interior it describes.u   ROOT INTERIOR PHOTOGRAPH — the same interior: its materials, finishes, furniture, lighting and wear are LOCKED to this photo.u   PREVIOUS ADJACENT VIEW — the immediately preceding plate of this same interior: keep every shared fixed feature identical where the views overlap.c                     t        j                  t              } t        t        z  }| d   }d }d }t        |      D ]  \  }}t        d|d    dz  }t        |fg}|dkD  r3|j                  t        |f       ||k7  r|j                  t        |f       t        j                  d|d    |d   |d|	       |dk(  r|}|}t        d
| d|d            y )Nr.  plate_r   r   r   s37_int_plate_r*  rM   rz   z[int_plates] r=   )r   r   rh   r}   r#  r   FP_REF_LABELr   ROOT_REF_LABELPREV_REF_LABELr   rk   )	rr   fpr&  	prev_path	root_pathr   r4  r   r   s	            r   stage_int_platesrA    s    ;;tD	wB,FII6"2fRYKt,,r"#q5KK34I%^Y78			N2e9+.;%	56I	aS2e9+./ #r   c            
          t        j                  t              } | d   }dj                  g d      }dddddddd	idd	idd	id
g d
ddidgd}dt	        |      z   dz   t        |      z   }t        j                  d|||      }|d   D ci c]  }|d   |
 }}|D cg c]	  }||vs| }	}|	rt        d|	       || d<   t        j                  t        |        |D ]"  }||   d   }
t        d| d|
r|
d d nd        $ y c c}w c c}w )Nrd   r&   )uY   당신은 콘티 연속성 편집자다. 같은 실내에서 찍는 샷 목록(시간순)uK   과 씬 원문 전문을 읽고, 각 샷마다 '이어받는 상태(carrieduP   state)' — 그 샷을 그릴 때 앞뒤 샷과 반드시 일치시켜야 하는uA   지속 시각 상태 — 를 영어 1~2문장으로 저작하라.rR   uQ   1) 대상 = 샷 사이에 지속되는 시각 상태: 움직일 수 없는 인물uX      (사망·의식불명)의 자세·위치와 그가 쥐거나 걸친 물건, 공간에uQ      남는 상태물(표식·흔적·물건의 위치), 인물이 계속 지니는u      소지물.uS   2) ★양방향 전파: 어떤 샷에서 확정되는 상태가 물리적으로 그uU      이전부터 존재했어야 하면 — 예: 움직일 수 없는 인물이 쥐고uW      있는 물건은 나중에 잡을 수 없으므로 그 인물이 등장하는 이전uO      샷부터 이미 쥐고 있어야 한다 — 이전 샷들의 carried 에도uW      소급해 명시하라. 이후 샷에는 원문에 바뀔 근거가 나올 때까지u      유지하라.uS   3) 오직 씬 원문 근거로만. 원문에 없는 상태 발명 금지. 시간이uU      지나 상태가 정리·소거되는 씬 경계(원문 근거)에서는 전파를u      끊어라.uL   4) 그 샷에 이어받는 상태가 없으면 carried_en 은 빈 문자열.uE   각 샷마다: shot(태그), carried_en, basis_ko(근거 한 구절).rS   FrX   rT   rU   rV   )r   
carried_enbasis_kor\   rW   r  u9   

샷 목록(시간순 — 각각 carried state 판정):
s37_int_contr   u   carried state 누락: int_contrC  z[int_cont] r=   P   u   (없음)
r   r   rh   r6   r:   r@   rf   r   rj   rk   )rr   rd   rn   ro   rp   rq   r   r   r8   r   cs              r   stage_int_contrJ    sd   ;;tDJH
))  C, 'e*%x0#X.L0 ;-< =N> IF ,mH.EELM8$%D %%T6
2C$'L
1Lb2f:r>LC
1"3(Qaslq(G31';<<DKKdF< A3b13B* =>?  23s   D	D)D)u?   PANELS ARE CHRONOLOGICAL — CONTINUE THE ACTION: compose everyz?panel as the direct continuation of the panel before it. BeforeuC   drawing a panel, read the previous panel's END STATE — where eachzBperson is, their pose and facing, what they hold, and the state ofu;   the room — and start this panel's action FROM that state,z<advancing only what this panel's shot text says. Consecutivez1panels must cut together as one continuous scene.z8IMMOBILE CHARACTERS NEVER MOVE: a character who is dead,zBunconscious or otherwise unable to move must appear in every laterz;panel EXACTLY as they were in the previous panel where theyuB   appeared — the same collapsed pose, same spot, same clothing andz=state, unmoved and unposed. Never re-pose, revive, tidy, seatzBupright or relocate an immobile character between panels; only thezcamera changes around them.c                  .   t        j                  t              } t               }t	        |      }| d   }i }t        |d      D ]  \  }}|d   D ]  }|||<   	  | d   }t        |      dkD  r
|d d |dd  gn|g}	| j                  di       }
t        d |	D              D ]  \  }}|D cg c]  }t        j                  |       }}t        t        |            \  }}}}g }t        |d      D ]  \  }\  }}t        j                  ||f   }d| d	| }d
| d|d    }|j                  |      }|r'|d|d    z  }|j                  d      r|d|d    z  }| j                  di       j                  |i       j                  dd      }|r|d| z  }|d||    dz  }|j                  |        dj                  g d      }t        j                   j#                  |      dt        j$                  t        j&                  t        j(                  t        j*                  t,        |ddj                  |      g
}|t        |      kD  r9|j                  t        j.                  j#                  t        |      |             |j                  t        j0                  j#                  dj                  d t3        dt        |      dz         D                           d j                  |      }d!| d"}||||d#|
t5        |      <   t        j6                  t        |        |D cg c]  }t8        d$|d%    d"z   }}t        j:                  d&| |||t8        |z  '       t=        d(| dt        |       d)t        |       d*        y c c}w c c}w )+Nr.  r   r)  rd   rK   
int_sketchc              3   &   K   | ]	  }|s|  y wr   r   )r1   rI  s     r   r2   z#stage_int_sketch.<locals>.<genexpr>?  s     6&QAq&s   r   r   r   r=   r>   r   rB   r   r   rF  rC   uO   
  CARRIED STATE (persist exactly — must match the panels before and after): r   r   r&   )z:BACKGROUND PHOTOGRAPHS (attached): each PANEL states whichz9attached photograph is its REAL location background. Drawz3that panel's environment faithfully FROM its statedu8   photograph — the same room, fixed features and spatialz4layout, translated into monochrome pencil storyboardu=   linework — then stage the figures per the panel's shot textz;and movement. All photographs are the SAME single interior.r   zXTHE LOCATION (same interior in all panels): the place shown in the attached photographs.r   r   r   c              3   2   K   | ]  }t        |        y wr   r   r   s     r   r2   z#stage_int_sketch.<locals>.<genexpr>j  s     G.Fc!f.Fr3   r   r/   sketch_int_r   r   r9  r   s37_int_sketch_r   z[int_sketch] u   패널 (refs r   )r   r   rh   r   rH   r   rl   
setdefaultr(   r5   rP   r?   rF   r   r6   r   r   r   r  r  r  r  ACTION_CONTr  r  r  r*   rj   r}   r	  rk   ) rr   r   rG   r&  	tag2plateidxr4  r8   r7   chunkssketchescichunkr
  r   r   r   r  r  r   r+   r  r  r   r  r   carriednoter   r   r   r   s                                    r   stage_int_sketchr\  3  s   ;;tDVF	6	B,FIVQ'RHAIaL  ( 
D%(Y]d2AhQR!F|R0H6&66	E#()5aq	5)#*3u:#6 vtS%dA.LAyCCy!AbTC5/CA3b6,DsA9!J-II55# 334Y<.B CDxx
B/33C<L"-  ;;B)E F #C.), -DLL# /$ yy 
  FFMMM(,IIqyy!**amm[<IIe
 3u:LLE
%HIQVV]]IIGeAs5zA~.FGG # I 	JKK2$d#%'%%'(*R	D$9?@2r%yk..@			OB4(!$T8	%bTCJ<}SYKtLMi 7)` As   (N%Nc                  ^   t        j                  t              } | d   | d   z   }dj                  g d      }ddddddd	d
id	d
idd	d
idd	d
idg dddidgd}dt	        |      z   dz   t        |      z   }t        j                  d|||      }|d   D cg c]  }|d   D ]  }||vr|
  }}}|rt        d|       |d   | d<   t        j                  t        |        |d   D ];  }t        d|d    d|d           t        d|d           t        d|d           = y c c}}w )Nrc   rd   r&   )uS   당신은 콘티 연속성 편집자다. 씬 원문 전문과 샷 목록을 읽고,uV   움직일 수 없는 상태(사망·의식불명 등)로 화면에 등장하는 인물uA   각각에 대해 '자세 정본(canonical pose)'을 저작하라.rR   uQ   1) pose_en = 영어 1~2문장, 그 인물의 몸 자세를 시각적으로 완전uV      서술: 앉음/누움/기댐 여부, 상체·머리·팔다리의 정확한 상태,uV      무엇에 기대거나 닿아 있는지, 몸의 방향. 이 문장은 그 인물이uS      등장하는 모든 샷에 글자 그대로 재사용된다 — 중의적 단어uN      (예: 위치 의미의 lie)는 피하고 자세 동사를 명확히 써라.uS   2) 자세는 오직 원문 근거로만. 원문이 특정한 순간부터 자세가uQ      바뀔 근거(이동·수습 등)가 있으면 그 구간별로 별도 항목.uO   3) shots = 그 정본이 적용되는 샷 태그들(그 인물이 그 자세로uF      화면에 보이거나 부분적으로라도 걸리는 샷 전부).u9   4) 해당 인물이 없으면 빈 배열을 반환하라.uB   각 항목: character_ko, pose_en, shots, basis_ko(근거 구절).rS   FimmobilerT   rU   rV   rW   )character_kopose_enr   rD  r\   u   씬 원문 전문:

u   

샷 목록(시간순):
s37_pose_canonr   u   pose_canon 미지의 샷: 
pose_canonz[pose_canon] r_  z shots=z  pose: r`  u
     근거: rD  rH  )	rr   rm   rn   ro   rp   rq   r   r8   bads	            r   stage_pose_canonrd  x  s   ;;tDJ$z"22H
))  C" We!' 2"H-")VX4FG#X.	L0
 I0J KNL  L"F %}X'>>,-/;H/EFD
%% #tV
4C: !71x 1C !
5cU;<<ZDKKd*ob01GFGI()
2j>*+, !s   D)c                     t        j                  t              } t               }t	        |      }| j                  di       }dj                  g d      }ddddiddiddidg dd	}| j                  d
g       D ]  }|d   D ]  }|j                  |i       }| j                  di       j                  |i       j                  dd      }	d|d    d|d    dt        j                  t        j                  |         d    d|j                  dd       d|j                  dd       d|	 }
t        j                  d| ||
|      }|||<   t        d| d         t        j                  t        |        y)uO   C안 — 정본과 모순되는 샷별 동선/크기/carried 문장 LLM 교정.pose_fixr&   )
uW   당신은 프롬프트 교정자다. 한 샷의 이미지 생성 프롬프트 문장들uL   (movement/figures/carried)과, 그 샷에 등장하는 '움직일 수 없는u6   인물'의 자세 정본(canonical pose)을 받는다.uX   각 문장을 정본과 대조해, 자세와 모순되거나 다르게 읽힐 수 있는uO   표현(예: 위치 의미로 쓴 lie 가 '누워있다'로 읽히는 중의성,u7   정본과 다른 자세 동사)만 최소 수정하라.uW   규칙: 모순 없는 부분은 글자 그대로 유지(불필요한 재작성 금지),uZ   자세 서술은 정본의 표현을 그대로 차용, 카메라·크기·깊이 정보는uA   보존. 수정이 전혀 불필요하면 원문 그대로 반환.uF   출력: movement_en, figures_en, carried_en (각각 교정본 전문).rS   FrU   rV   )movement_en
figures_enrC  r\   rb  r   rF  rC  rN  u   자세 정본(r_  z): r`  u   

샷 텍스트: r>   z

movement: rB   z

figures: r   z

carried: s37_pose_fix_z[pose_fix] u    교정 완료N)r   r   rh   r   rH   rR  r6   rF   r(   r?   r5   rf   rk   rj   )rr   r   rG   fixesrn   ro   r   r   r   rZ  rp   rq   s               r   stage_pose_fixrk    s   ;;tDVF	6	BOOJ+E
))  C )x(x(N* @	AF
 hh|R(g;CsBAxx
B/33C<L"- $R%7$8ByM? K&&'ffQVVC[&9&&A%B C!!"z2!6 7 8  !i 45 6  'y	*D
 %%-u-sD&ACE#JKuN34  ) KKdr   stillsuy  STORYBOARD PANEL — a REFERENCE ONLY, never the target: use it loosely for camera framing, figure placement and depth order. Do NOT photorealize this drawing as-is — the SHOT TEXT and the other references are authoritative; re-stage the moment naturally as a real photograph. Never copy the sketch's line style, paper texture, borders, simplified geometry or drawing errors.u   LOCATION PHOTOGRAPH — the exact place of this shot: its architecture, materials, fixed features and lighting mood are spatial truth; stage the moment inside this place. Never copy its camera framing.u  PREVIOUS SHOT STILL — a visually related earlier shot of this same place: the location's look, materials, fixed features, lighting mood and each person's clothing are LOCKED to this photo; never copy its camera framing. If this photo shows a character who cannot move (dead or unconscious), that character's exact pose, position and orientation are ALSO LOCKED — treat their body as a fixed prop of the set that only the camera moves around.c                     dd l } t        j                  t              }t	               }t        |      }i }t        t        gz   D ]3  }|j                  |j                  di       j                  |i              5 | j                         }| j                         }| j                         }i }	|j                         D ]1  \  \  }
}}|	j                  |
t                     j                  |       3 |d   D ci c]  }|d   |
 }}i }|d   D ]  }|d   D ]  }t         d|d    dz  ||<    ! |j                  d	i       }t"        j%                  d
d
       t        D cg c]  }||   d   D ]  }||f  c}}|d   D cg c]
  }t        |f c}z   }|D ]Y  \  }}t"        | dz  }|j'                         rt)        d| d       3t*        j,                  t+        j.                  |         }|j                  |i       }|t        k7  rt         d| dz  n||   }|j                  |      xs i j                  d      }d }d}g }|r>t"        | dz  j'                         r$|}|j1                  t2        t"        | dz  f       n:d
}|j1                  t4        t6        | dz  f       |j1                  t8        |f       |j                  t+        j.                  |      g       }|s9t;        |	j                  t+        j.                  |      d   t                           }g g } }|D ]  }!|!|v rB||!   \  }"}#|#j'                         s |j1                  |"       |j1                  d|" d|#f       I|!|v sN||!   \  }"}#|#j'                         sg| j1                  |"       |j1                  d|" d|#f        d| j=                  |      z   dz   d| j?                  |d          d||   d    d|rdndz   g}$|r"|$j1                  d jA                  g d!             |$j1                  | jB                         |j                  d"i       j                  |      }%|%xs i j                  d#      xs |j                  d$      }&|%xs i j                  d%      xs |j                  d&      }'|&r#|$j1                  d'| j?                  |&      z          |'r#|$j1                  d(| j?                  |'      z          |t        k(  r2|j                  d)i       j                  |i       j                  d*d+      nd+}(|%xs i j                  d*      xs |(}(|(r#|$j1                  d,| j?                  |(      z          |j                  d-g       D ]0  })||)d   v s|$j1                  d.| j?                  |)d/         z          2 |r'|$j1                  d0d1jA                  |      z   d2z          n|$j1                  d3       |$j1                  d4       d5jA                  |$      }*t        jD                  d6| |*|d7|8       ||||rd9ntG        |jH                        |*|D +#cg c]X  \  }+}#|+tG        |#      jK                  tG        tL                    rtG        |#jO                  tL                    n
tG        |#      d:Z c}#}+d;||<   t        jP                  t        |       t)        d| d<|jH                   d=| d>| d?|  d@       \ y c c}w c c}}w c c}w c c}#}+w )ANr   prevr   r   r.  r)  r9  r   
still_metaTrv   r   rd   _nb2.pngz	[stills] z skip(exists)r   Fu   CHARACTER REFERENCE — zN: the exact person appearing in this shot; match face, hair and build exactly.u   PROP REFERENCE — zU: the exact object appearing in this shot; match its look, material and wear exactly.u   Create ONE FINAL photorealistic live-action film still of the moment below — contemporary South Korea, 2026; all people are Korean unless stated. TIME OF DAY (lock): r   z#SHOT TEXT (authoritative, Korean): r>   zLOCATION (lock): place_enu,    The shot takes place here — the attached z+PREVIOUS SHOT STILL shows this exact place.z)LOCATION PHOTOGRAPH shows the exact spot.r&   )
z1THE STORYBOARD PANEL IS ONLY A REFERENCE: it is az-rough pre-production sketch, not the image toz-reproduce. Take from it only the shot's roughu4   composition — framing, where figures sit, near/farz5order. Everything else (real-world detail, materials,z4light, anatomy, environment richness) must come fromz.the shot text and the photographic references,z5re-staged as if actually filmed on a real set. If thez,sketch conflicts with the shot text or looksz2simplified/wrong, FOLLOW THE TEXT, not the sketch.rf  rg  rB   rh  r   zMOVEMENT (follow exactly): u+   FIGURES — size & depth (follow exactly): rF  rC  rN  uU   CARRIED STATE (persist exactly — must match the neighbouring shots of this scene): rb  u   IMMOBILE CHARACTER POSE — CANONICAL (this exact wording recurs in every shot where this character appears; if MOVEMENT, FIGURES or CARRIED STATE conflicts with it, THIS POSE WINS): r`  zPEOPLE: the SHOT TEXT alone decides whether any person is visible in this shot. IF a person appears, they must be one of the referenced people (r   uu   ) matched exactly to their reference photo — never anyone else, and never add a person the shot text does not show.z5No people appear unless the shot text itself says so.z6No text, captions, watermarks or annotations anywhere.r/   
s37_still_rM   rz   u   (미첨부 — prev 잠금))r   path)gkey	prev_used
panel_usedplater   r   u    완료 (plate=z, prev=z, chars=z, props=r,  ))s34_stillrunr   r   rh   r   rH   rC   rD   rE   rF   
_char_refs
_prop_refs_ve_idsrX   rR  r0  r}   OUTSr~   ri   rk   r(   r?   r5   r   PREV_STILL_LABELPANEL_REF_LABELOUTPPLATE_STILL_LABELr4   _time_of_softenr6   REALIZE_STILLr   r*   name
startswithrg   relative_torj   ),r   rr   r   rG   prev_allr!   charspropsvescene_unionr+   r  idsr   r    rT  r4  r8   metajobsrt  r   r   r  r   rw  prev_tagru  rv  r   ve_ids
char_names
prop_namescidr  r   r   fixrB   r   rZ  r   prompt_fullr   s,                                               r   stage_stillsr    s   ;;tDVF	6	BHI;&

62.222r:; 'LLNELLNE	
BK((*	S3r35)005 %!'!12!1AAeHaK!1D2I< HA6"U)D!99IaL  ! ??<,DJJtdJ+(Dj$r(72CQRG2CGjD#'
#3
4#3aIq>#3
45D	cuH%%::<IcU-01FF166#;FF3O+/9+<SE&3 	LL%+008	
8*H 55==? !IKK)4XJh2G+GHIJKK$C5*=>?KK*E23sR(KOOAFF3KNCEBCF!#RJ
Ce|*a88:%%d+KK24& 9* *+,!. / *a88:%%d+KK-dV 46 678!: ; $E jjo !$$ 2!))AfI2F1GHT
: 67 8, ,  ="
 LL $   	Q__%hhz2&**3/I2??=1FQUU:5F9"//,/C1553CLL699X./ 0LLF99W-. / /3i.? 88J+//R8Cb)R 	9"//,/:7LL D99W-. / ((<,Bbk!< ii9.	/0 - LL: ))J'("	"# LL % & " 	#kk%(			Jse$k4%	5 y$7@3uzz?! $()#'a  #Q**3t95 .1t1D-E;>q6D#')	
S	 	
D$	#oejj\ L"|8J<q: 	;s  3 E
4j)s   6[6 [;\A\c                  .   ddl m}  dd l}t        j                  t
              }t        j                  dd       ddddd	}|d
   gt        |j                  di       j                               D cg c]  \  }}|	 c}}z   }|D ]  }| j                  t        |d   z        j                  d      }|j                  d      j                  d       }	|	j                         }
|
rsd}t!        d|
d   |z
        t!        d|
d   |z
        t#        |j$                  d   |
d   |z         t#        |j$                  d   |
d   |z         f}
|j'                  |
      }|j$                  \  }}||d      \  }}|j)                  |j                  d            }|dk  }d }|dkD  r ||j+                  d      |dz
  |      ng }|dkD  r ||j+                  d      |dz
  |      ng }dg|z   |gz   }dg|z   |gz   }t-        |d         D ]]  \  }}||z  ||z  }}||   dz   ||   dz   ||dz      dz
  ||dz      dz
  f}|j'                  |      j/                  t        | dz         _ t1        d|d    dt3        |d          d| d|         y c c}}w )Nr   )ImageTrv   )   r   )r  r  )   r  )   r  )r  r  rJ   rK   r   rL  r   RGBLc                     | dk  rdS dS )N      r   r   )r   s    r   r   zstage_crop.<locals>.<lambda>  s    S#2Ga2Gr   r  r   r  r  r   x   c                    t        |       D cg c]  \  }}|dkD  s| }}}g }|D ]9  }|r#||d   d   z
  dk  r|d   j                  |       (|j                  |g       ; |D cg c]B  }|dz  t        |      t        |      z  cxk  r|dz  k  rn nt        |      t        |      z  D }}t        |      |k(  r|S t	        |      D 	cg c]  }	||	dz   z  |dz   z   c}	S c c}}w c c}w c c}	w )Ng?rJ   g{Gz?gQ?r   )r   r   r   rl   r  )
profilen_expecttotalr   r   candgsxcentersks
             r   _lineszstage_crop.<locals>._lines  s   "+G"4A"4$!QDA"4DAB!bfRj.A-rFMM!$IIqcN	 
 24 IA$,Q#a&G54<G 1vQ'G I7|x'"8_., QUO15,. . BI.s   C&C&(AC,C1)axisr   r   z[crop] r=   u	   패널 v=z h=)PILr  numpyr   r   rh   r  r~   r4   rF   rX   openr}   convertpointgetbboxr   r   r   cropasarraymeanr   saverk   rl   )r  nprr   GRIDMAPr   r   r  r   sheetmaskbboxpadWHcolsrowsarrdarkr  v_linesh_linesxsysr   r   rI  r  boxs                               r   
stage_cropr  {  s   ;;tDJJtdJ+V6:G#)$((<*D*J*J*L#M#O#M *.A1#M#O OD

3F+,44U;}}S!''(GH||~C47S=)3q$q'C-+@

1tAw}5

1tAw}57D JJt$Ezz1R[)
djjs+,Sy	. =A1H&*D1Ha8"<@1H&*D1Ha8"S7]aS S7]aS 7,FAst8Q$YqAa519beaiAEQ1q5	AFCJJsO  3%t!45 - 	6
|2c"W+&6%7 89Cy* 	+M #Os   3Jc                  h  +,-. t        j                  t              -d +d+fd	,-d   } dj                  +fd| d   D              }d}dD ]Z  }-j	                  di       j	                  |i       j	                  d	g       D ]#  }|d
| d|d    d|d    d +|d          d	z  }% \ d}-j	                  d      xs i j                         D ]0  \  }}|d   D ]#  }|d
| d +|d          d +|d          dz  }% 2 -j	                  dd      .dj                  ,-.fdt        D              }-j	                  d      }	|	r ,|	-j	                  d      sdnd      nd}
d}-d   D ]{  }-d   |   }|d| d +t        j                  t        j                  |         d          d  +|d!          d" ,d#| d$d%      z    ,d&| d$d'      z   d( +|d)          d*z   z  }} -j	                  d+i       } ,|j	                  d,d      d-t        |j	                  d.g              d/t        -d          d0      }-d1   }dj                  +fd2|d3   D              }d}t        -d4         D ]  \  }}|d5k(  rd6nd7| }|d5k(  rd8nd9}|d|d:z    d; +|d<          d=|d>    d?| d@| dA +|dB          dC +dDj                  |dE                dF ,dG|d>    d$dH      z   dI +|dJ          d*z   z  } d}-j	                  dKi       }|r5t               dL   D ci c]  }|d>   |
 }}t        t        gz   D ]?  }d}|t        k7  r7-d   D cg c](  }|j	                  |i       j	                  dM      |k(  r|* c}n-dN   D ]  }|j	                  |      }|sdj                  +fdO|dP   D              }|dP   D cg c]  }|dQ   j                  dR      s| } }|d| dS +|dT          dU +t!        |dV   xs dW             dXt        |        dY +t        j                  t        j                  |         d          dZ| d[| d\| d] +|d^          d*z  } |d_ +||   d`          d=| da| z  }B db|z   dcz   }-d   -dN   z   D cg c]%  }|j	                  |i       j	                  dV      r|' }!}d}"|!D ]q  }d}#ddD ]  \  }$}%de|$ df| dg}&|#dh|& di|& dj|% dkz  }# |"d| dl +||   dV          dm +t        j                  t        j                  |         d          d"|# dn	z  }"s |"r|do|"z   dcz   z  }d}'d}(t#        -j	                  dpi       j                               D ]  \  })}*|' ,|*d,   dqt%        |)      d:z    drt        |*d.          ds      z  }'|*d.   D ]D  }|(dt| du| dv| dw +t        j                  t        j                  |         d         d dx  dk	z  }(F  t&        j)                  dj                  g dy| dz +| d{          d| +| d}          d~| d| d| d|
 d| d| d +|j	                  d^d             d| d +|d          d ,t*        d       d +-j	                  dd             d| d|' d|( ddj                  +fdt#        -j	                  dpi       j                               D               d| d             t-        dt&                y c c}w c c}w c c}w c c}w )Nc                 F    t        j                  t        | xs d            S )NrN  )_htmlescaper*   )r8   s    r   esczstage_html.<locals>.esc  s    ||CRL))r   rN  c           
      8    d|  }d| d| d| d |       d	S )Nout/s37/z<figure class='z'><a href='' target=_blank><img src='' loading=lazy></a><figcaption></figcaption></figure>r   )r   capclsrelr  s       r   figzstage_html.<locals>.fig  sB    o!#k# 7 E ""3xj(>@ 	Ar   rb   c              3   6   K   | ]  }d  |       d  yw)z<li>z</li>Nr   )r1   rs   r  s     r   r2   zstage_html.<locals>.<genexpr>  s!     L4Kbd3r7)5)4Ks   rY   r   r   r   z<tr><td>z	</td><td>r   r   
verdict_koz
</td></tr>r   r   issue_kor   r   ?c           
   3      K   | ]T  \  }} |d | |k(  rdd   |    dn%dj                  di       j                  |d       dz   |k(  rdnd       V y	w)
u   마스터 후보 u    — 선택(합산 r   u   점)r/  r  selrN  )r  N)rF   )r1   r   r   r  rr   r  s      r   r2   zstage_html.<locals>.<genexpr>  s      $
 #GC	 	B#C5)* %T,%7%<$=TB$&txxb'A'E'Ec3'O&PPT"UW *"	/ 	/ #s   AAr   r   u"   기본 이미지(수정 반영본)u2   기본 이미지(결함 0 — 선택본 그대로)rc   r   z<div class=shot><h3>z</h3><div class=note>r>   u	   <br>뷰: r   z</div><div class=row>r   r   u-   배경 플레이트 (참조=기본 이미지)zpanels/u   스케치 패널u@   </div><details><summary>플레이트 프롬프트</summary><pre>r   z</pre></details></div>r   r   u   실외 분할 스케치 (r   u   패널 — 배경 u   장 동시 참조)r  c           
   3   l   K   | ]+  }d  |d          d |d          d |d          d - yw)z<li><b>r  u	   </b> — r  u   <br><span class=note>근거: r  z</span></li>Nr   r1   r  r  s     r   r2   zstage_html.<locals>.<genexpr>  sT        A #a	l#$Ic!M2B.C-D
'Am,<(='>l	Ls   14r  r.  r   u   뿌리(root)u   체인 FPu   FP + 뿌리 + 직전r   z. r'  z <span class=k>(r   u    · u    · 참조=u,   )</span></h3><div class=note>순서 이유: r(  u   <br>커버 샷: r   r)  z</div>r9  u   플레이트u-   <details><summary>프롬프트</summary><pre>r*  ro  r   rt  rd   c              3      K   | ]S  }|d    j                  d      r=d|d     d|d     d |d   j                  d      d   j                                d U y	w)
rs  r   z<figure class=pn><a href='r  r  r   u   —r   r  N)r  splitstripr  s     r   r2   zstage_html.<locals>.<genexpr>  sz      $H (1V9+?+?+F 16 <!!"6 ,##&qz'7'7'>q'A'G'G'I#J"K,	.
 (s   AAr   rs  r   u   <span class=k> — plate=rw  u	    · prev=ru  u   없음u$    · 외부 참조(캐릭터/소품) u   장</span></h3><div class=note>z5</div><div class=row><figure><a href='out/s37/stills/z1_nb2.png' target=_blank><img src='out/s37/stills/uL   _nb2.png' loading=lazy></a><figcaption>nb2 스틸</figcaption></figure><div>u@   </div></div><details><summary>프롬프트 전문</summary><pre>r   z<h3 style='margin-top:22px'>name_koz)</span></h3>u^   <section><h2>⑨ 실사 스틸 (스케치 패널+플레이트+prev+엔티티 참조, nb2)</h2>z
</section>))	stills_v1u   v1 패널+플레이트+prev)	stills_v2u   v2 패널+prev)rl  u   v3 prev만 (현행)r  /rp  z<figure class=cmp><a href='r  r  r  u   <span class=k> — prev=z</span></h3><div class=note>z</div></div>u  <section><h2>⑩ prev 13샷 — 참조 조합 3판 비교</h2><div class=note>v1=스케치 패널+배경 플레이트+prev / v2=스케치 패널+prev(플레이트 제외) / v3=prev만(콘티·플레이트 제외, 현행). 캐릭터·소품 참조는 3판 공통.</div>rL  u   실내 스케치 시트 r/  u   패널)z)<figure class=pn><a href='out/s37/panels/z-.png' target=_blank><img src='out/s37/panels/z#.png' loading=lazy></a><figcaption>u    — <   u}	  <!DOCTYPE html>
<html lang=ko><head><meta charset=utf-8>
<meta name=viewport content="width=device-width, initial-scale=1">
<title>s37 — 옥탑 23샷 전면 재구축 (LLM 자가 추론 체인)</title>
<style>
body { margin:0; padding:24px; background:#0f1216; color:#e6e6e6;
       font:14px/1.6 -apple-system,'Apple SD Gothic Neo',sans-serif; }
h1 { font-size:20px; } h2 { font-size:17px; margin:34px 0 8px;
     border-bottom:1px solid #333; padding-bottom:5px; }
h3 { font-size:15px; margin:12px 0 4px; }
.k { color:#8a939e; font-size:13px; font-weight:400; }
.row { display:flex; gap:14px; align-items:flex-start; margin:8px 0;
        flex-wrap:wrap; }
figure { margin:6px 8px 6px 0; display:inline-block;
          vertical-align:top; max-width:560px; }
figcaption { color:#c9d2dc; font-size:12.5px; }
img { max-width:560px; width:100%; border-radius:8px;
      border:1px solid #2a2f36; }
figure.sel img { outline:3px solid #2a7ae2; }
figure.pn { max-width:300px; } figure.pn img { max-width:300px; }
figure.cmp { max-width:420px; } figure.cmp img { max-width:420px; }
figure.pn figcaption { font-size:11px; }
.note { color:#8a939e; }
.box { background:#161b22; border:1px solid #2a2f36; border-radius:8px;
       padding:12px 16px; margin:12px 0; }
.shot { border-top:1px dashed #2a2f36; padding:10px 0; }
table { border-collapse:collapse; font-size:12.5px; margin:8px 0; }
td,th { border:1px solid #2a2f36; padding:4px 8px; }
details { margin:6px 0; } summary { color:#9ecbff; cursor:pointer; }
pre { background:#161b22; border:1px solid #2a2f36; padding:10px;
      white-space:pre-wrap; font-size:12px; }
</style></head><body>
<h1>s37 — 옥탑 관련 23샷 전면 재구축</h1>
<div class=box>하드코딩 0: 건물 구조·크기·규모 전부 LLM 이 씬 원문
전문에서 자가 추론. <b>실외(8샷)</b>: LLM 마스터 프롬프트 저작 → nb2
3롤 → GPT/Gemini VLM 합산 판정 선택 → 결함 취합 i2i 수정 = 기본 이미지
→ 샷별 배경 플레이트 8장(기본 이미지 참조) → 배경 8장 동시 참조 8패널
분할 스케치. <b>실내(15샷)</b>: LLM 평면도 스펙 추론 → i2 FP → LLM 이
그리는 순서 스스로 판단(뿌리 → 체인, 커버 샷 배정) → nb2 플레이트
체이닝(FP+뿌리+직전 참조) → 전 플레이트 동시 참조 스케치 2시트(8+7).
</div>

<section><h2>① 실외 — LLM 자가 추론 (구조·규모 근거)</h2>
<ul>u(   </ul>
<div class=note>카메라 선택: r[   uW   </div>
<details><summary>마스터 t2i 프롬프트 전문 (LLM 저작)</summary>
<pre>rZ   uo   </pre></details></section>

<section><h2>② 실외 — 마스터 3롤 + VLM 합산 판정</h2>
<div class=row>uQ   </div>
<table><tr><th>VLM</th><th>후보</th><th>점수</th><th>판정</th></tr>
u   </table></section>

<section><h2>③ 실외 — VLM 결함 취합 수정 → 기본 이미지</h2>
<table><tr><th>VLM</th><th>결함</th><th>수정 지시</th></tr>z	</table>
ub   </section>

<section><h2>④ 실외 — 샷별 배경 플레이트 + 스케치 패널 (8샷)</h2>
uE   </section>

<section><h2>⑤ 실외 — 분할 스케치 시트</h2>
u@   
<details><summary>스케치 프롬프트 전문</summary>
<pre>u[   </pre></details></section>

<section><h2>⑥ 실내 — LLM 평면도 추론 + FP</h2>
<ul>u%   </ul>
<div class=note>크기 추정: r  z</div>
u'   평면도 (i2, LLM 저작 프롬프트)u9   
<details><summary>FP 프롬프트 전문</summary>
<pre>r  ui   </pre></details></section>

<section><h2>⑦ 실내 — 플레이트 체인 (LLM 이 정한 순서)</h2>
uu   </section>

<section><h2>⑧ 실내 — 분할 스케치 시트 (전 플레이트 동시 참조)</h2>
<div class=row>z</div>
<div class=row>uM   </div>
<details><summary>스케치 프롬프트 전문 (시트별)</summary>
c              3   B   K   | ]  \  }}d  |d          d  yw)z<pre>r   z</pre>Nr   )r1   r   r   r  s      r   r2   zstage_html.<locals>.<genexpr>  s0      	5	3 05q"5R\"#6	*	3s   z
</details></section>
z
</body></html>z[html] )rN  )r   r   rh   r6   rF   rX   r   r(   r?   r5   rl   r   r   rC   rD   r  r*   r4   intPAGE
write_textr#  rk   )/emfactsjrowsr   r   crowsrI  r   candsfixed	fixed_figbg_figsr   r   esext_sketch_figr2  r  
plate_secsr4  role	refs_desc
still_secssmr   gmap35rt  r  r8   mt	ref_itemsr  ext_refs	prev_tags	comp_rowscellsverr  r  int_sketch_figsint_panel_figsrX  r   r  r  rr   r  s/                                              @@@@r   
stage_htmlr    s"   ;;tD*A 
l	BGGLB7J4KLLEE"+r*..q"599*bIA9QwZL 9wZL	#ao2F1G"$ %E J #
 E.)/R66818A9S:-?,@ A 8-.j: ;E  9 ((>3
'CGG $
 #$ $E HH%&E NS EHH./ @HJXZ  GJ(^C "3% ("166!&&+#6v#>?@ A9&''<> CuD/#RST GC5%'9:	;
>*+,,BDD	E   
,	#B+ 0!"&&""567 8 j!1233E.G HN 	?DGG   g   E J4-.2!"a~wqc]!VT)?	"1q5'C:,?+@r%ykdV;yk J..1"X,.?-@ AtyyH678	@
 F2e9+T*N;<"[/*++ACC	D
 / J	,	#B	'+vh'78'7!!E(A+'78),DD  9, %)$4 ?$4qFF1bM--f5= $4 ?26z2BC VVC[GG $H  Z$H H	 (*&z @z!#$V9#7#7#> z @*3%/BwK0@/AC;(C8$D EF:3x=/ J''*166!&&++>v+F'G&H77:e <?e %; '8-..DFGC: 9!&,y"9:;-dV=H IJ? -F!#-.0<= 	 "&j!1D4D!D 8!D1q"))+6 !D	 8	CE@S !Qse847u =669U ;;;>%24 5	@ 04 C!567 8- s!4V!<=> ?,,17,@ AI   ! $-	- 0<	<=J ON,399;<B3r&z!9#b'A+!#C7$4#5W >? 	? g;C;C5 A;;>% @114UqvvaffSk*623CR89 :N 	 = 	OO S S + SV GWSV#WSX $'r+#7"8YSX9YS\ 
"
 !"]S\#]Sb wcSbcSf gSfBgSl CHmSlImSn oSnoSt 		uSt
uSz  {Sz{S~ 
"&&2
 S~!SD GESD ESF !$D);$< =>GSF?GSH W78 9ISH:ISL 
$(($b
)*+MSL,MSR SSRSSX   YSX!YSZ [SZ [S^  	5	r*002	3	5 5 6_S`6aSd eSdeS Sh 
GD6
G 9?@,8s   "\ -\%\**\/)
ext_prompt
ext_photosr   ext_fixext_bg_promptsext_bgsr   r  fp_imgint_planr.  rF  rL  r  rb  rf  rl  html__main__z--onlyText_allint_all)r_   choicesstage_      )P__doc__argparser  r  syspathlibr   __file__parentHERErs  insertr*   
forest_libr   s34_conti_sheetr   s35_fullrunr(   
s29_top_v2r   rg   r}   r  r  rh   r   rC   rD   r   r   r#  r   r"   r-   r:   r@   rH   rP   rt   r   r   r   r   r   r   r6   r  r  r"  r  r$  r7  r;  r<  r=  rA  rJ  rS  r\  rd  rk  r|  r~  r  r}  r  r  r  STAGES__name__ArgumentParserapadd_argument
parse_argsaglobalsfnsonlyr  )r  s   0r   <module>r,     s  2   
 H~ 3t9     
UlU
X~((-
#	*%
!7
7
H+,^*>@"(J(6VF " )) 	 	&JV II 	 		#(L;-|G+@
0*-@` ii  $@NJ)-X$R X~@  @ Q;l/+dod
 z	 	 	 	"BOOHt"i%;;  =
A/5
6v!1gi&%%v
6CvvACFH 	
9	"ACFH  	AFF 
 7s   G