
    i8                        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
  ed      Z ed      Zedz  Zed	z  Zed
z  ZdZdZdZddZdZddZddZddZedk(  r e        yy)u   
Concept #20 — 좌우 분할 솔루션형 (Split-Layout Solution) 광고 이미지 생성기
Gemini AI 배경 + HTML/CSS Playwright 오버레이 하이브리드 파이프라인
    )annotationsN)Path)sync_playwrightz&/home/jay/workspace/tools/ai-image-genzC/home/jay/workspace/output/meta-ads/concept-catalog/20-split-layoutzbg.pngztemplate.htmlz
sample.pngz0https://generativelanguage.googleapis.com/v1betaz3https://www.googleapis.com/auth/generative-languageut  A thoughtful Korean professional man in his late 30s, wearing business casual attire (white shirt, dark blazer), standing slightly turned to the left side, gaze directed slightly downward with a pensive, introspective expression — not sad, but quietly concerned about career stagnation. The figure is positioned in the LEFT HALF of a square frame, leaving the right half as empty space. Background is a softly blurred modern office in cool grey-blue tones. Cool neutral side lighting from upper left. Shallow depth of field. Photorealistic high-quality editorial photography. No text. No logos. Square 1:1 format, 1080x1080px.c            
     <   t         j                  j                  dt        t                     ddl} t        d       | j                  t              }t        dt        |       d       g d}|D ]o  }t        d|        t         d| d	}d
