
    i0                       U 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mZ ddl	m
Z
 ddlZddlZ ed      Zedz  Zed	z  Zd
ZdZdZddddZded<   ddZdZ	 d	 	 	 	 	 	 	 	 	 ddZ	 	 	 	 	 	 	 	 	 	 ddZddZedk(  r e        yy)uo  Gemini Nano Banana Pro (gemini-3-pro-image-preview) 이미지 생성 스크립트.

SA(서비스 계정) Bearer 토큰으로 Gemini API REST를 직접 호출합니다(방법 3).
Pro 모델 호출 실패(403/404) 시 gemini-3.1-flash-image-preview로 자동 fallback합니다.
시나리오 A, B, C에 대한 보험 GA 리크루팅 광고 이미지를 생성합니다.
    )annotationsN)datetime)Path)Anyz;/home/jay/workspace/tools/ai-image-gen/output/v3-gemini-prozresults.jsonz
errors.logzgemini-3-pro-image-previewz0https://generativelanguage.googleapis.com/v1betaz3https://www.googleapis.com/auth/generative-languageu\  Create a premium insurance agency recruitment advertisement image.

COMPOSITION: Rule of thirds, subject at right vertical third. Golden hour backlighting.
SUBJECT: Korean male, early 30s, tailored navy double-breasted suit, confident half-smile, chin slightly raised. Standing by floor-to-ceiling window.
ENVIRONMENT: 100th-floor Seoul panoramic office. Minimalist interior, warm oak accents. Seoul skyline (Lotte Tower, Han River) visible through glass.
LIGHTING: Rim lighting from golden hour sun behind subject. Soft fill light on face at 45°. Subtle volumetric light rays through window.
COLOR: Navy blue dominant, warm gold accents. Split-complementary: navy + amber + cream.
CAMERA: Shot on Phase One IQ4 150MP, 85mm f/1.4 portrait lens. Shallow depth of field, background softly bokeh'd.
TEXT: Korean text "새로운 시작" in bold sans-serif, upper right. Small subtitle below.
STYLE: Like a Rolex or Patek Philippe advertisement. No stock photo aesthetic. No watermark. No clipart.
MOOD: Aspirational, confident, premium corporate recruitment.
ASPECT: 1:1 square format, 1080x1080px for Meta advertising.u  Create a premium insurance consultant personal branding image.

COMPOSITION: 3/4 angle portrait, subject centered. Rembrandt triangle lighting on face.
SUBJECT: Korean male consultant, mid-40s, round gold-rimmed glasses, warm genuine smile. Navy blazer over cream turtleneck. Arms crossed confidently.
ENVIRONMENT: Luxury private consultation room. Dark walnut bookshelf with leather-bound books behind. Mahogany desk with neat documents. Brass desk lamp.
LIGHTING: 45° key light creating Rembrandt triangle. Warm ambient fill from desk lamp. Hair light separating subject from background.
COLOR: Warm palette — amber, cream, dark chocolate brown. Rich earth tones.
CAMERA: Hasselblad H6D-100c, 110mm f/2 lens. Creamy bokeh on background. Sharp focus on eyes.
TEXT: None — pure image quality focus.
STYLE: Like a private banking advertisement for UBS or Goldman Sachs. Trustworthy, sophisticated, premium.
MOOD: Warm trust, deep expertise, approachable authority.
ASPECT: 1:1 square, 1080x1080px.u  Create a cinematic career transition motivational image for insurance professionals.

