
    1j/k                        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	m
Z
mZmZmZ ddlmZ ddlmZ  ej&                  e      ZdZd	Z G d
 de      Zy)u  W21B space_set_bg step — frame/addon/life 3층 공간 세트 BG (2026-06-10 사용자 합의 방식).

장소 그룹(master_plan group = loc 묶음)당:
  ① analyze (frame/addon/life_baseline + construction + access, 씬·전문 무삭제)
  ② place_desc whole/indoor/outdoor 분리 (+visible adjacent masses)
  ③ view briefs (wide establishing 기준)
  ④ 실내: frame 2D(t2i) → addon i2i = ★최종 2D FP★ → frame_check(VLM 진단)
     → VLM 공간 좌표 → ★공간당 단일 번호 마킹★(PIL) → 마킹 사본 base 로 BG i2i
  ⑤ 옥외(open_air): FP 미경유 — 공간당 ★단 한 장★ T2I 기준 BG
  ⑥ threshold = connector(plate 생략) / same_space = canonical 사진 참조 i2i
산출: checkpoint manifest + assets/<gid>/ 아래 png + space_plate_map.

★3D FP 단계 없음(실험 비교로 제거 확정). ★generic — 시나리오/품목/장소 하드코딩 0.
opt-in: settings.space_set_bg_enabled (default False) → OFF 시 not_applicable 만
기록하고 기존 FP/BG 체인 영향 0. 하류(scene_image) 배선은 Phase 2 (이 step 은
plate 산출/계약까지 — dwelling_zone_map Phase 접근과 동일).
    )annotationsN)Path)AnyCallableDictListOptional)
StepRunner)space_set_bg   z4.202606111309c                  
    e Zd ZU dZdZded<   dZded<   dZded<   dZded<   ddddd		 dd
Z	d f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ed#d       Zed$d       Z	 	 	 	 	 	 	 	 	 	 	 	 d%dZd&d'dZ xZS )(SpaceSetBgStepu<   frame/addon/life 3층 공간 세트 BG 파이프라인 step.NzOptional[Callable[..., str]]_text_override_vision_overridezOptional[Callable[..., None]]_t2i_override_i2i_override)textvisiont2ii2ic               <    || _         || _        || _        || _        y N)r   r   r   r   )selfr   r   r   r   s        V/Users/manta/Documents/Projects/TheRoad-I1/backend/app/core/steps/space_set_bg_step.pyset_overrides_for_testingz(SpaceSetBgStep.set_overrides_for_testing,   s$     # &      c                Z    ddl m} t        t        |dd            syt        |          S )u   flag OFF 면 not_applicable 로 마킹되게 (completed empty cp 방지 — Codex 리뷰 #2).
        ON 이면 기본 applicability(if_background_mode) 평가로 위임.r   settingsspace_set_bg_enabledF)app.core.configr   boolgetattrsupercheck_applicability)r   r   	__class__s     r   r%   z"SpaceSetBgStep.check_applicability5   s+     	-GH&<eDEw*,,r   c                L   ddl m} t        |j                        | j                  z  dz  dz  | j
                  z  |z  dz  }|j                         r&	 t        j                  |j                  d            S y # t        $ r!}t        j                  d||       Y d }~y d }~ww xY w)	Nr   r   checkpointsepisodeszmanifest.jsonutf-8encodingz!space_set_bg: %s parse failed: %s)r!   r   r   projects_dir
project_id
episode_idexistsjsonloads	read_text	Exceptionloggerwarning)r   step_idr   cpexcs        r   _load_prev_checkpointz$SpaceSetBgStep._load_prev_checkpoint=   s    ,&&'$//9MI??+-457FG 	 99;Rzz",,,"@AA   RBGSQQRs   $A9 9	B#BB#c                   ddl m} t        t        |dd            }|t        |dd      t        |dd      t        |dd      t        t
        t        j                  d	}|rt        j                         |d
