
    KiD                    \   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ddl	m
Z
 ddlmZmZmZ ej                  j!                  d e ee      j&                               ddlZeZdZdZd	Zd
Zedz  Zedz  Zedz  Zedz  Zedz  ZdZdZ ddgZ!ddZ"ddZ#ddZ$ddZ%e&dk(  r e%        yy)u  Meta 캐러셀 광고 A-1 Hook 슬라이드 — Production v6.

제이회장님 피드백 4건 완전 반영:
1. 모든 텍스트 40px 이상 (예외 없음)
2. font-weight 400 이상만 사용
3. WCAG AAA 대비율 (일반 7:1, 대형 4.5:1)
4. 서울대보험쌤 로고 이미지 사용 (흰색 버전 PNG)
   + 반투명 오버레이 (opacity 0.45~0.55) + 글래스모피즘 카드
    )annotationsN)Path)sync_playwright)WORKSPACE_ROOTFONT_DIR
CTA_MIN_PX,   X   gzG?g333333?z%output/meta-ads/a-group-v6/productionz_bg_a1_hook.pngzmeta-A1-hook.pngz_a1_hook_template.htmlz(assets/brand/logo-snuinsurance-white.pnguu  Cinematic photograph, professional camera shot. Scene: A lone insurance salesperson sitting at a cluttered desk in a dimly lit office late at night. The person is seen from behind or in silhouette — exhausted posture, head slightly bowed. Desk covered with stacked paper documents, a laptop glowing faintly, scattered sticky notes, a cold coffee cup, and a smartphone face-down. Large window in background shows dark city lights outside at night. Office mostly dark — only the laptop screen and distant city lights illuminate the scene. Color palette: deep charcoal, cold navy blue, dark slate. Atmosphere: isolation, quiet exhaustion, invisible labor, late-night solitude. The bottom 40% of frame is darkest — fading into near-black for text overlay. Shot on Sony A7RIV, 35mm f/2.0, ISO 6400, slight film grain. 1:1 square composition 1080x1080. No text, no watermark, no logos.z0https://generativelanguage.googleapis.com/v1betazgemini-3.1-flash-image-previewzgemini-3-pro-image-previewc            
     b   t         j                         rt        dt                 t         S t        d       t        j                         } t        dt        |        d       d|  dd}d}t        D ]  }t         d	| d
}ddt        igigdddgid}t        d| d       t        j                         }	 t        j                  |||d      }|j                  dv r)t        d|j                   d       d|j                   }|j                          t        j                         |z
  }	|j!                         }
|
j#                  dg       }|st        d       dt        |
      dd  }|d   j#                  d i       j#                  dg       }t%        d! |D        d      }|@|D cg c]  }d|v s|j#                  dd"       }}t        d#|dd$  d       d%|dd$  }y|d&   j#                  d'd(      }t'        j(                  |d&   d)         }t         }|j+                  |       t        d*|j,                   d+t        |      d,d-|	d.d/       |c S  t/        d0|       # t        j                  $ r%}t        d| d       t        |      }Y d}~0d}~ww xY wc c}w )1uF   Gemini API로 배경 이미지를 생성하고 PNG로 저장합니다.u,   [배경] 캐시된 배경 이미지 사용: u(   [배경] Gemini API 토큰 획득 중...u   [배경] 토큰 획득 완료 (z chars)zBearer zapplication/json)AuthorizationzContent-TypeNz/models/z:generateContentpartstextresponseModalitiesIMAGETEXT)contentsgenerationConfigu1   [배경] 이미지 생성 요청 중... (모델: )i,  )headersjsontimeout)i  i  u$   [배경] 모델 접근 불가 (HTTP u   ). 다음 모델 시도...zHTTP u   [배경] HTTP 오류: u   . 다음 모델 시도...
