
    i_                     l   U d 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mZ  ed      Z e	e      ej                  vr"ej                  j                  d e	e             ddlmZ ddlmZ 	 ddlZddlmZ dd	lmZ dZdZ ed      Zedz  ZdZdddZdddddddZe e!e	e	f   e	f   e"d<   g dZ#e$e!e%e	e	e	f      e"d<   ddd d!d"d#d$d%d&d'	Z&e e	e	f   e"d(<   d)d)d*d+Z'e e	e	f   e"d,<   d-d.d/d+Z(e e	e	f   e"d0<   d1d2gZ)d3e	d4dfd5Z*d6e	d7e	d4e+fd8Z,d7e	d4e e!e	e	f   e+f   fd9Z-dFd:Z.d;ed<e	d=e	d>e	d?e	d4e fd@Z/dAe d4dfdBZ0dFdCZ1d4ejd                  fdDZ3e4dEk(  r4 e3       Z5e5jl                  r e.         ej0                  d        e1        yy# e$ r(Z ed
e         ej0                  d       Y dZ[3dZ[ww xY w)Gu  
Meta Marketing API - 크리에이티브 9개 + 광고 18개 생성 스크립트
기존 캠페인/광고세트/이미지 해시를 활용하여 크리에이티브와 광고를 생성한다.

담당: 엔키 (개발5팀)
생성일: 2026-04-06
관련 태스크: task-1491.2 (task-1491.1에서 생성된 광고세트/이미지해시 사용)

실행:
    python meta_creative_ad_setup.py
    python meta_creative_ad_setup.py --dry-run
    N)datetime)Pathz/home/jay/workspace)load_env_keys)MetaAdsClient)Ad)	AdAccountu5   [ERROR] 필수 패키지를 찾을 수 없습니다:    z/home/jay/workspace/.env.keysz https://graph.facebook.com/v25.0z*/home/jay/workspace/teams/dev5-team/outputzmeta_creative_ad_result.jsonzhttps://incar-top1.tistory.com120244493213800104120244493213880104)   리드   잠재고객120244493234600104120244493237840104120244493238350104120244493218590104120244493230370104120244493230950104))r      인카금융서비스)r   GA)r      서울대보험쌤)r   r   )r   r   )r   r   	ADSET_MAP)	)r	   cell-1-incar-fairr      공정한수수료)   cell-2-incar-leaderr      리더지원)   cell-3-incar-supportr      업무지원)   cell-4-ga-fairr   r   )   cell-5-ga-leaderr   r   )   cell-6-ga-supportr   r   )   cell-7-snu-fairr   r   )   cell-8-snu-leaderr   r   )	   cell-9-snu-supportr   r   	CELL_INFO 431704f93354d64849ca9b950b1a58f8 860a2df81739d8311146d028bb43aa8b 2639214e727e766249d3d72c7745201b b358438a4a136d6173dc4dacad1c7aa4 d0ed5f2ebdea82adf9bcc4b6d99b938b 03762a14491ff58b4d8a4ccbdff978c5 d7b07745b21c842034957a737de0ad89 8e43730baea0377fdbfde0bb9fef06d0 0d3c288465dd9e6a93003c9bf7d19aad)	r   r   r   r!   r#   r%   r'   r)   r+   IMAGE_HASH_MAPMETA_PAGE_ID_RECRUITMETA_PAGE_ID_SNUr   r   r   BRAND_TO_PAGE_ENVuz   인카금융서비스와 함께 성공적인 보험 커리어를 시작하세요! 경력직/신입 모두 환영합니다.um   GA(General Agency)에서 당신의 보험 전문가 역량을 키워보세요. 지금 바로 지원하세요!uq   서울대 출신 보험 전문가들과 함께하는 성장의 기회! 서울대보험쌤 팀에 합류하세요.BRAND_MESSAGESr   r   msgreturnc                 l    t        j                         j                  d      }t        d| d|         y)u%   타임스탬프 포함 콘솔 로그.z%H:%M:%S[z] N)r   nowstrftimeprint)r<   tss     _/home/jay/workspace/.worktrees/task-2116-dev1/teams/dev5-team/scripts/meta_creative_ad_setup.pylogrE      s,    		 	 	,B	AbTC5/    page_idaccess_tokenc           
         t          d|  }d|d}	 t        j                  ||d      }|j                         }d|v r(t	        d|  d|d   j                  d	|d                 y
|j                  dd      }t	        d|j                  d       d|        y# t
        $ r}t	        d|  d|        Y d}~y