<   t        j                  t        j                  |d      j                  d            j                         d d S )Nr   r   r    Fspace_set_bg_text_model space_set_bg_vision_modelspace_set_bg_render_model)enabled
text_modelvision_modelrender_modelschema_versionprompt_versioncore_schema_versionprompt_packT)	sort_keysr*      )r!   r   r"   r#   SCHEMA_VERSIONPROMPT_VERSIONcorepack_identityhashlibsha256r1   dumpsencode	hexdigest)r   r   r@   payloads       r   _config_hashzSpaceSetBgStep._config_hashJ   s    ,wx)?GH!(,ErJ#H.I2N#H.I2N,,#'#6#6
 %)%7%7%9GM"~~JJw$/66w?

)+cr 	r   c                8    dddt         | j                         i dS )Nr   applicable_countcompleted_countfailed_countrD   config_hashdata)rJ   rT   )r   s    r   _not_applicablezSpaceSetBgStep._not_applicable`   s'     ! ,,,.
 	
r   c          
         | j                   | j                  |||      S ddlm} ddlm} |j                  |||t        |d|j                              S )Nsystemuser
max_tokensr   r   space_set_bg_providerr<   )r_   r`   ra   model)r   r!   r   app.modules.pipelinerc   text_completionr#   TEXT_MODEL_DEFAULT)r   r_   r`   ra   r   provs         r   _textzSpaceSetBgStep._textk   s^    *&&f4J&WW,F##($=t?V?VW $ 
 	
r   c                   | j                   | j                  ||||      S ddlm} ddlm} |j                  ||||t        |d|j                              S )Nr_   r`   image_pathsra   r   r   rb   r>   )r_   r`   rl   ra   rd   )r   r!   r   re   rc   vision_completionr#   VISION_MODEL_DEFAULT)r   r_   r`   rl   ra   r   rh   s          r   _visionzSpaceSetBgStep._visionu   sk      ,((Dkj ) Z Z,F%%+*($?AZAZ[ & 
 	
r   c          	         | j                   | j                  ||       y ddlm} ddlm} |j                  ||t        |d|j                               y )Npromptout_pathr   r   rb   r?   )rr   rs   rd   )r   r!   r   re   rc   image_generater#   IMAGE_MODEL_DEFAULT)r   rr   rs   r   rh   s        r   _t2izSpaceSetBgStep._t2i   sU    )fx@,FH($?AYAYZ 	 	
r   c          
         | j                   | j                  |||       y ddlm} ddlm} |j                  |||t        |d|j                               y )Nbase_image_pathrr   rs   r   r   rb   r?   )ry   rr   rs   rd   )r   r!   r   re   rc   
image_editr#   ru   )r   ry   rr   rs   r   rh   s         r   _i2izSpaceSetBgStep._i2i   sX    )vX`a,F+FX($?AYAYZ 	 	
r   c               4    ddl m} |j                  ||      S )Nr   rb   what)re   rc   
parse_json)r   r   r~   rh   s       r   _parse_jsonzSpaceSetBgStep._parse_json   s    Ft$//r   c                   ddl m} ddlm} | j                  j                  |      j                   ||j                              j                  |j                  | j                  k(        j                         }|r|j                  xs dS dS )Nr   )undefer)Episoder=   )sqlalchemy.ormr   app.models.projectr   dbqueryoptionsfulltextfilteridr/   first)r   r   r   eps       r   _load_fulltextzSpaceSetBgStep._load_fulltext   sh    *.GGMM'"WWW--./VGJJ$//12UW	 	 ')!r0b0r   c                $   | xs i j                  d      xs i }|j                  d      xs |j                  d      xs |}t        |t              si S d}|D ci c]&  }|j                  |      ||j                  |      ( }}|xs |S c c}w )Nr[   guide
guide_json)world_setting_summarylocation_guardrailsstyle_rulesimage_generation_notes)get
isinstancedict)world_guide_cpr[   r   keysksubsets         r   _world_guide_subsetz"SpaceSetBgStep._world_guide_subset   s    %2**628b!CTXXl%;Ct%&Ih+/L4a599Q<3K!UYYq\/4L Ms   B1Bc                ,   g }| D ]  }|j                  d      }|j                  d      xs g D ]a  }|j                  ||j                  d      |j                  d      xs d|j                  d      xs d|j                  d      xs dd       c  |S )	u   _select_scenes_for_group 의 scenes → core.shot_blocks 입력 행으로.
        scene 원문(text)은 summary 슬롯에 그대로(무삭제).
        shot 인덱스 포함 — Phase 2 shot→space 배정의 deterministic 조인 키.scene_indexshots
shot_indexheadingr=   r   description)sceneshotr   summary	shot_desc)r   append)scenesrowsscsishs        r   _scenes_to_shot_rowsz#SpaceSetBgStep._scenes_to_shot_rows   s    
 &(B&BffWo++FF<0!vvi06B!vvf~3!#!6!<"  ,  r   c                   |j                  dd       | j                  |      }t        |D ch c]  }|j                  d      |d    c}      }t	        j
                  |      }	| j                  | j                  t        j                  t	        j                  |	||      d      | d      }
