
    (<i"J                     t   d 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  ee      j                  Zedz  Zedz  Zedz  Zed	z  Zej&                  j)                  d ee             ddlZd
ZdZdZdZdZdZdZdZg dZdedede fdZ!dZ"dededdfdZ#dededdfdZ$d Z%e&dk(  r e%        yy) u   
Meta carousel slide A-5 (CTA) 생성 스크립트
Hybrid pipeline: Gemini background + HTML/CSS Playwright overlay
Output: /home/jay/workspace/output/meta-ads/a-group-v6/pilot/pilot-A5-cta.png
    N)Path)sync_playwright)WORKSPACE_ROOTz output/meta-ads/a-group-v6/pilotzpilot-A5-bg.jpgzpilot-A5-overlay.htmlzpilot-A5-cta.png      $   .   D   gQ?gffffff?u  
Create a cinematic, premium insurance consultation advertisement background image.

COMPOSITION: Square 1:1 format (1080x1080px). Abstract architectural space.
SCENE: Dark, deep navy interior space — like the threshold of an important decision.
View from slightly below center, looking toward a wide-open double door or archway.
Through the opening: warm golden-amber volumetric light cascades in dramatic god-rays,
illuminating floating dust particles. The space beyond is warm, brilliant, inviting.
The foreground/corridor is deep navy (#1A2F5E) fading to almost black at corners.

LIGHTING: Extreme chiaroscuro. Deep navy darkness in corners and edges.
Brilliant golden-amber glow (#C9A84C tones) streaming through the center opening.
Volumetric light rays — like sunlight through cathedral glass. Cinematic depth.
Subtle radial glow emanating from center-top area of the image.

COLOR GRADE: Deep navy (#1A2F5E) dominant background. Warm gold (#C9A84C) light source center.
Rich navy-to-gold gradient across the image. No cold blues, no grey. Warm and vivid.

STYLE: Like Denis Villeneuve / Christopher Nolan cinematography. Ultra-premium.
Clean, abstract — NO people, NO faces, NO text, NO logos, NO UI elements.
No arrows, no buttons, no symbols. Pure atmospheric cinematic background only.

MOOD: The warmest, most vivid, most hopeful slide of a 5-slide series.
"A door opening at the end of a long journey." Clear, solid energy. Decisive.

ASPECT: Exactly 1:1 square, 1080x1080px. Maximum cinematic quality.
)zgemini-2.5-flash-imagezgemini-3-pro-image-previewzgemini-3.1-flash-image-previewtokenoutput_pathreturnc           
         d|  dd}ddt         igigdddgid	}t        D ]  }d
| d}t        d| d       t        j                         }	 t	        j
                  |||d      }|j                  dv rt        d|j                   d       o	 |j                          t        j                         |z
  }	|j                         }
|
j                  dg       }|s&t        dt        j                  |
      dd          y|d   j                  di       j                  dg       }t        d |D        d      }|7|D cg c]  }d|v s|j                  dd       }}t        d|dd           yt!        j"                  |d!   d"         }|j%                  |       t        d#| d$t'        |      d%d&|	d'd(        y) t        d*       y# t        j                  $ r}t        d|        Y d}~d}~ww xY w# t        j                  $ rG}t        d|j                  j                   d|j                  j                  dd         Y d}~ yd}~ww xY wc c}w )+uE   Gemini REST API로 배경 이미지 생성 (SA Bearer 토큰 사용).zBearer zapplication/json)AuthorizationzContent-TypepartstextresponseModalitiesIMAGETEXT)contentsgenerationConfigz8https://generativelanguage.googleapis.com/v1beta/models/z:generateContentu   [배경 생성] 모델 u    호출 중...   )headersjsontimeoutu   [WARN] 요청 실패: N)i  i  i  z[WARN] HTTP u    — 다음 모델 시도z[ERROR] HTTP z: i,  F