COMPOSITION: Wide angle, subject as small silhouette walking toward bright doorway. Leading lines from corridor walls converging on door.
SUBJECT: Business professional silhouette walking from dark corridor toward brilliantly lit open door. One hand reaching toward the light.
ENVIRONMENT: Dark corporate corridor with cold fluorescent remnants behind. Warm, golden, volumetric god-rays streaming through the open door ahead. Dust particles visible in light beams.
LIGHTING: Extreme contrast. Behind: cold blue-grey. Ahead: warm golden volumetric rays. Cinematic chiaroscuro.
COLOR: Teal-and-orange cinematic grade. Cold background desaturation, warm foreground saturation.
CAMERA: ARRI Alexa 65, Ultra Prime 16mm wide angle. Deep depth of field. Dramatic perspective.
TEXT: Korean text "지금, 당신의 차례" centered in warm light area. Clean sans-serif.
STYLE: Christopher Nolan / Denis Villeneuve film still. Cinematic 2.39:1 feel cropped to 1:1. No stock photo. Dramatic.
MOOD: Hope, courage, decisive moment, new beginning.
ASPECT: 1:1 square, 1080x1080px.ABCzdict[str, str]	SCENARIOSc                    t        j                         j                         }t        t        dd      5 }|j                  d| d|  d       ddd       t        d|         y# 1 sw Y   xY w)	u+   에러 로그를 파일에 기록합니다.autf-8encoding[] 
Nz[ERROR] )r   now	isoformatopen
ERRORS_LOGwriteprint)message	timestampfs      W/home/jay/workspace/.worktrees/task-2116-dev1/tools/ai-image-gen/gemini_pro_generate.py	log_errorr   G   sc    ((*I	j#	0 .A	!I;b	,-.	HWI
. .s   A%%A.zgemini-3.1-flash-image-previewc                    t          d| d}d|  dd}dddigidd|igigd	d
dgid}t        j                  ||||      S )uL   Gemini generateContent REST API를 호출하고 Response를 반환합니다.z/models/z:generateContentzBearer zapplication/json)AuthorizationzContent-Typepartstexta  You are an image generation AI. Generate high-quality images based on the user's description. NEVER render the description text or prompt text as visible text within the image. The image should visually depict the described scene, concept, or composition. If the description mentions text to include in the image (like Korean text), render only that specific text naturally integrated into the design.responseModalitiesIMAGETEXT)systemInstructioncontentsgenerationConfig)headersjsontimeout)GEMINI_API_BASErequestspost)tokenmodel_idpromptr+   urlr)   payloads          r   _call_gemini_restr4   R   s     XhZ/?
@C"5'**G l	
  01231GV3DEG  ==gGWMM    c                   t         }t        d| d| d       t        j                         }t        | ||      }|j                  dv r5t        d| d|j                   dt
                t
        }t        | ||      }|j                          t        j                         |z
  }|j                         }|j                  dg       }	|	s$t        dt        j                  |      d	d
        |	d   j                  di       j                  dg       }
d	}|
D ]
  }d|v s|} n |5|
D cg c]  }d|v s|j                  dd       }}t        d|d	d        |d   j                  dd      }|d   d   }t        j                  |      }d|v rdnd}|j                  j                         |k7  r|j                  |      }|j!                  |       |j#                         j$                  }t        d| d|j&                   d|dd|dd| d       ||dt)        j*                         j-                         |j&                  t/        |      t1        |d      ||d	d 
S c c}w )!u   Gemini API REST 호출로 이미지를 생성하고 PNG 파일로 저장합니다.

    Pro 모델(MODEL_ID) 호출 실패(403/404) 시 FALLBACK_MODEL_ID로 자동 재시도합니다.
    u   [시나리오 u*   ] 이미지 생성 요청 중... (모델: ))i  i  u!   ] Pro 모델 접근 실패 (HTTP u!   ). Fallback 모델로 재시도: 
candidatesu.   응답에 candidates가 없습니다. 응답: N,  r   contentr!   
inlineDatar"    uA   이미지 데이터가 응답에 없습니다. 텍스트 파트:    mimeTypez
image/jpegdatajpegz.jpg.pngu
   ] 완료: z (,z bytes, .1fu
   초, mime=)sa_bearer_token_generative-language_scope
scenariomodelauth_methodr   filenamefilepathtime_secondsfile_size_bytes	mime_typeerror)MODEL_IDr   timer4   status_codeFALLBACK_MODEL_IDraise_for_statusr*   getRuntimeErrordumpsbase64	b64decodesuffixlowerwith_suffixwrite_bytesstatst_sizenamer   r   r   strround)r/   r1   output_pathrF   active_model
start_timeresponseelapsedr?   r8   r!   
image_partpartp
text_partsrM   	image_b64image_bytesext	file_sizes                       r   generate_image_via_gemini_apiro   q   s    L	N8*$N|n\]
^_J f=H z)XJ&GH\H\G] ^-->,?A	
 )$UL&AiikJ&G#==?D,+JKDJJW[L\]a^aLbKcdeeqMi,00"=E(,J 4J
 16FA&A+aeeFB'F
Fbcmnpopcqbrstt-11*lKI-f5I""9-K i'&VC!S(!--c2K(  "**I	

*[-=-=,>fYqMQYZabeYffpqzp{{|}
 B\\^--/$$$gq)$ % Gs   (	I2Ic                    t         j                  dd       t        d       t        d       t        dt         dt         d       t        dt                 t        d	       t        d       t        d
       	 t        j                  t              } t        dt        |        d       g }t        j                         }dD ]  }t        |   }t         d| dz  }|t        dt!        j"                         j%                         d| dt'        |      ddddd
}t        d| d       t        d|dd  d       	 t)        | |||      }	|j+                  |	       |j7                  |        t        j                         |z
  }