d}~ww xY w)u/  
    Graph API로 페이지 존재 여부를 확인한다.

    GET https://graph.facebook.com/v25.0/{page_id}?fields=id,name&access_token=...

    Args:
        page_id: 검증할 Facebook 페이지 ID
        access_token: Meta 액세스 토큰

    Returns:
        bool: 페이지 유효 여부
    /zid,namefieldsrH      paramstimeouterroru+     [ERROR] 페이지 검증 실패 (page_id=): messageFname   (이름 없음)u     페이지 확인: id=idz  name=Tu6     [ERROR] 페이지 검증 중 예외 발생 (page_id=N)_GRAPH_API_BASErequestsgetjsonrE   	Exception)rG   rH   urlrO   respdata	page_namees           rD   validate_page_idra      s     Qwi
(C$F||C;yy{d?=gYc$w-J[J[\egklsgtJuIvwxHHV%67	%dhhtn%5WYKHI DWISQRPSTUs   AB &2B 	B="B88B=c                 *   i }t         j                         D ]  \  \  }}}t         d| }d| d}	 t        j                  ||d      }|j                         }d|v r5t        d| d| d	| d
|d   j	                  d|d                 d|||f<   nN|j	                  dd      }	|j	                  dd      }
t        d|	 d|j	                  d       d|
        d|||f<    |S # t        $ r%}t        d| d| d
|        d|||f<   Y d}~d}~ww xY w)u   
    기존 광고세트 6개의 존재 여부를 확인한다.

    GET /v25.0/{adset_id}?fields=id,name,status

    Returns:
        dict: (campaign_type, brand) → 유효 여부
    rJ   zid,name,statusrK   rM   rN   rQ   u     [WARN] 광고세트 없음 (_z, id=rR   rS   FrT   rU   statusUNKNOWNu     광고세트 확인:   id=rV   z	  status=Tu0     [WARN] 광고세트 확인 중 예외 발생 (N)r   itemsrW   rX   rY   rZ   rE   r[   )rH   validitycampaign_typebrandadset_idr\   rO   r]   r^   
adset_nameadset_statusr`   s               rD   verify_adsetsrn      sd    -/H,5OO,= 5( !8*-&(
	5<<FB?D99;D$4]O1UG5QYPZZ]G}((DMBCE 49-/0!XXf.?@
#xx)<-j\txx~>NiXdWefg37-/0'50 O	  	5B=/QRSXRYY\]^\_`a/4HmU+,	5s   B/C$$	D-DDc                  @   	 t        t               t        j                  j                  dd      } t        j                  j                  dd      }t        j                  j                  dd      }t        d       t        d       t        d	       t        d
       t        d       t        d|  d       t        dt         d       t        d| d       t        dt         d       t        d       t        d       t        j                         D ]  \  \  }}}t        d| d| d|         t        d       t        D ]j  \  }}}}t        |   }	t        j                  j                  |	d|	 d      }
d| d| d| }t        |   }t        d| d|        t        d| d|
        l t        d       t        D ]c  }dD ]\  }t        ||f   }t        D cg c]  \  }}}}||k(  s||||f }}}}}|D ]"  \  }}}}| d| d | }t        d| d!|        $ ^ e t        d"       t        d#t                t        d$       t        d%|         t        d&|        t        d'|        t        d(       y)# t        $ r Y w xY wc c}}}}w )*u7   실제 API 호출 없이 실행 구조를 출력한다.r7   u    (META_PAGE_ID_RECRUIT 미설정)r8   u   (META_PAGE_ID_SNU 미설정)META_PIXEL_IDu   (META_PIXEL_ID 미설정)zB
