
    iB                    <   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Zej                  j                  dd       ddlZddlmZ  ed      Zej                  dd	        ej                          d
z  ZdZdZdZdZddZddZddZddZddZedk(  r e        yy)u   M3-2 서울대보험쌤 × 관리자 비전 Google 광고 배너 생성.

Gemini AI 배경 + Playwright HTML 오버레이 하이브리드 방식.
출력: snu-leader-1200x628.png, snu-leader-1080x1080.png
    )annotationsN)Pathz&/home/jay/workspace/tools/ai-image-gen)sync_playwrightz-/home/jay/workspace/output/google-ads/bannersT)parentsexist_okz.local/share/fonts/Pretendardz)gemini-2.0-flash-preview-image-generationzgemini-2.0-flash-expz0https://generativelanguage.googleapis.com/v1betaa+  Photo of a modern shared office space in Seoul. Wide shot showing individual workstations and a meeting area coexisting. On one side, a private office is visible through glass partitions. Bright natural sunlight streaming through large windows. Plant decorations throughout, warm wooden tone furniture. The look of a growing organization in its early stages. Photorealistic quality, warm yet organized atmosphere. No people. Warm tones, beige and wood colors dominating. Soft shadows, professional interior photography style. High resolution, sharp focus.c                (   t        d       d}	 t        j                         }t        dt        |       d       |rd| dd	}d
dg}t
         d}n6t        j                  d      }|st        d       yddi}g d}t
         d| }ddt        igigdddgid}|D ]}  }|j                  |      }	t        d|        	 t        j                         }
t        j                  |	||d      }|j                  dvr,t        d| d|j                   d |j                  dd!         |j                         }|j                  d"i g      d#   j                  d$i       j                  dg       }t!        d% |D        d      }|s4t        d| d&|D cg c]  }|j                  dd'       c}dd(         t#        j$                  |d)   d*         }| j'                  |       t        j                         |
z
  }t        d+|  d,t        |      d-d.|d/d0        y1 t        d5       y# t        $ r}t        d| d       Y d}~d}~ww xY wc c}w # t        $ r2}t        d2| d3t)        |      j*                   d4|        Y d}~d}~ww xY w)6u9   Gemini API로 배경 이미지 생성 (SA 토큰 우선).u'   [배경] Gemini 이미지 생성 중...Nu1   [배경] SA Bearer 토큰 인증 사용 (길이: )u   [배경] SA 토큰 실패: u   , API Key fallback 시도...zBearer zapplication/json)AuthorizationContent-Typegemini-3-pro-image-previewgemini-3.1-flash-image-previewz/models/{model}:generateContentGEMINI_API_KEYu   [오류] 인증 수단 없음Fr   )r   r   zgemini-2.5-flash-imagez$/models/{model}:generateContent?key=partstextresponseModalitiesIMAGETEXT)contentsgenerationConfig)modelu   [배경] 모델 시도: x   )headersjsontimeout)   u	   [배경] u	    실패 (z):    