t!        j"                         j%                         t        dt9        |
d!      |d"}t;        t<        d#d$%      5 }t?        j@                  ||d&d!'       ddd       t        d(       t        d)       t        d       tC        d* |D              }t        |      |z
  }t        d+| d,| d-       t        d.|
d/d0       t        d1t<                tD        jG                         rt        d2tD                |D ]g  }|jI                  d      d3nd4}|jI                  d5      }|jI                  d6      }|r|d7d8nd9}|r|d:d0nd9}t        d;|d<    d=| d>| d>|        i y# t        $ r7}dt        |      j                   d| }t        |       t        d      |d}~ww xY w# t,        j.                  $ rQ}d| d|j0                  j2                   d|j0                  j4                  dd  }t        |       ||d<   Y d}~>d}~wt        $ r9}d| d t        |      j                   d| }t        |       ||d<   Y d}~~d}~ww xY w# 1 sw Y   xY w)?u+   메인: 3개 시나리오 이미지 생성.T)parentsexist_okz<============================================================u.   Gemini Nano Banana Pro 이미지 생성 시작u   모델: u    (실패 시 fallback: r7   u   출력 디렉토리: u;   인증 방법: SA Bearer 토큰 (generative-language scope)u2   
[인증] SA 서비스 계정 토큰 획득 중...u*   [인증] SA 토큰 획득 성공 (길이: z chars)u   SA 토큰 획득 실패: z:    Nr   gemini_pro_rA   rD   rE   z
[u   ] 시나리오 처리 중...u     프롬프트: P   z...u   시나리오 u    HTTP 오류: z - i  rN   u	    오류: r=   )run_timestamprG   rH   total_time_seconds	scenarioswr   r   F)ensure_asciiindentz=
============================================================u   생성 결과 요약c              3  D   K   | ]  }|j                  d       d  yw)rN   Nrs   )rT   ).0rs     r   	<genexpr>zmain.<locals>.<genexpr>  s     EaaeeGn.DEs     u   성공: u   /3, 실패: z/3u   총 소요 시간: rC   u   초u   결과 저장: u   에러 로그: OKFAILrL   rK   rB   z byteszN/Az.2fz  [rF   r   z | )%
OUTPUT_DIRmkdirr   rO   rR   gcloud_authget_service_account_tokenGEMINI_SCOPElen	Exceptiontype__name__r   
SystemExitrP   r   r   r   r   r`   ro   updater-   	HTTPErrorre   rQ   r"   appendra   r   RESULTS_JSONr*   dumpsumr   existsrT   )r/   e	error_msgresultstotal_startrF   r1   rb   result
gen_resulttotal_elapsedresults_datar   success_count
fail_countr~   statussizetsize_strtime_strs                        r   mainr      s   TD1	(O	
:;	HXJ56G5H
JK	!*
./	GI	(O 

?@#55lC:3u:,gNO %'G))+K#  8$ [
$#?? !F!113%hZt4K( #"
 	H:9:; S12
	(6ufkS[\JMM*% 	vA D IIK+-M "113B#M15$L 
lC'	2 Aa		,a@A 
/	
 !	(OE7EEMW-J	H]O<
|2
>?	c2#
67	OL>
*+
|,- Iw/Vuu&'EE.!(,d1XV$%$%aWC=5AjM?"VHCzXJGHII  #/Q0@0@/AA3G	)m"#> !! 	('zAJJDZDZC[[^_`_i_i_n_nosps_t^uvIi 'F7O 	('z47;K;K:LBqcRIi 'F7O	($A AsI   <1K9 >L<O#9	L92L44L9<O ANO '.OO #O-__main__)r   r`   returnNone)r9   )
r/   r`   r0   r`   r1   r`   r+   intr   zrequests.Response)
r/   r`   r1   r`   rb   r   rF   r`   r   zdict[str, Any])r   r   )__doc__
__future__r   rW   r*   rP   r   pathlibr   typingr   r   r-   r   r   r   rO   r,   r   r   __annotations__r   rR   r4   ro   r   r    r5   r   <module>r      s   #        OP
N*,&
'DD
	G
	+
	+9(	> (V  5  	NNN N 	N
 N>FFF F 	F
 FRZIz zF r5   