candidatesu3   [배경] candidates 없음. 다음 모델 시도...u   candidates 없음:    r   contentc              3  *   K   | ]  }d |v s|  yw)
inlineDataN ).0ps     C/home/jay/workspace/tools/ai-image-gen/gen_production_a1_hook_v6.py	<genexpr>z&generate_background.<locals>.<genexpr>v   s     A|q/@1As   	 u0   [배경] 이미지 데이터 없음. 텍스트:    u'   이미지 데이터 없음. 텍스트: r   mimeTypez	image/pngdatau   [배경] 완료:  (,z bytes, z.1fu   초)u(   모든 모델 실패. 마지막 오류: )BG_PNGexistsprintgcloud_authget_access_tokenlenMODEL_CANDIDATESGEMINI_API_BASE	BG_PROMPTtimerequestspoststatus_coderaise_for_status	HTTPErrorstrr   getnextbase64	b64decodewrite_bytesnameRuntimeError)tokenr   
last_errormodel_idurlpayloadstartrespeelapsedr%   r   r   
image_partr   textsmimeimage_bytes	save_paths                      r    generate_backgroundrM   H   s   }}<VHEF	
45((*E	+CJ<w
?@ #5'**G
 J$ + !(3CD!VY$7#89:!57H I

 	A(1MN		
	==gGSQD:-<T=M=M<NNhij$T%5%5$67
!!# ))+%yy{XXlB/
GI.s4y#.?@J1!!)R044WbAAeA4H
05E11QUU62&EEEDU2AYKOhijB5!9+NJ,'++JD&&z,'?'GH	k*!)..!1C4DQ3GxPWX[}\`abW+Z A*N
OO; !! 	*1#-FGHQJ	  Fs+   ;AI1I11	J,;J,1J)J$$J)c                    dt          dt          dt          dt          dt          dt          d|  dt         d	t         d
t         dt         dt
         d| dS )u  A-1 Hook 슬라이드 HTML 오버레이 빌드.

    피드백 준수:
    - 모든 텍스트 40px 이상
    - font-weight 400 이상만 사용 (300 이하 없음)
    - WCAG AAA: 흰색 텍스트 on 다크 배경 = 충분한 대비율
    - 로고 <img> 태그 사용 (흰색 PNG)
    - 반투명 다크 오버레이 opacity 0.50 + 글래스모피즘 카드 (opacity 0.20, backdrop-filter blur)
    z<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<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://u  /Pretendard-Regular.otf') format('opentype');
    font-weight: 400;
  }

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

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

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

  /* ─── 배경 이미지 ─── */
  .bg {
    position: absolute;
    inset: 0;
    background: url('file://u  ') center center / cover no-repeat;
  }

  /* ─── 반투명 다크 오버레이 (opacity 0.50) ─── */
  /* 피드백: 반투명 레이어 opacity 0.4~0.6 */
  .overlay-dark {
    position: absolute;
    inset: 0;
    background: linear-gradient(
      to bottom,
      rgba(5, 8, 18, 0.78) 0%,
      rgba(5, 8, 18, 0.50) 25%,
      rgba(5, 8, 18, 0.40) 45%,
      rgba(5, 8, 18, 0.60) 65%,
      rgba(3, 5, 12, 0.96) 100%
    );
  }

  /* ─── 상단 로고 영역 (Top 20%) ─── */
  .top-zone {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 216px;
    display: flex;
    align-items: center;
    padding: 0 64px;
  }

  /* 서울대보험쌤 로고 이미지 — <img> 태그 사용 (피드백 #4) */
  .brand-logo {
    height: 72px;
    width: auto;
    object-fit: contain;
    /* 가독성 보조: 로고 아래 미세 드롭쉐도우 */
    filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.60));
  }

  /* ─── 골드 구분선 ─── */
  .divider {
    position: absolute;
    top: 216px;
    left: 64px;
    right: 64px;
    height: 2px;
    background: linear-gradient(
      to right,
      transparent 0%,
      rgba(201, 168, 76, 0.70) 15%,
      rgba(201, 168, 76, 0.90) 50%,
      rgba(201, 168, 76, 0.70) 85%,
      transparent 100%
    );
  }

  /* ─── 헤드라인 영역 (중앙 45%) ─── */
  /* y=220 ~ y=702 사이 중앙 배치 */
  .headline-zone {
    position: absolute;
    top: 228px;
    left: 0;
    right: 0;
    height: 470px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    padding: 0 64px;
    text-align: center;
  }

  .headline {
    font-size: u   px;
    font-weight: 900;   /* Pretendard Black — 피드백 #2: 400 이상 */
    color: #F2F3F8;     /* WCAG AAA: 흰색 on 다크 배경 > 7:1 */
    line-height: ux  ;
    letter-spacing: -3px;
    word-break: keep-all;
    text-shadow:
      0 2px 32px rgba(0, 0, 0, 0.70),
      0 1px 8px rgba(0, 0, 0, 0.50);
  }

  /* 골드 강조 텍스트 */
  .headline .accent {
    color: #C9A84C;    /* 브랜드 골드 — WCAG AA on 다크 (4.5:1 충족) */
    text-shadow:
      0 0 32px rgba(201, 168, 76, 0.45),
      0 2px 16px rgba(0, 0, 0, 0.60);
  }

  /* ─── 하단 서브카피 영역 (Bottom 35%) ─── */
  .bottom-zone {
    position: absolute;
    top: 702px;
    left: 0;
    right: 0;
    bottom: 0;
  }

  /* 하단 그라디언트 */
  .bottom-gradient {
    position: absolute;
    inset: 0;
    background: linear-gradient(
      to bottom,
      rgba(3, 5, 12, 0.0) 0%,
      rgba(3, 5, 12, 0.88) 35%,
      rgba(3, 5, 12, 0.97) 100%
    );
  }

  /* 글래스모피즘 카드 — 피드백 #5: opacity 0.15~0.30, backdrop-filter blur */
  .glass-card {
    position: absolute;
    bottom: 72px;
    left: 64px;
    right: 64px;
    background: rgba(255, 255, 255, 0.08);  /* opacity ~0.08 (배경색 반영 시 체감 0.15~0.25) */
    backdrop-filter: blur(16px) saturate(140%);
    -webkit-backdrop-filter: blur(16px) saturate(140%);
    border: 1px solid rgba(201, 168, 76, 0.28);
    border-radius: 20px;
    padding: 40px 48px;
  }

  /* 서브카피 — 피드백 #1: 40px 이상, #2: font-weight 400 */
  .subcopy {
    font-size: u   px;
    font-weight: 400;    /* Regular — 피드백 #2 준수 */
    color: rgba(226, 228, 238, 0.92);  /* WCAG AAA: 대비율 > 7:1 on 다크 */
    line-height: u  ;
    letter-spacing: -1px;
    word-break: keep-all;
  }

  /* 강조 단어 — font-weight 600 (SemiBold) */
  .subcopy .em {
    color: #E8EAF4;     /* 거의 흰색 — AAA 기준 충족 */
    font-weight: 600;   /* SemiBold — 피드백 #2 준수 */
  }

  /* ─── 페이지 인디케이터 — 피드백 #1: 40px 이상 ─── */
  .page-indicator {
    position: absolute;
    top: 164px;
    right: 64px;
    font-size: u8  px;    /* 최소 40px 준수 */
    font-weight: 500;   /* Medium — 피드백 #2 준수 */
    color: rgba(201, 168, 76, 0.85);
    letter-spacing: 2px;
  }

