
    (<itY                       d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	m
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mZmZmZ eZdZdZd	Zd
ZdZdZdZ dZ!dZ"dZ#edz  Z$e$jK                  dd       edz  dz  dz  Z&e&jK                  dd       edz  Z'dZ(dZ)dZ*dZ+ejX                  j[                  dd      Z.dZ/dZ0de d e d!e d"e d#e d$e d%e d&e d'e d(e# d)e d*e d+e! d,Z1d-e d e d!e d"e d#e d$e d.e d/e d0e d1e" d2e d3e d4e  d5Z2d<d=d6Z3d<d>d7Z4d<d?d8Z5	 	 	 	 	 	 	 	 	 	 	 	 	 	 d@d9Z6dAd:Z7e8d;k(  r e7        yy)Bu  Cell-1 인카금융서비스 '정당한 보상' 배너 생성기 (v3.2 최종본).

Gemini API로 포토리얼 배경을 생성하고,
HTML/CSS + Playwright로 한글 텍스트를 정밀하게 오버레이합니다.

출력:
  - /home/jay/workspace/output/banners/cell-1-incar-fair/meta-feed-1080x1080.png
  - /home/jay/workspace/output/banners/cell-1-incar-fair/google-resp-1200x628.png
    )annotationsN)Path)sync_playwright)
