
    oNjvA                        d Z ddlZddlZddlZddlmZ ej                  j                  d e	 ee
      j                               ddlZddlZej                   dz  Zej$                  dz  ZdZg dZdZd	Zd
 Zd Zdj5                  g d      Zdddg ddddg dddddddg ddddiddidg ddddg ddZdj5                  g d      ZddddddddiddidddgddidgdZdj5                  dd g      Zdj5                  g d!      Z d"Z!dj5                  g d#      Z"d$ Z#d7d%Z$d& Z%d' Z&d( Z'd) Z(d* Z)e*d+k(  r ejV                         Z,e,j[                  d,d-g d./       e,j]                         Z/eja                  d0d01       e/jb                  d2v r e%        e/jb                  d3v r e&        e/jb                  d4v r e'        e/jb                  d5v r e(        e/jb                  d6v r e)        yyy)8u:  s29 — TOP 체인 v2 (사용자 "그대로 다시, 최종 수정된 것 기반, 맵 완성까지",
2026-07-09. 커밋 금지).

s20 ⓪ TOP 체인 재실행 — 이번엔 프롬프트가 최종 자산 기반:
s27 상세 스펙(공간 단서 그래프 저작 15항목) + SCALE & MASSING(3층·8-10m·
다단 철제 계단=제작자 정정) + ID-free 범례(nb2 라벨 습성 대응, x_nb2_r2 검증).