t	        j                  |
      }
|dz  j                  t        j                  |
d	d
      d       t	        j                  |
      }t        |      dkD  }|
j                  d      xs g }i }d|fgt!        |j#                               z   D ]@  \  }}| j                  t        j$                  t	        j&                  |
|||      d      ||<   B |dz  j                  t        j                  |d	d
      d       | j                  | j                  t        j(                  t	        j*                  |
      d      | d      }t	        j,                  |
|      \  }}i }i }|D ch c]  }|d   dk(  s|d    }}|j#                         D ]  \  }}|rd| nd}||vr| j                  t        j.                  t	        j0                  |
||d      d      }|d| dz  j                  |d       |d| dz  }| j3                  |t5        |              |D cg c]>  }|j                  d!      xs g D ]$  }|j                  d"      r|j                  d"      & @ }}}|d#| dz  }| j7                  t5        |      t        j8                  j;                  d$j=                  |      %      t5        |      &       |||<   	 | j                  | j?                  t        j@                  d't5        |      t5        |      gd()      | d*|       ||<    i }!|D ci c]  }|j                  d,      | }"}i }#|D ]  }|d-   |d.   |d   |d   f\  }$}%}&}|d/|% dz  }'d	}(|&d0k(  r||d/|d1    dz  })|)jE                         sd2d3|d4    d5|#|$<   V| j7                  t5        |)      t        jF                  j;                  |d6   7      t5        |'      &       d8|d4    }*n|&d9k(  r|j                  d:      xs |j                  d      xs d}+|"j                  |$      xs i },| j                  t        jH                  t	        jJ                  |
|,|+|d6         d      }-|d;|% dz  j                  |-d       | j3                  |-t5        |'              d<}*n4|&d=k(  r|j                  d>      xs |j                  d      xs d}+|"j                  |$      xs i },| j                  t        jL                  t	        jN                  |
|,|+|d6         d      }-|d?|% dz  j                  |-d       | j3                  |-t5        |'              d@}*n}|j                  |      }.|.|.jE                         sd2dA| dBd5|#|$<   F||!vr|D /cg c]  }/|/d   dk(  r|/d   |k(  r|/d-    }0}/| j                  | j?                  t        jP                  t	        jR                  |0      t5        |.      gdC)      | dD|       }1|1j                  dE      xs g D /ci c]H  }/|/j                  d,      tU        |/j                  dFdG            tU        |/j                  dHdG            fJ c}/|!|<   |!|   j                  |$      }2|2d}(tV        jY                  dI||$       dJ}2|dK|% dz  }3dLdMl-m.}4  |4| j^                  | j`                  dNO      5  t	        jb                  t5        |.      t5        |3      |2dL   |2d   |dP          d d d        |"j                  |$      xs i },|,j                  dQ      xs g D 5cg c]%  }5|5j                  dR      s|5j                  dR      ' }6}5|j                  d>      xs |j                  d      xs d}+| j7                  t5        |3      t	        jd                  |dP   |+|d6   |6      t5        |'      &       dS|dP    }*dT|&|'jf                  |%|dP   |*|dU   dV}7|&dk(  r|(rd|7dW<   |7|#|$<    i }8g }9	 | j                  | j                  t        jh                  t	        jj                  |
|      dX      | dY      }:t	        jl                  |:xs i j                  dZ      xs g |#|D ;ch c]%  };|;j                  d-      s|;j                  d-      ' c};[      \  }8}9i }<|8j#                         D ]
  \  }%}7|7j                  d`      dak7  rdb |%js                  dd      D        \  }=}>||7j                  dc      xs dz  }?dd|% d}@	 |?ju                         stw        de|?jf                         | j7                  t5        |?      t	        jx                  |7j                  df      xs d      t5        |@z        &       |@|7dg<   dT|@|7j                  dh      |7j                  di      |7j                  df      dj|<|%<    dT|D cg c]  }|j                  d,       c}|
j                  do      xs i ||#||t5        |      |8|9|<dpS c c}w c c}w c c}}w # tB        $ r} d t5        |       d+||<   Y d } ~ d } ~ ww xY wc c}w c c}/w c c}/w # 1 sw Y   `xY wc c}5w c c};w # tB        $ r@} tV        jY                  d\||        d]to        |       jp                   d^|  d_g}9Y d } ~ 	d } ~ ww xY w# tB        $ r} tV        jY                  dk||%|7j                  di      |        d|7dl<   d2to        |       jp                   d^|  |7j                  dh      |7j                  di      dm|<|%<   |9j{                  dl|=|>|7j                  di      to        |       jp                   d^|  dn       Y d } ~ d } ~ ww xY wc c}w )qNT)parentsexist_okr   i>  r^   z analyzer}   zspace_analysis.jsonF   )ensure_asciiindentr*   r+   r   spaceswholei  zplace_desc.jsonil  z view_briefskindmarked_indoorgroup_suffix_r=   )
frame_onlyi  frame_promptz.txtfp_frame_2dz.pngrq   addonimplementationfp_final_2dz, )addonsrx   u   첫째 이미지 = FRAME 평면도(구조 셸). 둘째 이미지 = addon i2i 결과. frame(벽/문/창/통로/access path) 보존 여부를 schema 로 판단하라.i  rk   z frame_check )frame_preservederrornameroomkeybg_samespace_refref_keyr   zcanonical missing: ref_roomstatusr   view)r   z
canonical:outdoor_t2ioutdooroutdoor_bg_prompt_u   single_t2i (FP 미경유)
indoor_t2iindoorindoor_bg_prompt_u2   single_t2i (FP 미경유 — 단일 실내 공간)zfinal 2D FP missing (suffix=)i  z space_positions	positionscx      ?cyu9   space_set_bg %s: VLM 위치 누락 %s → 중앙 fallback)r   r   
fp_marked_r   )generation_contextspace_set_marked_fp)stagenumlife_baselineitemzmarked_fp:#ok	enclosure)r   r   pngr   r   	referencer   position_missing_fallbacki.  z shot_assignassignments)connector_namesu6   space_set_bg %s: shot 배정 실패 (비치명) — %sassign_call_failed: )reasonr   plate_actionderive_from_basec              3  2   K   | ]  }t        |        y wr   )int).0xs     r   	<genexpr>z,SpaceSetBgStep._run_group.<locals>.<genexpr>  s     :(91A(9s   canonical_plate_pngbg_derived_zcanonical plate png missing: derive_instruction	plate_pngcanonical_plate_keyspace)r   r   r   r   r   uW   space_set_bg %s: derive 실패 (비치명, canonical fallback) — shot %s space %s: %sderive_failed)r   r   r   r   )r   r   r   r   r   _validation)r   r   
validationframe_checksplates
connectorsdescs
assets_dirshot_plate_mapshot_assign_diagnosticsderived_plates)>mkdirr   sortedr   rL   shot_blocksr   ri   ANALYZE_FA_SYSbuild_analyze_uservalidate_fa
write_textr1   rP   enclosure_groupslenlistitemsPLACE_GROUP_SYSbuild_place_group_userVIEW_BRIEF_SYSbuild_view_briefs_userplan_space_viewsFRAME_FP_SYSbuild_fp_userrv   strr{   	ADDON_I2Iformatjoinro   FRAME_CHECK_SYSr4   r0   SAMESPACE_VIEWOUTDOOR_BG_T2I_SYSbuild_outdoor_bg_userINDOOR_BG_T2I_SYSbuild_indoor_bg_userSPACE_POS_SYSbuild_space_positions_userfloatr5   r6   "app.services.image_capture.contextr   r.   r/   mark_fpbuild_marked_view_promptr   SHOT_ASSIGN_SYSbuild_shot_assign_userbuild_shot_plate_maptype__name__splitis_fileFileNotFoundErrorbuild_derive_plate_promptr   )Ar   gidr   r   r   out_dir	shot_rowsr
scene_numsblocksanalysisgroupsmulti
all_spacesr   gkeygspacesbriefsplansr   fp_by_suffixr   pmarked_suffixesgksfxfprompt	frame_pngsaaddon_itemscomp_pngr9   positions_cachespace_by_namer   rnr   r   outpposition_fallbackcanon	ref_labelplacesp
t2i_promptcompqnamespos_resposmarkedr   r   lifeentryr   assign_diagsassignscr  scishisrcdst_namesA                                                                    r   
_run_groupzSpaceSetBgStep._run_group   s    	dT2--f5	YAaeeGn>XQwZYZ
!!), ##JJd11 33FHjQ"'  ) 5!	 $ #
 ##H-	(	(44JJxeA> 	5 	R &&x0Fa\\(+1r
 !#&