candidatesr   contentc              3  *   K   | ]  }d |v s|  yw)
inlineDataN ).0ps     G/home/jay/workspace/output/google-ads/banners/gen_snu_leader_banners.py	<genexpr>z-generate_gemini_background.<locals>.<genexpr>[   s     EQ<13DqEs   	u   : 이미지 없음.     r    datau   [배경] 저장 완료:  (,z bytes, z.1fu   초)Tu	   [오류] u    호출 실패: : u   [오류] 모든 모델 실패)printgcloud_authget_service_account_tokenlen	ExceptionGEMINI_API_BASEget_api_key	BG_PROMPTformattimerequestspoststatus_coder   r   getnextbase64	b64decodewrite_bytestype__name__)output_pathsa_tokener   models_to_trybase_url_fmtapi_keypayloadr   urlstartrespr(   r   
image_partr#   image_byteselapseds                     r$   generate_gemini_backgroundrM   -   s   	35 HM88:A#h-PQRS &xj1.
 67WX)**KL))*:;12!#56r)**PQXPYZ  34561GV3DEG
  !!!.(01	IIKE==gGSQDv-	%	$2B2B1C3tyyQURUFWXY99;DHH\B40377	2FJJ7TVWEE%EtLJ	%(<X]=^STaeeF2>N=^_a`a=b<cde **:l+CF+KLK##K0iikE)G,[MC<LQ;OxX_`cWddhij/: 

)*m  M+A3.JKLLMP >_  	IeW$4T!W5E5E4FbLM	sP   ,H+ A&I*A(II+I9A#I+	I4I		II	J'JJc                J    t        t              }d| d| d| d| d| d|  dS )N<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
  @font-face {
    font-family: 'Pretendard';
    src: url('file:///Pretendard-Black.otf') format('opentype');
    font-weight: 900;
  }
  @font-face {
    font-family: 'Pretendard';
    src: url('file:///Pretendard-ExtraBold.otf') format('opentype');
    font-weight: 800;
  }
  @font-face {
    font-family: 'Pretendard';
    src: url('file:///Pretendard-Bold.otf') format('opentype');
    font-weight: 700;
  }
  @font-face {
    font-family: 'Pretendard';
    src: url('file:///Pretendard-SemiBold.otf') format('opentype');
    font-weight: 600;
  }
  @font-face {
    font-family: 'Pretendard';
    src: url('file://uW  /Pretendard-Medium.otf') format('opentype');
    font-weight: 500;
  }

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

  body {
    width: 1200px;
    height: 628px;
    overflow: hidden;
    background: #FFF8E7;
  }

  .canvas {
    width: 1200px;
    height: 628px;
    position: relative;
    font-family: 'Pretendard', 'Noto Sans KR', sans-serif;
    background: #FFF8E7;
    overflow: hidden;
  }

  /* 우측 배경 이미지 (45%) */
  .bg-image {
    position: absolute;
    top: 0;
    right: 0;
    width: 570px;
    height: 628px;
    background-image: url('file://u>
  ');
    background-size: cover;
    background-position: center;
  }

  /* 좌측 → 투명 그라데이션 (배경 위) */
  .bg-gradient-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 780px;
    height: 628px;
    background: linear-gradient(to right, #FFF8E7 0%, #FFF8E7 55%, rgba(255,248,231,0) 100%);
    z-index: 2;
  }

  /* 좌측 텍스트 영역 */
  .text-area {
    position: absolute;
    top: 0;
    left: 0;
    width: 660px;
    height: 628px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 0 60px 0 64px;
    z-index: 10;
  }

  /* 뱃지 */
  .badge {
    display: inline-flex;
    align-items: center;
    background: #C9A84C;
    color: #1A0E00;
    font-size: 28px;
    font-weight: 700;
    padding: 10px 22px;
    border-radius: 6px;
    margin-bottom: 28px;
    width: fit-content;
    letter-spacing: -0.3px;
  }

  .badge-dot {
    width: 10px;
    height: 10px;
    background: #1A0E00;
    border-radius: 50%;
    margin-right: 10px;
    flex-shrink: 0;
  }

  /* 헤드라인 */
  .headline {
    font-size: 50px;
    font-weight: 700;
    color: #3E2723;
    line-height: 1.25;
    letter-spacing: -1.5px;
    margin-bottom: 22px;
    white-space: pre-line;
  }

  /* 서브 카피 */
  .subcopy {
    font-size: 32px;
    font-weight: 600;
    color: #A07828;
    letter-spacing: -0.5px;
    margin-bottom: 40px;
    line-height: 1.4;
  }

  /* CTA 버튼 */
  .cta-btn {
    display: inline-flex;
    align-items: center;
    background: linear-gradient(135deg, #C9A84C 0%, #D4B87A 100%);
    color: #1A0E00;
    font-size: 30px;
    font-weight: 700;
    padding: 18px 36px;
    border-radius: 6px;
    letter-spacing: -0.3px;
    width: fit-content;
    box-shadow: 0 4px 16px rgba(160,120,40,0.30);
  }

  .cta-arrow {
    margin-left: 10px;
    font-size: 26px;
  }
</style>
</head>
<body>
<div class="canvas">

  <!-- 우측 배경 이미지 -->
  <div class="bg-image"></div>

  <!-- 그라데이션 오버레이 -->
  <div class="bg-gradient-overlay"></div>

  <!-- 좌측 텍스트 영역 -->
  <div class="text-area">

    <!-- 뱃지 -->
    <div class="badge">
      <span class="badge-dot"></span>
      서울대보험쌤
    </div>

    <!-- 헤드라인 -->
    <div class="headline">서울대 출신 지점장과<br>함께 시작</div>

    <!-- 서브 카피 -->
    <div class="subcopy">AI자동화 | 멘토링 | 100일 로드맵</div>

    <!-- CTA 버튼 -->
    <div class="cta-btn">
      조직 설계 상담 받기
      <span class="cta-arrow">→</span>
    </div>

  </div>

</div>
</body>
</html>strFONT_DIRbg_image_pathfont_dirs     r$   build_html_1200x628rZ   s   sg    8}H Z  
 Z  
 Z  
 Z  
 Z ! #B $1/ B2y~ ~    c                J    t        t              }d| d| d| d| d| d|  dS )NrO   rP   rQ   rR   rS   u:  /Pretendard-Medium.otf') format('opentype');
    font-weight: 500;
  }

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

  body {
    width: 1080px;
    height: 1080px;
    overflow: hidden;
    background: #FFF8E7;
  }

  .canvas {
    width: 1080px;
    height: 1080px;
    position: relative;
    font-family: 'Pretendard', 'Noto Sans KR', sans-serif;
    overflow: hidden;
  }

  /* 전체 배경 이미지 */
  .bg-full {
    position: absolute;
    top: 0;
    left: 0;
    width: 1080px;
    height: 1080px;
    background-image: url('file://u  ');
    background-size: cover;
    background-position: center;
    z-index: 1;
  }

  /* 크림 반투명 오버레이 (하단 2/3) */
  .overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 1080px;
    height: 1080px;
    background: linear-gradient(
      to bottom,
      rgba(255,248,231,0.15) 0%,
      rgba(255,248,231,0.25) 20%,
      rgba(255,248,231,0.50) 45%,
      rgba(255,248,231,0.82) 65%,
      rgba(255,248,231,0.95) 80%,
      rgba(255,248,231,1.00) 100%
    );
    z-index: 2;
  }

  /* 전체 콘텐츠 래퍼 */
  .content {
    position: absolute;
    top: 0;
    left: 0;
    width: 1080px;
    height: 1080px;
    z-index: 10;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 0 80px;
  }

  /* 상단 뱃지 영역 (상단 12%) */
  .badge-wrap {
    padding-top: 64px;
    display: flex;
    justify-content: center;
    width: 100%;
  }

  .badge {
    display: inline-flex;
    align-items: center;
    background: #C9A84C;
    color: #1A0E00;
    font-size: 34px;
    font-weight: 700;
    padding: 12px 28px;
    border-radius: 6px;
    letter-spacing: -0.3px;
  }

  .badge-dot {
    width: 12px;
    height: 12px;
    background: #1A0E00;
    border-radius: 50%;
    margin-right: 12px;
    flex-shrink: 0;
  }

  /* 헤드라인 영역 (중앙 상단 35%) */
  .headline-wrap {
    margin-top: 48px;
    text-align: center;
    flex: 0 0 auto;
  }

  .headline {
    font-size: 66px;
    font-weight: 700;
    color: #3E2723;
    line-height: 1.25;
    letter-spacing: -2px;
    text-align: center;
  }

  /* 서브 카피 (중앙 25%) */
  .subcopy-wrap {
    margin-top: 36px;
    text-align: center;
  }

  .subcopy {
    font-size: 42px;
    font-weight: 600;
    color: #A07828;
    letter-spacing: -0.8px;
    line-height: 1.4;
    text-align: center;
  }

  /* 구분선 */
  .divider {
    width: 120px;
    height: 3px;
    background: linear-gradient(to right, transparent, #C9A84C, transparent);
    margin: 32px auto 0;
  }

  /* CTA 영역 (하단 28%) */
  .cta-wrap {
    margin-top: auto;
    padding-bottom: 80px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 20px;
    width: 100%;
  }

  .cta-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, #C9A84C 0%, #D4B87A 100%);
    color: #1A0E00;
    font-size: 44px;
    font-weight: 700;
    padding: 24px 64px;
    border-radius: 6px;
    letter-spacing: -0.5px;
    box-shadow: 0 6px 24px rgba(160,120,40,0.35);
    width: 100%;
    max-width: 780px;
  }

  .cta-arrow {
    margin-left: 14px;
    font-size: 38px;
  }

  /* URL 힌트 */
  .url-hint {
    font-size: 26px;
    font-weight: 500;
    color: #8D6E3E;
    letter-spacing: 0;
  }
