
    (<iK                    J   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dZdZdZ dZ!edz  Z"e"jG                  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 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*e d+e  d,e d-e d.e d/e d0Z*d5d1Z+	 	 	 	 	 	 	 	 	 	 	 	 	 	 d6d2Z,d7d3Z-e.d4k(  r e-        yy)8u=  Cell-2 인카다이렉트 × 관리자/조직 비전 배너 생성기.

Gemini API로 임원급 고층 오피스 야경 배경을 생성하고,
HTML/CSS + Playwright로 한글 텍스트를 정밀하게 오버레이합니다.

산출물:
  - /home/jay/workspace/output/banners/cell-2-incar-leader/meta-feed-1080x1080.html
  - /home/jay/workspace/output/banners/cell-2-incar-leader/meta-feed-1080x1080.png
  - /home/jay/workspace/output/banners/cell-2-incar-leader/google-resp-1200x628.html
  - /home/jay/workspace/output/banners/cell-2-incar-leader/google-resp-1200x628.png
    )annotationsN)Path)sync_playwright)
CTA_MIN_PXFONT_DIRWORKSPACE_ROOT,   0   :   <   4   8   L   g333333?g      ?z"output/banners/cell-2-incar-leaderT)parentsexist_okz0https://generativelanguage.googleapis.com/v1betazgemini-2.0-flash-expzgemini-2.5-flash-preview-04-17a   Premium high-rise office interior at night, floor-to-ceiling windows showing city skyline with warm golden lights, dark elegant workspace, leather executive chair, warm ambient lighting from desk lamp, professional meeting room atmosphere, no people, cinematic, ultra-realistic photographa  Panoramic view of city skyline at night from executive office, floor-to-ceiling windows, golden city lights reflecting, dark premium interior visible on left side, warm desk lamp glow, corporate atmosphere, no people, ultra-realistic photograph, landscape formatz<!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: 24px; 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: aX  ;
      letter-spacing: -1.5px;
      white-space: nowrap;
    }
    .headline .gold { color: #C9A84C; }

    .gold-divider {
      width: 100%;
      height: 2px;
      background: linear-gradient(to right, transparent, #C9A84C 20%, #C9A84C 80%, transparent);
      opacity: 0.60;
      flex-shrink: 0;
    }

    .sub-copy {
      font-size: zpx; font-weight: 500;
      color: #6B5010;
      white-space: nowrap;
      letter-spacing: -0.02em;
    }

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

    .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: um  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">지점장 이직, 89일이 <span class="gold">골든타임</span></p>
      <div class="gold-divider"></div>
      <p class="sub-copy">본부 5개 | 지점 10개 | 200명+ 조직</p>
      <p class="urgency">사무실 개설비 지원 | 1200% 룰 시행 전 지금</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: z;
      letter-spacing: -1.2px;
      white-space: nowrap;
    }
    .headline .gold { color: #C9A84C; }

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

    .urgency {
      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: u  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: 12px;
    }
  </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">지점장 이직, 89일이 <span class="gold">골든타임</span></p>
      <p class="sub-copy">본부 5개 | 지점 10개 | 200명+ 조직</p>
      <p class="urgency">사무실 개설비 지원 | 1200% 룰 시행 전 지금</p>
      <div class="cta-btn">지점장 이직 상담받기 →</div>
    </div>
  </div>
</body>
</html>c                ,   t        d| d       t        j                         }t         d}ddi}d|  dd}d|igd	d
|v rdnddd}t         d}	dd|igigdddgid}
d}d}dD ]w  }t         d| d}	 t        d| d| d       t        j                  |||
d      }|j
                  r|} n/t        d| d|j                   d |j                  dd!         d}y ||j
                  st        d| d#      t        d| d$|        |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/         }d0|v rd1nd2}|j!                  |      }|j#                  |       t        j                         |z
  }t        d| d3|j$                   d4t'        |      d5d6|d7d8	       |S # t        $ r}t        d| d"|        d}Y d}~!d}~ww xY wc c}w )9u?   Gemini API로 배경 이미지를 생성하고 저장합니다.u   [배경:u   ] Gemini API 생성 중...z'/models/imagen-3.0-generate-002:predictContent-Typezapplication/jsonzBearer )Authorizationr   prompt   1080z1:1z16:9)sampleCountaspectRatio)	instances
parametersz./models/gemini-2.5-flash-image:generateContentpartstextresponseModalitiesIMAGETEXT)contentsgenerationConfigN )zgemini-2.5-flash-imagezgemini-3.1-flash-image-previewzgemini-3-pro-image-previewz/models/z:generateContentz] u
    시도...i,  )headersjsontimeoutu   ] 실패 HTTP z:    u
   ] 예외: u   ] 모든 모델 실패u   ] 사용 모델: 
candidatesu   응답에 candidates 없음: r   contentc              3  *   K   | ]  }d |v s|  yw)
inlineDataN ).0ps     b/home/jay/workspace/.worktrees/task-2057-dev2/tools/ai-image-gen/gen_cell2_incar_leader_banners.py	<genexpr>z$generate_bg_image.<locals>.<genexpr>r  s     =Q<1+<q=s   	u'   이미지 데이터 없음. 텍스트:    r+   mimeTypez
image/jpegdatajpegz.jpgz.pngu
   ] 완료:  (,z bytes, z.1fu   초))printtimeGEMINI_API_BASErequestspostokstatus_coder   	ExceptionRuntimeErrorr%   getdumpsnextbase64	b64decodewith_suffixwrite_bytesnamelen)tokenoutput_pathr   labelstart
