
    iH                    ,   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 ddlmZmZmZ eZdZdZd	Zd
ZdZdZ ee      j0                  Zedz  Zedz  dz  Ze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%d!dZ&d Z'e(dk(  r e'        yy)"u  M3-3 서울대보험쌤 × 영업지원 Google 광고 배너 생성
- m3-3-1200x628.png (가로형)
- m3-3-1080x1080.png (정사각형)

디자인 톤: 가장 밝은 톤 (크림 화이트 + 다크 골드)
배경: 카페 스타일 홈오피스, 아침 햇살
    )annotationsN)Path)sync_playwright)
CTA_MIN_PXFONT_DIRWORKSPACE_ROOT*   ,   0   :   >   g333333?zoutput/google-ads/banners/m3outputz	v4-hybridzbg_m3_3.jpgz0https://generativelanguage.googleapis.com/v1betazgemini-3-pro-image-previewzgemini-3.1-flash-image-previewum  Photographic scene of a bright, cafe-like home office workspace. Medium shot, front-facing eye-level angle. A clean white desk near a large window — morning light streaming through, creating soft natural lens flare on the left side. A person visible from the left side only: arm in a casual white shirt sleeve, hand on a white MacBook keyboard. Face completely outside the frame. On the desk: an open planner/notebook with neat handwriting (not readable), a ceramic mug with coffee (steam visible), and a small potted plant. Through the window: green trees or foliage visible — urban outdoor but natural feel. The wall behind is white with one small framed print (abstract, not text-based). The overall atmosphere is bright, calm, and full of quiet optimism — the first morning of a new beginning. Warm morning color temperature. No text. No logos. No icons. No graphics.c                     t         j                  j                  dt        t                     ddl} | j                         S )u7   gcloud_auth 모듈로 Bearer 토큰을 획득합니다.r   N)syspathinsertstrBASE_DIRgcloud_authget_access_token)r   s    T/home/jay/workspace/.worktrees/task-2116-dev1/tools/ai-image-gen/gen_m3_3_banners.pyget_auth_tokenr   ?   s*    HHOOAs8}%''))    c                    t          d| d}d|  dd}t        j                  |||d      }|j                  dk(  r|S |r+t          d| d	| }d
di}t        j                  |||d      S |S )u6   SA 토큰 우선, 실패 시 API 키로 Gemini 호출.z/models/z:generateContentzBearer zapplication/json)AuthorizationContent-Type,  )headersjsontimeout   z:generateContent?key=r   )GEMINI_API_BASErequestspoststatus_code)	tokenapi_keymodelpayload
url_bearerheaders_bearerrespurl_keyheaders_keys	            r   _call_modelr/   F   s    #$HUG3CDJ)0'8J\]N==^'SVWD3$%XeW4I'S%'9:}}WkQTUUKr   c                    t         j                         r9t         j                         j                  dkD  rt	        dt                 t         S t	        d       t               } t        j                  j                  dt        t                     ddl}|j                  d      }ddt        igigd	d
dgid}t        t        g}d}t!        |d      D ]  \  }}t	        d| d|        	 t#        | |||      }|j&                  dv r9t	        d|j&                   d|j(                  dd  d       d|j&                   }n|j&                  dk7  r8t	        d|j&                   d|j(                  dd         d|j&                   }|j+                         }
|
j-                  dg       }|s(t	        dt+        j.                  |
      dd         d}|d   j-                  di       j-                  dg       }t1        d |D        d      }|7t	        d|D cg c]  }t3        |j5                                c}        d}r|d    j-                  d!d"      }t7        j8                  |d    d#         }t         j;                  |       t	        d$t          d%t=        |      d&d'| d       t         c S  t?        d(|       # t$        $ r$}	t        |	      }t	        d|	        Y d}	~	d}	~	ww xY wc c}w ))uI   Gemini API로 배경 이미지를 생성하고 경로를 반환합니다.iP  u,   [배경] 기존 배경 이미지 재사용: u5   [배경] Gemini API로 배경 이미지 생성 중...r   NGEMINI_API_KEYpartstextresponseModalitiesIMAGETEXT)contentsgenerationConfig   u	     시도 u	   : 모델=u     요청 실패: )i  i  i  u     모델 접근 실패 (z: r!   )zHTTP z  HTTP r   