</style>
</head>
<body>
<div class="canvas">

  <!-- 배경 이미지 -->
  <div class="bg-full"></div>

  <!-- 크림 오버레이 -->
  <div class="overlay"></div>

  <!-- 콘텐츠 -->
  <div class="content">

    <!-- 상단 뱃지 -->
    <div class="badge-wrap">
      <div class="badge">
        <span class="badge-dot"></span>
        서울대보험쌤
      </div>
    </div>

    <!-- 헤드라인 -->
    <div class="headline-wrap">
      <div class="headline">서울대 출신 지점장과<br>함께 시작</div>
    </div>

    <!-- 서브 카피 -->
    <div class="subcopy-wrap">
      <div class="subcopy">AI자동화 | 멘토링 | 100일 로드맵</div>
      <div class="divider"></div>
    </div>

    <!-- CTA 영역 -->
    <div class="cta-wrap">
      <div class="cta-btn">
        조직 설계 상담 받기
        <span class="cta-arrow">→</span>
      </div>
      <div class="url-hint">incar-top.tistory.com</div>
    </div>

  </div>

</div>
</body>
</html>rT   rW   s     r$   build_html_1080x1080r]   :  sg    8}H Z  
 Z  
 Z  
 Z  
 Z   #@ $1/ @2w{ {r[   c                   |j                  d      }|j                  | d       t        d|        	 t               5 }|j                  j                         }	 |j                  ||d      }|j                  d|j                          d	       |j                  d
       |j                  t        |      d       |j                          	 ddd       |j                         j                  dz  }t        d| d|dd       y# |j                          w xY w# 1 sw Y   OxY w# t        $ r.}	t        dt!        |	      j"                   d|	        Y d}	~	yd}	~	ww xY w)u.   Playwright로 HTML을 캡처하여 PNG 저장.z.htmlzutf-8)encodingu   [HTML] 템플릿 저장: )widthheight)viewportzfile://networkidle)
