
    iS                    8   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mZ dZeZdZd	Zd
ZdZeZdZ ee      j4                  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"dZ(d#dZ)e*dk(  r e)        yy)$un  Concept 38: Cannes Grid Opportunity — 프로덕션 배너 생성
- c38-1200x628.png  (가로형 Meta/Google 광고)
- c38-1200x1200.png (정사각형 Meta 광고)
- c38-1200x628.html
- c38-1200x1200.html

캠페인: TOP사업단 리쿠르팅 마케팅 v2.0
디자인: 다크 배경 + 황금 그리드 구조 + 황금빛 스포트라이트 (Cannes-award aesthetic)
    )annotationsN)Path)sync_playwright)
CTA_MIN_PXFONT_DIRHEAD_SUB_RATIOWORKSPACE_ROOT&   ,   0   6   <   g?z=output/meta-ads/production-banners/38-cannes-grid-opportunityoutputz	v4-hybridzbg_c38_cannes.jpgz0https://generativelanguage.googleapis.com/v1betazgemini-3-pro-image-previewzgemini-3.1-flash-image-previewu  Abstract golden spotlight on very dark background. Subtle geometric grid pattern lines in deep charcoal — thin gold lines forming a precise grid, like a luxury advertising layout guide. Central warm golden glow radiating outward, fading to deep near-black edges (#1A1A1A to pure black). Metallic gold dust particles suspended in the air, catching light. The center has a soft warm amber-gold luminous halo effect. Premium luxury advertising aesthetic — like a Cannes Lions award-winning campaign background. No people. No text. No logos. No UI elements. Photorealistic render quality. The grid lines are very subtle — barely visible, like watermarks on expensive paper. Overall mood: sophisticated, premium, aspirational, dark luxury.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    _/home/jay/workspace/.worktrees/task-2116-dev1/tools/ai-image-gen/gen_c38_cannes_grid_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_modelr0   G   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     모델 접근 실패 (: 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	enumerater0   	Exceptionr&   r4   r    getdumpsnextlistkeysbase64	b64decodewrite_byteslenRuntimeError)r'   gar(   r*   models_to_try
last_errorattemptr)   r-   erF   r=   r3   
image_partrC   mime	img_bytess                    r   generate_backgroundrf   V   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t         d| dt         dt         d	t         d
t
         dt         dt         dS )u  1200x628 가로형 배너 HTML 생성.

    디자인: Cannes 그리드-오퍼튜니티
    - 다크 배경 + Gemini 스포트라이트 이미지 (우측 40%)
    - 좌측-to-우측 그라데이션 오버레이: 다크 샤코올 좌측 60% 커버
    - 황금 수평 그리드 액센트라인
    - T.O.P 사업단 브랜드 뱃지 (골드)
    - 헤드라인 + 골드 키워드 하이라이트
    - 서브카피 + 혜택 텍스트
    - CTA 버튼 (골드 그라데이션)
    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-ExtraBold.otf') format('opentype');
    font-weight: 800;
  }
  @font-face {
    font-family: 'Pretendard';
    src: url('file:///Pretendard-Medium.otf') format('opentype');
    font-weight: 500;
  }
  @font-face {
    font-family: 'Pretendard';
    src: url('file://u3  /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: #1A1A1A;
  }

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

  /* 배경 이미지: 전체 (우측 스포트라이트 강조) */
  .bg-image {
    position: absolute;
    inset: 0;
    background-image: url('u  ');
    background-size: cover;
    background-position: center right;
  }

  /* 좌→우 다크 그라데이션 오버레이 */
  .gradient-overlay {
    position: absolute;
    inset: 0;
    background: linear-gradient(
      to right,
      rgba(26,26,26,0.97) 0%,
      rgba(26,26,26,0.94) 35%,
      rgba(26,26,26,0.82) 52%,
      rgba(26,26,26,0.42) 70%,
      rgba(26,26,26,0.10) 85%,
      transparent 100%
    );
  }

  /* 황금 그리드 라인 — 수평 */
  .grid-line-h1 {
    position: absolute;
    top: 120px;
    left: 0;
    right: 0;
    height: 1px;
    background: linear-gradient(to right, rgba(201,168,76,0.18) 0%, rgba(201,168,76,0.06) 65%, transparent 100%);
  }
  .grid-line-h2 {
    position: absolute;
    top: 510px;
    left: 0;
    right: 0;
    height: 1px;
    background: linear-gradient(to right, rgba(201,168,76,0.18) 0%, rgba(201,168,76,0.06) 65%, transparent 100%);
  }

  /* 황금 세로 액센트바 */
  .accent-bar {
    position: absolute;
    top: 60px;
    left: 0;
    width: 3px;
    height: 508px;
    background: linear-gradient(to bottom, transparent, #C9A84C 15%, #D4B87A 50%, #C9A84C 85%, transparent);
  }

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

  /* 브랜드 텍스트 */
  .brand {
    font-size: u   px;
    font-weight: 600;
    color: #C9A84C;
    letter-spacing: 1px;
    margin-bottom: 22px;
    opacity: 0.9;
    word-break: keep-all;
  }

  /* 헤드라인 */
  .headline {
    font-size: z?px;
    font-weight: 700;
    color: #FFFFFF;
    line-height: uQ  ;
    letter-spacing: -0.8px;
    margin-bottom: 18px;
    word-break: keep-all;
  }
  .headline .gold {
    color: #C9A84C;
  }

  /* 서브카피 구분선 */
  .divider {
    width: 48px;
    height: 2px;
    background: #C9A84C;
    margin-bottom: 18px;
    border-radius: 1px;
  }

  /* 서브카피 */
  .sub-copy {
    font-size: u   px;
    font-weight: 700;
    color: #C9A84C;
    letter-spacing: -0.5px;
    margin-bottom: 22px;
    word-break: keep-all;
  }

  /* 혜택 텍스트 */
  .benefits {
    font-size: u  px;
    font-weight: 500;
    color: rgba(255,255,255,0.82);
    letter-spacing: -0.3px;
    margin-bottom: 28px;
    word-break: keep-all;
    white-space: nowrap;
  }
  .benefits .sep {
    color: rgba(201,168,76,0.55);
    margin: 0 10px;
  }

  /* CTA 버튼 */
  .cta-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, #C9A84C 0%, #D4B87A 100%);
    color: #1A1A1A;
    font-size: ud  px;
    font-weight: 700;
    height: 58px;
    padding: 0 32px;
    border-radius: 6px;
    letter-spacing: -0.3px;
    box-shadow: 0 4px 20px rgba(201,168,76,0.38);
    white-space: nowrap;
    width: fit-content;
  }
</style>
</head>
<body>
<div class="container">
  <!-- 배경 이미지 -->
  <div class="bg-image"></div>
  <!-- 다크 그라데이션 오버레이 -->
  <div class="gradient-overlay"></div>
  <!-- 황금 그리드 라인 -->
  <div class="grid-line-h1"></div>
  <div class="grid-line-h2"></div>
  <!-- 황금 세로 액센트바 -->
  <div class="accent-bar"></div>
  <!-- 텍스트 영역 -->
  <div class="text-area">
    <div class="brand">T.O.P 사업단</div>
    <div class="headline">열심히는 하는데,<br>월급은 <span class="gold">제자리걸음?</span></div>
    <div class="divider"></div>
    <div class="sub-copy">이 자리만 다릅니다.</div>
    <div class="benefits">신입 정착지원금 최대 1,000만원<span class="sep">|</span>경력직 직전연봉 50%까지 지원</div>
    <div class="cta-btn">지금 상담 신청하기 →</div>
  </div>
</div>
</body>
</html>)resolver   _CTA_PX
_SIZE_54PX	_LH_RATIO
_SIZE_44PXbg_pathbg_uris     r   make_html_1200x628ru      s     w()*F Z  
 Z  
 Z  
 Z  2 #8 @$@ y  |   ( | 
 y ( y "_Q Qr   c                    d| j                          }dt         dt         dt         dt         d| dt         dt         d	t         d
t
         dt         dt         dt
         dS )u  1200x1200 정사각형 배너 HTML 생성.

    디자인: Cannes 그리드-오퍼튜니티 (중앙 패널 구조)
    - 다크 배경 + Gemini 스포트라이트 (중앙 글로우)
    - 다크 오버레이 (opacity 0.58)
    - 중앙 크림 패널 (rgba(255,248,231,0.82)) — knowhow Template B
    - 황금 그리드 장식 라인
    - T.O.P 사업단 골드 뱃지
    - 헤드라인 다크 텍스트 + 골드 키워드
    - 서브카피 + 혜택 + CTA
    rh   ri   rj   rk   rl   u.  /Pretendard-SemiBold.otf') format('opentype');
    font-weight: 600;
  }
  * { margin: 0; padding: 0; box-sizing: border-box; }

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

  .container {
    position: relative;
    width: 1200px;
    height: 1200px;
    overflow: hidden;
    background: #1A1A1A;
  }

  /* 배경 이미지: 전체 (중앙 스포트라이트) */
  .bg-image {
    position: absolute;
    inset: 0;
    background-image: url('u  ');
    background-size: cover;
    background-position: center center;
  }

  /* 다크 오버레이 (0.58 opacity) */
  .dark-overlay {
    position: absolute;
    inset: 0;
    background: rgba(26,26,26,0.58);
  }

  /* 황금 그리드 라인 — 수평 장식 */
  .grid-line-top {
    position: absolute;
    top: 88px;
    left: 80px;
    right: 80px;
    height: 1px;
    background: rgba(201,168,76,0.20);
  }
  .grid-line-bottom {
    position: absolute;
    bottom: 88px;
    left: 80px;
    right: 80px;
    height: 1px;
    background: rgba(201,168,76,0.20);
  }
  /* 모서리 황금 장식 */
  .corner-tl {
    position: absolute;
    top: 60px;
    left: 60px;
    width: 40px;
    height: 40px;
    border-top: 2px solid rgba(201,168,76,0.55);
    border-left: 2px solid rgba(201,168,76,0.55);
  }
  .corner-tr {
    position: absolute;
    top: 60px;
    right: 60px;
    width: 40px;
    height: 40px;
    border-top: 2px solid rgba(201,168,76,0.55);
    border-right: 2px solid rgba(201,168,76,0.55);
  }
  .corner-bl {
    position: absolute;
    bottom: 60px;
    left: 60px;
    width: 40px;
    height: 40px;
    border-bottom: 2px solid rgba(201,168,76,0.55);
    border-left: 2px solid rgba(201,168,76,0.55);
  }
  .corner-br {
    position: absolute;
    bottom: 60px;
    right: 60px;
    width: 40px;
    height: 40px;
    border-bottom: 2px solid rgba(201,168,76,0.55);
    border-right: 2px solid rgba(201,168,76,0.55);
  }

  /* 중앙 크림 패널 (Template B 구조) */
  .central-panel {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 920px;
    padding: 60px 64px 56px 64px;
    background: rgba(255,248,231,0.82);
    border-radius: 8px;
    backdrop-filter: blur(6px);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 28px;
    text-align: center;
    /* 황금 테두리 */
    border: 1px solid rgba(201,168,76,0.28);
    box-shadow: 0 0 80px rgba(201,168,76,0.12), 0 20px 60px rgba(26,26,26,0.30);
  }

  /* 브랜드 뱃지 */
  .brand-badge {
    display: inline-flex;
    align-items: center;
    background: linear-gradient(135deg, #C9A84C 0%, #D4B87A 100%);
    color: #1A1A1A;
    font-size: u   px;
    font-weight: 700;
    height: 52px;
    padding: 0 24px;
    border-radius: 6px;
    letter-spacing: 0.5px;
    width: fit-content;
    white-space: nowrap;
  }

  /* 헤드라인 */
  .headline {
    font-size: z?px;
    font-weight: 700;
    color: #1A1A1A;
    line-height: uL  ;
    letter-spacing: -1px;
    text-align: center;
    word-break: keep-all;
  }
  .headline .gold {
    color: #A07828;
  }

  /* 구분선 */
  .divider {
    width: 56px;
    height: 2px;
    background: linear-gradient(to right, #C9A84C, #D4B87A);
    border-radius: 1px;
  }

  /* 서브카피 */
  .sub-copy {
    font-size: u   px;
    font-weight: 700;
    color: #A07828;
    letter-spacing: -0.5px;
    word-break: keep-all;
  }

  /* 혜택 텍스트 */
  .benefits {
    font-size: zpx;
    font-weight: 500;
    color: #3D3D3D;
    letter-spacing: -0.3px;
    word-break: keep-all;
    text-align: center;
    line-height: u(  ;
  }
  .benefits .sep {
    display: block;
    width: 100%;
    height: 0;
  }

  /* CTA 버튼 */
  .cta-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, #C9A84C 0%, #D4B87A 100%);
    color: #1A1A1A;
    font-size: u  px;
    font-weight: 700;
    height: 72px;
    padding: 0 48px;
    border-radius: 6px;
    letter-spacing: -0.3px;
    box-shadow: 0 6px 24px rgba(201,168,76,0.42);
    white-space: nowrap;
    width: fit-content;
    margin-top: 4px;
  }
</style>
</head>
<body>
<div class="container">
  <!-- 배경 이미지 -->
  <div class="bg-image"></div>
  <!-- 다크 오버레이 -->
  <div class="dark-overlay"></div>
  <!-- 황금 그리드 장식 -->
  <div class="grid-line-top"></div>
  <div class="grid-line-bottom"></div>
  <!-- 코너 장식 -->
  <div class="corner-tl"></div>
  <div class="corner-tr"></div>
  <div class="corner-bl"></div>
  <div class="corner-br"></div>
  <!-- 중앙 크림 패널 -->
  <div class="central-panel">
    <div class="brand-badge">T.O.P 사업단</div>
    <div class="headline">열심히는 하는데,<br>월급은 <span class="gold">제자리걸음?</span></div>
    <div class="divider"></div>
    <div class="sub-copy">이 자리만 다릅니다.</div>
    <div class="benefits">신입 정착지원금 최대 1,000만원<span class="sep"></span>경력직 직전연봉 50%까지 지원</div>
    <div class="cta-btn">지금 상담 신청하기 →</div>
  </div>
</div>
</body>
</html>)rm   r   rn   
_SIZE_60PXrp   
_SIZE_48PX
_SIZE_38PX_LH_1_6rr   s     r   make_html_1200x1200r{   x  s     w()*F Z  
 Z  
 Z  
 Z  2 #8 ^$| y  |   & | 	 |    | &[s sr   c           
        t         d| d| dz  }|j                  | d       |r>|j                  j                  dd       |j                  | d       t	        d|        t               5 }|j                  j                         }	 |j                  ||d	
      }|j                  d|j                          d       |j                  d       |j                  j                  dd       |j                  t        |      ddd||d       |j                         j                  dz  }	t	        d| d|	dd       |j!                          	 ddd       y# |j!                          w xY w# 1 sw Y   yxY w)u:   HTML을 Playwright로 캡처하여 PNG로 저장합니다.	_tmp_c38_xz.htmlzutf-8)encodingTparentsexist_okz	  [HTML] )widthheight)viewportrh   networkidle)