candidatesu     응답에 candidates 없음: zNo candidatescontentc              3  *   K   | ]  }d |v s|  yw)
inlineDataN ).0ps     r   	<genexpr>z&generate_background.<locals>.<genexpr>   s     A|q/@1As   	u     이미지 없음. parts: zNo inlineDatar>   mimeTypez
image/jpegdatau     [배경] 저장 완료:  (,z bytes, mime=u    배경 이미지 생성 실패: ) BG_PATHexistsstatst_sizeprintr   r   r   r   r   r   r   get_api_key	BG_PROMPTMODEL_IDFALLBACK_MODEL_ID	enumerater/   	Exceptionr%   r3   r   getdumpsnextlistkeysbase64	b64decodewrite_byteslenRuntimeError)r&   gar'   r)   models_to_try
last_errorattemptr(   r,   erD   r;   r2   
image_partrA   mime	img_bytess                    r   generate_backgroundrd   U   s   ~~GLLN22V;<WIFG	
ABEHHOOAs8}%nn-.G  34561GV3DEG
 01MJ#M15 &	')E734	ugug>D .,T-=-=,>b4C@QQRST !1!1 23Js"GD,,-R		$3/@AB !1!1 23Jyy{XXlB/
3DJJt4DTc4J3KLM(J1!!)R044WbAAeA4H
/0OAaffh0O/PQR(J,'++JE$$Z%=f%EF	I&*7)2c)nQ5G}UYTZZ[\]M&P 9*F
GGI  	QJ%aS)*	4 1Ps   +K K3	K0K++K0c                    d| j                          }dt         dt         dt         d| dt         dt         dt         d	t
         d
t         dS )u  1200x628 가로형 배너 HTML 생성.

    디자인 (업데이트: 딥 브라운 그라데이션 오버레이 → 프리미엄 다크 스타일):
    - Gemini 배경 전체
    - 딥 브라운 좌→우 그라데이션 오버레이 (m3-1 템플릿 A 적용)
    - 크림 헤드라인 #FFF8E7
    - 골드 서브카피 #C9A84C
    - CTA: 골드 그라데이션 배경, 다크 텍스트 #1A0E00
    - 골드 세로 액센트바
    file://<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
  @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-Medium.otf') format('opentype');
    font-weight: 500;
  }
  @font-face {
    font-family: 'Pretendard';
    src: url('file://u  /Pretendard-SemiBold.otf') format('opentype');
    font-weight: 600;
  }
  * { margin: 0; padding: 0; box-sizing: border-box; }

  body {
    width: 1200px;
    height: 628px;
    overflow: hidden;
    font-family: 'Pretendard', 'Noto Sans KR', sans-serif;
    background: #1A0E00;
  }

  .container {
    position: relative;
    width: 1200px;
    height: 628px;
    overflow: hidden;
  }

  /* 배경 이미지: 전체 */
  .bg-image {
    position: absolute;
    inset: 0;
    background-image: url('uL  ');
    background-size: cover;
    background-position: center right;
  }

  /* 딥 브라운 그라데이션 오버레이 (강화: 좌측 완전 커버) */
  .gradient-overlay {
    position: absolute;
    inset: 0;
    background: linear-gradient(
      to right,
      rgba(40,20,10,0.88) 0%,
      rgba(40,20,10,0.88) 38%,
      rgba(40,20,10,0.78) 52%,
      rgba(40,20,10,0.45) 68%,
      rgba(40,20,10,0.12) 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;
  }

  /* 텍스트 영역: 좌측 62% */
  .text-area {
    position: absolute;
    left: 0;
    top: 0;
    width: 62%;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 48px 56px 48px 60px;
    gap: 0;
  }

  /* 브랜드 뱃지 */
  .brand-badge {
    display: inline-flex;
    align-items: center;
    background: #C9A84C;
    color: #1A0E00;
    font-size: u  px;
    font-weight: 700;
    height: 48px;
    padding: 0 20px;
    border-radius: 6px;
    letter-spacing: -0.5px;
    margin-bottom: 28px;
    width: fit-content;
    white-space: nowrap;
  }

  /* 헤드라인: 크림 #FFF8E7 */
  .headline {
    font-size: z?px;
    font-weight: 700;
    color: #FFF8E7;
    line-height: u   ;
    letter-spacing: -1px;
    margin-bottom: 20px;
    white-space: pre-line;
  }

  /* 지원 항목: 골드 #C9A84C */
  .support-items {
    font-size: u  px;
    font-weight: 500;
    color: #C9A84C;
    letter-spacing: -0.5px;
    margin-bottom: 36px;
    white-space: nowrap;
  }

  /* CTA 버튼: 골드 그라데이션 + 다크 텍스트 */
  .cta-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, #C9A84C 0%, #D4B87A 100%);
    color: #1A0E00;
    font-size: u  px;
    font-weight: 700;
    height: 56px;
    width: 260px;
    border-radius: 6px;
    letter-spacing: -0.5px;
    box-shadow: 0 4px 16px rgba(201,168,76,0.35);
    white-space: nowrap;
  }
