
    3i\Y                       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ZddlZddl	m
Z
 ddlZddlmZ  e
e      j                  Zej"                  j%                  d ee             ddlZ e
d      Zej-                  dd       ed	z  d
z  dz  Zej-                  dd        e
d      ZdZdZdZdZej:                  j=                  dd      ZdZ dZ!dZ"dZ#dddZ$dddZ%dd dZ&	 	 	 	 	 	 	 	 	 	 	 	 	 	 d!dZ'd"dZ(e)dk(  r e(        yy)#u  Cell-1 인카금융서비스 '정당한 보상' 배너 생성기 (v3.2 최종본).

Gemini API로 포토리얼 배경을 생성하고,
HTML/CSS + Playwright로 한글 텍스트를 정밀하게 오버레이합니다.

출력:
  - /home/jay/workspace/output/banners/cell-1-incar-fair/meta-feed-1080x1080.png
  - /home/jay/workspace/output/banners/cell-1-incar-fair/google-resp-1200x628.png
    )annotationsN)Path)sync_playwrightz4/home/jay/workspace/output/banners/cell-1-incar-fairTparentsexist_okoutputz	v4-hybridzcell-1-incar-fairzQ/home/jay/workspace/output/meta-ads/concept-catalog/35-hybrid-v4-refined-A/bg.pngz0https://generativelanguage.googleapis.com/v1betaz3https://www.googleapis.com/auth/generative-languagez)gemini-2.0-flash-preview-image-generationzgemini-2.5-flash-imageGEMINI_API_KEY'AIzaSyDEy7IcOoTbQsI4nxfPOw3ZFbYqEL_PgFUaA  Professional financial advisor's mahogany desk with scattered contract documents and a fountain pen, dramatic side lighting through venetian blinds casting shadow patterns, deep navy blue and warm amber tones, cinematic shallow depth of field, photorealistic office scene, no people, no text, no logos. Square 1:1 format.a$  Wide panoramic view of a modern Korean corporate office at golden hour, glass windows with warm sunlight streaming in, premium mahogany desk with financial documents, warm amber and navy tones, cinematic composition, photorealistic, no people, no text, no logos. Wide landscape 1.91:1 format.u  <!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=1080">
  <style>
    @font-face {{ font-family: 'Pretendard'; src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-Black.otf') format('opentype'); font-weight: 900; }}
    @font-face {{ font-family: 'Pretendard'; src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-ExtraBold.otf') format('opentype'); font-weight: 800; }}
    @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-SemiBold.otf') format('opentype'); font-weight: 600; }}
    @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-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; font-family: 'Pretendard', sans-serif; word-break: keep-all; }}

    .canvas {{ position: relative; width: 1080px; height: 1080px; overflow: hidden; }}
    .bg-image {{ position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; }}
    .dark-overlay {{ position: absolute; inset: 0; background: rgba(10, 22, 40, 0.58); }}

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

    .badge {{
      display: inline-block;
      background: #C9A84C; color: #1A0E00;
      font-size: 40px; font-weight: 700;
      height: 52px; padding: 0 24px;
      border-radius: 6px;
      white-space: nowrap;
      letter-spacing: -0.03em;
      line-height: 52px;
    }}

    .headline {{
      font-size: 60px; font-weight: 700;
      color: #3E2723; line-height: 1.25;
      letter-spacing: -1.5px;
    }}
    .headline .gold {{ color: #C9A84C; }}

    .sub-copy {{
      font-size: 44px; font-weight: 500;
      color: #A07828;
      white-space: nowrap;
      letter-spacing: -0.02em;
    }}

    .cta-btn {{
      display: inline-block;
      background: linear-gradient(135deg, #C9A84C 0%, #D4B87A 100%);
      color: #1A0E00;
      font-size: 48px; font-weight: 700;
      height: 76px; line-height: 76px;
      padding: 0 40px;
      min-width: 360px;
      width: auto;
      border-radius: 6px;
      box-shadow: 0 6px 24px rgba(201,168,76,0.45);
      white-space: nowrap;
      letter-spacing: -0.03em;
      text-align: center;
    }}
  </style>
</head>
<body>
  <div class="canvas">
    <img class="bg-image" src="{bg_url}" alt="background">
    <div class="dark-overlay"></div>
    <div class="text-panel">
      <span class="badge">인카금융서비스 TOP사업단</span>
      <p class="headline">같은 계약,<br>수수료가 왜 <span class="gold">다른가요?</span></p>
      <p class="sub-copy">정착지원금 최대 1,000만원<br>경력직 직전연봉 50% 지원</p>
      <div class="cta-btn">수익 구조 지금 확인 →</div>
    </div>
  </div>
</body>
</html>u@  <!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=1200">
  <style>
    @font-face {{ font-family: 'Pretendard'; src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-Black.otf') format('opentype'); font-weight: 900; }}
    @font-face {{ font-family: 'Pretendard'; src: url('file:///home/jay/.local/share/fonts/Pretendard/Pretendard-ExtraBold.otf') format('opentype'); font-weight: 800; }}
    @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-SemiBold.otf') format('opentype'); font-weight: 600; }}
    @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-Regular.otf') format('opentype'); font-weight: 400; }}

    *, *::before, *::after {{ box-sizing: border-box; margin: 0; padding: 0; }}
    html, body {{ width: 1200px; height: 628px; overflow: hidden; font-family: 'Pretendard', sans-serif; word-break: keep-all; }}

    .canvas {{ position: relative; width: 1200px; height: 628px; overflow: hidden; }}
    .bg-image {{ position: absolute; right: 0; top: 0; width: 65%; height: 100%; object-fit: cover; object-position: center right; }}

    .gradient-overlay {{
      position: absolute; inset: 0;
      background: linear-gradient(
        to right,
        rgba(10,22,40,0.95) 0%,
        rgba(10,22,40,0.95) 40%,
        rgba(10,22,40,0.85) 52%,
        rgba(10,22,40,0.50) 68%,
        rgba(10,22,40,0.15) 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;
    }}

    .text-area {{
      position: absolute;
      top: 0; left: 0;
      width: 62%; height: 100%;
      padding: 48px 56px 48px 60px;
      display: flex; flex-direction: column;
      justify-content: center;
      gap: 20px;
    }}

    .badge {{
      display: inline-block;
      background: #C9A84C; color: #1A0E00;
      font-size: 40px; font-weight: 700;
      height: 48px; line-height: 48px;
      padding: 0 20px;
      border-radius: 6px;
      white-space: nowrap;
      letter-spacing: -0.03em;
      align-self: flex-start;
      margin-bottom: 6px;
    }}

    .headline {{
      font-size: 54px; font-weight: 700;
      color: #FFF8E7; line-height: 1.2;
      letter-spacing: -1.2px;
    }}
    .headline .gold {{ color: #C9A84C; }}

    .sub-copy {{
      font-size: 44px; font-weight: 500;
      color: #C9A84C;
      text-shadow: 0 1px 3px rgba(0,0,0,0.5);
      white-space: nowrap;
      letter-spacing: -0.02em;
    }}

    .cta-btn {{
      display: inline-block;
      background: linear-gradient(135deg, #C9A84C 0%, #D4B87A 100%);
      color: #1A0E00;
      font-size: 44px; font-weight: 700;
      height: 56px; line-height: 56px;
      padding: 0 32px;
      min-width: 220px;
      width: auto;
      border-radius: 6px;
      box-shadow: 0 4px 16px rgba(201,168,76,0.35);
      white-space: nowrap;
      letter-spacing: -0.03em;
      align-self: flex-start;
      text-align: center;
      margin-top: 16px;
    }}
  </style>
</head>
<body>
  <div class="canvas">
    <img class="bg-image" src="{bg_url}" alt="background">
    <div class="gradient-overlay"></div>
    <div class="accent-bar"></div>
    <div class="text-area">
      <span class="badge">인카금융서비스 TOP사업단</span>
      <p class="headline">같은 계약,<br>수수료가 왜 <span class="gold">다른가요?</span></p>
      <p class="sub-copy">정착지원금 최대 1,000만원<br>경력직 직전연봉 50% 지원</p>
      <div class="cta-btn">수익 구조 지금 확인 →</div>
    </div>
  </div>
</body>
</html>c                    t        d| d       t        j                         }t         dt         dt         }ddi}dd| igigd	d
dgid}	 t        j                  |||d      }|j                  dv rXt        d| dt         d|j                   dt                t         dt         dt         }t        j                  |||d      }|j                  s,t        d| d|j                   d|j                  dd         y|j                         }	|	j                  dg       }
|
s(t        d| dt        j                  |	      dd         y|
d   j                  di       j                  dg       }t        d |D        d      }|9|D cg c]  }d|v s|j                  dd       }}t        d| d|dd         y|d   j                  d d!      }t        j                   |d   d"         }d#|v rd$nd%}|j#                  |      }|j%                  |       t        j                         |z
  }t        d| d&|j&                   d't)        |      d(d)|d*d+	       |S c c}w # t*        $ r}t        d| d,|        Y d}~yd}~ww xY w)-u6   Gemini API 키로 배경 이미지를 생성합니다.   [배경u5   ] Gemini API 키 방식으로 이미지 생성 중.../models/z:generateContent?key=Content-Typeapplication/jsonpartstextresponseModalitiesIMAGETEXTcontentsgenerationConfig,  headersjsontimeout  i  i  	   ] 모델     실패 (HTTP ). Fallback:    ] API 오류:  - Nr   