CTA_MIN_PXFONT_DIRWORKSPACE_ROOT,   0   6   <   4   8   L   g333333?g      ?z output/banners/cell-1-incar-fairTparentsexist_okoutputz	v4-hybridzcell-1-incar-fairz=output/meta-ads/concept-catalog/35-hybrid-v4-refined-A/bg.pngz0https://generativelanguage.googleapis.com/v1betaz3https://www.googleapis.com/auth/generative-languagez)gemini-2.0-flash-preview-image-generationzgemini-2.5-flash-imageGEMINI_API_KEY'AIzaSyDEy7IcOoTbQsI4nxfPOw3ZFbYqEL_PgFUaA  Professional financial advisor's mahogany desk with scattered contract documents and a fountain pen, dramatic side lighting through venetian blinds casting shadow patterns, deep navy blue and warm amber tones, cinematic shallow depth of field, photorealistic office scene, no people, no text, no logos. Square 1:1 format.a$  Wide panoramic view of a modern Korean corporate office at golden hour, glass windows with warm sunlight streaming in, premium mahogany desk with financial documents, warm amber and navy tones, cinematic composition, photorealistic, no people, no text, no logos. Wide landscape 1.91:1 format.z<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=1080">
  <style>
    @font-face { font-family: 'Pretendard'; src: url('file://z}/Pretendard-Black.otf') format('opentype'); font-weight: 900; }
    @font-face { font-family: 'Pretendard'; src: url('file://z/Pretendard-ExtraBold.otf') format('opentype'); font-weight: 800; }
    @font-face { font-family: 'Pretendard'; src: url('file://z|/Pretendard-Bold.otf') format('opentype'); font-weight: 700; }
    @font-face { font-family: 'Pretendard'; src: url('file://z/Pretendard-SemiBold.otf') format('opentype'); font-weight: 600; }
    @font-face { font-family: 'Pretendard'; src: url('file://z~/Pretendard-Medium.otf') format('opentype'); font-weight: 500; }
    @font-face { font-family: 'Pretendard'; src: url('file://up  /Pretendard-Regular.otf') format('opentype'); font-weight: 400; }

    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
    html, body { width: 1080px; height: 1080px; overflow: hidden; font-family: 'Pretendard', sans-serif; word-break: keep-all; }

    .canvas { position: relative; width: 1080px; height: 1080px; overflow: hidden; }
    .bg-image { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; }
    .dark-overlay { position: absolute; inset: 0; background: rgba(10, 22, 40, 0.58); }

    /* 중앙 크림 반투명 패널 */
    .text-panel {
      position: absolute;
      top: 50%; left: 50%;
      transform: translate(-50%, -50%);
      width: 860px;
      padding: 56px 48px;
      background: rgba(255, 248, 231, 0.82);
      border-radius: 12px;
      backdrop-filter: blur(4px);
      box-shadow: 0 8px 32px rgba(0,0,0,0.2);
      display: flex; flex-direction: column;
      align-items: center;
      gap: 28px; text-align: center;
    }

    .badge {
      display: inline-block;
      background: #C9A84C; color: #1A0E00;
      font-size: zpx; font-weight: 700;
      height: 52px; padding: 0 24px;
      border-radius: 6px;
      white-space: nowrap;
      letter-spacing: -0.03em;
      line-height: z,px;
    }

    .headline {
      font-size: z9px; font-weight: 700;
      color: #3E2723; line-height: zp;
      letter-spacing: -1.5px;
    }
    .headline .gold { color: #C9A84C; }

    .sub-copy {
      font-size: a  px; font-weight: 500;
      color: #A07828;
      white-space: nowrap;
      letter-spacing: -0.02em;
    }

    .cta-btn {
      display: inline-block;
      background: linear-gradient(135deg, #C9A84C 0%, #D4B87A 100%);
      color: #1A0E00;
      font-size: z7px; font-weight: 700;
      height: 76px; line-height: u  px;
      padding: 0 40px;
      min-width: 360px;
      width: auto;
      border-radius: 6px;
      box-shadow: 0 6px 24px rgba(201,168,76,0.45);
      white-space: nowrap;
      letter-spacing: -0.03em;
      text-align: center;
    }
  </style>
</head>
<body>
  <div class="canvas">
    <img class="bg-image" src="{bg_url}" alt="background">
    <div class="dark-overlay"></div>
    <div class="text-panel">
      <span class="badge">인카금융서비스 TOP사업단</span>
      <p class="headline">같은 계약,<br>수수료가 왜 <span class="gold">다른가요?</span></p>
      <p class="sub-copy">정착지원금 최대 1,000만원<br>경력직 직전연봉 50% 지원</p>
      <div class="cta-btn">수익 구조 지금 확인 →</div>
    </div>
  </div>
</body>
</html>z<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=1200">
  <style>
    @font-face { font-family: 'Pretendard'; src: url('file://um  /Pretendard-Regular.otf') format('opentype'); font-weight: 400; }

    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
    html, body { width: 1200px; height: 628px; overflow: hidden; font-family: 'Pretendard', sans-serif; word-break: keep-all; }

    .canvas { position: relative; width: 1200px; height: 628px; overflow: hidden; }
    .bg-image { position: absolute; right: 0; top: 0; width: 65%; height: 100%; object-fit: cover; object-position: center right; }

    .gradient-overlay {
      position: absolute; inset: 0;
      background: linear-gradient(
        to right,
        rgba(10,22,40,0.95) 0%,
        rgba(10,22,40,0.95) 40%,
        rgba(10,22,40,0.85) 52%,
        rgba(10,22,40,0.50) 68%,
        rgba(10,22,40,0.15) 82%,
        transparent 100%
      );
    }

    /* 좌측 골드 세로 액센트바 */
    .accent-bar {
      position: absolute;
      top: 80px; left: 0;
      width: 4px; height: 460px;
      background: linear-gradient(to bottom, #C9A84C, #D4B87A);
      border-radius: 2px;
    }

    .text-area {
      position: absolute;
      top: 0; left: 0;
      width: 62%; height: 100%;
      padding: 48px 56px 48px 60px;
      display: flex; flex-direction: column;
      justify-content: center;
      gap: 20px;
    }

    .badge {
      display: inline-block;
      background: #C9A84C; color: #1A0E00;
      font-size: z7px; font-weight: 700;
      height: 48px; line-height: zpx;
      padding: 0 20px;
      border-radius: 6px;
      white-space: nowrap;
      letter-spacing: -0.03em;
      align-self: flex-start;
      margin-bottom: 6px;
    }

    .headline {
      font-size: z9px; font-weight: 700;
      color: #FFF8E7; line-height: zp;
      letter-spacing: -1.2px;
    }
    .headline .gold { color: #C9A84C; }

    .sub-copy {
      font-size: a3  px; font-weight: 500;
      color: #C9A84C;
      text-shadow: 0 1px 3px rgba(0,0,0,0.5);
      white-space: nowrap;
      letter-spacing: -0.02em;
    }

    .cta-btn {
      display: inline-block;
      background: linear-gradient(135deg, #C9A84C 0%, #D4B87A 100%);
      color: #1A0E00;
      font-size: z7px; font-weight: 700;
      height: 56px; line-height: uo  px;
      padding: 0 32px;
      min-width: 220px;
      width: auto;
      border-radius: 6px;
      box-shadow: 0 4px 16px rgba(201,168,76,0.35);
      white-space: nowrap;
      letter-spacing: -0.03em;
      align-self: flex-start;
      text-align: center;
      margin-top: 16px;
    }
  </style>
</head>
<body>
  <div class="canvas">
    <img class="bg-image" src="{bg_url}" alt="background">
    <div class="gradient-overlay"></div>
    <div class="accent-bar"></div>
    <div class="text-area">
      <span class="badge">인카금융서비스 TOP사업단</span>
      <p class="headline">같은 계약,<br>수수료가 왜 <span class="gold">다른가요?</span></p>
      <p class="sub-copy">정착지원금 최대 1,000만원<br>경력직 직전연봉 50% 지원</p>
      <div class="cta-btn">수익 구조 지금 확인 →</div>
    </div>
  </div>
</body>
</html>c                    t        d| d       t        j                         }t         dt         dt         }ddi}dd| igigd	d
dgid}	 t        j                  |||d      }|j                  dv rXt        d| dt         d|j                   dt                t         dt         dt         }t        j                  |||d      }|j                  s,t        d| d|j                   d|j                  dd         y|j                         }	|	j                  dg       }
|
s(t        d| dt        j                  |	      dd         y|
d   j                  di       j                  dg       }t        d |D        d      }|9|D cg c]  }d|v s|j                  dd       }}t        d| d|dd         y|d   j                  d d!      }t        j                   |d   d"         }d#|v rd$nd%}|j#                  |      }|j%                  |       t        j                         |z
  }t        d| d&|j&                   d't)        |      d(d)|d*d+	       |S c c}w # t*        $ r}t        d| d,|        Y d}~yd}~ww xY w)-u6   Gemini API 키로 배경 이미지를 생성합니다.   [배경u5   ] Gemini API 키 방식으로 이미지 생성 중.../models/z:generateContent?key=Content-Typeapplication/jsonpartstextresponseModalitiesIMAGETEXTcontentsgenerationConfig,  headersjsontimeout  i  i  	   ] 모델     실패 (HTTP ). Fallback:    ] API 오류:  - Nr)   