</style>
</head>
<body>
<div class="container">
  <!-- 배경 이미지 -->
  <div class="bg-image"></div>
  <!-- 딥 브라운 그라데이션 오버레이 -->
  <div class="gradient-overlay"></div>
  <!-- 골드 세로 액센트바 -->
  <div class="accent-bar"></div>
  <!-- 텍스트 영역 -->
  <div class="text-area">
    <div class="brand-badge">서울대보험쌤 · TOP사업단</div>
    <div class="headline">영업 못하는 게 아닙니다&#10;— <span style="color:#C9A84C">시스템</span>이 없었을 뿐</div>
    <div class="support-items">AI자동화&nbsp;&nbsp;|&nbsp;&nbsp;DB영업&nbsp;&nbsp;|&nbsp;&nbsp;정착금 1,000만원</div>
    <div class="cta-btn">무료 상담 신청 →</div>
  </div>
</div>
</body>
</html>)resolver   _CTA_PX
_SIZE_58PX_LH_1_2
_SIZE_42PX
_SIZE_44PXbg_pathbg_uris     r   make_html_1200x628rs      s     w()*F Z  
 Z  
 Z  0 #8 3$f y  |    |  | G_ _r   c                    d| j                          }dt         dt         dt         d| dt         dt         dt         d	t
         d
t         dS )um  1080x1080 정사각형 배너 HTML 생성.

    디자인:
    - Gemini 배경 전체
    - 크림 반투명 오버레이 opacity 0.38 (배경 아침 햇살/식물이 보이도록)
    - 중앙정렬 레이아웃
    - 딥 브라운 헤드라인 #3E2723
    - 다크 골드 서브카피 #A07828
    - CTA: 다크 골드 배경 #A07828, 크림 텍스트 #FFF8E7
    rf   rg   rh   ri   u  /Pretendard-SemiBold.otf') format('opentype');
    font-weight: 600;
  }
  * { margin: 0; padding: 0; box-sizing: border-box; }

  body {
    width: 1080px;
    height: 1080px;
    overflow: hidden;
    font-family: 'Pretendard', 'Noto Sans KR', sans-serif;
    background: #FFF8E7;
  }

  .container {
    position: relative;
    width: 1080px;
    height: 1080px;
    overflow: hidden;
  }

  /* 전체 배경 이미지 */
  .bg-image {
    position: absolute;
    inset: 0;
    background-image: url('u  ');
    background-size: cover;
    background-position: center;
  }

  /* 크림 반투명 오버레이 opacity 0.55 */
  .cream-overlay {
    position: absolute;
    inset: 0;
    background: rgba(255, 248, 231, 0.55);
  }

  /* 전체 컨텐츠 */
  .content {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 80px 72px;
    gap: 32px;
    text-align: center;
  }

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

  /* 브랜드 뱃지 */
  .brand-badge {
    display: inline-flex;
    align-items: center;
    background: #C9A84C;
    color: #1A0E00;
    font-size: u   px;
    font-weight: 700;
    height: 52px;
    padding: 0 22px;
    border-radius: 6px;
    letter-spacing: -0.5px;
    width: fit-content;
  }

  /* 헤드라인 */
  .headline {
    font-size: z?px;
    font-weight: 700;
    color: #3E2723;
    line-height: u   ;
    letter-spacing: -1px;
    text-align: center;
    white-space: pre-line;
    text-shadow: 0 1px 8px rgba(255, 248, 231, 0.6);
  }

  /* 지원 항목 */
  .support-items {
    font-size: u  px;
    font-weight: 500;
    color: #A07828;
    letter-spacing: -0.5px;
    text-align: center;
    white-space: nowrap;
    text-shadow: 0 0 8px rgba(255, 248, 231, 1), 0 0 16px rgba(255, 248, 231, 0.8);
  }

  /* CTA 버튼: 골드 그라데이션 + 다크 텍스트 */
  .cta-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, #C9A84C 0%, #D4B87A 100%);
    color: #1A0E00;
    font-size: u
  px;
    font-weight: 700;
    height: 68px;
    width: 420px;
    border-radius: 6px;
    letter-spacing: -0.5px;
    box-shadow: 0 6px 24px rgba(201,168,76,0.40);
    white-space: nowrap;
    margin-top: 8px;
  }
</style>
</head>
<body>
<div class="container">
  <div class="bg-image"></div>
  <div class="cream-overlay"></div>

  <div class="text-panel">
    <div class="brand-badge">서울대보험쌤 · TOP사업단</div>
    <div class="headline">영업 못하는 게 아닙니다&#10;— <span style="color:#A07828">시스템</span>이 없었을 뿐</div>
    <div class="support-items">AI자동화&nbsp;&nbsp;|&nbsp;&nbsp;DB영업&nbsp;&nbsp;|&nbsp;&nbsp;정착금 1,000만원</div>
    <div class="cta-btn">무료 상담 신청 →</div>
  </div>