</style>
</head>
<body>
<div class="canvas">

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

  <!-- 반투명 다크 오버레이 (opacity 0.45~0.55 범위) -->
  <div class="overlay-dark"></div>

  <!-- 상단 로고 영역 (Top 20%) -->
  <div class="top-zone">
    <!-- 서울대보험쌤 로고 이미지 — 피드백 #4: img 태그 사용 -->
    <img
      class="brand-logo"
      src="file://uQ  "
      alt="서울대보험쌤"
    />
  </div>

  <!-- 페이지 인디케이터 — 40px 이상 (피드백 #1) -->
  <div class="page-indicator">01 / 05</div>

  <!-- 골드 구분선 -->
  <div class="divider"></div>

  <!-- 헤드라인 (중앙 45%) -->
  <div class="headline-zone">
    <div class="headline">
      열심히 했다.<br>
      근데 왜 <span class="accent">나만 안 되지?</span>
    </div>
  </div>

  <!-- 하단 서브카피 영역 (Bottom 35%) -->
  <div class="bottom-zone">
    <div class="bottom-gradient"></div>
    <!-- 글래스모피즘 카드 (피드백 #5) -->
    <div class="glass-card">
      <p class="subcopy">
        <span class="em">방문 횟수, 전화 통화, 상담 건수</span>—<br>
        숫자는 쌓이는데 통장은 그대로다.
      </p>
    </div>
  </div>

</div>
</body>
</html>)r   
_SIZE_88PX_LH_1_18
_SIZE_44PX_LH_1_70_CTA_PX)bg_path	logo_paths     r    
build_htmlrV      s     Z  
 Z  
 Z  
 Z  
 Z  
 Z  : %I I&R |   5j |     y , + !OH H    c                4   t        t        j                               }t        t        | j                               |      }t        j                  |d       t        dt                t        d       t               5 }|j                  j                         }	 |j                  ddd      }|j                  dt        j                          d	
       |j                  d       t        j                  j                  dd       |j!                  t        t              d       |j#                          	 ddd       t        j%                         j&                  }t        dt         d|dd       y# |j#                          w xY w# 1 sw Y   TxY w)uN   HTML 오버레이를 Playwright로 캡처하여 최종 PNG를 저장합니다.zutf-8)encodingu&   [오버레이] HTML 템플릿 저장: u*   [오버레이] Playwright 캡처 시작...i8  )widthheight)viewportzfile://networkidle)