=================================================================u-     DRY-RUN 모드 — 실제 API 호출 없음zA=================================================================u=   
[1] MetaAdsClient 초기화 + 토큰/계정 유효성 확인u.   
[2] 페이지 ID 유효성 검증 (Graph API)z    META_PAGE_ID_RECRUIT ()z
      GET z/{page_id}?fields=id,namez    META_PAGE_ID_SNU (u-       ※ 검증 실패 시 스크립트 중단uY   
[3] 기존 광고세트 6개 존재 확인 (GET /v25.0/{adset_id}?fields=id,name,status)z    rc   rf   uD   
[4] 크리에이티브 9개 생성 (기존 이미지 해시 사용)(u    미설정)   리쿠르팅_Cellz    Cellz  z           image_hash=z
  page_id=uF   
[5] 광고 18개 생성 (각 광고세트 × 3개 크리에이티브)r9   _Cellz  adset_id=u   
[6] 결과 JSON 저장u       → u   
환경변수 현황:z    META_PAGE_ID_RECRUIT = z    META_PAGE_ID_SNU     = z    META_PIXEL_ID        = zC
=================================================================
N)r   _ENV_KEYS_PATHr[   osenvironrY   rB   rW   r   rg   r,   r:   r6   CAMPAIGN_TYPESOUTPUT_FILE)page_recruitpage_snupixel_idri   rj   rk   cell_nocell_diranglepage_envrG   creative_nameimg_hashnodbabrand_cellsrc   ad_names                       rD   dry_run_reportr      s   n% ::>>"8:\]Lzz~~02PQHzz~~o/JKH	/	
9:	(O	
JK	
;<	&|nA
67	J''B
CD	"8*A
./	J''B
CD	
9:	
fg,5OO,= =(]O1UG5
;<= 

QR+4 F'5%$U+**..Qxj+DE+G9AeWAeWE!(+	M?34&xj
7)DEF 

ST' =J 	=E -!78H<ETT[RAqeB1a=TKT$/ = Aq*O1UG5	BWI[
;<=	== 

$%	H[M
"#	
"#	'~
67	'z
23	'z
23	
 !c  J Us   J "J2J	JJ
ad_accountrk   creative_idrT   r|   c                 p   t         j                  j                  |t         j                  j                  |t         j                  j                  d|it         j                  j
                  dt         j                  j                  dg|gdgi}| j                  g |       t        dfd             }|S )u   
    facebook_business SDK의 AdAccount.create_ad를 사용하여 광고를 생성한다.
    MetaAdsClient에 create_ad 메서드가 없으므로 SDK를 직접 사용한다.
    r   PAUSEDoffsite_conversion)zaction.typefb_pixel)rL   rO   export_all_datac                      t               S )N)dict)	ad_results   rD   <lambda>z_create_ad.<locals>.<lambda>5  s    tI rF   )	r   FieldrT   rk   creativerd   tracking_specs	create_adgetattr)r   rk   r   rT   r|   rO   r^   r   s          @rD   
_create_adr     s     	t
8
M;7

 45%J"
F $$Bv$>IO$57NOQDKrF   resultc                     t         j                  dd       t        t        dd      5 }t	        j
                  | |dd       d	d	d	       t        d
t                y	# 1 sw Y   xY w)u&   결과를 JSON 파일로 저장한다.T)parentsexist_okwzutf-8)encodingFr   )ensure_asciiindentNu   결과 저장 완료: )
OUTPUT_DIRmkdiropenry   rZ   dumprE   )r   fs     rD   _saver   >  sZ    TD1	k3	1 ;Q		&!%:;
 ./; ;s   AA(c                  j   t        j                         j                         di i g g g d} t        d       	 t	               }t        j                  j                  d