wait_untili  pngr   )r~   yr   r   )r   typeclip   z  [PNG] rG   .0fz KB)N)TMP_DIR
write_textparentmkdirrM   r   chromiumlaunchnew_pagegotorm   wait_for_timeout
screenshotr   rK   rL   close)
html_contentr   r   output_pathhtml_save_pathtmp_htmlrC   browserpagesize_kbs
             r   capture_html_to_pngr   }  sx   9UG1VHE::Hw7 ##D4#@!!,!A	.)*+		 a**##%	##u-O#PDII 0 0 234IO!!$'$$TD$AOO[!1Q&EO  "&&(0047GH[MGC==>MMO  MMO s%   .E2
B9EE2E//E22E;c                    t        d       t        d       t        d       t        j                  dd       t        j                  dd       t	               } t        d       t        |       }t        |ddt        dz  t        d	z  
       t        d       t        |       }t        |ddt        dz  t        dz  
       t        d       t        d       t        dt                t        j                         D ]<  }|j                         j                  dz  }t        d|j                   d|dd       > t        d       y )Nz<============================================================u<   Concept 38: Cannes Grid Opportunity — 배너 생성 시작Tr   u*   
[1200x628] 가로형 배너 생성 중...i  it  zc38-1200x628.pngzc38-1200x628.html)r   r   r   r   r   u.   
[1200x1200] 정사각형 배너 생성 중...zc38-1200x1200.pngzc38-1200x1200.htmlz=
============================================================u   완료!u   출력 디렉토리: r   z  r;   r   z KB)rM   r   r   
OUTPUT_DIRrf   ru   r   r{   iterdirrK   rL   name)rs   html_628	html_1200fr   s        r   mainr     s,   	(O	
HI	(OMM$M.TD1 "#G 

78!'*H!33!$77 

;<#G,I!44!$88 
/	)	!*
./! /&&(""T)166("WSM-./ 
(Or   __main__)returnr   )
r'   r   r(   z
str | Noner)   r   r*   dictr   zrequests.Response)r   r   )rs   r   r   r   )N)r   r   r   intr   r   r   r   r   zPath | Noner   None)r   r   )+__doc__
__future__r   rY   r    r   timepathlibr   r$   playwright.sync_apir   
gen_configr   r   r   r	   ry   rn   rq   rx   ro   rw   rp   rz   __file__r   r   r   r   rI   r#   rP   rQ   rO   r   r0   rf   ru   r{   r   r   __name__rA   r   r   <module>r      s    #   
    / K K 





	
 >  ]]

X

+
'
' E'4 
G 
"*<HB^B@J:'T zF r   