
    (<iD                    6   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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eZdZdZ edz  Z!e!jE                  dd       edz  dz  dz  Z#e#jE                  dd       dZ$dZ%dZ&dZ'dZ(de de de de de de  d e d!e d"Z)d#e d$e d%e de d&e d'e  d(e d)e d*Z*d/d+Z+	 	 	 	 	 	 	 	 	 	 	 	 d0d,Z,d1d-Z-e.d.k(  r e-        yy)2u  인카다이렉트 M1-2 '관리자 비전' Google 광고 배너 생성기.

Gemini API로 서울 고층빌딩 프라이빗 오피스 배경을 생성하고,
HTML/CSS + Playwright로 한글 텍스트를 정밀하게 오버레이합니다.

출력:
  - /home/jay/workspace/output/google-ads/banners/m1/m1-2-1200x628.png
  - /home/jay/workspace/output/google-ads/banners/m1/m1-2-1080x1080.png
    )annotationsN)Path)sync_playwright)
CTA_MIN_PXHEAD_SUB_RATIOWORKSPACE_ROOT,   :   >   0   4   g333333?g?gffffff?zoutput/google-ads/banners/m1Tparentsexist_okoutputz	v4-hybridzm1-2-leaderz0https://generativelanguage.googleapis.com/v1betaz3https://www.googleapis.com/auth/generative-languagez)gemini-2.0-flash-preview-image-generationzgemini-2.5-flash-imageu#  Photographic scene of a spacious, modern private office in a Seoul high-rise building. Wide angle shot from the doorway, looking in. Floor-to-ceiling windows spanning the back wall reveal a panoramic Seoul cityscape with afternoon natural light streaming through. A clean, uncluttered desk made of warm walnut wood in the foreground, with a MacBook Pro open and two neatly stacked documents. A single leather executive chair behind the desk — empty, suggesting the owner's presence without showing a person. No clutter on the desk except a sleek desk lamp on the right corner. The room feels owned and purposeful, not just leased. Warm, directional late afternoon sunlight. Bokeh background city view. Shot on full-frame camera, f/2.8 equivalent quality. Professional, aspirational, ownership feeling.u  <!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1200">
<style>
  @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700;900&display=swap');

  * { margin: 0; padding: 0; box-sizing: border-box; }

  body {
    width: 1200px;
    height: 628px;
    overflow: hidden;
    font-family: 'Pretendard', 'Noto Sans KR', 'Apple SD Gothic Neo', sans-serif;
  }

  .banner {
    position: relative;
    width: 1200px;
    height: 628px;
    overflow: hidden;
    background: #1B365D;
  }

  /* 배경 이미지 - 전체, 우측 중심 */
  .bg-image {
    position: absolute;
    top: 0; left: 0;
    width: 100%; height: 100%;
    background-image: url('{bg_url}');
    background-size: cover;
    background-position: center right;
  }

  /* 좌측 코퍼레이트 블루 그라데이션 오버레이 (0~660px) */
  .left-overlay {
    position: absolute;
    top: 0; left: 0;
    width: 660px;
    height: 100%;
    background: linear-gradient(
      to right,
      rgba(43, 87, 151, 0.88) 0%,
      rgba(43, 87, 151, 0.82) 70%,
      rgba(43, 87, 151, 0.40) 90%,
      rgba(43, 87, 151, 0.00) 100%
    );
  }

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

  /* 텍스트 콘텐츠 영역 */
  .text-area {
    position: absolute;
    top: 0; left: 0;
    width: 620px;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 52px 60px;
  }

  /* 뱃지 */
  .badge {
    display: inline-block;
    background: #C5A572;
    color: #1B365D;
    font-size: z=px;
    font-weight: 700;
    height: 48px;
    line-height: u   px;
    padding: 8px 20px;
    border-radius: 4px;
    letter-spacing: -0.03em;
    white-space: nowrap;
    box-sizing: content-box;
    margin-bottom: 24px;
  }

  /* 메인 헤드라인 */
  .headline {
    font-size: z?px;
    font-weight: 700;
    color: #F0F4F8;
    line-height: u   ;
    letter-spacing: -0.01em;
    margin-bottom: 20px;
    word-break: keep-all;
  }

  /* 혜택 나열 */
  .benefits {
    font-size: z?px;
    font-weight: 500;
    color: #F0F4F8;
    line-height: u  ;
    letter-spacing: -0.03em;
    margin-bottom: 36px;
    word-break: keep-all;
    white-space: nowrap;
    text-shadow: 0 1px 3px rgba(0,0,0,0.4);
  }

  /* CTA 버튼 - 절대 위치 */
  .cta-btn {
    position: absolute;
    bottom: 52px;
    left: 60px;
    display: inline-block;
    background: linear-gradient(135deg, #C5A572 0%, #D4B87A 100%);
    color: #1A0E00;
    font-size: zpx;
    font-weight: 700;
    padding: 14px 36px;
    border-radius: 6px;
    letter-spacing: 0.02em;
    min-width: 280px;
    text-align: center;
    line-height: u`  ;
    box-shadow: 0 4px 16px rgba(197, 165, 114, 0.35);
    white-space: nowrap;
  }
</style>
</head>
<body>
<div class="banner">
  <div class="bg-image"></div>
  <div class="left-overlay"></div>
  <div class="accent-bar"></div>
  <div class="text-area">
    <div class="badge">인카금융서비스 | 지점장 성장</div>
    <div class="headline"><span style="color:#C5A572">모든 권한</span>으로<br>조직 운영하세요</div>
    <div class="benefits">개설비 전액 지원 | 리쿠르팅 협업</div>
  </div>
  <div class="cta-btn">지점 개설 조건 확인 →</div>
</div>
</body>
</html>u`  <!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1080">
<style>
  @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700;900&display=swap');

  * { margin: 0; padding: 0; box-sizing: border-box; }

  body {
    width: 1080px;
    height: 1080px;
    overflow: hidden;
    font-family: 'Pretendard', 'Noto Sans KR', 'Apple SD Gothic Neo', sans-serif;
  }

  .banner {
    position: relative;
    width: 1080px;
    height: 1080px;
    overflow: hidden;
    background: #1B365D;
  }

  /* 배경 이미지 전체 */
  .bg-image {
    position: absolute;
    top: 0; left: 0;
    width: 100%; height: 100%;
    background-image: url('{bg_url}');
    background-size: cover;
    background-position: center center;
  }

  /* 상단 코퍼레이트 블루 그라데이션 오버레이 (70% 높이) */
  .top-overlay {
    position: absolute;
    top: 0; left: 0;
    width: 100%;
    height: 70%;
    background: linear-gradient(
      to bottom,
      rgba(43, 87, 151, 0.85) 0%,
      rgba(43, 87, 151, 0.70) 40%,
      rgba(43, 87, 151, 0.50) 70%,
      rgba(43, 87, 151, 0.00) 100%
    );
  }

  /* 하단 코퍼레이트 블루 그라데이션 오버레이 (38% 높이) */
  .bottom-overlay {
    position: absolute;
    bottom: 0; left: 0;
    width: 100%;
    height: 38%;
    background: linear-gradient(
      to top,
      rgba(43, 87, 151, 0.92) 0%,
      rgba(43, 87, 151, 0.70) 60%,
      rgba(43, 87, 151, 0.00) 100%
    );
  }

  /* 전체 텍스트 레이아웃 */
  .content {
    position: absolute;
    top: 0; left: 0;
    width: 100%; height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 60px 80px;
    justify-content: center;
  }

  /* 뱃지 */
  .badge {
    display: inline-block;
    background: #C5A572;
    color: #1B365D;
    font-size: z=px;
    font-weight: 700;
    height: 52px;
    line-height: u   px;
    padding: 10px 24px;
    border-radius: 4px;
    letter-spacing: -0.03em;
    white-space: nowrap;
    box-sizing: content-box;
    margin-bottom: 32px;
  }

  /* 메인 헤드라인 */
  .headline {
    font-size: u  ;
    letter-spacing: -0.01em;
    text-align: center;
    margin-bottom: 36px;
    word-break: keep-all;
  }

  /* 골드 구분선 */
  .divider {
    width: 60px;
    height: 3px;
    background: linear-gradient(to right, #C5A572, #D4B87A);
    margin: 0 auto 36px auto;
    border-radius: 2px;
    flex-shrink: 0;
  }

  /* 혜택 목록 */
  .benefits {
    display: flex;
    flex-direction: column;
    gap: 18px;
    width: 100%;
    align-items: center;
    margin-bottom: 0;
  }

  .benefit-item {
    font-size: z?px;
    font-weight: 500;
    color: #FFFFFF;
    line-height: u  ;
    text-align: center;
    word-break: keep-all;
    padding: 0 20px;
    text-shadow: 0 2px 6px rgba(0,0,0,0.6);
  }

  /* CTA 버튼 - 절대 위치 */
  .cta-btn {
    position: absolute;
    bottom: 60px;
    left: 50%;
    transform: translateX(-50%);
    display: inline-block;
    background: linear-gradient(135deg, #C5A572 0%, #D4B87A 100%);
    color: #1A0E00;
    font-size: zpx;
    font-weight: 700;
    padding: 18px 56px;
    border-radius: 6px;
    letter-spacing: 0.03em;
    min-width: 300px;
    text-align: center;
    line-height: u  ;
    box-shadow: 0 6px 24px rgba(197, 165, 114, 0.40);
    white-space: nowrap;
  }
</style>
</head>
<body>
<div class="banner">
  <div class="bg-image"></div>
  <div class="top-overlay"></div>
  <div class="bottom-overlay"></div>
  <div class="content">
    <div class="badge">인카금융서비스 | 지점장 성장</div>
    <div class="headline"><span style="color:#C5A572">모든 권한</span>으로<br>조직 운영하세요</div>
    <div class="divider"></div>
    <div class="benefits">
      <div class="benefit-item"><span style="color:#C5A572">개설비 전액 | 리쿠르팅 협업</span></div>
      <div class="benefit-item">조직 확장 시스템 지원</div>
    </div>
  </div>
  <div class="cta-btn">지점 개설 조건 확인 →</div>
</div>
</body>
</html>c           	        t        dt         d       t        j                         }t         dt         d}d|  dd}dd	t        igigd
ddgid}t        j                  |||d      }|j                  dv rOt        dt         d|j                   dt                t         dt         d}t        j                  |||d      }|j                  s8t        d|j                   d|j                  dd         |j                          |j                         }|j                  dg       }	|	s$t        dt        j                  |      dd        |	d   j                  di       j                  dg       }
t!        d |
D        d      }|5|
D cg c]  }d	|v s|j                  d	d       }}t        d|dd        |d    j                  d!d"      }t#        j$                  |d    d#         }d$|v rd%nd&}|j'                  |      }|j)                  |       t        j                         |z
  }t        d'|j*                   d(t-        |      d)d*|d+d,       |S c c}w )-u?   Gemini API로 배경 이미지를 생성하고 저장합니다.u?   [배경] Gemini API로 오피스 배경 생성 중... (모델: )z/models/z:generateContentzBearer zapplication/json)AuthorizationzContent-TypepartstextresponseModalitiesIMAGETEXT)contentsgenerationConfigi,  )headersjsontimeout)  i  i  u   [배경] 모델 u    실패 (HTTP z). Fallback: u   [배경] API 오류: z - Nr   