wait_untili  Tparentsexist_okpng)pathtypeNu   [오버레이] 완료: r&   r'   z bytes))r7   
LOGO_WHITEresolverV   	HTML_TEMP
write_textr*   r   chromiumlaunchnew_pagegotowait_for_timeout
OUTPUT_PNGparentmkdir
screenshotclosestatst_size)rT   rU   html_contentr   browserpagesizes          r    capture_overlayry     sE   J&&()Ic'//"34i@L8	29+
>?	
67		 
a**##%	##tt-L#MDII	 1 1 345-IP!!$'##D4#@OOZuO=MMO
 ??$$D	#J<r$q
AB MMO
 
s%   ?FBE9*F9FFFc                 z   t        d       t        d       t        dt                t        d       t        d       t        j                  dd       t        j                         st        dt               t        dt                t               } t        |        t        d	       t        d
       t        dt                t        dt                t        dt                t        d       t        d       t        d       t        d       t        d       t        d       t        d       y )Nz<============================================================u:   Meta 캐러셀 A-1 Hook 이미지 생성 — Production v6u   출력: u,   제이회장님 피드백 4건 완전 반영Tr_   u   로고 파일 없음: u   [로고] 확인 완료: z=
============================================================u   완료!u     배경:    z  HTML:    u     최종PNG: u   
[품질 체크리스트]u_     ✓ 모든 텍스트 40px 이상 (헤드라인 88px, 서브카피 44px, 인디케이터 40px)uU     ✓ font-weight 400 이상만 사용 (Regular/Medium/SemiBold/Bold/ExtraBold/Black)uD     ✓ WCAG AAA: 흰색(#F2F3F8) on 다크 배경 → 대비율 > 7:1uA     ✓ 로고 이미지 <img> 태그 (logo-snuinsurance-white.png)uR     ✓ 반투명 다크 오버레이 (0.40~0.78 범위) + 글래스모피즘 카드)r*   rn   
OUTPUT_DIRrp   re   r)   FileNotFoundErrorrM   ry   r(   rg   )rT   s    r    mainr}     s   	(O	
FG	HZL
!"	
89	(OTD1 "8 EFF	$ZL
12 "#G G	/	)	M&
"#	K	{
#$	M*
&'	(O	
&'	
kl	
ab	
PQ	
MN	
^_rW   __main__)returnr   )rT   r7   rU   r7   r   r7   )rT   r   r   None)r   r   )'__doc__
__future__r   r:   sysr1   pathlibr   r2   playwright.sync_apir   
gen_configr   r   r   rc   insertr7   __file__ro   r+   rS   rQ   rO   rP   rR   r{   r(   rn   rg   re   r0   r/   r.   rM   rV   ry   r}   __name__r   rW   r    <module>r      s    #  
    / ; ; 3tH~,,- . 


 EE
	'	',,
11	HH
I 
& E$  =PJRtC:`D zF rW   