candidatesu   [ERROR] candidates 없음: r   contentc              3   *   K   | ]  }d |v s|  yw)
inlineDataN ).0ps     T/home/jay/workspace/.worktrees/task-2057-dev2/tools/ai-image-gen/gen_pilot_a5_cta.py	<genexpr>z-generate_gemini_background.<locals>.<genexpr>w   s     A|q/@1As   	 u,   [ERROR] 이미지 파트 없음. 텍스트:    r   datau   [배경 생성] 완료: z (,z bytes, z.1fu   초)Tu$   [ERROR] 모든 모델 시도 실패.)GEMINI_BG_PROMPTMODELS_TO_TRYprinttimerequestspostRequestExceptionstatus_coderaise_for_status	HTTPErrorresponser   r   getdumpsnextbase64	b64decodewrite_byteslen)r   r   r   payloadmodel_idurlstartrespeelapsedr&   r   r   
image_partr!   
text_partsimage_bytess                    r"   generate_gemini_backgroundrD   N   s    #5'**G
 )9 :;<=1GV3DEG
 " (H
Rbc'z@A			==gGSQD
 .L!1!1 22KLM	!!#
 ))+%yy{XXlB/
/

40@#0F/GHI1!!)R044WbAAeA4H
5:Jfk!%%+JJJ@BQ@PQR&&z,'?'GH,(RK8H7K8T[\_S``defQ(T 

01I (( 	*1#./	 !! 	M!**"8"8!9AJJOODS<Q;RST	  Ks<   GG>	IIG;"G66G;>I<IIu>*  <!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=1080" />
  <title>Meta Ad A-5 CTA</title>
  <style>
    @font-face {{
      font-family: 'Pretendard';
      src: local('Pretendard-Black'),
           url('/home/jay/.local/share/fonts/Pretendard/Pretendard-Black.otf') format('opentype');
      font-weight: 900;
    }}
    @font-face {{
      font-family: 'Pretendard';
      src: local('Pretendard-Bold'),
           url('/home/jay/.local/share/fonts/Pretendard/Pretendard-Bold.otf') format('opentype');
      font-weight: 700;
    }}
    @font-face {{
      font-family: 'Pretendard';
      src: local('Pretendard-SemiBold'),
           url('/home/jay/.local/share/fonts/Pretendard/Pretendard-SemiBold.otf') format('opentype');
      font-weight: 600;
    }}
    @font-face {{
      font-family: 'Pretendard';
      src: local('Pretendard-Medium'),
           url('/home/jay/.local/share/fonts/Pretendard/Pretendard-Medium.otf') format('opentype');
      font-weight: 500;
    }}
    @font-face {{
      font-family: 'Pretendard';
      src: local('Pretendard-Regular'),
           url('/home/jay/.local/share/fonts/Pretendard/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;
      -webkit-font-smoothing: antialiased;
      text-rendering: optimizeLegibility;
    }}

    body {{
      font-family: 'Pretendard', 'Noto Sans KR', sans-serif;
      position: relative;
      background: #0a1225;
    }}

    /* ── 배경 레이어 ── */
    #bg {{
      position: absolute;
      inset: 0;
      z-index: 0;
      background-image: url('file://{bg_path}');
      background-size: cover;
      background-position: center center;
    }}

    /* ── 상단 어두운 오버레이 (텍스트 가독성) ── */
    #overlay {{
      position: absolute;
      inset: 0;
      z-index: 1;
      background: linear-gradient(
        180deg,
        rgba(15, 22, 50, 0.72) 0%,
        rgba(15, 22, 50, 0.45) 35%,
        rgba(15, 22, 50, 0.20) 55%,
        rgba(10, 18, 40, 0.60) 80%,
        rgba(10, 18, 40, 0.85) 100%
      );
    }}

    /* ── 중앙 골드 광원 효과 ── */
    #glow {{
      position: absolute;
      inset: 0;
      z-index: 2;
      background: radial-gradient(
        ellipse 60% 50% at 50% 42%,
        rgba(201, 168, 76, 0.12) 0%,
        transparent 70%
      );
      pointer-events: none;
    }}

    /* ── 전체 래퍼 ── */
    #wrapper {{
      position: relative;
      width: 1080px;
      height: 1080px;
      z-index: 10;
      display: flex;
      flex-direction: column;
      align-items: center;
    }}

    /* ── 브랜드 로고 (상단 10%) ── */
    #brand-logo {{
      margin-top: 48px;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 8px;
    }}

    .brand-emblem {{
      width: 52px;
      height: 52px;
      position: relative;
    }}

    .brand-emblem svg {{
      width: 52px;
      height: 52px;
    }}

    .brand-name {{
      font-family: 'Pretendard', sans-serif;
      font-size: {_SIZE_22PX}px;
      font-weight: 700;
      color: #C9A84C;
      letter-spacing: 0.04em;
      text-shadow: 0 0 20px rgba(201, 168, 76, 0.5);
    }}

    /* ── 헤드라인 영역 (상단~중앙 40%) ── */
    #headline-section {{
      flex: 1;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      padding: 0 70px;
      margin-top: -20px;
    }}

    .headline {{
      font-family: 'Pretendard', sans-serif;
      font-size: {_SIZE_68PX}px;
      font-weight: 900;
      line-height: {_LH_1_22};
      letter-spacing: -0.03em;
      color: #ffffff;
      text-align: center;
      word-break: keep-all;
      text-shadow:
        0 2px 20px rgba(0, 0, 0, 0.6),
        0 4px 50px rgba(0, 0, 0, 0.4);
      margin-bottom: 28px;
    }}

    .headline .accent {{
      color: #C9A84C;
      text-decoration: underline;
      text-decoration-color: rgba(201, 168, 76, 0.7);
      text-decoration-thickness: 3px;
      text-underline-offset: 6px;
      text-shadow:
        0 0 30px rgba(201, 168, 76, 0.6),
        0 2px 20px rgba(0, 0, 0, 0.5);
    }}

    /* ── 구분 장식선 ── */
    .divider {{
      display: flex;
      align-items: center;
      gap: 16px;
      width: 100%;
      max-width: 540px;
      margin-bottom: 28px;
    }}

    .divider-line {{
      flex: 1;
      height: 1px;
      background: linear-gradient(90deg, transparent, rgba(201, 168, 76, 0.5), transparent);
    }}

    .divider-dot {{
      width: 6px;
      height: 6px;
      background: #C9A84C;
      border-radius: 50%;
      box-shadow: 0 0 8px rgba(201, 168, 76, 0.8);
      flex-shrink: 0;
    }}

    /* ── 서브카피 (중앙 25%) ── */
    .subcopy {{
      font-family: 'Pretendard', sans-serif;
      font-size: {_SIZE_36PX}px;
      font-weight: 400;
      line-height: {_LH_1_65};
      color: rgba(255, 255, 255, 0.82);
      text-align: center;
      word-break: keep-all;
      letter-spacing: -0.01em;
    }}

    /* ── 하단 영역 (하단 25%) ── */
    #bottom-section {{
      width: 100%;
      padding: 0 60px 56px;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 24px;
    }}

    /* ── CTA 버튼 ── */
    .cta-btn {{
      width: 100%;
      max-width: 840px;
      background: linear-gradient(
        135deg,
        #C9A84C 0%,
        #E8C870 40%,
        #D4AD52 70%,
        #B8922A 100%
      );
      color: #ffffff;
      font-family: 'Pretendard', sans-serif;
      font-size: {_SIZE_46PX}px;
      font-weight: 900;
      letter-spacing: -0.02em;
      text-align: center;
      padding: 34px 48px;
      border-radius: 18px;
      word-break: keep-all;
      box-shadow:
        0 0 40px rgba(201, 168, 76, 0.55),
        0 8px 30px rgba(0, 0, 0, 0.45),
        inset 0 2px 0 rgba(255, 255, 255, 0.35),
        inset 0 -3px 0 rgba(0, 0, 0, 0.20);
      text-shadow: 0 1px 4px rgba(0, 0, 0, 0.30);
      position: relative;
      overflow: hidden;
    }}

    .cta-btn::after {{
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      height: 50%;
      background: linear-gradient(180deg, rgba(255,255,255,0.15) 0%, transparent 100%);
      border-radius: 18px 18px 0 0;
    }}

    /* ── 트러스트 앵커 배지 ── */
    .trust-row {{
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 24px;
    }}

    .trust-item {{
      display: flex;
      align-items: center;
      gap: 8px;
      font-family: 'Pretendard', sans-serif;
      font-size: {_SIZE_26PX}px;
      font-weight: 500;
      color: rgba(255, 255, 255, 0.68);
      letter-spacing: 0.01em;
    }}

    .trust-icon {{
      width: 20px;
      height: 20px;
      color: #C9A84C;
    }}

    .trust-sep {{
      width: 4px;
      height: 4px;
      background: rgba(201, 168, 76, 0.5);
      border-radius: 50%;
    }}

    /* ── 페이지 인디케이터 ── */
    #page-indicator {{
      position: absolute;
      top: 54px;
      right: 54px;
      z-index: 20;
      font-family: 'Pretendard', sans-serif;
      font-size: {_SIZE_22PX}px;
      font-weight: 500;
      color: rgba(255, 255, 255, 0.45);
      letter-spacing: 0.05em;
    }}
  </style>