체인: [1]photos nb2 3롤(참조 0) → [2]judge GPT/Gemini VLM 0-10 합산 선택
(동점=Gemini 순위 우선 — 물리 결함 감지 우세 판정 지식) → [3]fix 양쪽 VLM
결함 질문·코드 취합(중복 판단 없음)→nb2 i2i 수정(결함 0=생략) →
[4]map 수정본 기반 탑다운 맵 작도 — 경찰서 FP 스타일(s27 STYLE_MAP)
+ 마커(P–W, s27 detail items) + 수직 재투영 계약(s20 FPFLAT_VERTICAL_NOTE_V2
판정 지식) — 사진→수직 재투영은 gpt 전담(판정 지식).
사용: backend/.venv/bin/python s29_top_v2.py [--only photos|judge|fix|map|html|all]
산출: out/forest_map/top2/*.png + plans/top2_place_v1.json + top2.html
    N)Pathtop2z	top2.htmltop2_place_v1))Aztop2_photo_nb2_a.png)Bztop2_photo_nb2_b.png)Cztop2_photo_nb2_c.pngztop2_photo_fixed_nb2.pngztop2_map_gpt.pngc                 >    dj                  d | d   d   D              S )N
c              3   8   K   | ]  }d |d    d|d      yw)z- name_en    — placement_enN .0its     N/Users/manta/Documents/Projects/TheRoad-I1/scratchpad/forest_exp/s29_top_v2.py	<genexpr>z!_idfree_legend.<locals>.<genexpr>(   s/      86 "Y-b.@-AB6s   detailitems)join)specs    r   _idfree_legendr   &   s)    99 8#H~g68 8 8    c                     | d   }dj                  ddddd|d   z   d	t        |       z   d
dddddddt        j                  t        j                  g      S )u.   x_nb2_r2 검증본과 동일 구성 (ID-free).r   

z<Create ONE PHOTOREALISTIC aerial location still of a filmingz@property, from a 45-degree high aerial camera looking across thez@yard toward the building (whole property in frame). No referenceu;   image is attached — build the scene from this text alone.zLAYOUT (ground truth):
layout_narration_enz?ELEMENTS (render each as the real thing, in its listed place):
z9SCALE & MASSING: the main building is a three-storey agedzAmulti-family villa, roof deck roughly 8-10 m above the yard, withzAthe small rooftop-room unit as a fourth-level volume on the deck;z;the steel retrofit stair climbs the full three storeys as az@multi-flight zig-zag run with intermediate landings; each facadez>storey shows a few modest windows of the regional multi-familyz@type; surrounding blocks are a dense low-rise Korean town, fullyz'real (windows, roofs, wires, pavement).)r   r   S27NO_ANNOTATION
REAL_FACTSr   ds     r   _photo_promptr#   ,   ss    XA;;FJJE"Q'<%==J

	CKKEJHJ1#  r   r
   )z=You are given ONE image-generation prompt and THREE candidatez=images, labelled A, B, C in the order attached, all generatedzfrom that exact prompt.z@Pick the ONE candidate that most faithfully realises the prompt.z=Judge ONLY fidelity to the prompt: its stated structure (whatz?contains or carries what, counts, connections, placements), thez?camera it asks for, materials and state, and its exclusions (noz;people, no readable text). Ignore generic aesthetic appeal.z>Check every candidate against the prompt point by point beforez5deciding; base every verdict only on what is visible.z=Also give every candidate an integer score 0-10 for that samez	fidelity.z@Output: winner, ranking best-to-worst, and per candidate a scorezAplus a one-line Korean verdict citing the decisive prompt points.objectFstring)r   r   r   )typeenumarray)r&   r   r&   integer)labelscore
verdict_ko)r&   additionalProperties
propertiesrequired)winnerrankingverdicts)z<You are given the image-generation prompt and ONE photographz:generated from it. List what is WRONG with the photograph:z:- fidelity: any visible deviation from the prompt's statedz@  structure (what contains or carries what, counts, connections,z7  placements), its camera, materials and state, and itsz+  exclusions (no people, no readable text),z@- physical coherence: any construction that could not physicallyz=  work in reality (broken, floating or overlapping structure,z+  unreachable routes, impossible geometry).z:Base every finding only on what is visible. Ignore genericzaesthetic taste.z=issues: each finding as issue_ko (one short Korean line) plusz:fix_en (ONE imperative English edit instruction that fixesz>exactly that finding while changing nothing else). Empty arrayzif nothing is wrong.issues)issue_kofix_enr4   r5   z?Edit this photograph. Fix ONLY the issues listed below, each inz0place, changing nothing else about the property:)uB   PRESERVE EVERYTHING ELSE EXACTLY as in the original photograph —z>buildings, roof objects, yard, surroundings, lighting, camera,z.framing. No people, no readable text anywhere.u^   PHOTOGRAPH TO EDIT — fix ONLY the issues the prompt lists; preserve everything else exactly.)zAOUTPUT MEDIUM: a flat 2D architectural SITE-PLAN DRAWING on plainuA   drawing paper — NOT a photograph, NOT a rendering of the scene.z?The attached photograph is ONLY a source of layout information;u<   do NOT reproduce or imitate its camera angle or its look —z;RE-PROJECT everything to a TRUE ORTHOGRAPHIC PLAN seen fromz1DIRECTLY ABOVE (90 degrees, straight-down nadir).z@Absolutely NO 3D of any kind: no perspective, no foreshortening,z@no axonometric or oblique tilt, no facades, no wall surfaces, nou@   volume sides, no cast shadows, no photographic texture — everyz>element appears ONLY as its pure plan geometry (roof outlines,z=ground shapes, openings marked in wall lines) in uniform flatz"fills and clean drafting linework.c                     | d   }dj                  ddddddt        d	d
ddj                  d |d   D              z   ddj                  |d         z   t        j                  t        j                  g      S )Nr   r   z9Draw ONE detailed top-down architectural SITE PLAN of theu9   filming property shown in the attached photograph — thez9property inside its boundary wall (building, rooftop deckz;contents, external stair, yard, gate, approach) plus a thinz:strip of the immediate surroundings as simple flat contextzblocks.z<CIRCLED MARKERS (all of them, nothing else): place each as az>small white circle with a thin black ring containing the code,z5exactly on its element as located in the photograph:
r
   c              3   D   K   | ]  }d |d    d|d    d|d      yw)- (code) r   r   r   Nr   r   s     r   r   z_map_prompt.<locals>.<genexpr>   s9      *( "V*R9eB~<N;OP(s    r   zAllowed zone labels: z, zone_labels_en)r   VERTICAL_NOTEr   	STYLE_MAPSTYLE_REF_NOTEr!   s     r   _map_promptr?      s    XA;;CCCEDFH@
)) *j* *	* 	 $))A.>,?"@@  r   c                 \    	 t        j                  |       S # t        $ r ||cY S i cY S w xY wN)F	load_plan	Exception)namedefaults     r   load_plan_orrG      s5    6{{4   6!-w5256s    +++c            	      T   t        j                  t        j                        } t	        |       }t        j
                  t        |t        t              d       t        D ]7  \  }}t        j                  d|j                          |g dt        |z         9 t        dt               y )N)photo_prompt_en
candidatess29_top2_photo_1:1aspect_ratioout_pathu   [photos] nb2 3롤 완료 →)rB   rC   r   SPECr#   	save_planPLANdict
CANDIDATESimg_nb2lowerOUTTprint)r   plabfns       r   stage_photosr\      s~    ;;sxx DdAKK!%)*%57 8R			OCIIK=11b$tby	:  

($/r   c            
         t        j                  t              } 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 ]J  \  }}t        j                  |t        |t        |	      |<   t        d
| d|   d    d|   d           L 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 )Ntextz<THE PROMPT (all three candidates were generated from this):
rI   r&   r^   u   후보 이미지 없음: z
Candidate :))gpts29_top2_judge_gpt)
gemini-pros29_top2_judge_geminimodelzjudge[z
]: winner=r0   z	 ranking=r1   c              3   R   K   | ]  }t        fd |   d   D                 yw)c              3   :   K   | ]  }|d    k(  s|d     yw)r*   r+   Nr   )r   vrZ   s     r   r   z(stage_judge.<locals>.<genexpr>.<genexpr>   s#     K!5A7s9JQwZ!5s   
r2   N)next)r   mjudgerZ   s     r   r   zstage_judge.<locals>.<genexpr>   s-      (&A 	Kq*!5KK&s   $'ra   rc   rc   c                 2    | v rj                  |       S dS )Nc   )index)rZ   gem_ranks    r   <lambda>zstage_judge.<locals>.<lambda>   s%    Xo *2)< *.+-*.r   )key)rl   totalsselectedselected_filezjudge: totals=z
 selected=)rB   rC   rR   rT   rW   existsappendpng_data_urlllmJUDGE_SYSTEMJUDGE_SCHEMArX   summaxvaluesr   minupdaterS   rQ   )planpartsr*   r[   frf   tagrZ   _rt   bestttiedru   rq   rl   s          `      @@r   stage_judger      s   ;;tD(*./@*ABD EE  	r2Ixxz:6qc::zf
5'.CDEQ^^A&'	  
 E@
suuS,|#(*eugZeX(>'?%,y124 	5	@ 7AB6@FC 3 (&( ( (6@  B v}}D$lln:nFCT	CnD:\"9-H4 . /HKK%6x"&z"28"<> ?KKd	N6(*XJ
78B ;s   1 F? GGc                  x   t        j                  t              } t        | d   z  }|j	                         s
J d|        dd| d   z   ddddt        j
                  |      g}i }dD ]J  \  }}t        j                  |t        |t        |	      ||<   t        d
| dt        ||   d                 L || 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        ddj                  |      z   t        g      }	|	| d<   t        | d<   t        j                  t        |        t        j                   d|	t"        |fgdt        t        z         t        dt        t        z         y c c}}}w )Nrv   u   선택본 없음: r^   z5THE PROMPT (the photograph was generated from this):
rI   r_   zPhotograph to examine:))ra   s29_top2_critique_gpt)rc   s29_top2_critique_geminire   z	critique[z
]: issues=r3   critique))ra   zGPT VLM)rc   z
Gemini VLMr8   r:   r5   
fixed_fileTfix_skippedu   fix: 결함 0 — 수정 생략r   zISSUES TO FIX:
r
   
fix_prompts29_top2_photo_fixedrL   rM   u   [fix] 수정본 완료 →)rB   rC   rR   rW   rw   ry   rz   CRITIQUE_SYSTEMCRITIQUE_SCHEMArX   lenrQ   r   FIX_HEADPRESERVE_TAILFIXEDrU   	FIX_LABEL)
r   srcr   r   rf   r   titlei	fix_linesrY   s
             r   	stage_fixr      s   ;;tD
o&
&C::<3-cU33<#%)*;%<=? &>?^^C 	"E
 HC
s%%_e /u>	%
3xx/H+I*JKL	C
  D&D5&D\UE"5/(3Q ugR(}- 4 .&D  5 !/2\"]	D$/0X1DIIi4HH"$ 	%ADDKKdII$a9c*:); 4%<9	
&u5#5s    "F5c                     t        j                  t        j                        } t        j                  t              }t
        |d   z  }|j                         s
J d|        t        |       }||d<   t        |d<   t        j                  t        |       t        j                  d||t        j                  gdt
        t        z         t        dt
        t        z         y )	Nr   u   수정본 없음: 
map_promptmap_files29_top2_map_gpt	1024x1024)refssizerO   u   [map] 완료 →)rB   rC   r   rP   rR   rW   rw   r?   MAP_OUTrQ   img_gptSTYLE_FPrX   )r   r   r   rY   s       r   	stage_mapr     s    ;;sxx D;;tD
l#
#C::<3-cU33<DADDKKdII !3*=9	
dWn-r   c                  x  
 t        j                  t        j                        } t	        t
              d 
d1
fd	j                  di       }j                  di       }d}dD ]5  }||vr||   d   D ]#  }|d| d	|d
    d	|d    d	 
|d          d	z  }% 7 d}j                  d      xs i j                         D ]0  \  }}|d   D ]#  }|d| d	 
|d          d	 
|d          dz  }% 2 d 
j                  dd             d 
|       ddj                  fdt        D               d| d 
j                  dd             dj                  d      rdnd d| dj                  d       r- j                  d d      j                  d      sd!nd"d#      nd d$ 
j                  d%d&             d'j                  d(      r j                  d(d      d)d#      nd* d+ 
j                  d,d&             d-}	t        j                  |	d./       t        d0t                y )2Nc                 >    t        j                  t        |             S rA   )_htmlescapestr)r   s    r   esczstage_html.<locals>.esc,  s    ||CF##r   c           
      8    d|  }d| d| d| d |       d	S )Nzout/forest_map/top2/z<figure style='width:z%'><a href='z'><img src='z!' loading='lazy'></a><figcaption>z</figcaption></figure>r   )r[   capwidthrelr   s       r   figzstage_html.<locals>.fig/  sD    $RD)'wl3% @ E ""3xj(>@ 	Ar   rl   rt    rm   r2   z<tr><td>z	</td><td>r*   r+   r,   z
</td></tr>r   r3   r4   r5   uN  <!doctype html><html lang=ko><head><meta charset=utf-8>
<title>s29 TOP 체인 v2 — 실사 3롤→VLM 판정→수정→맵</title><style>
body{font-family:'Apple SD Gothic Neo',sans-serif;margin:24px;max-width:1500px}
figure{display:inline-block;margin:1%;vertical-align:top}
img{width:100%;border:1px solid #ccc} figcaption{font-size:13px;text-align:center}
pre{font-size:11px;background:#f7f7f7;border:1px solid #ddd;padding:8px;
white-space:pre-wrap;max-height:320px;overflow:auto}
table{border-collapse:collapse;font-size:12px;width:100%}
td,th{border:1px solid #ccc;padding:4px 6px;text-align:left}
h2{border-bottom:2px solid #333;padding-bottom:4px;margin-top:36px}
.sel{outline:4px solid #2a7ae2}</style></head><body>
<h1>s29 — TOP 체인 v2 (2026-07-09)</h1>
<p>프롬프트 기반=최종 자산: s27 상세 스펙+SCALE &amp; MASSING(3층·철제 계단
정정)+ID-free. 체인=nb2 3롤 → GPT/Gemini VLM 0-10 합산 선택(동점=Gemini
우선) → 결함 취합 nb2 i2i 수정 → 경찰서 FP 스타일 탑다운 맵(gpt 재투영).</p>

<h2>① 후보 3롤 (nb2, 참조 0) — 선택=ru   ?u	   
(합산 z)</h2>
c              3   n   K   | ],  \  }} |d | j                  d      |k(  rdndz          . yw)u   후보 ru   u
    ★선택r   N)get)r   rZ   r[   r   r   s      r   r   zstage_html.<locals>.<genexpr>W  sB      	$"WS" 
R73%DHHZ4HC4OLUWX	Y"s   25uQ   
<table><tr><th>VLM</th><th>후보</th><th>score</th><th>한줄 판정</th></tr>
uN   </table>
<details><summary>실전송 프롬프트(3롤 공통)</summary>
<pre>rI   u;   </pre></details>

<h2>② 결함 취합 → nb2 i2i 수정 r   u   (결함 0 — 생략)z?</h2>
<table><tr><th>VLM</th><th>issue</th><th>fix_en</th></tr>z	</table>
r   u   수정본(fixed)u   선택본 그대로(결함 0),   u5   
<details><summary>수정 프롬프트</summary><pre>r   u   (없음)u   </pre></details>

<h2>③ 맵 형태 완성 — 수정 실사 → 경찰서 FP 스타일 탑다운 (gpt 재투영, 마커 P–W)</h2>
r   u   최종 맵 (top2_map_gpt)u   <p>(미생성)</p>u2   
<details><summary>맵 프롬프트</summary><pre>r   z</pre></details>
</body></html>zutf-8)encodingz[html] )   )rB   rC   r   rP   rG   rR   r   r   r   rT   PAGE
write_textrX   )r   rl   rt   jrowsrk   ri   crowscr   docr   r   r   s             @@@r   
stage_htmlr   (  s   ;;sxx DD$A HHWb!EXXh#FE"E>q*%A9QwZL 9wZL	#ao2F1G"$ %E & # E*%+22418A9S:-?,@ A 8-.j: ;E  5
0  14DHHZ4L0M/N O		V  	$"	$ $ %% 	$(($R
()* +*EIXXmE\*Abd)e f::? A AE  AI  AI  JV  AWTXXlB488M;R!3Xwy{|  ]_  ` `558,z9Z5[4\ ] CG((:BVTXXj92>\p q r225dhh|J6W2X1Y ZA!CD 	OOC'O*	GD6
r   __main__z--onlyall)photosrl   fixmaphtmlr   )rF   choicesT)parentsexist_ok)r   r   )rl   r   )r   r   )r   r   )r   r   rA   )2__doc__argparser   r   syspathlibr   pathinsertr   __file__parent
forest_librB   s27_forest_mapr   OUTrW   EXPr   rR   rT   r   r   r   r#   r   r{   r|   r   r   r   r   r   r<   r?   rG   r\   r   r   r   r   __name__ArgumentParserapadd_argument
parse_argsamkdironlyr   r   r   <module>r      s}      
  3tH~,,- .  
wwuu{-
 	#
82 yy  $ e#_=#&.HJ  %&.H$i0#)8"4
 =
	" 2', ))  & e %!' 2%x0 (2

 
$ 99E6 
 		  2	 		   *609>!6H.@F z	 	 	 	"BOOHeL  N
AJJtdJ+vv""vv!!vvvvvv  ! r   