34tFLLN7KKMD'**++005$P %  E$K L
 
$	$00JJu5;g 	1 	O !!JJd11 77Ad  T5% " ' !11(FCz
 )+')6;\eqyO?[1^,e\!<<>KB#AbT(C/)jj(('''2$O !  G cU$//;;Gg;VKuD"99IIIWs9~I>1818A%%..B.A1559I3J &'. (   ;se4!88HIIc)n!^^22$))K:P2Q"8}  . !)L	P#'#3#3LL#33o%(^S]$CPT	 ! V
  5bT2 $4 $4R + *@ 683=>:av):>,.A!"6AeHai>AR!RBT3s3%t_,D %&C)~T"::||~,3@STUV`TaSb>c!dF2J		#e*!%!4!4!;!;6!;!K#&t9  . ):8	&		),H		'0BHb"&&r*0b!ZZ2233Hb%6S" ( $
 /uD99EEj[bEc		c$i	@7	%		(+Guyy/AGR"&&r*0b!ZZ11228R&	R" ( $
 .se488DDZZaDb		c$i	@P	#'',<t{{},3@\]`\aab>c!dF2Jo-+0+0aV97An<MQT<T &	5   #..D,>,>*.*I*I%*P25d) % O !$u$4SE:	 / <G #*++k":"@b"@,"@A faeeD#.>(?quuTSVGWAX'YY"@,OC( &c*..r2;(,%NN#^`cegh$C ZuD#99
 R'OOT__<Q LLTCKQQ5R #&&r*0b020G0M20M`0M!RSRWRWX^R_f0M`		(+Guyy/AGR		#f+!%!>!>qxPQRXPY[_!`#&t9  . *!E(4	TYYsxian%E &+<5912F2Je l *,-/	G&&