candidatesu   응답에 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_m1_2_leader_banners.py	<genexpr>z$generate_bg_image.<locals>.<genexpr>  s     =Q<1+<q=s   	 u'   이미지 데이터 없음. 텍스트:    r#   mimeTypez
image/jpegdatajpegz.jpgz.pngu   [배경] 완료:  (,z bytes, z.1fu   초))printMODEL_IDtimeGEMINI_API_BASE	BG_PROMPTrequestspoststatus_codeFALLBACK_MODEL_IDokr   raise_for_statusr   getRuntimeErrordumpsnextbase64	b64decodewith_suffixwrite_bytesnamelen)tokenoutput_pathstarturlr   payloadresponseurl2r,   r    r   
image_partr&   
text_parts	mime_typeimage_bytesext
final_pathelapseds                      r'   generate_bg_imagerS     s   	KH:UV
WXIIKEXhZ/?
@C"5'**G
  34561GV3DEG
 }}S'MH . 
.9M9M8Nm\m[nop!"(+<*==MN==wWcR;;%h&:&:%;3x}}Tc?R>STU!!#==?D,+J:4::d;KDS;Q:RSTTqMi,00"=E=%=tDJ16FA&A+aeeFB'F
FDZPRQR^DTUVV<(,,ZFI"":l#;F#CDKi'&VC((-J;'iikE!G	joo.b[1A!0DHWUXMY]
^_ Gs   	I!I!c           
        d|j                          }| j                  |      }t        d| d| dz  }|j                  |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       |j!                  d       y# |	j                          w xY w# 1 sw Y   1xY w)uY   HTML 템플릿에 배경 이미지 URL을 삽입하고 Playwright로 PNG 캡처합니다.zfile://)bg_urltmp_xz.htmlzutf-8)encodingu   [캡처] Playwright로 u    캡처 중...z--no-sandboxz--disable-gpu)args)widthheight)viewportnetworkidle)