candidates   ] 응답에 candidates 없음: r   contentc              3  *   K   | ]  }d |v s|  yw
inlineDataN .0ps     `/home/jay/workspace/.worktrees/task-2057-dev2/tools/ai-image-gen/gen_cell1_incar_fair_banners.py	<genexpr>z+generate_bg_image_apikey.<locals>.<genexpr>G       A|q/@1A   	 )   ] 이미지 데이터 없음. 텍스트:    r4   mimeType
image/jpegdatajpeg.jpg.png
   ] 완료:  (, bytes, .1f   초)   ] 예외 발생: )printtimeGEMINI_API_BASEMODEL_IDr   requestspoststatus_codeFALLBACK_MODEL_IDokr   r&   getdumpsnextbase64	b64decodewith_suffixwrite_bytesnamelen	Exception)promptoutput_pathlabelstarturlr%   payloadresponseurl2rB   r/   r   
image_partr8   
text_parts	mime_typeimage_bytesext
final_pathelapsedes                        r9   generate_bg_image_apikeyrp   &  s   	GE7O
PQIIKE XhZ/D^DT
UC12G 01231GV3DEG
(==gGSQ ?2GE7)H:^HDXDXCYYfgxfyz{%&h/@.AAVWeVfgD}}T7RUVH{{GE7.1E1E0Fc(--X\Y\J]I^_`}}XXlB/
GE7"A$**TBRSWTWBXAYZ[1!!)R044WbAAeA4H
5:Jfk!%%+JJJGE7"KJWYXYNK[\]|,00\J	&&z,'?'GH)+f ,,S1
{+))+%wj(9C<LQ;OxX_`cWddhij K  w/s34sE   B6I) AI) >I) 	I$I$-I) BI) $I) )	J2JJc                   t        d| d       t        j                         }t         dt         d}d| dd}dd	| igigd
ddgid}	 t	        j
                  |||d      }|j                  dv rRt        d| dt         d|j                   dt                t         dt         d}	t	        j
                  |	||d      }|j                  s,t        d| d|j                   d|j                  dd         y|j                         }
|
j                  dg       }|s(t        d| dt        j                  |
      dd         y|d   j                  di       j                  dg       }t        d |D        d      }|9|D cg c]  }d	|v s|j                  d	d       }}t        d| d|dd         y|d    j                  d!d"      }t        j                  |d    d#         }d$|v rd%nd&}|j!                  |      }|j#                  |       t        j                         |z
  }t        d| d'|j$                   d(t'        |      d)d*|d+d,	       |S c c}w # t(        $ r}t        d| d-|        Y d}~yd}~ww xY w).uC   Bearer 토큰으로 Gemini API 배경 이미지를 생성합니다.r   u4   ] Bearer 토큰 방식으로 이미지 생성 중...r   z:generateContentzBearer r   )Authorizationr   r   r   r   r   r   r    r#   r$   r(   r*   r+   r,   r-   r.   Nr)   r/   r0   r   r1   c              3  *   K   | ]  }d |v s|  ywr3   r5   r6   s     r9   r:   z+generate_bg_image_bearer.<locals>.<genexpr>  r;   r<   r=   r>   r?   r4   r@   rA   rB   rC   rD   rE   rF   rG   rH   rI   rJ   rK   rL   )rM   rN   rO   rP   rQ   rR   rS   rT   rU   r   r&   rV   rW   rX   rY   rZ   r[   r\   r]   r^   r_   )r`   ra   tokenrb   rc   rd   r%   re   rf   rg   rB   r/   r   rh   r8   ri   rj   rk   rl   rm   rn   ro   s                         r9   generate_bg_image_bearerru   ^  s   	GE7N
OPIIKEXhZ/?
@C"5'**G
  01231GV3DEG
'==gGSQ?2GE7)H:^HDXDXCYYfgxfyz{%&h/@.AAQRD}}T7RUVH{{GE7.1E1E0Fc(--X\Y\J]I^_`}}XXlB/
GE7"A$**TBRSWTWBXAYZ[1!!)R044WbAAeA4H
5:Jfk!%%+JJJGE7"KJWYXYNK[\]|,00\J	&&z,'?'GH)+f ,,S1
{+))+%wj(9C<LQ;OxX_`cWddhij K  w/s34sE   B0I! =AI! 	>I! 	II%I! <BI! I! !	J*J  Jc                   t        | ||      }|r|S t        d| d       	 t        j                         }t	        | |||      }|r|S 	 t        d| dt                t        j                         rXt        j                  }|j                  |      }t        j                  t        |       t        d| d|j                          |S t        dt               # t
        $ r}t        d| d|        Y d}~d}~ww xY w)u>   배경 이미지를 생성하거나 폴백을 사용합니다.r   u:   ] API 키 방식 실패 → Bearer 토큰 방식 시도...u   ] Bearer 토큰 획득 실패: Nu4   ] Gemini 생성 실패 → 폴백 이미지 사용: u   ] 폴백 복사 완료: u   폴백 이미지도 없음: )rp   rM   gcloud_authget_access_tokenru   r_   FALLBACK_BGexistssuffixr[   shutilcopy2r]   RuntimeError)r`   ra   rb   resultrt   ro   rl   fallback_dests           r9   get_or_generate_bgr     s    &fk5AF 
GE7T
UVC,,.)&+ueLM  
GE7N{m
\]  #//4[-0w6}7I7I6JKL9+GHH  Cw=aSABBCs   %C 	D %C;;D c           
        d|j                          }| j                  |      }|j                  |d       t        d|        t        d| d| d       t	               5 }|j
                  j                  d	d