</head>
<body>

  <!-- 배경 -->
  <div id="bg"></div>

  <!-- 어두운 오버레이 -->
  <div id="overlay"></div>

  <!-- 중앙 골드 글로우 -->
  <div id="glow"></div>

  <!-- 페이지 인디케이터 -->
  <div id="page-indicator">5 / 5</div>

  <!-- 메인 래퍼 -->
  <div id="wrapper">

    <!-- 브랜드 로고 -->
    <div id="brand-logo">
      <div class="brand-emblem">
        <!-- 서울대보험쌤 심볼 (미니멀 방패+별) -->
        <svg viewBox="0 0 52 52" fill="none" xmlns="http://www.w3.org/2000/svg">
          <defs>
            <linearGradient id="g1" x1="0%" y1="0%" x2="100%" y2="100%">
              <stop offset="0%" style="stop-color:#E8C870"/>
              <stop offset="100%" style="stop-color:#B8922A"/>
            </linearGradient>
          </defs>
          <!-- 방패 외형 -->
          <path d="M26 4 L46 13 L46 30 C46 40 36 47 26 50 C16 47 6 40 6 30 L6 13 Z"
                fill="url(#g1)" opacity="0.15" stroke="url(#g1)" stroke-width="1.5"/>
          <!-- 별 심볼 -->
          <path d="M26 14 L28.4 21.2 L36 21.2 L30 25.6 L32.4 32.8 L26 28.4 L19.6 32.8 L22 25.6 L16 21.2 L23.6 21.2 Z"
                fill="url(#g1)"/>
        </svg>
      </div>
      <div class="brand-name">서울대보험쌤</div>
    </div>

    <!-- 헤드라인 섹션 -->
    <div id="headline-section">
      <h1 class="headline">전략을 바꿀 준비가 됐다면,<br>지금 <span class="accent">딱 한 번</span> 물어보세요.</h1>

      <div class="divider">
        <div class="divider-line"></div>
        <div class="divider-dot"></div>
        <div class="divider-line"></div>
      </div>

      <p class="subcopy">서울대보험쌤 팀장이 직접 답합니다.<br>조건 없는 상담, 당신 상황에 맞는 방향 제시.</p>
    </div>

    <!-- 하단 CTA 영역 -->
    <div id="bottom-section">
      <div class="cta-btn">무료 상담 신청하기</div>

      <!-- 트러스트 앵커 -->
      <div class="trust-row">
        <div class="trust-item">
          <svg class="trust-icon" viewBox="0 0 20 20" fill="none">
            <path d="M10 2L12.2 7.4L18 7.8L13.6 11.8L15.2 17.4L10 14.4L4.8 17.4L6.4 11.8L2 7.8L7.8 7.4Z"
                  fill="#C9A84C"/>
          </svg>
          조건 없음
        </div>
        <div class="trust-sep"></div>
        <div class="trust-item">
          <svg class="trust-icon" viewBox="0 0 20 20" fill="none">
            <circle cx="10" cy="10" r="8" stroke="#C9A84C" stroke-width="1.5"/>
            <path d="M7 10L9.5 12.5L14 7.5" stroke="#C9A84C" stroke-width="1.5" stroke-linecap="round"/>
          </svg>
          무료 상담
        </div>
        <div class="trust-sep"></div>
        <div class="trust-item">
          <svg class="trust-icon" viewBox="0 0 20 20" fill="none">
            <path d="M10 2C7.2 2 5 4.2 5 7C5 9.8 7.2 12 10 12C12.8 12 15 9.8 15 7C15 4.2 12.8 2 10 2Z"
                  stroke="#C9A84C" stroke-width="1.5"/>
            <path d="M3 18C3 15.2 6.1 13 10 13C13.9 13 17 15.2 17 18"
                  stroke="#C9A84C" stroke-width="1.5" stroke-linecap="round"/>
          </svg>
          팀장 직접 응대
        </div>
      </div>
    </div>

  </div>