wait_untili	  Tr   pngr   )rW   yrZ   r[   )pathtypeclipu   [캡처] 저장 완료: N)
missing_ok)resolveformatTMP_DIR
write_textr0   r   chromiumlaunchnew_pagegotowait_for_timeoutparentmkdir
screenshotstrcloseunlink)html_contentbg_pathrF   rZ   r[   rU   html_filledtmp_htmlr&   browserpages              r'   capture_html_to_pngrz     sm    w()*F%%V%4K 4waxu55Hg6	#E7!F8>
BC		 a**##./)J#K	##u-O#PDII 0 0 234IO!!$'$$TD$AOO[!1Q&EO  ,[M:;MMO OOtO$ MMO s%   %EBEEEEE&c                    t        d       t        d       t        d       t        d       	 t        j                         } t        dt        |        d       t        d       t        d	z  }t        t        j                  d
            }|r|d   }t        d|j                          n	 t        | |      }t        d       t        dz  }	 t        t        ||dd       |j                         j                  dz  }t        d| d|dd       t        d       t        dz  }	 t        t$        ||dd       |j                         j                  dz  }t        d| d|dd       t        d       t        d       t        d |        t        d!|        t        d       y # t        $ r}t        d|        t        d      |d }~ww xY w# t        $ r}t        d|        t        d      |d }~ww xY w# t        $ r-}t        d|        dd l}|j#                          Y d }~d }~ww xY w# t        $ r,}t        d|        dd l}|j#                          Y d }~d }~ww xY w)"Nz<============================================================uF   인카다이렉트 M1-2 '관리자 비전' Google 배너 생성 시작u!   