$"6"6 $ ; ;Hi P&+  - uL)	 ' +G
 ,0+D+DB##M28b&8B T
1aeeFmv
 T,V(NL 57(..0JCyy(,>>:		#q(9:HCUYY'<=CDC$SE.H{{}+.KCHH:,VWW		$'H99%))DX:Y:_]_` 8!34  6 &.k""8+0995J+K"YYw/*/))4H*I	's# 1J .89jquuV}j9",,}5;($g,,'3,
 	
y ZT ]"  P7;c#h#OR P
 ?T, 
 a6 !U 	GNNSUXZ]^';)-c););(<Bse&DF GL	G:  +,/eii6H#O *.o&% $S	 2 232cU;+0995J+K"YYw/	's# ##-S"YYw/ $S	 2 232cU;%  $ :s   kk&k4kAk Ak& llAl
5l3l*
l*A6l4 :l/l/$l4 B4n q&	l/lll'	/l4 4	m==5m88m= 	p?	B+p::p?c           
        ddl m} t        t        |dd            s| j	                         S | j                  d      }| j                  d      }| j                  d      }| j                  d      }| j                  d	      }| j                  d
      }|xs i j                  di       xs i j                  di       xs i }	|	s| j	                         S ddlm}
 |xs i j                  di       xs i j                  dg       xs g }i }|xs i j                  di       xs i j                  dg       xs g D ]=  }|j                  d      }|j                  dd      xs d}|-|s0||t        |      <   ? | j                  |      }| j                         }t        t        |dd            }i }dx}x}}|	j                         D ]  \  }}|xs i j                  d      dk7  r |xs i j                  d      xs i }|j                  d      xs g D ch c]%  }|j                  d      s|j                  d      ' }}|s|t        |      D cg c]  }|dd	 c}d} |