d      }	 j                         }|j                  dd      sBt        d       | d   j                  ddd       t        |        t        j                  d       t        d|j                  d       d       	 j                         }|j                  dt        j                  j                  dd            }|j!                  d      sd| }|| d<   t        d| d|j                  dd       d|j                  d              t#        | d         }t        j                  j                  d d!      }t        j                  j                  d"d      }	t        j                  j                  d#d      }
|	st        d$       |
st        d%       t        d&       i }|	r|	|d"<   |
r|
|d#<   i }|j%                         D ]o  \  }}t'        ||      }|||<   ||d'| d(   |<   |r%t        d)| d*| d+       | d   j                  d,||d-d.       t        |        t        j                  d       q |	|	|
d/}t        d0       t)        |      }|j%                         D ci c]  \  \  }}}| d1| t*        ||f   |d2 c}}}| d3<   |j%                         D cg c]  \  }}|r	||f }}}|r+|D ]&  \  \  }}}t        d4| d1| d5t*        ||f    d       ( t        d6       i }t,        D ]  \  }}}}t.        |   }|j                  |d      }d7| d1| d1| }t0        |   } |s/t        d8| d9| d       | d   j                  d:|d;| dd<       h	 j3                  |||| t4        =      }!|!j                  dd      }"|"||<   | d>   j                  ||"|||||d?       t        d@| dA|"         t        dE       dF}#t6        D ]  }$d/D ]  }t*        j                  |$|f      }%|%st        dG|$ d1| d       /t,        D &'cg c]  \  }&}}'}|'|k(  s|&||'|f }(}'}}&}|(D ]  \  }}}}|j                  |      }"|"s*t        dH| d       | d   j                  dI||$|dJdK       E|$ d1| dL| })	 t9        ||%|"|)|M      }*|*j                  dd      }+| dN   j                  |)|+|$|||%|"dO       |#dz  }#t        dP|) dA|+          
 t        dS|# dT       t        dU       t        |        t        dV       t        dW       t        dX| d           t        dYt;        | d>          dZ       t        d[t;        | dN          dZ       t        d\t;        | d          d]       t        d^t<                t        dV       y	# t
        $ rY}t        d|        | d   j                  dt        |      d       t        |        t        j                  d       Y d	}~d	}~ww xY w# t
        $ r9}t        d|        | d   j                  dt        |      d       Y d	}~d	}~ww xY w# t
        $ rY}t        d|        | d   j                  dt        |      d       t        |        t        j                  d       Y d	}~d	}~ww xY wc c}}}w c c}}w # t
        $ r>}t        dB| dC|        | d   j                  d:||t        |      dD       Y d	}~ d	}~ww xY wc c}}'}}&w # t
        $ r?}t        dQ|) dC|        | d   j                  dI|)|%|"t        |      dR       Y d	}~d	}~ww xY w)_u7   크리에이티브 9개 + 광고 18개를 생성한다. )	timestamp
account_idpage_validationadset_validation	creativesadserrorsu"   [1] MetaAdsClient 초기화 중...u*   [ERROR] 클라이언트 초기화 실패: r   init)steprQ   r	   NMETA_ACCESS_TOKENis_validFu6   [ERROR] 액세스 토큰이 유효하지 않습니다.check_tokenzis_valid=Falseu     토큰 유효 확인 (app_id=app_idrq   u7   [WARN] 토큰 유효성 확인 실패 (계속 진행): rV   META_AD_ACCOUNT_IDact_r   u     계정 확인: u	     통화=currencyUSDu	     상태=account_statusu%   [ERROR] 계정 정보 조회 실패: get_account_inforp   1461062562329883r7   r8   uI   [WARN] META_PAGE_ID_RECRUIT 환경변수가 설정되지 않았습니다.uE   [WARN] META_PAGE_ID_SNU 환경변수가 설정되지 않았습니다.u(   [2] 페이지 ID 유효성 검증 중...)rG   validr   u$   [ERROR] 페이지 ID 검증 실패 (=u#   ). 스크립트를 중단합니다.validate_pageu   페이지 검증 실패)r   env_keyrG   rQ   r9   u:   [3] 기존 광고세트 존재 여부 확인 중 (6개)...rc   )rk   r   r   u%     [WARN] 광고세트 조회 실패: z (id=u'   [4] 크리에이티브 생성 (9개)...rs   u(     [SKIP] 크리에이티브 스킵 (Cellu   ): page_id 없음 (브랜드=create_creativeu   page_id 없음 (브랜드=)r   cellrQ   )rT   
image_hashrG   rS   linkr   )rT   rV   r   rj   r   r   rG   u$     크리에이티브 생성 완료: rf   u,     [ERROR] 크리에이티브 생성 실패 (rR   )r   r   rT   rQ   u<   [5] 광고 생성 (18개 — 각 광고세트에 3개씩)...r   u-     [SKIP] 광고 스킵: 광고세트 없음 (u3     [SKIP] 광고 스킵: 크리에이티브 없음 (r   u5   creative_id 없음 (크리에이티브 생성 실패))r   r   ri   rj   rQ   rt   )r   rk   r   rT   r|   r   )rT   rV   ri   rj   r}   rk   r   u     광고 생성 완료: u      [ERROR] 광고 생성 실패 ()r   rT   rk   r   rQ   u     총 u   개 광고 생성 완료u   [6] 결과 저장 중...z7=======================================================u   실행 완료 요약u
     계정: u     크리에이티브: u
   개 생성u
     광고: u
     오류: u   건u     결과 파일: )r   r@   	isoformatrE   r   r[   appendstrr   sysexitrv   rw   rY   r   r   
startswithr   rg   ra   rn   r   r,   r6   r;   r   LANDING_URLrx   r   lenry   ),r   clientr`   rH   
token_infoaccount_infor   r   r|   rz   r{   page_ids_to_check
page_validr   pidr   brand_page_mapadset_validityctrj   r   kvinvalid_adsetsrc   creative_mapr}   r~   r   r   rG   r   rS   r   r   ad_countri   rk   r   r   r   r   r   ad_ids,                                               rD   runr   K  s    \\^--/F ,- ::>>"5r:L
J'')
~~j%0HI8##]EU$VW&MHHQK-jnnX.F-GqIJ..0!%%dBJJNN;OQS,TU
$$V,
|,J)|
|9\5E5EjRW5X4Y Z"&&'789;	
 6,/0J zz~~o/ABH::>>"8"=Lzz~~0"5HWXST
 23(*4@0108,-"$J)//1 
#C6&
79<x-P !'*6wiqEhij8##(WWpq &MHHQK
 ".&&N DE"<0N #1"6"6"8" "KR $awiU&<uMM"F
 *8)=)=)?IAqq!fINI, 	dNKR7t1UG5TVX]S^I_H``abc	d 12 $&L+4 0'5%#H-
 $$UB/+G9AeWAeWE ':7)C`af`gghij8##-$9%B 	--"%  . H #,,tR0K%0L";&&)%$""",&
 6}oU;-XYM0j FGH' :J 9	E }}mU%;<HCM?RSTYSZZ[\] S\jj8NHa_`di_iB!U3jKj+6 0'1a*..x8"MhZWXYZ8$++$/$,-:%*%\ *O1UG5	B  *#-!)$/$!)!I &MM$3E5M(($+"'-:%*'.(0+6
 MH27)5HIK09	:x &
