
    iC                       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  ee      j                  Z ed      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dZddZd Zedk(  r e        yy)uv   M3-1 서울대보험쌤 × 정당한 대우 Google 광고 배너 생성
- 1200x628 가로형
- 1080x1080 정사각형
    )annotationsN)Path)sync_playwrightz-/home/jay/workspace/output/google-ads/bannersoutputz	v4-hybridzbg_snu_fair.jpgz0https://generativelanguage.googleapis.com/v1betazgemini-3-pro-image-previewzgemini-3.1-flash-image-previewu  A premium private study or home office at evening. Warm indirect lighting, wooden bookshelf with neatly arranged books, a clean desk with a laptop and a notepad. Through the window, a softly glowing city night view can be seen. The atmosphere feels like a professional's personal workspace — warm yet professional, sophisticated. Dark-to-mid tones with warm gold accent lighting. No people. No text. No logos. Photorealistic quality, cinematic lighting, 8K resolution. Landscape orientation suitable for a wide banner.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/_backup/gen_snu_fair_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'   2   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>r   s     A|q/@1As   	u     이미지 없음. parts: zNo inlineDatar6   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   r+   r   getdumpsnextlistkeysbase64	b64decodewrite_byteslenRuntimeError)r   gar   r!   models_to_try
last_errorattemptr    r$   er<   r3   r*   
image_partr9   mime	img_bytess                    r   generate_backgroundr\   B   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                4    d| j                          }d| dS )u&   1200x628 가로형 배너 HTML 생성.file://u7  <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
  @font-face {
    font-family: 'Pretendard';
    src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-Bold.otf') format('opentype');
    font-weight: 700;
  }
  @font-face {
    font-family: 'Pretendard';
    src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-Medium.otf') format('opentype');
    font-weight: 500;
  }
  @font-face {
    font-family: 'Pretendard';
    src: url('file:///home/jay/.local/share/fonts/Pretendard/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;
  }

  /* 배경 이미지: 우측 60% 영역 */
  .bg-image {
    position: absolute;
    right: 0;
    top: 0;
    width: 60%;
    height: 100%;
    background-image: url('u	  ');
    background-size: cover;
    background-position: center;
  }

  /* 좌→우 그라데이션 오버레이 (다크 브라운→투명) */
  .gradient-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(
      to right,
      #3E2723 0%,
      #3E2723 38%,
      rgba(62,39,35,0.92) 50%,
      rgba(62,39,35,0.5) 65%,
      rgba(62,39,35,0.1) 80%,
      transparent 100%
    );
  }

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

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

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

  /* 서브 카피 */
  .sub-copy {
    font-size: 40px;
    font-weight: 500;
    color: #C9A84C;
    letter-spacing: -0.5px;
    margin-bottom: 38px;
  }

  /* CTA 버튼 */
  .cta-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, #C9A84C 0%, #D4B87A 100%);
    color: #1A0E00;
    font-size: 40px;
    font-weight: 700;
    padding: 16px 44px;
    border-radius: 6px;
    letter-spacing: -0.5px;
    width: fit-content;
    box-shadow: 0 4px 16px rgba(201,168,76,0.35);
  }
</style>
</head>
<body>
<div class="container">
  <!-- 배경 이미지 -->
  <div class="bg-image"></div>
  <!-- 그라데이션 오버레이 -->
  <div class="gradient-overlay"></div>
  <!-- 텍스트 영역 -->
  <div class="text-area">
    <div class="brand-badge">서울대보험쌤</div>
    <div class="headline">지점장이 직접 컨설팅하는&#10;보험영업</div>
    <div class="sub-copy">AI 시스템으로 실적을 극대화</div>
    <div class="cta-btn">무료 상담 신청</div>
  </div>
</div>
</body>
</html>resolvebg_pathbg_uris     r   make_html_1200x628rd      s6    w()*F,X #8 h$YT Tr   c                4    d| j                          }d| dS )u*   1080x1080 정사각형 배너 HTML 생성.r^   u  <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
  @font-face {
    font-family: 'Pretendard';
    src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-Bold.otf') format('opentype');
    font-weight: 700;
  }
  @font-face {
    font-family: 'Pretendard';
    src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-Medium.otf') format('opentype');
    font-weight: 500;
  }
  @font-face {
    font-family: 'Pretendard';
    src: url('file:///home/jay/.local/share/fonts/Pretendard/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: #1A0E00;
  }

  .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.5) */
  .dark-overlay {
    position: absolute;
    inset: 0;
    background: rgba(62, 39, 35, 0.55);
  }

  /* 하단 그라데이션 (텍스트 가독성 강화) */
  .bottom-gradient {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 65%;
    background: linear-gradient(
      to bottom,
      transparent 0%,
      rgba(30, 15, 5, 0.6) 40%,
      rgba(30, 15, 5, 0.82) 100%
    );
  }

  /* 전체 텍스트 레이아웃 */
  .content {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    padding: 54px 60px 60px;
  }

  /* 상단 뱃지 영역 (상단 12%) */
  .top-area {
    height: 12%;
    display: flex;
    align-items: flex-start;
  }

  .brand-badge {
    display: inline-flex;
    align-items: center;
    background: #C9A84C;
    color: #1A0E00;
    font-size: 42px;
    font-weight: 700;
    padding: 8px 24px;
    border-radius: 6px;
    letter-spacing: -0.5px;
    width: fit-content;
  }

  /* 중앙 헤드라인 영역 (중앙 40%) */
  .middle-area {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
    gap: 28px;
    padding: 0 20px;
  }

  .headline {
    font-size: 62px;
    font-weight: 700;
    color: #FFF8E7;
    line-height: 1.28;
    letter-spacing: -1.5px;
    text-align: center;
    white-space: pre-line;
    text-shadow: 0 2px 12px rgba(0,0,0,0.5);
  }

  .sub-copy {
    font-size: 42px;
    font-weight: 500;
    color: #C9A84C;
    letter-spacing: -0.5px;
    text-align: center;
    text-shadow: 0 2px 8px rgba(0,0,0,0.4);
  }

  /* 하단 CTA 영역 (하단 25%) */
  .bottom-area {
    height: 25%;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .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: 22px 80px;
    border-radius: 6px;
    letter-spacing: -0.5px;
    box-shadow: 0 6px 24px rgba(201,168,76,0.45);
    min-width: 380px;
  }