| dd}ddt        igigdddgid}	 t        j                  |||d      }|j                  dv rt        d|j                   d       {|j                          |j#                         }	|	j%                  dg       }
|
st        d       |
d   j%                  di       j%                  dg       }t'        d |D        d      }|st        d       |d   j%                  dd       }t)        j*                  |d   d!         }t,        j/                  |       t        d"t,         d#t        |      d$d%| d&       t,        c S  t1        d'      # t        j                   $ r}t        d| d       Y d}~d}~ww xY w)(u?   Gemini API로 배경 이미지를 생성하고 저장합니다.r   Nu2   [1/3] Gemini API로 배경 이미지 생성 중...u'         SA 토큰 획득 성공 (길이: z chars))zgemini-3-pro-image-previewzgemini-3.1-flash-image-previewz)gemini-2.0-flash-preview-image-generationu         모델 시도: z/models/z:generateContentzBearer zapplication/json)AuthorizationzContent-TypepartstextresponseModalitiesIMAGETEXT)contentsgenerationConfigx   )headersjsontimeout)i  i  z      HTTP u    — 다음 모델로 시도u         HTTP 오류: 
candidatesu3         candidates 없음 — 다음 모델로 시도contentc              3  *   K   | ]  }d |v s|  yw)
inlineDataN ).0ps     \/home/jay/workspace/.worktrees/task-2116-dev1/tools/ai-image-gen/generate_concept20_split.py	<genexpr>z&generate_background.<locals>.<genexpr>Y   s     A|q/@1As   	u<         이미지 데이터 없음 — 다음 모델로 시도r   mimeTypez
image/jpegdatau         배경 저장: z (,z bytes, mime=)u>   모든 Gemini 모델 실패 — 배경 이미지 생성 불가)syspathinsertstrBASE_DIRgcloud_authprintget_service_account_tokenGEMINI_SCOPElenGEMINI_API_BASE	BG_PROMPTrequestspoststatus_coderaise_for_status	HTTPErrorr   getnextbase64	b64decodeBG_PATHwrite_bytesRuntimeError)r%   tokenmodelsmodel_idurlr   payloadresper   r   r   
image_part	mime_typeimage_bytess                  r   generate_backgroundrB   -   s-   HHOOAs8}%	
>?11,?E	3CJ<w
GHF  &%hZ01 !(3CD&ug..

 "VY$7#89:!57H I

	==gGSQD:-D$4$4#55QRS!!#
 yy{XXlB/
GH1!!)R044WbAAeA4H
PQ|,00\J	&&z,'?'GHK(%gYb[1A!0DMR[Q\\]^_M&P W
XX- !! 	's*FGH	s   *A G.+G..HHHu  <!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <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;
    }}

    * {{ margin: 0; padding: 0; box-sizing: border-box; }}
    body {{
      width: 1080px;
      height: 1080px;
      overflow: hidden;
      font-family: 'Pretendard', 'Noto Sans KR', sans-serif;
      -webkit-font-smoothing: antialiased;
    }}
    .container {{
      display: flex;
      width: 1080px;
      height: 1080px;
    }}

    /* ── 좌측 패널 ── */
    .left-panel {{
      width: 540px;
      height: 1080px;
      position: relative;
      overflow: hidden;
    }}
    .left-panel img {{
      width: 100%;
      height: 100%;
      object-fit: cover;
      filter: saturate(0.65) brightness(0.92);
    }}
    .left-vignette {{
      position: absolute;
      inset: 0;
      background:
        radial-gradient(ellipse at 30% 30%, rgba(28,43,58,0.35) 0%, transparent 60%),
        linear-gradient(to bottom, transparent 40%, rgba(28,43,58,0.80) 100%);
    }}
    .left-hook {{
      position: absolute;
      bottom: 64px;
      left: 40px;
      right: 32px;
      color: #FFFFFF;
      font-size: 42px;
      font-weight: 700;
      line-height: 1.4;
      letter-spacing: -0.5px;
      text-shadow: 0 2px 12px rgba(0,0,0,0.80), 0 4px 24px rgba(0,0,0,0.60);
      word-break: keep-all;
    }}

    /* ── 우측 패널 ── */
    .right-panel {{
      width: 540px;
      height: 1080px;
      background: linear-gradient(160deg, #FFFBF0 0%, #FFF0E6 100%);
      display: flex;
      flex-direction: column;
      justify-content: center;
      padding: 56px 48px;
    }}
    .solution-label {{
      font-size: 18px;
      font-weight: 600;
      color: #E8600A;
      margin-bottom: 36px;
      letter-spacing: -0.2px;
      word-break: keep-all;
    }}
    .benefits-list {{
      display: flex;
      flex-direction: column;
      gap: 32px;
      margin-bottom: 48px;
    }}
    .benefit-item {{
      display: flex;
      align-items: flex-start;
      gap: 14px;
    }}
    .benefit-icon {{
      font-size: 22px;
      margin-top: 8px;
      flex-shrink: 0;
      line-height: 1;
    }}
    .benefit-icon.check {{ color: #E8600A; }}
    .benefit-icon.warn {{ color: #C8860A; }}
    .benefit-label {{
      font-size: 18px;
      font-weight: 500;
      color: #5A6A7A;
      line-height: 1.4;
      margin-bottom: 4px;
      word-break: keep-all;
    }}
    .benefit-value {{
      font-size: 36px;
      font-weight: 800;
      color: #1A2E4A;
      line-height: 1.2;
      letter-spacing: -1px;
      word-break: keep-all;
    }}
    .benefit-value .highlight {{ color: #E8600A; }}
    .benefit-value.amber {{ font-size: 30px; color: #C8860A; }}
    .cta-button {{
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 10px;
      background: #E8600A;
      color: #FFFFFF;
      font-size: 22px;
      font-weight: 700;
      height: 64px;
      border-radius: 8px;
      margin-bottom: 18px;
      letter-spacing: -0.3px;
      word-break: keep-all;
    }}
    .org-label {{
      font-size: 15px;
      font-weight: 400;
      color: #8A9AAA;
      text-align: center;
      word-break: keep-all;
    }}
  </style>
</head>
<body>
  <div class="container">
    <div class="left-panel">
      <img src="file://{bg_path}" alt="person">
      <div class="left-vignette"></div>
      <div class="left-hook">열심히는 하는데<br>소득은<br>제자리걸음인가요?</div>
    </div>
    <div class="right-panel">
      <div class="solution-label">T.O.P 사업단의 파격적 정착지원금</div>
      <div class="benefits-list">
        <div class="benefit-item">
          <span class="benefit-icon check">✓</span>
          <div>
            <div class="benefit-label">신입 정착지원금</div>
            <div class="benefit-value">최대 <span class="highlight">1,000만원</span></div>
          </div>
        </div>
        <div class="benefit-item">
          <span class="benefit-icon check">✓</span>
          <div>
            <div class="benefit-label">경력직 지원</div>
            <div class="benefit-value">직전연봉 <span class="highlight">50%</span>까지</div>
          </div>
        </div>
        <div class="benefit-item">
          <span class="benefit-icon warn">⚠</span>
          <div>
            <div class="benefit-label">조건 변경 예정</div>
            <div class="benefit-value amber">2026년 7월</div>
          </div>
        </div>
      </div>
      <div class="cta-button">지금 상담 신청하기 <span>→</span></div>
      <div class="org-label">T.O.P 사업단 | 인카금융서비스 코스닥 상장</div>
    </div>
  </div>
</body>
</html>
c                    t        d       t        j                  t        | j	                                     }t
        j                  |d       t        dt
                t
        S )uN   배경 이미지 경로를 주입한 HTML 템플릿 파일을 생성합니다.u/   [2/3] HTML 오버레이 템플릿 생성 중...)bg_pathzutf-8)encodingu         템플릿 저장: )r&   HTML_TEMPLATEformatr#   resolveTEMPLATE_PATH
write_text)rD   html_contents     r   create_html_templaterL   7  sS    	
;< ''GOO4E0F'GL\G<	$]O
45    c                    t        d       |j                  j                  dd       t               5 }|j                  j                         }	 |j                  ddd      }d| j                          }|j                  |d	       |j                  d
       |j                  t        |      d       t        d|        |j                          	 ddd       y# |j                          w xY w# 1 sw Y   yxY w)uW   Playwright 헤드리스 브라우저로 HTML을 렌더링하여 PNG로 저장합니다.u2   [3/3] Playwright로 최종 이미지 캡처 중...Tparentsexist_oki8  )widthheight)viewportzfile://networkidle)