wait_untili	  png)pathr>   Ni   u   [캡처] 저장 완료: r)   z.0fz KB)Tu   [오류] 캡처 실패: r+   F)with_suffix
write_textr,   r   chromiumlaunchnew_pagegotoresolvewait_for_timeout
screenshotrU   closestatst_sizer0   r>   r?   )
html_contentr@   r`   ra   	html_filer#   browserpagesize_kbrB   s
             r$   capture_bannerrx   :  sM   ''0I8	%i[
12 	 !jj'')G ''5F1S'T		GI$5$5$7#89m	T%%d+S%5EB	  ""$,,t3(R}DIJ	 	  	   (a)9)9(:"QC@AsG   
D+ DA&D
 D8D+ 
DDD($D+ +	E"4$EE"c            
        t        d       t        d       t        d       t        dz  } | j                         rt        d|         d}nt        |       }|st        d       d}nt	        | j                               }i }t        d       t        d	z  }t        |      }t        ||d
d      }t	        |      |d|d<   t        d       t        dz  }t        |      }t        ||dd      }	t	        |      |	d|d<   t        d       t        d       t        d       |j                         D ]%  \  }
}|d   rdnd}t        d|
 d| d|d           ' y )Nz<============================================================u9   M3-2 서울대보험쌤 × 관리자 비전 배너 생성zsnu_leader_bg.jpgu%   [배경] 기존 이미지 재사용: TuJ   [경고] 배경 생성 실패. 크림 단색 배경으로 대체합니다.r&   u,   
[배너 1] 1200x628 가로형 생성 중...zsnu-leader-1200x628.pngi  it  )rf   success1200x628u0   
[배너 2] 1080x1080 정사각형 생성 중...zsnu-leader-1080x1080.pngi8  	1080x1080z=
============================================================u   생성 결과 요약rz   u   성공u   실패z  [z] r+   rf   )
r,   
OUTPUT_DIRexistsrM   rU   rm   rZ   rx   r]   items)bg_pathbg_okrX   resultsoutput_1200	html_1200ok1output_1080	html_1080ok2sizerstatuss                r$   mainr   T  s]   	(O	
EF	(O..G ~~5gY?@*73Z[GOO-.G 

9:88K#M2I
Ks
;C#&{#3DGJ 

=>99K$]3I
Kt
<C$'$4EGK 
/	
 !	(O==? 3ay\xD6F82ai[123r[   __main__)r@   r   returnbool)rX   rU   r   rU   )
rs   rU   r@   r   r`   intra   r   r   r   )r   None)__doc__
__future__r   r;   sysr5   pathlibr   r6   rf   insertr-   playwright.sync_apir   r}   mkdirhomerV   MODEL_IDFALLBACK_MODEL_IDr1   r3   rM   rZ   r]   rx   r   r?   r!   r[   r$   <module>r      s    #  
    ; <  /AB
 
    -499;88 7* D@ 
?L@N}@4+3\ zF r[   