|||||      \  }}t        |      |k  r|rdt        |      |d||<   |dz  }| j                  d z  |z  } 	 | j!                  |||||       ||<   |dz  } |||t,        | j/                         |t0        t2        j4                  t3        j6                         d%d&d'S c c}w c c}w # t"        $ rF}!t$        j'                  d!|       d"t)        |!      j*                   d#|! d$||<   |dz  }Y d }!~!d }!~!ww xY w)(Nr   r   r    Fbackground_master_plan
scene_saveshot_validatorshot_selectionworld_guidescene_directorr[   r:  )_select_scenes_for_groupsegmentsr   r   primary_locationr=   space_set_bg_min_scenesr   r   r   planbackgroundsloc_id)rm  label)group_idmembers)scene_primaryskipped_low_frequency)r   scene_count
min_scenesr   assetszspace_set_bg group %s failedr   r   r   )modulestems)r4  rE   rG   rV   )r!   r   r"   r#   r\   r:   r   *app.core.steps.background_master_plan_steprg  r   r   r   r  r  r
  _cp_dirr_  r4   r5   	exceptionr'  r(  rJ   rT   rK   rL   PROMPT_PACK_MODULErM   )"r   moder   plans_cpscene_save_cpshot_validator_cpshot_selection_cpr   scene_director_cp	plans_maprg  scene_segmentsrq  r   r   primaryr   r   rt  results
applicable	completedfailedr-  rW  rk  bgmember_locslocsynthetic_groupr   	_shot_idsr.  r9   s"                                     r   _executezSpaceSetBgStep._execute  s   ,GH&<eDE''))--.FG22<@ 667GH 667GH33MB 667GHn"))&"5;@@"MSQS	''))W!r&&vr28b==j"MSQS 	
 )+%+00<BGGRTU[Y[[B&Bff/4:G~')0c"g&	 \
 ((8&&( +DaHI
"$*++
+Y#//+JC  *d2KR$$V,2D7;xx7N7TRT7Tj7TY[Y_Y_`hYi266(+7TKjDJ;DWXDWSsR8DWXO !91BDU+!-FI 6{Z'.E36v;j$ZGCL!OJllX-3G#sFE8WUQ	/ ,< !+(",,,.!"0 #55!//1 	
 	
3 k
 Y    !?E*1tCy?Q?Q>RRTUXTY<Z[!s*   L-LL/L	M.(;M))M.)returnNone)r  r"   )r7   r  r  Optional[Dict[str, Any]])r  r  )r  Dict[str, Any])r_   r  r`   r  ra   r   r  r  )
r_   r  r`   r  rl   z	List[str]ra   r   r  r  )rr   r  rs   r  r  r  )ry   r  rr   r  rs   r  r  r  )r   r  r~   r  r  r   )r   r  r  r  )r   List[Dict[str, Any]]r  r  )r-  r  r   r  r   r  r   r  r.  r   r  r  )resume)r|  r  r  r  )r(  
__module____qualname____doc__r   __annotations__r   r   r   r   r%   r:   rT   r\   ri   ro   rv   r{   r   r   staticmethodr   r   r_  r  __classcell__)r&   s   @r   r   r   #   s    F 48N07592937M0737M07 4Tt!	!-,

	
	
	
0
	1    $r
r
 %r
 	r

 r
 r
 
r
jP
 P
r   r   )r  
__future__r   rN   r1   loggingpathlibr   typingr   r   r   r   r	   app.core.step_runnerr
   re   r   rL   	getLoggerr(  r5   rJ   rK   r    r   r   <module>r     sQ   " #     6 6 + 5			8	$!e
Z e
r   