candidates   ] 응답에 candidates 없음: r   contentc              3  *   K   | ]  }d |v s|  yw
inlineDataN .0ps     N/home/jay/workspace/tools/ai-image-gen/_backup/gen_cell1_incar_fair_banners.py	<genexpr>z+generate_bg_image_apikey.<locals>.<genexpr>8       A|q/@1A   	 )   ] 이미지 데이터 없음. 텍스트:    r*   mimeType
image/jpegdatajpeg.jpg.png
   ] 완료:  (, bytes, .1f   초)   ] 예외 발생: )printtimeGEMINI_API_BASEMODEL_IDr
   requestspoststatus_codeFALLBACK_MODEL_IDokr   r   getdumpsnextbase64	b64decodewith_suffixwrite_bytesnamelen	Exception)promptoutput_pathlabelstarturlr   payloadresponseurl2r8   r%   r   
image_partr.   
text_parts	mime_typeimage_bytesext
final_pathelapsedes                        r/   generate_bg_image_apikeyrf     s   	GE7O
PQIIKE XhZ/D^DT
UC12G 01231GV3DEG
(==gGSQ ?2GE7)H:^HDXDXCYYfgxfyz{%&h/@.AAVWeVfgD}}T7RUVH{{GE7.1E1E0Fc(--X\Y\J]I^_`}}XXlB/
GE7"A$**TBRSWTWBXAYZ[1!!)R044WbAAeA4H
5:Jfk!%%+JJJGE7"KJWYXYNK[\]|,00\J	&&z,'?'GH)+f ,,S1
{+))+%wj(9C<LQ;OxX_`cWddhij K  w/s34sE   B6I) AI) >I) 	I$I$-I) BI) $I) )	J2JJc                   t        d| d       t        j                         }t         dt         d}d| dd}dd	| igigd
ddgid}	 t	        j
                  |||d      }|j                  dv rRt        d| dt         d|j                   dt                t         dt         d}	t	        j
                  |	||d      }|j                  s,t        d| d|j                   d|j                  dd         y|j                         }