234
 "#	&M M*VL)*+,
 VK%8!9 :*EF*S'(
34*S)*+3/0
K=)*MY  8<=x#a& ABf	   JEaSIJxQ HIIJ  3A378x);c!f MNf	n"
 Jh  		>}oSQRPSTU8##-$) V	 		2 kP ! 
:7)3qcJK8$++$/$+(0+6%(V 
s   
W< "BY! %BZ& 
!\
\\A\6]"]"%A]*<	YAYY!	Z#*.ZZ#&	\/A\\	]!3]]*	^2	34^-	-^2	c                      t        j                  dt         j                  t              } | j	                  dddd       | j                         S )NuM   Meta Marketing API 크리에이티브 9개 + 광고 18개 생성 스크립트)descriptionformatter_classepilogz	--dry-run
store_trueFu7   실제 API 호출 없이 실행 구조만 출력한다.)actiondefaulthelp)argparseArgumentParserRawDescriptionHelpFormatter__doc__add_argument
parse_args)parsers    rD   r   r   Q  sS    $$c <<F
 F	   rF   __main__)r=   N)7r   r   rZ   rv   r   r   pathlibr   
_WORKSPACEr   pathinsertutils.env_loaderr   utils.meta_ads_clientr   rX   facebook_business.adobjects.adr   %facebook_business.adobjects.adaccountr   ImportErrorr`   rB   r   ru   rW   r   ry   r   CAMPAIGN_IDSr   r   tuple__annotations__r,   listintr6   r:   r;   rx   rE   boolra   rn   r   r   r   r   	Namespacer   __name__argsdry_run rF   rD   <module>r     s     	 
   '(
z?#(("HHOOAs:' * /1? 14>?
99. #( *>*&:/C0,@)	4c3h$% 
.	4c3S()* 
 <=>8:;9;<
"S#X 
& 4
 ,% 4S>  Z
y N"S#X  N+S T c   J# #U38_d-B(C #V6"|  	
  
B0$ 04 0~LH&&  z<D||E {  	A!
EFCHHQKKs   +F F3F..F3