</body>
</html>
bg_pathoutput_html_pathc                     t         j                  t        |             }|j                  |d       t	        d|        y)u    HTML 오버레이 파일 생성.)rE   zutf-8)encodingu   [HTML] 오버레이 생성: N)HTML_TEMPLATEformatstr
write_textr*   )rE   rF   html_contents      r"   create_htmlrN     s>     ''G'=Lw?	()9(:
;<    	html_pathoutput_png_pathc                    t        d       t               5 }|j                  j                  ddg      }	 |j	                  ddd      }|j                  d| j                          d	
       |j                  d       |j                  j                  dd       |j                  t        |      d       t        d|        |j                          	 ddd       y# |j                          w xY w# 1 sw Y   yxY w)u"   Playwright로 HTML → PNG 캡처.u!   [캡처] Playwright 실행 중...z--no-sandboxz--disable-dev-shm-usage)argsi8  )widthheight)viewportzfile://networkidle)
wait_untili	  Tparentsexist_okpng)pathtypeu   [캡처] 완료: N)r*   r   chromiumlaunchnew_pagegotoresolvewait_for_timeoutparentmkdir
screenshotrK   close)rP   rQ   r!   browserpages        r"   capture_screenshotrk   "  s    	
-.		 
a**##.:S)T#U	##tt-L#MDII	 1 1 345-IP!!$'""(((EOO_!5EOB%o%678MMO
 
 MMO
 