[인증] SA 토큰 획득 중...u'   [인증] 토큰 획득 성공 (길이: z chars)u   [인증] 실패:    u(   
[배경] 배경 이미지 확인 중...bg_m1_2_leaderzbg_m1_2_leader.*r   u%   [배경] 기존 이미지 재사용: u   [배경] 생성 실패: u,   
[배너 1] 1200x628 가로형 생성 중...zm1-2-1200x628.pngi  it  )rt   ru   rF   rZ   r[   i   u   [배너 1] 완료: r.   z.0fz KB)u   [배너 1] 실패: u0   
[배너 2] 1080x1080 정사각형 생성 중...zm1-2-1080x1080.pngi8  u   [배너 2] 완료: u   [배너 2] 실패: z=
============================================================u   생성 완료u     배너 1: u     배너 2: )r0   gcloud_authget_access_tokenrD   	Exception
SystemExitrg   listglobrC   rS   
OUTPUT_DIRrz   HTML_1200x628statst_size	traceback	print_excHTML_1080x1080)	rE   ebg_tmp_pathexistingru   output_1200size_kbr   output_1080s	            r'   mainr     sm   	(O	
RS	(O 

./#,,.7E
|7KL 

56,,KGLL!345H1+5gll^DE	''{;G 

9:22K0&#	
 ""$,,t3#K=73-tDE 

=>33K0'#	
 ""$,,t3#K=73-tDE
 
/	/	L
&'	L
&'	(Oq  #!!%&m"#  	',QC01Q-Q&	'"  0#A3'()--//0"  0#A3'()--//0sa   ,F) -G AG? 'AH8 )	G2GG	G<G77G<?	H5"H00H58	I-"I((I-__main__)rE   rq   rF   r   returnr   )rt   rq   ru   r   rF   r   rZ   intr[   r   r   None)r   r   )/__doc__
__future__r   r?   r   sysr2   pathlibr   r5   playwright.sync_apir   __file__rn   TOOL_DIRra   insertrq   r~   
gen_configr   r   r   _CTA_PX
_SIZE_44PX
_SIZE_58PX
_SIZE_62PX_LH_48PX_LH_52PX_LH_1_2	_LH_RATIO_LH_1_35_LH_1_4r   ro   rg   r3   GEMINI_SCOPEr1   r8   r4   r   r   rS   rz   r   __name__r$       r'   <module>r      s0   #   
    / >   3x= !  A A 



	
 <<
 
    -
X

+m
; dT * ED6, 
O 
"LX y    |    |     |   RhQb y    |   8 |     y   qoh0j%%% % 	%
 % 
%HBJ zF r   