g      }		 |	j                  ||d      }
|
j                  d|j                          d       |
j                  d       |j                  j                  dd       |
j                  t        |      ddd||d       t        d|        |	j                          	 ddd       y# |	j                          w xY w# 1 sw Y   yxY w)uY   HTML 템플릿에 배경 이미지 URL을 삽입하고 Playwright로 PNG 캡처합니다.zfile://)bg_urlzutf-8)encodingu   [HTML] 저장 완료: u   [캡처] Playwright로 xu    캡처 중...z--no-sandboxz--disable-gpu)args)widthheight)viewportnetworkidle)
wait_untili	  Tr   pngr   )r   yr   r   )pathtypeclipu   [캡처] 저장 완료: N)resolveformat
write_textrM   r   chromiumlaunchnew_pagegotowait_for_timeoutparentmkdir
screenshotstrclose)html_contentbg_pathhtml_output_pathpng_output_pathr   r   r   html_filledr8   browserpages              r9   capture_html_to_pngr     s_    w()*F%%V%4K g>	"#3"4
56 
#E7!F8>
BC		 a**##./)J#K	##u-O#PDII 0 8 8 :;<IW!!$'""(((EOO_!5EQ&IO  ,_,=>?MMO  MMO s%   #E	BD4E	4EE		Ec            	     l   t        d       t        d       t        d       g } t        d       t        dz  }t        t        j                  d            }|r|d   }t        d|j                          nt        t        |d      }t        d|j                  z   z  }|j                         r5|j                         j                  |j                         j                  k  rt        j                  ||       t        d	       t        d
z  }t        dz  }	 t        t        |||dd       |j                         j                   dz  }t        d| d|dd       | j#                  dd|ddf       t        d       t        dz  }
t        t        j                  d            }|r|d   }t        d|j                          nt        t,        |
d      }t        d|j                  z   z  }|j                         r5|j                         j                  |j                         j                  k  rt        j                  ||       t        d       t        dz  }t        dz  }	 t        t.        |||dd        |j                         j                   dz  }t        d!| d|dd       | j#                  dd|ddf       t        d#       t        d$       t        d       | D ]  \  }}}t        d%| d&| d'|         t        d(       t1        t        j3                               D ]2  }|j                         j                   dz  }t        d)| d*|dd       4 t5        d+ | D              }|st7        j8                  d,       y y # t$        $ rJ}t        d|        dd l}	|	j)                          | j#                  ddt+        |      f       Y d }~ed }~ww xY w# t$        $ rJ}t        d"|        dd l}	|	j)                          | j#                  ddt+        |      f       Y d }~ld }~ww xY w)-Nz<============================================================uK   Cell-1 인카금융서비스 '정당한 보상' 배너 생성 시작 (v3.2)u2   
[Step 1] 1080x1080 배경 이미지 생성 중...zbg-cell1-1080zbg-cell1-1080.*r   u&   [배경1] 기존 이미지 재사용: 1080u+   
[Step 2] 1080x1080 배너 렌더링 중...zmeta-feed-1080x1080.htmlzmeta-feed-1080x1080.pngi8  )r   r   r   r   r   r   i   u   [배너1] 완료: rG   z.0fz KB)SUCCESSz KBu   [배너1] 실패: FAILEDu1   
[Step 3] 1200x628 배경 이미지 생성 중...zbg-cell1-1200zbg-cell1-1200.*u&   [배경2] 기존 이미지 재사용: 1200u*   
[Step 4] 1200x628 배너 렌더링 중...zgoogle-resp-1200x628.htmlzgoogle-resp-1200x628.pngi  it  u   [배너2] 완료: u   [배너2] 실패: z=
============================================================u   결과 요약z  [z] u    — u   
산출물 경로:z  z  (c              3  .   K   | ]  \  }}}|d k(    yw)r   Nr5   )r7   _ss      r9   r:   zmain.<locals>.<genexpr>2  s     7GAq!i7s      )rM   TMP_DIRlistglobr]   r   BG_PROMPT_1080
OUTPUT_DIRr{   rz   statst_mtimer|   r}   r   HTML_1080x1080st_sizeappendr_   	traceback	print_excr   BG_PROMPT_1200HTML_1200x628sortediterdirallsysexit)resultsbg1080_pathexisting_1080bg1080
bg1080_outhtml_1080_pathpng_1080_pathsize_kbro   r   bg1200_pathexisting_1200bg1200
bg1200_outhtml_1200_pathpng_1200_pathfnamestatusinfofsizeall_oks                         r9   mainr     s   	(O	
WX	(OG 

?@O+K&789Mq!6v{{mDE#NKH >?J*//"3"<"<v{{}?U?U"UVZ(	
89"<<N!::MF'+)	
  $$&..5"=/GC=EF19S>QRS 

>?O+K&789Mq!6v{{mDE#NKH>?J*//"3"<"<v{{}?U?U"UVZ(	
78"==N!;;MG&+)	
  $$&..5"=/GC=EF2I'#c?RST 
/	/	(O& 2vtF82eWE$012 

 J&&() )vvx$&1#Sc
$'() 7w77F i  F"1#&')--/18SVDEEFD  G"1#&')--/2Hc!fEFFGs2   AN
 %AO  
	O?OO 	P3)?P..P3__main__)r=   )r`   r   ra   r   rb   r   returnPath | None)
r`   r   ra   r   rt   r   rb   r   r   r   )r`   r   ra   r   rb   r   r   r   )r   r   r   r   r   r   r   r   r   intr   r   r   None)r   r   )9__doc__
__future__r   rY   r&   osr   rN   r|   pathlibr   rQ   playwright.sync_apir   __file__r   TOOL_DIRr   insertr   rw   
gen_configr   r   r   _CTA_PX
_SIZE_44PX
_SIZE_48PX
_SIZE_54PX
_SIZE_60PX_LH_48PX_LH_52PX_LH_56PX_LH_76PX_LH_1_2_LH_1_25r   r   r   ry   rO   GEMINI_SCOPErP   rT   environrV   r   r   r   r   r   rp   ru   r   r   r   __name__r5       r9   <module>r      s   #   	 
     / >   3x= !  ; ; 




 @@
 
    -
X

+.A
A dT * ^^ ED6,   02[\
T . ? @Hj I??Gj I??Gj I??Gj I??Gj I??Gj I8  
 :   $$,: .  
  ""* ,EZ|? @Hj I??Gj I??Gj I??Gj I??Gj I??Gj +IV  ""* 
,  $$+9 -    ""* ,ioh5p6rI>  	
   
HZz zF r   