imagen_urlheaders_jsonheaders_authimagen_payload
gemini_urlgemini_payloadresponse
used_model	try_modeltry_urler3   r(   r   
image_partr.   
text_parts	mime_typeimage_bytesext
final_pathelapseds                              r/   generate_bg_imager_   8  s%   	HUG5
67IIKE $$$KLJ"$67L #5'**L
  ()$*eO5
N $$$RSJ 01231GV3DEN
 HJ p 	$%Xi[8HI	HUG2i[
;<}}WladeH{{&
~h6J6J5K2hmm\`]`NaMbcd x{{XeW,BCDD	HUG,ZL
9:==?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	HUG:joo%6b[9I!8LHU\]`Taae
fg=  	HUG:aS12H	$ Gs*   89I'3-I'	J J'	J0J		Jc           
     p   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                  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	  pngr   )rc   yre   rf   )pathtypeclipu   [캡처] 저장 완료: N)resolveformat
write_textr7   r   chromiumlaunchnew_pagegotowait_for_timeout
screenshotstrclose)html_contentbg_pathhtml_output_pathpng_output_pathre   rf   ra   html_filledr.   browserpages              r/   capture_html_to_pngr     sC    w()*F%%V%4K g>	O,-
./	#E7!F8>
BC		 a**##./)J#K
	##u-O#PDII 0 8 8 :;<IW!!$'OO_!5EQ&IO  ,_,=>?MMO  MMO s%   #D,A:D=D,D))D,,D5c                    t        d       t        d       t        d       t        d       	 t        j                         } t        dt        |        d       t        d       t        d	z  }	 t        | |t        d
      }t        d       t        dz  }	 t        | |t        d      }t        d       t        dz  }t        dz  }	 t        t        |||dd       |j                         j                  dz  }t        d| d|dd       t        d       t        dz  }
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'|        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|        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 }~ad }~ww xY w)+Nz<============================================================uI   Cell-2 인카다이렉트 × 관리자/조직 비전 배너 생성 시작u!   
[인증] SA 토큰 획득 중...u'   [인증] 토큰 획득 성공 (길이: z chars)u   [인증] 실패: r   u2   
[배경] 1080x1080 배경 이미지 생성 중...zbg-cell2-1080r   u   [배경:1080] 생성 실패: u1   
[배경] 1200x628 배경 이미지 생성 중...zbg-cell2-12001200u   [배경:1200] 생성 실패: u-   
[배너 1] meta-feed-1080x1080 생성 중...zmeta-feed-1080x1080.htmlzmeta-feed-1080x1080.pngi8  )rz   r{   r|   r}   re   rf   i   u   [배너 1] 완료: r5   z.0fz KB)u   [배너 1] 실패: r   u.   
[배너 2] google-resp-1200x628 생성 중...zgoogle-resp-1200x628.htmlzgoogle-resp-1200x628.pngi  it  u   [배너 2] 완료: u   [배너 2] 실패: z=
============================================================u   Cell-2 배너 생성 완료u     배경 1080: u     배경 1200: u     배너 1 HTML: u     배너 1 PNG:  u     배너 2 HTML: u     배너 2 PNG:  )r7   gcloud_authget_access_tokenrH   r>   
SystemExit
OUTPUT_DIRr_   BG_PROMPT_1080BG_PROMPT_1200r   	HTML_1080statst_size	traceback	print_exc	HTML_1200)rI   rW   bg_path_1080_basebg_path_1080bg_path_1200_basebg_path_1200	html_1080png_1080size_kbr   	html_1200png_1200s               r/   mainr     s   	(O	
UV	(O 

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

?@"_4#(0A>SYZ 

>?"_4#(0A>SYZ 

:;77I55H0" &$	
 --/))D0#H:R}DAB 

;<88I66H0" &$	
 --/))D0#H:R}DAB
 
/	
'(	OL>
*+	OL>
*+	i[
)*	hZ
()	i[
)*	hZ
()	(OI  #!!%&m"#  #-aS12m"#  #-aS12m"#&  0#A3'()--//0&  0#A3'()--//0sy   ,G$ /H H: AI% )AJ $	H-HH	H7H22H7:	I"II"%	J."JJ	K'"KK__main__)
rI   rx   rJ   r   r   rx   rK   rx   returnr   )rz   rx   r{   r   r|   r   r}   r   re   intrf   r   r   None)r   r   )/__doc__
__future__r   rC   r%   sysr8   pathlibr   r:   playwright.sync_apir   __file__parentTOOL_DIRrl   insertrx   r   
gen_configr   r   r   _CTA_PX
_SIZE_44PX
_SIZE_48PX
_SIZE_58PX
_SIZE_60PX_LH_48PX_LH_52PX_LH_56PX_LH_76PX_LH_1_2_LH_1_25r   mkdirr9   MODEL_IDFALLBACK_MODEL_IDr   r   r   r   r_   r   r   __name__r,       r/   <module>r      s  
 #   
    / >   3x= !  ; ; 




 BB
 
    - E!4 
7  ? @Hj I??Gj I??Gj I??Gj I??Gj I??Gj I8  
 :   $$,: .    
  ""* ,el	`? @Hj I??Gj I??Gj I??Gj I??Gj I??Gj +IV  ""* 
,  $$+9 -      ""* ,{y	|I\  	
   
DNb zF r   