s#   C6BC!C6!C33C66C?c                  `   t        d       t        d       t        d       t        j                  dd       t        d       	 t        j                         } t        dt        |        d       t        j                         rt        d
t                n2t         t              }|s t        d       t        j                  d	       t        t        t               t        t        t               t        j                         rOt        j!                         j"                  dz  }t        dt                t        d|dd       t        d       y t        d       t        j                  d	       y # t        $ r.}t        d|        t        j                  d	       Y d }~7d }~ww xY w)Nz<============================================================u*   Meta 캐러셀 A-5 CTA 슬라이드 생성TrY   u1   [인증] SA 서비스 계정 토큰 획득 중...u*   [인증] SA 토큰 획득 완료 (길이: )u!   [ERROR] SA 토큰 획득 실패:    u,   [배경] 기존 배경 이미지 재사용: u8   [ERROR] 배경 이미지 생성 실패. 중단합니다.i   u
   
[완료] u          파일 크기: z.0fz KBu          해상도: 1080x1080pxu@   [ERROR] 최종 이미지 파일이 생성되지 않았습니다.)r*   
OUTPUT_DIRrf   gcloud_authget_service_account_tokenr9   	ExceptionsysexitBG_PATHexistsrD   rN   	HTML_PATHrk   
FINAL_PATHstatst_size)r   r?   successsize_kbs       r"   mainr}   2  sK   	(O	
67	(OTD1 

=>557:3u:,aHI ~~<WIFG,UG<LMHHQK # y*- //#++d2J<()&wsm378-/PQ7  1!56s   ,E6 6	F-?#F((F-__main__)'__doc__r6   r   rs   r+   pathlibr   r,   playwright.sync_apir   
gen_configr   __file__re   TOOL_DIRro   ru   rw   rx   r]   insertrK   rp   
_SIZE_22PX
_SIZE_26PX
_SIZE_36PX
_SIZE_46PX
_SIZE_68PX_LH_1_22_LH_1_65r(   r)   boolrD   rI   rN   rk   r}   __name__r   rO   r"   <module>r      s      
    / %
 >  @@

(
(00	,,
 3x= ! 




 :6c 6 6 6zM`= = =$ =$  $  &R zF rO   