</style>
</head>
<body>
<div class="container">
  <div class="bg-image"></div>
  <div class="dark-overlay"></div>
  <div class="bottom-gradient"></div>

  <div class="content">
    <div class="top-area">
      <div class="brand-badge">서울대보험쌤</div>
    </div>

    <div class="middle-area">
      <div class="headline">지점장이 직접 컨설팅하는&#10;보험영업</div>
      <div class="sub-copy">AI 시스템으로 실적을 극대화</div>
    </div>

    <div class="bottom-area">
      <div class="cta-btn">무료 상담 신청</div>
    </div>
  </div>
</div>
</body>
</html>r_   ra   s     r   make_html_1080x1080rf     s6    w()*F)R #8 F$So or   c                 j    t        t        d            j                  dd      j                  dd      S )u/   배경 이미지 없는 1200x628 폴백 배너./nonexistent-background-image: url('file:///nonexistent');z/* no bg */zbackground: linear-gradient(
      to right,
      #3E2723 0%,
      #3E2723 38%,
      rgba(62,39,35,0.92) 50%,
      rgba(62,39,35,0.5) 65%,
      rgba(62,39,35,0.1) 80%,
      transparent 100%
    );zKbackground: linear-gradient(135deg, #3E2723 0%, #5D3A28 50%, #3E2723 100%);)rd   r   replacer7   r   r   make_html_no_bg_1200x628rk     s:    d>23;;7 g 	]Ur   c                 J    t        t        d            j                  dd      S )u0   배경 이미지 없는 1080x1080 폴백 배너.rh   ri   zKbackground: linear-gradient(160deg, #2C1810 0%, #4A2C1C 40%, #3E2723 100%);)rf   r   rj   r7   r   r   make_html_no_bg_1080x1080rm     s%    tN34<<7U 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_banner_xz.htmlzutf-8)encoding)widthheight)viewportr^   networkidle)
wait_untili  Tparentsexist_okpngr   )rp   yrr   rs   )r	   typeclipu     [캡처] r=   i   z.0fz KB)N)
missing_ok)TMP_DIR
write_textr   chromiumlaunchnew_pagegotor`   wait_for_timeoutparentmkdir
screenshotr   rC   rA   rB   closeunlink)html_contentrr   rs   output_pathtmp_htmlr9   browserpages           r   capture_html_to_pngr     s@   <waxu==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                 4   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	d
|       t        d|        t        dz  }t        d       	 | rt        |       n	t               }t        |dd|       t        d|        t        d       t        d       t        d|        t        d|        t        d       y # t
        $ r%}t        d|        t        d       d } Y d }~d }~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-1 서울대보험쌤 배너 생성 시작Trw   u   [오류] 배경 생성 실패: u=   [폴백] 다크 그라데이션 배경으로 대체합니다.zsnu-fair-1200x628.pngu,   
[1] 1200x628 가로형 배너 생성 중...i  it  u
     완료: u     [오류] zsnu-fair-1080x1080.pngu0   
[2] 1080x1080 정사각형 배너 생성 중...i8  z=
============================================================u   생성 완료!z  1200x628: z  1080x1080: )rC   r   r   
OUTPUT_DIRr\   rI   rd   rk   r   rf   rm   )rb   rX   out_1200	html_1200out_1080	html_1080s         r   mainr     s   	(O	
89	(OMM$M.TD1%' 33H	
9:3:&w/@X@Z	ItS(;
8*%& 44H	
=>4;'0AZA\	ItT8<
8*%&
 
/	
	L

#$	M(
$%	(O?  /s34MN  A3   A3 sH   
D) 03E 83E: )	E2EE	E7#E22E7:	FFF__main__)returnr   )
r   r   r   z
str | Noner    r   r!   dictr   zrequests.Response)r   r   )rb   r   r   r   )
r   r   rr   intrs   r   r   r   r   None) __doc__
__future__r   rO   r   r   timepathlibr   r   playwright.sync_apir   __file__r   r   r   r   r?   r   rF   rG   rE   r   r'   r\   rd   rf   rk   rm   r   r   __name__r7   r   r   <module>r      s   
 #   
    / >  AB

X

+
%
% E'4 G 
* =HDWtrn%0*Z zF r   