|
j                  dg       }|s(t        d| dt        j                  |
      dd         y|d   j                  di       j                  dg       }t        d |D        d      }|9|D cg c]  }d	|v s|j                  d	d       }}t        d| d|dd         y|d    j                  d!d"      }t        j                  |d    d#         }d$|v rd%nd&}|j!                  |      }|j#                  |       t        j                         |z
  }t        d| d'|j$                   d(t'        |      d)d*|d+d,	       |S c c}w # t(        $ r}t        d| d-|        Y d}~yd}~ww xY w).uC   Bearer 토큰으로 Gemini API 배경 이미지를 생성합니다.r   u4   ] Bearer 토큰 방식으로 이미지 생성 중...r   z:generateContentzBearer r   )Authorizationr   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   Nr   r%   r&   r   r'   c              3  *   K   | ]  }d |v s|  ywr)   r+   r,   s     r/   r0   z+generate_bg_image_bearer.<locals>.<genexpr>q  r1   r2   r3   r4   r5   r*   r6   r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   )rC   rD   rE   rF   rG   rH   rI   rJ   rK   r   r   rL   rM   rN   rO   rP   rQ   rR   rS   rT   rU   )rV   rW   tokenrX   rY   rZ   r   r[   r\   r]   r8   r%   r   r^   r.   r_   r`   ra   rb   rc   rd   re   s                         r/   generate_bg_image_bearerrk   O  s   	GE7N