</div>
</body>
</html>)rj   r   rk   
_SIZE_62PXrm   ro   
_SIZE_48PXrp   s     r   make_html_1080x1080rw   D  s     w()*F Z  
 Z  
 Z  0 #8 1$b y  |   	 |   | CZ Zr   c           
        t         d| d| dz  }|j                  | d       t               5 }|j                  j	                         }	 |j                  ||d      }|j                  d|j                          d	
       |j                  d       |j                  j                  dd       |j                  t        |      ddd||d       t        d| d|j                         j                  dz  dd       |j!                          	 ddd       |j#                  d       y# |j!                          w xY w# 1 sw Y   1xY w)u:   HTML을 Playwright로 캡처하여 PNG로 저장합니다.
_tmp_m3_3_xz.htmlzutf-8)encoding)widthheight)viewportrf   networkidle)
wait_untili  Tparentsexist_okpngr   )rz   yr|   r}   )r   typeclipu     [캡처] rE      .0f KB)N)
missing_ok)TMP_DIR
write_textr   chromiumlaunchnew_pagegotorj   wait_for_timeoutparentmkdir
screenshotr   rK   rI   rJ   closeunlink)html_contentr|   r}   output_pathtmp_htmlrA   browserpages           r   capture_html_to_pngr     s@   :eWAfXU;;Hw7		 a**##%
	##u-O#PDII 0 0 234IO!!$'$$TD$AOO[!1Q&EO  K}B{/?/?/A/I/ID/PQT.UUYZ[MMO OOtO$ MMO s$   E
B7D-E-D??EEc                 "   t        d       t        d       t        d       t        j                  dd       t        j                  dd       	 t	               } t        dz  }t        d       	 | rt        |       }n$t        t        d	            j                  d
d      }t        |dd|       t        d|        t        dz  }t        d       	 | rt        |       }n$t        t        d	            j                  d
d      }t        |dd|       t        d|        t        d       t        d       t        d| d|j                         j                  dz  dd       t        d| d|j                         j                  dz  dd       t        d       y # t
        $ r&}t        d|        t        d       d } Y d }~nd }~ww xY w# t
        $ r}t        d|         d }~ww xY w# t
        $ r}t        d|         d }~ww xY w)Nz<============================================================u<   M3-3 서울대보험쌤 × 영업지원 배너 생성 시작Tr   u   [오류] 배경 생성 실패: uG   [폴백] 크림 화이트 그라데이션 배경으로 대체합니다.zm3-3-1200x628.pngu,   
[1] 1200x628 가로형 배너 생성 중...z/nonexistentz-background-image: url('file:///nonexistent');z>background: linear-gradient(135deg, #FFF8E7 0%, #F5E8C4 100%);i  it  u
     완료: u     [오류] zm3-3-1080x1080.pngu0   
[2] 1080x1080 정사각형 배너 생성 중...zKbackground: linear-gradient(160deg, #FFF8E7 0%, #F0DFA8 60%, #FFF8E7 100%);i8  z=
============================================================u   생성 완료!z  1200x628: rE   r   r   r   z  1080x1080: )rK   r   r   
OUTPUT_DIRrd   rQ   rs   r   replacer   rw   rI   rJ   )rq   r`   out_1200	html_1200out_1080	html_1080s         r   mainr     s    	(O	
HI	(OMM$M.TD1%' //H	
9:*73I +4+?@HH?PI 	ItS(;
8*%& 00H	
=>+G4I+D,@AII?]I 	ItT8<
8*%&
 
/	
	L
"X]]_%<%<t%CC$H
MN	M(2hmmo&=&=&DS%I
NO	(OY  /s34WX&  A3 "  A3 sJ   
F 0AG AG1 	G(G		G	G.G))G.1	H:H		H__main__)returnr   )
r&   r   r'   z
str | Noner(   r   r)   dictr   zrequests.Response)r   r   )rq   r   r   r   )
r   r   r|   intr}   r   r   r   r   None))__doc__
__future__r   rW   r   r   timepathlibr   r#   playwright.sync_apir   
gen_configr   r   r   rk   rn   ro   rv   rl   ru   rm   __file__r   r   r   r   rG   r"   rN   rO   rM   r   r/   rd   rs   rw   r   r   __name__r?   r   r   <module>r      s    #   
    / ; ; 





 >  <<

X

+
M
! E'4 0 
&*<HBk\fV%07t zF r   