wait_untili	  png)r!   typeu         최종 이미지 저장: N)r&   parentmkdirr   chromiumlaunchnew_pagerH   gotowait_for_timeout
screenshotr#   close)template_pathoutput_pathr   browserpagetemplate_urls         r   capture_final_imagerg   D  s    	
>?TD9		 a**##%		##tt-L#MD$]%:%:%<$=>LIIl}I=!!$'OO[!1O>3K=ABMMO  MMO s$   C4A6CC4C11C44C=c                 H   t        d       t        d       t        d       t        d       t        j                         } t        j                  dd       t	               }t        |      }t        |t               t        j                         | z
  }t        j                         j                  dz  }t                t        d       t        d|dd	       t        d
|        t        d|        t        dt                t        d|dd       t        d       y )Nz<============================================================uB   Concept #20 — 좌우 분할 솔루션형 광고 이미지 생성uD   Gemini AI 배경 + HTML 오버레이 하이브리드 파이프라인TrO   i   u   완료! 총 소요시간: z.1fu   초u   배경 이미지: u   HTML 템플릿: u   최종 출력: u   파일 크기: z.0fz KB)
r&   time
OUTPUT_DIRrZ   rB   rL   rg   FINAL_OUTPUTstatst_size)
start_timerD   rb   elapsedsize_kbs        r   mainrq   \  s    	(O	
NO	
PQ	(OJTD1 "#G )1M |4iikJ&G!))D0G	G	(O	&wsm3
78	wi
()	]O
,-	OL>
*+	OGC=
,-	(OrM   __main__)returnr   )rD   r   rs   r   )rb   r   rc   r   rs   None)rs   rt   )__doc__
__future__r   r3   r    ri   pathlibr   r,   playwright.sync_apir   r$   rj   r5   rI   rk   r*   r(   r+   rB   rF   rL   rg   rq   __name__r   rM   r   <module>rz      s   
 #  
    / 89WX

x
_,L(DDl 
7Y|IX0@ zF rM   