OPIIKEXhZ/?
@C"5'**G
  01231GV3DEG
'==gGSQ?2GE7)H:^HDXDXCYYfgxfyz{%&h/@.AAQRD}}T7RUVH{{GE7.1E1E0Fc(--X\Y\J]I^_`}}XXlB/
GE7"A$**TBRSWTWBXAYZ[1!!)R044WbAAeA4H
5:Jfk!%%+JJJGE7"KJWYXYNK[\]|,00\J	&&z,'?'GH)+f ,,S1
{+))+%wj(9C<LQ;OxX_`cWddhij K  w/s34sE   B0I! =AI! 	>I! 	II%I! <BI! I! !	J*J  Jc                   t        | ||      }|r|S t        d| d       	 t        j                         }t	        | |||      }|r|S 	 t        d| dt                t        j                         rXt        j                  }|j                  |      }t        j                  t        |       t        d| d|j                          |S t        dt               # t
        $ r}t        d| d|        Y d}~d}~ww xY w)u>   배경 이미지를 생성하거나 폴백을 사용합니다.r   u:   ] API 키 방식 실패 → Bearer 토큰 방식 시도...u   ] Bearer 토큰 획득 실패: Nu4   ] Gemini 생성 실패 → 폴백 이미지 사용: u   ] 폴백 복사 완료: u   폴백 이미지도 없음: )rf   rC   gcloud_authget_access_tokenrk   rU   FALLBACK_BGexistssuffixrQ   shutilcopy2rS   RuntimeError)rV   rW   rX   resultrj   re   rb   fallback_dests           r/   get_or_generate_bgrw     s    &fk5AF 
GE7T
UVC,,.)&+ueLM  
GE7N{m
\]  #//4[-0w6}7I7I6JKL9+GHH  Cw=aSABBCs   %C 	D %C;;D c           
        d|j                          }| j                  |      }|j                  |d       t        d|        t        d| d| d       t	               5 }|j
                  j                  d	d
g      }		 |	j                  ||d      }
|
j                  d|j                          d       |
j                  d       |j                  j                  dd       |
j                  t        |      ddd||d       t        d|        |	j                          	 ddd       y# |	j                          w xY w# 1 sw Y   yxY w)uY   HTML 템플릿에 배경 이미지 URL을 삽입하고 Playwright로 PNG 캡처합니다.zfile://)bg_urlzutf-8)encodingu   [HTML] 저장 완료: u   [캡처] Playwright로 xu    캡처 중...z--no-sandboxz--disable-gpu)args)widthheight)viewportnetworkidle)
wait_untili	  Tr   pngr   )r{   yr}   r~   )pathtypeclipu   [캡처] 저장 완료: N)resolveformat
write_textrC   r   chromiumlaunchnew_pagegotowait_for_timeoutparentmkdir
screenshotstrclose)html_contentbg_pathhtml_output_pathpng_output_pathr}   r~   ry   html_filledr.   browserpages              r/   capture_html_to_pngr     s_    w()*F%%V%4K g>	"#3"4
56 
#E7!F8>
BC		 a**##./)J#K	##u-O#PDII 0 8 8 :;<IW!!$'""(((EOO_!5EQ&IO  ,_,=>?MMO  MMO s%   #E	BD4E	4EE		Ec            	     l   t        d       t        d       t        d       g } t        d       t        dz  }t        t        j                  d            }|r|d   }t        d|j                          nt        t        |d      }t        d|j                  z   z  }|j                         r5|j                         j                  |j                         j                  k  rt        j                  ||       t        d	       t        d
z  }t        dz  }	 t        t        |||dd       |j                         j                   dz  }t        d| d|dd       | j#                  dd|ddf       t        d       t        dz  }
t        t        j                  d            }|r|d   }t        d|j                          nt        t,        |
d      }t        d|j                  z   z  }|j                         r5|j                         j                  |j                         j                  k  rt        j                  ||       t        d       t        dz  }t        dz  }	 t        t.        |||dd        |j                         j                   dz  }t        d!| d|dd       | j#                  dd|ddf       t        d#       t        d$       t        d       | D ]  \  }}}t        d%| d&| d'|         t        d(       t1        t        j3                               D ]2  }|j                         j                   dz  }t        d)| d*|dd       4 t5        d+ | D              }|st7        j8                  d,       y y # t$        $ rJ}t        d|        dd l}	|	j)                          | j#                  ddt+        |      f       Y d }~ed }~ww xY w# t$        $ rJ}t        d"|        dd l}	|	j)                          | j#                  ddt+        |      f       Y d }~ld }~ww xY w)-Nz<============================================================uK   Cell-1 인카금융서비스 '정당한 보상' 배너 생성 시작 (v3.2)u2   
[Step 1] 1080x1080 배경 이미지 생성 중...zbg-cell1-1080zbg-cell1-1080.*r   u&   [배경1] 기존 이미지 재사용: 1080u+   
[Step 2] 1080x1080 배너 렌더링 중...zmeta-feed-1080x1080.htmlzmeta-feed-1080x1080.pngi8  )r   r   r   r   r}   r~   i   u   [배너1] 완료: r=   z.0fz KB)SUCCESSz KBu   [배너1] 실패: FAILEDu1   
[Step 3] 1200x628 배경 이미지 생성 중...zbg-cell1-1200zbg-cell1-1200.*u&   [배경2] 기존 이미지 재사용: 1200u*   
[Step 4] 1200x628 배너 렌더링 중...zgoogle-resp-1200x628.htmlzgoogle-resp-1200x628.pngi  it  u   [배너2] 완료: u   [배너2] 실패: z=
============================================================u   결과 요약z  [z] u    — u   
산출물 경로:z  z  (c              3  .   K   | ]  \  }}}|d k(    yw)r   Nr+   )r-   _ss      r/   r0   zmain.<locals>.<genexpr>#  s     7GAq!i7s      )rC   TMP_DIRlistglobrS   rw   BG_PROMPT_1080
OUTPUT_DIRrq   rp   statst_mtimerr   rs   r   HTML_1080x1080st_sizeappendrU   	traceback	print_excr   BG_PROMPT_1200HTML_1200x628sortediterdirallsysexit)resultsbg1080_pathexisting_1080bg1080
bg1080_outhtml_1080_pathpng_1080_pathsize_kbre   r   bg1200_pathexisting_1200bg1200
bg1200_outhtml_1200_pathpng_1200_pathfnamestatusinfofsizeall_oks                         r/   mainr     s   	(O	
WX	(OG 

?@O+K&789Mq!6v{{mDE#NKH >?J*//"3"<"<v{{}?U?U"UVZ(	
89"<<N!::MF'+)	
  $$&..5"=/GC=EF19S>QRS 

>?O+K&789Mq!6v{{mDE#NKH>?J*//"3"<"<v{{}?U?U"UVZ(	
78"==N!;;MG&+)	
  $$&..5"=/GC=EF2I'#c?RST 
/	/	(O& 2vtF82eWE$012 

 J&&() )vvx$&1#Sc
$'() 7w77F i  F"1#&')--/18SVDEEFD  G"1#&')--/2Hc!fEFFGs2   AN
 %AO  
	O?OO 	P3)?P..P3__main__)r3   )rV   r   rW   r   rX   r   returnPath | None)
rV   r   rW   r   rj   r   rX   r   r   r   )rV   r   rW   r   rX   r   r   r   )r   r   r   r   r   r   r   r   r}   intr~   r   r   None)r   r   )*__doc__
__future__r   rO   r   osr   rD   rr   pathlibr   rG   playwright.sync_apir   __file__r   TOOL_DIRr   insertr   rm   r   r   r   ro   rE   GEMINI_SCOPErF   rJ   environrL   r
   r   r   r   r   rf   rk   rw   r   r   __name__r+       r/   <module>r      sp   #   	 
     / >   3x= ! HI
 
    -
X

+.A
A dT * fg ED6,   02[\
T . Z|oh5p6rI>  	
   
HZz zF r   