
    i                      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	Z	ddl
mZ ddlmZ ddlmZmZmZmZ ddlmZ ddlmZmZmZmZ dd	lmZ  ee      j;                         j<                  j<                  Z e e      e	jB                  vr"e	jB                  jE                  d e e             dd
l#m$Z$m%Z% ddl&m'Z'm(Z( ddl)m*Z*m+Z+ ddl,m-Z- ddl.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z=m>Z?m@Z@mAZAmBZBmCZCmDZDmEZEmFZFmGZGmHZHmIZImJZJmKZKmLZLmMZMmNZN  ej                  eP      ZQ ee      j;                         j<                  ZReRdz  ZSddZTedd       ZU eddeU      ZVeVj                  edgddgdg       eVj                  d e e eS            d       edz  ZYeYj                  dd       eVj                  d e e eY            d       eVj                  d      d        Z\eVj                  d       d!        Z]eVj                  d"      d#        Z^eVj                  d$      d%        Z_eVj                  d&      dd'       Z`eVj                  d$      dd(       ZbeVj                  d&      dd)       ZdeVj                  d&      dd*       ZfeVj                  d+      dd,       ZgeVj                  d-      dd.       Zhdd/ZieVj                  d0      d1        ZjeVj                  d0      dd2       ZkeVj                  d3      ddd4       ZleVj                  d5      d6        ZmeVj                  d5      dd7       ZneVj                  d8      d9        ZoeVj                  d:      d;        ZpeVj                  d:      dd<       ZqeVj                  d=      dd>       ZreVj                  d?      dd@       ZseVj                  dA      dB        ZteVj                  dC      ddD       ZueVj                  dE      dF        ZveVj                  dG      ddH       ZweVj                  dI      ddJ       ZxeVj                  dK      ddL       ZyeVj                  dM      ddN       ZzeVj                  dO      dP        Z{eVj                  dQ      dR        Z|eVj                  dQ      ddS       Z}eVj                  dT      ddU       ZeVj                  dV      dW        ZeVj                  dX      dY        ZeVj                  dZ      dd[       ZeVj                  dZ      dd\       ZeVj                  d]      dd^       ZeVj                  d_      dd`       ZeVj                  da      ddb       ZeVj                  dc      ddd       ZeVj                  de      ddf       ZeVj                  dg      ddh       ZeVj                  di      ddj       ZeVj                  dk      ddl       ZeVj                  dm      ddn       ZeVj                  do      ddp       ZeVj                  dq      ddr       Zdads ZddtZ	 	 	 	 	 	 	 	 	 	 dduZeVj                  dv      ddw       ZeVj                  dx      ddy       ZeVj                  dz      dd{       ZeVj                  d|      d}        ZeVj                  d~      dd       ZeVj                  d      d        ZeVj                  d      dd       ZeVj5                  d      dd       Zy)z
FastAPI application for the Video Production Pipeline web interface.

Provides REST endpoints for configuration and a WebSocket endpoint
for real-time pipeline execution with event streaming.
Persistent SQLite storage via web/database.py.
    )annotationsN)asynccontextmanagerPath)FastAPIRequest	WebSocketWebSocketDisconnect)CORSMiddleware)FileResponseJSONResponseResponseStreamingResponse)StaticFiles)build_configlist_available_templates)PipelineEventPipelineMode)	save_jsonsave_markdown)Pipeline)character_countclose_dbdelete_characterdelete_grok_accountdelete_imagedelete_projectget_characterget_character_by_nameget_next_grok_accountget_projectget_project_imagesget_project_videosget_project_audiosget_settingset_settingget_all_settingsinit_dbinsert_characterinsert_grok_accountinsert_projectlist_characterslist_grok_accountslist_projectsupdate_characterupdate_image_pathupdate_image_statusupdate_project_resultupdate_project_statusupsert_imageupsert_videoupsert_audiostaticc                   K   ddl } t                d{   }|dkD  ryt        dz  }|j                         syt	        |j                  d            D ]J  }	 ddl}|j                  |j                  d            }t        t        | j                               |j                  d|j                        |j                  dd	      |j                  d
g       |j                  dg       |j                  dg       |j                  dd	      |j                  dd	      |j                  dd	      |j                  dd	      |j                  dd	      |j                  dd	      d       d{    t        j                  d|j                  d|j                               M y7 7 ;# t         $ r"}t        j#                  d||       Y d}~zd}~ww xY ww)z8Seed character DB from JSON templates if table is empty.r   Ncharacter_templatesz*.jsonutf-8encodingnamephysical_description style_keywordsnegative_keywordshard_prohibitionscamera_settingslighting_settings	pose_ruleenvironment_ruleclothing_ruleanatomical_highlight_rulesT)idr=   r>   r@   rA   rB   rC   rD   rE   rF   rG   rH   
is_defaultzSeeded character: %sz$Failed to seed character from %s: %s)uuidr   _PROJECT_ROOTexistssortedglobjsonloads	read_textr)   struuid4getstemloggerinfo	Exceptionwarning)rK   counttemplates_dirpath_jsondataexcs          0/root/.openclaw/workspace/visionaryfx/web/app.py_seed_characters_from_jsonrb   T   s    !##Eqy!$99M!}))(34 N	N ;;t~~w~?@D"tzz|$XXfdii0%)XX.Db%I#xx(8"="&((+>"C"&((+>"C $):B ?"&((+>"C((;3!%*<b!A"hh;+/884PRT+U   KK.0KL)N $   	NNNA4MM	NsM   GF"AGDF')F%*4F'G%F''	G0GGGGc                  K   t                d{    t                d{    d t                d{    y7 .7 7 	w)zDModern lifespan context manager replacing on_event startup/shutdown.N)r(   rb   r   )apps    ra   lifespanre   w   s:      )OO
$
&&&	
*	 & s.   A?AAAAAAAzVideo Production Pipelinez2.0.0)titleversionre   *T)allow_originsallow_credentialsallow_methodsallow_headersz/static)	directory)r=   outputparentsexist_okz/output/c                 @   K   t        t        t        dz              S w)Nz
index.html)r   rS   _STATIC_DIR     ra   indexrw      s     K,6788s   z/healthc                    K   dddS w)z!Health check endpoint for Docker.healthy
postgresql)statusdatabaseru   ru   rv   ra   health_checkr}      s       \::s   z/api/templatesc                 f   K   t                d{   } d| D cg c]  }|d   	 c}iS 7 c c}w w)zEList available character templates (legacy, redirects to characters).N	templatesr=   r,   )charscs     ra   get_templatesr      s5      "##EU3!F)344 $3s   1*	1,11z/api/charactersc                 :   K   t                d{   } d| iS 7 w)z"List all characters with metadata.N
charactersr   )r   s    ra   api_list_charactersr      s#      "##E%   $   	z/api/characters/{char_id}c                Z   K   t        |        d{   }|t        ddid      S |S 7 w)zGet a single character by ID.NerrorCharacter not found  status_code)r   r   )char_idchars     ra   api_get_characterr      s7      w''D|W&;<#NNK (s   +)+c                6  K   ddl }	 | j                          d{   }|j	                  dd      j                         }|st        dd	id      S t        |       d{   }|rt        dd
| did      S t        |j                               }t        |||j	                  dd      |j	                  dg       |j	                  dg       |j	                  dg       |j	                  dd      |j	                  dd      |j	                  dd      |j	                  dd      |j	                  dd      |j	                  dd             d{    t        |       d{   }t        |d      S 7 V# t        $ r t        ddid      cY S w xY w7 37 H7 7w)zCreate a new character.r   Nr   Invalid JSON  r   r=   r?   zName is requiredzCharacter 'z' already exists  r>   r@   rA   rB   rC   rD   rE   rF   rG   rH   )rI   r=   r>   r@   rA   rB   rC   rD   rE   rF   rG   rH      )rK   rP   rY   r   rU   stripr   rS   rT   r)   r   )requestrK   bodyr=   existingr   r   s          ra   api_create_characterr      s     H\\^# 88FB%%'DW&89sKK*400HD6)9:;
 	
 $**,G
!XX&<bAxx 0"5((#6;((#6;!2B7((#6;((;+"4b9hh3#'88,H"#M   w''D#..? $ HWn53GGH 1 (sh   FE4 E1E4 ?FF C,FFFF F1E4 4FFFFFFc                  K   t        |        d{   }|t        ddid      S 	 |j                          d{   }h d}|j	                         D ci c]  \  }}||v s|| }}}|st        dd	id      S d
|v r/t        |d
          d{   }|r|d   | k7  rt        ddid      S t        | |       d{    t        |        d{   S 7 7 # t        $ r t        ddid      cY S w xY wc c}}w 7 l7 A7 0w)z(Update individual fields of a character.Nr   r   r   r   r   r   >   r=   rE   rG   r@   rC   rF   rB   rD   rA   r>   rH   zNo valid fields to updater=   rI   zName already takenr   )r   r   rP   rY   itemsr   r/   )	r   r   r   r   allowedkvupdatesr   s	            ra   api_update_characterr      s%     w''D|W&;<#NNH\\^#G !%

=1Wq!t=G=W&ABPSTT .wv??'1*> ?SQQ
7G
,,,w'''C (
 $ HWn53GGH  > @ -'s   DCDC CC  DC9$C9))DC?,D?D DDDC C63D5C66
DDDc                  K   t        |        d{   }|t        ddid      S |j                  d      r0t        |d         }|j	                         r|j                  d       t        |        d{    d	| d
S 7 n7 w)zDelete a character.Nr   r   r   r   thumbnail_pathT)
missing_okdeletedr{   rI   )r   r   rU   r   rM   unlinkr   )r   r   thumbs      ra   api_delete_characterr     s      w''D|W&;<#NNxx !T*+,<<>LLDL)
7
###w// ( $s"   BB A$B6B7
BBz,/api/characters/{char_id}/generate-thumbnailc                `  K   t        |        d{   }|t        ddid      S |j                  dd      }|st        ddid	      S d
j                  |j                  dg             }d| d| dt        dz  dz  }|j                  dd       ||  dz  	 fd}t        j                  |       d{    t        | dt              i       d{    dd|  d| dS 7 7 /7 # t        $ r2}t        j                  d|        t        dd| id      cY d}~S d}~ww xY ww)z3Generate a thumbnail preview image for a character.Nr   r   r   r   r>   r?   z(No physical description to generate fromr   z, r@   zgPortrait shot, neutral standing pose, studio lighting, dark gradient background, centered composition,  z9. Photorealistic, 8K, sharp focus, no text, no watermark.r_   
thumbnailsTro   .pngc                 n    ddl m}   |        5 }|j                         d d d        y # 1 sw Y   y xY w)Nr   )GoogleFlowImageProvider)providers.google_flow_providerr   generate)r   provprompt
thumb_paths     ra   _genz$api_generate_thumbnail.<locals>._gen?  s1    N(* 2dfj12 2 2s   +4r   	generatedz/api/characters/z
/thumbnail)r{   thumbnail_urlr   z,Thumbnail generation failed for character %szGeneration failed:   )r   r   rU   joinrL   mkdirasyncio	to_threadr/   rS   rY   rW   	exception)	r   r   physstyle_kw	thumb_dirr   r`   r   r   s	          @@ra   api_generate_thumbnailr   $  sr     w''D|W&;<#NN88*B/D@As
 	
 yy"2B78H!!%a* B	C  &5IOOD4O0y--JU	2 %%%w)93z?(KLLL "/y
C
 	
E (< 	&L  UGQW(;C5&ABPSTTUsd   D.C*B	D.C0 <C,=C0 C.C0 )D.,C0 .C0 0	D+9'D& D+!D.&D++D.z#/api/characters/{char_id}/thumbnailc                   K   t        |        d{   }|t        ddid      S |j                  dd      }|rt        |      j	                         st        ddid      S t        t        |            S 7 ew)	z$Serve a character's thumbnail image.Nr   r   r   r   r   r?   zNo thumbnail available)r   r   rU   r   rM   r   rS   )r   r   r   s      ra   api_serve_thumbnailr   S  sx      w''D|W&;<#NN*B/JT*-446W&>?SQQJ(( (s   A9A7A&A9c                T   t         dz  }|j                         r|j                         nd}t               }g }|j	                         D ]]  }d|v r|j                  dd      d   nd}|| v r+|j                  | d| |           |j                  |       M|j                  |       _ | j                         D ]   \  }}||vs|j                  | d|        " |j                  dj                  |      dz          | j                         D ]  \  }}|t        j                  |<    y)z8Update keys in the .env file and in the running process..envr?   =   r   
N)rL   rM   rR   set
splitlinessplitappendaddr   
write_textr   osenviron)	r   env_pathcontentfound	new_lineslinekeyr   r   s	            ra   _update_env_keysr   d  s!   v%H&.oo&7h  "RGEEI""$ #'*d{djja #'>uAgcl^45IIcNT"#  )1E>s!A3Z() 		),t34 1

1rv   z/api/settings/llmc                   K   t                d{   } | j                  d      xs  t        j                  j                  dd      }|j	                  dd      }t        |      dk(  r|d   nd	}t        |      dk(  r|d   n|d   }| j                  d
      xs  t        j                  j                  dd      }| j                  d      xs  t        j                  j                  dd      }|||t        |      t        |      dS 7 w)z3Return current LLM provider, model, and key status.N	llm_model	LLM_MODELopenai/gpt-4orr   r      r   openaiopenai_api_keyOPENAI_API_KEYr?   anthropic_api_keyANTHROPIC_API_KEY)providermodelr   has_openai_keyhas_anthropic_key)db_get_all_settingsrU   r   r   r   lenbool)db_settingsr   partsr   r   
openai_keyanthropic_keys          ra   get_llm_settingsr   ~  s      ,--K,\

{O0\IOOC#Eu:?uQxHE
aE!HU1XE!12ZbjjnnEUWY6ZJOO$78cBJJNNK^`b<cM z*!-0  .s   D	DC7D	c                  K   	 | j                          d{   }|j                  dd      j	                         }|j                  dd      j	                         }|j                  d	d      j	                         }|d
vrt        ddid      S |rV|dk(  r)t        d|d       d{    |t        j                  d<   n(t        d|d       d{    |t        j                  d<   |r| d| }nf|rbt                d{   }|j                  d      xs  t        j                  j                  dd      }|j                  dd      d   }| d| }nd}|r(t        d|d       d{    |t        j                  d<   |xsC t                d{   j                  d      xs  t        j                  j                  dd      }	d|	dS 7 # t        $ r t        ddid      cY S w xY w7 H7 "7 7 7 ew)z(Update LLM provider, API key, and model.Nr   r   r   r   r   r?   api_keyr   )r   	anthropicz(Provider must be 'openai' or 'anthropic'r   r   OpenAI API keyr   r   Anthropic API keyr   rr   r   r   r   r   LLM model identifierupdated)r{   r   )
rP   rY   r   rU   r   r&   r   r   r   r   )
r   r   r   r   r   r   r   currentcurrent_modelfinal_models
             ra   update_llm_settingsr     s    H\\^# xx
B'--/Hhhy"%++-GHHWb!'')E..@As
 	
 x.9IJJJ+2BJJ'(17<OPPP.5BJJ*+j%)		/11//+.^"**..o2^c1-b1j-1		+y2HIII"+

;p&9&; ;@@MpQSQ[Q[Q_Q_`kmoQpKk::I $ HWn53GGH K Q 2 	J !<s   G:G GG B
G:&G.'(G:G10G: G4A(G:)G6*(G:G8:G:G G+(G:*G++G:1G:4G:6G:8G:z/api/settings/llm/modelsc                  K   | dk(  rt                d{   }|j                  d      xs  t        j                  j                  dd      st	        ddid	      S 	 d
dlt        j                  fd       d{   }|j                  dk7  rt	        dd|j                   id	      S |j                         }t        |j                  dg       D cg c]  }d|d   v s|d    c}d      }d|dS | dk(  rt                d{   }|j                  d      xs  t        j                  j                  dd      st	        ddid	      S 	 d
dlt        j                  fd       d{   }|j                  dk7  rt	        dd|j                   id	      S |j                         }t        |j                  dg       D cg c]  }|d   	 c}d      }d|dS t	        ddid	      S 7 7 |c c}w # t        $ r"}t	        dt        |      id	      cY d}~S d}~ww xY w7 %7 c c}w # t        $ r"}t	        dt        |      id	      cY d}~S d}~ww xY ww)z2Fetch available models from the selected provider.r   Nr   r   r?   r   zOPENAI_API_KEY not configuredr   r   r   c                 6    j                  ddd  id      S )Nz https://api.openai.com/v1/modelsAuthorizationBearer    headerstimeoutrU   r   httpxs   ra   <lambda>z!list_llm_models.<locals>.<lambda>  s*    		6,y.AB "  rv      zOpenAI API error: i  r_   gptrI   T)reverse)r   modelsr   r   r   r   z ANTHROPIC_API_KEY not configuredc                 2    j                  d ddd      S )Nz#https://api.anthropic.com/v1/modelsz
2023-06-01)z	x-api-keyzanthropic-versionr   r   r  r  s   ra   r  z!list_llm_models.<locals>.<lambda>  s(    		9%,-9  "  rv   zAnthropic API error: zUnknown provider)r   rU   r   r   r   r  r   r   r   rP   rN   rY   rS   )	r   r   resr_   mr	  r`   r   r  s	          @@ra   list_llm_modelsr    sz     8/11//"23[rzz~~FVXZ7[9: 	F)) C #%# 23??2CDESV  88:D"&((62"6KQ%1T7:J4KF !)F;; 
[	 /11//"56a"**..I\^`:a<=3 	F))	 	C #%# 5coo5FGH #  88:D"&((62"67Q47F !,v>> "453GG 2 L  	F#c( 3EE	F 2	" 8  	F#c( 3EE	Fs   I+G:AI+! H G=.H 0I+1)H H 'H .H ;I+H3AI+ H= 8H69.H= 'I+()H= H8H= *I+=H  H 	H0H+%H0&I++H00I+6H= 8H= =	I(I#I(I+#I((I+z/api/settings/cookiesc                 *  K   t         dz  } t        j                  j                  dd      }t        j                  j                  dd      }t	        |      t	        |      t        |      dkD  r|dd dz   n|t        |      dkD  r
|dd dz   dS |dS w)	z,Check if Google Flow cookies are configured.r   GOOGLE_FLOW_SESSION_TOKENr?   GOOGLE_FLOW_CSRF_TOKEN   N...)has_session_tokenhas_csrf_tokensession_token_previewcsrf_token_preview)rL   r   r   rU   r   r   )r   sessioncsrfs      ra   get_cookies_statusr  	  s      v%Hjjnn8"=G::>>2B7D!']t*9<W9J"!5PW36t9r>d3Bi%/	  HL	 s   BBc                  K   	 | j                          d{   }t        |t              st        ddid      S d}d}|D ]6  }|j                  dd      }|j                  d	d      }|d
k(  r|}/|dk(  s5|}8 |st        ddid      S |st        ddid      S 	 t        d|d       d{    t        d|d       d{    t        ddd       d{    |t        j                  d<   |t        j                  d<   d|dd dz   |dd dz   dS 7 # t        $ r t        ddid      cY S w xY w7 7 s7 `# t        $ r1}t        j                  d       t        dd| id      cY d}~S d}~ww xY ww)z<Update Google Flow cookies from browser-exported JSON array.Nr   r   r   r    Expected a JSON array of cookiesr?   r=   valuez __Secure-next-auth.session-tokenz__Host-next-auth.csrf-tokenz;Cookie '__Secure-next-auth.session-token' not found in JSONz6Cookie '__Host-next-auth.csrf-token' not found in JSONgoogle_flow_session_tokenzGoogle Flow session cookiegoogle_flow_csrf_tokenzGoogle Flow CSRF cookieimage_providergoogle_flowActive image providerr  r  z'Failed to save Flow cookies to databaseFailed to save: r   r   r  r  )r{   r  r  )rP   rY   r   
isinstancelistrU   r&   r   r   rW   r   )r   r   session_token
csrf_tokencookier=   r  r`   s           ra   update_cookiesr(    s    H\\^# dD!89s
 	

 MJ zz&"%

7B'55!M22J ST
 	
 NO
 	

	R5}Fbccc2J@YZZZ*M;RSSS2?

.//9

+, !.s!3e!;("o5 U $ HWn53GGH> 	dZS  RBCW(8&>?SQQRs   E7D DD AE76&E7D: -D4.D: D6D: D8*D: E7D D1.E70D11E74D: 6D: 8D: :	E4&E/)E4*E7/E44E7z/api/settings/flow-auto-setupc                   K   t         j                  j                  dd      } t         j                  j                  dd      }| r|st        ddid      S 	 dd	lm}  || |       d
{   }|j                  d      rt        dd|d    id      S i }|j                  d      r|d   |d<   |j                  d      r|d   |d<   |rt        |       d|j                  d      t        |j                  d            |j                  d      rddS ddS 7 # t        $ r t        ddid      cY S t        $ r7}t        j                  d       t        dt        |      id      cY d
}~S d
}~ww xY ww)zGUse headless Playwright to auto-extract project_id and reCAPTCHA token.r  r?   r  r   z9Cookies must be configured first (session + CSRF tokens).r   r   r   )auto_setup_flow_credentialsNzAuto-setup failed: r   
project_idGOOGLE_FLOW_PROJECT_IDrecaptcha_tokenGOOGLE_FLOW_RECAPTCHA_TOKENokz,Flow API credentials extracted successfully!zcCould not extract project_id. Try generating an image manually on labs.google/fx first, then retry.)r{   r+  has_recaptchamessagezWPlaywright is not installed. Run: pip install playwright && playwright install chromiumzFlow auto-setup error)r   r   rU   r   providers.flow_token_servicer*  r   r   ImportErrorrY   rW   r   rS   )r%  r&  r*  resultr   r`   s         ra   flow_auto_setupr5  L  s     JJNN#>CM 8"=J
QR
 	

(BL2=*MM::g/w/@AB 
 ::l#06|0DG,-::'(5;<M5NG12W%  **\2!&**->"?@ ::l+ ?	
 		
 {	
 		
# N8  
r 	
 	
  B01Wc#h/SAABsm   AE6D )D*)D E6A?D E6D E6D E32E64E3<,E.(E3)E6.E33E6z/api/settings/grok-cookiesc                 ,  K   t                d{   } | D cg c]O  }|d   |d   |d   |d   |d   |d   |d   r|d   j                         nd|d	   r|d	   j                         ndd
Q c}t        |       t        d | D              dS 7 |c c}w w)z%Check if Grok cookies are configured.NrI   labeluser_id	is_activeusage_countdaily_usage_countlast_used_at
created_at)rI   r7  r8  r9  r:  r;  r<  r=  c              3  ,   K   | ]  }|d    s	d  ywr9  r   Nru   .0as     ra   	<genexpr>z*get_grok_cookies_status.<locals>.<genexpr>  s     <AQ{^a<s   
)accountstotalactive)r-   	isoformatr   sum)rD  rB  s     ra   get_grok_cookies_statusrI    s      ())H 
  g7Y<{^ /%&':%;AB>AR. 1 ; ; =X\=>|_ao779RV	
 X<<<  *
s!   BBBAB-!BBc                  K   	 | j                          d{   }t        |t              st        ddid      S d}d}d}|D ]>  }|j                  dd      }|j                  d	d      }|d
k(  r|}/|dk(  r|}7|dk(  s=|}@ |st        ddid      S |st        ddid      S |st        ddid      S d}|D ]-  }|j                  dd      dk(  s|j                  d	d      dd }/ 	 t        ||||       d{   }	t        ddd       d{    d|	d   |	d   |dS 7 # t        $ r t        ddid      cY S w xY w7 G7 4# t        $ r1}
t        j                  d       t        dd|
 id      cY d}
~
S d}
~
ww xY ww)z5Update Grok cookies from browser-exported JSON array.Nr   r   r   r   r  r?   r=   r  ssosso-rwx-useridzCookie 'sso' not found in JSONz!Cookie 'sso-rw' not found in JSONz#Cookie 'x-userid' not found in JSONr  )r7  	sso_tokensso_rw_tokenr8  video_providergrokActive video providerz'Failed to save Grok account to databaser"  r   addedrI   r7  )r{   
account_idr7  r8  )
rP   rY   r   r#  r$  rU   r*   r&   rW   r   )r   r   rN  rO  r8  r'  r=   r  r7  accountr`   s              ra   update_grok_cookiesrV    s    H\\^# dD!89s
 	

 ILG zz&"%

7B'5=IX LZG 67
 	
 9:
 	
 ;<
 	
 E 1::fb!Z/JJw+CR0E1R+%	
 
 *F4KLLL dm!	 w $ HWn53GGH\
 	M RBCW(8&>?SQQRs   FD( D%D( A#F AFF,E
 >E?E
 EE
 F%D( (E FEFE
 E
 
	F&E?9F:F?FFz'/api/settings/grok-cookies/{account_id}c                `   K   t        |        d{   }|st        ddid      S d| dS 7 w)zRemove a Grok account.Nr   zAccount not foundr   r   r   )r{   rT  )r   r   )rT  r   s     ra   remove_grok_accountrX    s;      (
33GW&9:LLz:: 4s   .,.z#/api/settings/grok-cookies/validatec                T  K   	 | j                          d{   }|j                  dd      j	                         }|j                  dd      j	                         }|j                  d	d      j	                         }|r|st        dd
id      S 	 ddl}|||d}|j                  d      4 d{   }|j                  d|       d{   }ddd      d{    j                  dk(  rd|ddS |j                  dv rdd|j                   ddS dd|j                   ddS 7 # t        $ r t        ddid      cY S w xY w7 7 7 r# 1 d{  7  sw Y   xY w# t        $ r7}	t        j                  d       t        dt        |	      id      cY d}	~	S d}	~	ww xY ww)z7Validate Grok cookies by making a lightweight API call.Nr   r   r   r   rN  r?   rO  r8  z'sso_token and sso_rw_token are requiredr   )rK  rL  rM  
   r  z,https://grok.com/rest/app-chat/conversations)cookiesr  TzCookies are valid)validusernamer1  )  i  FzAuthentication failed (HTTP )r]  r1  zUnexpected response (HTTP zGrok cookie validation errorr   )rP   rY   r   rU   r   r  AsyncClientr   rW   r   rS   )
r   r   rN  rO  r8  r  r\  clientrespr`   s
             ra   validate_grok_cookiesre    s    H\\^# b)//1I88NB/557Lhhy"%++-GL?@
 	

!B "

 $$R$0 	 	F> $  D	 	 s"#. 
 +9$:J:J9K1M  78H8H7IK Q $ HWn53GGH*		 	 	 	.  B78Wc#h/SAABs   F(D, D)D, A3F( E% 0E
1E% 4EEEE% EE% 4F(5 E% F(E% (F()D, ,EF(EF(
E% EE% E"EE"E% %	F%.,F F%F( F%%F(z/api/settings/grok-sessionc            
     :  K   t         j                  j                  dd      } t         j                  j                  dd      }t         j                  j                  dd      }t        | ||g      st	        ddid      S 	 d	d
lm}  |       4 d{   }|j                  j                  d       d{   }|j                          d{   }|j                  d| dddd|dddd|dddg       d{    |j                          d{   }|j                  dd       d{    |j                  d       d{    |j                  d       d{   }|j                          d{    ||rdnddcddd      d{    S 7 7 7 7 7 7 s7 \7 E7 /7 # 1 d{  7  sw Y   yxY w# t         $ r t	        ddid      cY S t"        $ r7}	t$        j'                  d       t	        dt)        |	      id      cY d}	~	S d}	~	ww xY ww)z4Validate if Grok session is active using Playwright.GROK_SSO_TOKENr?   GROK_SSO_RW_TOKENGROK_USER_IDr   z7Grok cookies not configured. Please save cookies first.r   r   r   )async_playwrightNT)headlessrK  z	.grok.comrr   )r=   r  domainr]   rL  rM  zhttps://grok.com/i0u  r[  domcontentloadedaA  
                () => {
                    // Check for profile button or user menu
                    const pfp = document.querySelector('img[alt="pfp"]');
                    const userMenu = document.querySelector('[aria-label="pfp"]');
                    return !!(pfp || userMenu);
                }
            zSession is activez'Session expired - please update cookiesra  zTPlaywright not installed. Run: pip install playwright && playwright install chromiumr   zGrok session validation error)r   r   rU   allr   playwright.async_apirj  chromiumlaunchnew_contextadd_cookiesnew_pagegotowait_for_load_stateevaluatecloser3  rY   rW   r   rS   )
rK  sso_rwr8  rj  pbrowsercontextpageis_logged_inr`   s
             ra   validate_grok_sessionr  %  s2     **..)2
.CZZ^^/4Fjjnn^R0GVW%&OP
 	

:B9#% ,	 ,	JJ--t-<<G#//11G %%"SKQTU (!'"- #	 !+!("- #	  $ !))++D))/)???**+=>>> "& 0 " L --/!! & />	O,	 ,	 ,	<1$ ,?> "K,	 ,	 ,	 ,	\  
o 	
 	
  B89Wc#h/SAABs&  A>HF? FF?  F*6F7F*F*F*9F:F*FF*,F -F*F"F*F$F*6F&7F*F? F(F? HF? F*F*F*F* F*"F*$F*&F*(F? *F<0F31F<8F? ;H<F? ?HHH!,HHHHHz/api/settings/leonardoc                  K   	 | j                          d{   }|j                  dd      j	                         }|j                  dd	      j	                         }|st        dd
id      S |dvrd	}|t
        j                  d<   |t
        j                  d<   	 t        d|d       d{    t        d|d       d{    t        ddd       d{    d|dS 7 # t        $ r t        ddid      cY S w xY w7 S7 @7 -# t        $ r1}t        j                  d       t        dd| id      cY d}~S d}~ww xY ww)z(Update Leonardo AI API key and settings.Nr   r   r   r   r   r?   
resolution720zAPI key is required)480r  LEONARDO_API_KEYLEONARDO_RESOLUTIONleonardo_api_keyzLeonardo AI API keyleonardo_resolutionzLeonardo video resolutionrP  leonardorR  z,Failed to save Leonardo settings to databaseFailed to save settings: r   r   )r{   r  
rP   rY   r   rU   r   r   r   r&   rW   r   )r   r   r   r  r`   s        ra   update_leonardo_settingsr  r  sV    H\\^# hhy"%++-G,.446JW&;<#NN'
 &-BJJ!"(2BJJ$%[,g7LMMM/=XYYY*J8OPPP   5 $ HWn53GGH$ 	NYP [GHW(A#&GHVYZZ[s   EC  CC  A=ED *C>+D ?D  D DD EC   C;8E:C;;E>D  D D 	D>&D93D>4E9D>>Ez/api/settings/leonardo/testc                 r  K   t        d       d{   xs  t        j                  j                  dd      } | st	        ddid      S 	 d	dl}|j                  d
      4 d{   }|j                  ddd|  d       d{   }|j                  dk(  r]|j                         }|j                  di g      d	   }d|j                  dd      |j                  dd      dcddd      d{    S |j                  dk(  rdddcddd      d{    S t	        dd|j                   i|j                        cddd      d{    S 7 A7 7 7 h7 E7 # 1 d{  7  sw Y   yxY w# t        $ r7}t        j                  d       t	        dt        |      id      cY d}~S d}~ww xY ww)z/Test Leonardo AI API key by fetching user info.r  Nr  r?   r   zLeonardo API key not configuredr   r   r      r[  z(https://cloud.leonardo.ai/api/rest/v1/mezapplication/jsonr   )acceptauthorizationr   r  user_detailsTapiConcurrencySlotsunknownr^  )r]  creditsr^  r_  FInvalid API keyr]  r   API error: zLeonardo API test errorr   )r%   r   r   rU   r   r  rb  r   rP   rY   rW   r   rS   )r   r  rc  rd  r_   r  r`   s          ra   test_leonardo_apir    s       233]rzz~~FXZ\7]G78
 	

B$$R$0 	 	F:0'.wi%8 $  D 3&yy{#xx=a@!+//0EyQ , 0 0R @	 	 	" !!S(!&1BC%	 	 	( $D,<,<+=>? $ 0 0)	 	 	 4		 	 	 	 	 	2  B23Wc#h/SAABs   F7E7F7
E4 $E%E4 (EEAE$E4 0E1E4 5F76E	E4 EE4 F7%E E4 EE4 F7E4 EE4 E4 E4 E1%E(&E1-E4 0F71E4 4	F4=,F/)F4*F7/F44F7z/api/settings/pollinationsc                `  K   	 | j                          d{   }|j                  dd      j	                         }|j                  dd	      j	                         }|j                  d
d      j	                         }|j                  dd      j	                         }|r|t
        j                  d<   |t
        j                  d<   |t
        j                  d<   |t
        j                  d<   	 |rt        d|d       d{    t        d|d       d{    t        d|d       d{    t        d|d       d{    d|||dS 7 1# t        $ r t        ddid      cY S w xY w7 k7 X7 E7 2# t        $ r1}t        j                  d       t        dd| id      cY d}~S d}~ww xY ww)z)Update Pollinations API key and settings.Nr   r   r   r   r   r?   image_modelfluxvideo_modelseedance	tts_voicenovaPOLLINATIONS_API_KEYPOLLINATIONS_IMAGE_MODELPOLLINATIONS_VIDEO_MODELPOLLINATIONS_TTS_VOICEpollinations_api_keyPollinations API keypollinations_image_modelPollinations image modelpollinations_video_modelPollinations video modelpollinations_tts_voicePollinations TTS voicez0Failed to save Pollinations settings to databaser  r   r   )r{   r  r  r  r  )r   r   r   r  r  r  r`   s          ra   update_pollinations_settingsr    s    H\\^# hhy"%++-G((=&1779K((=*5;;=Kf-335I -4

)*-8BJJ)*-8BJJ)*+4BJJ'([4g?UVVV4kC]^^^4kC]^^^2I?WXXX ""	 9 $ HWn53GGH& W^^X [KLW(A#&GHVYZZ[s   F.E EE CF.+E1 =E)>E1 E+E1 'E-(E1 <E/=E1 F.E E&#F.%E&&F.)E1 +E1 -E1 /E1 1	F+:&F& F+!F.&F++F.z /api/settings/pollinations/imagec                  K   	 | j                          d{   }|j                  dd      j	                         }|j                  dd	      j	                         }|j                  d
d	      j	                         }|j                  dd      j	                         }|t
        j                  d<   |t
        j                  d<   |t
        j                  d<   |r|t
        j                  d<   	 t        d|d       d{    t        d|d       d{    t        d|d       d{    |rt        d|d       d{    t        ddd       d{    d|||d S 7 F# t        $ r t        ddid      cY S w xY w7 7 o7 \7 G7 4# t        $ r1}t        j                  d       t        dd| id      cY d}~S d}~ww xY ww)!z#Update Pollinations Image settings.Nr   r   r   r   r   r  width1024heightr   r?   r  POLLINATIONS_IMAGE_WIDTHPOLLINATIONS_IMAGE_HEIGHTr  r  r  pollinations_image_widthzPollinations image widthpollinations_image_heightzPollinations image heightr  r  r  pollinationsr!  z*Failed to save Pollinations Image settingsr"  r   r   )r{   r   r  r  r  )r   r   r   r  r  r   r`   s          ra   "update_pollinations_image_settingsr    s    H\\^# HHWf%++-EHHWf%++-EXXh'--/Fhhy"%++-G-2BJJ)*-2BJJ)*.4BJJ*+-4

)*	R4e=WXXX4e=WXXX5v?Z[[[4g?UVVV*N<STTT
  %%6RR5 $ HWn53GGH 	YX[VT REFW(8&>?SQQR   GE  EE  CG+F ;E><F F F %F&F <F=F FF GE   E;8G:E;;G>F  F F F F 	G&F=7G8G=GGz/api/settings/pollinations/ttsc                $  K   	 | j                          d{   }|j                  dd      j	                         }|j                  dd	      j	                         }|j                  d
d      j	                         }|j                  dd      j	                         }|j                  dd      j	                         }|t
        j                  d<   |t
        j                  d<   |t
        j                  d<   |t
        j                  d<   |r|t
        j                  d<   	 t        d|d       d{    t        d|d       d{    t        d|d       d{    t        d|d       d{    |rt        d|d       d{    t        dd d!       d{    d%||||d&S 7 # t        $ r t        ddid      cY S w xY w7 7 7 r7 _7 J7 7# t        $ r1}t        j                  d"       t        dd#| id$      cY d}~S d}~ww xY ww)'z!Update Pollinations TTS settings.Nr   r   r   r   r   r   voicer  speed1.0formatmp3r   r?   POLLINATIONS_TTS_MODELr  POLLINATIONS_TTS_SPEEDPOLLINATIONS_TTS_FORMATr  pollinations_tts_modelzPollinations TTS modelr  r  pollinations_tts_speedzPollinations TTS speedpollinations_tts_formatzPollinations TTS formatr  r  tts_providerr  zActive TTS providerz(Failed to save Pollinations TTS settingsr"  r   r   )r{   r   r  r  r  r  )r   r   r   r  r  r  r   r`   s           ra    update_pollinations_tts_settingsr    s    H\\^# HHWh'--/EHHWf%++-EHHWe$**,EXXh&,,.Fhhy"%++-G+0BJJ'(+0BJJ'(+0BJJ'(,2BJJ()-4

)*
R2E;STTT2E;STTT2E;STTT3V=VWWW4g?UVVV..:OPPP
  %%%[abb; $ HWn53GGH" 	UTTWVP RCDW(8&>?SQQRs   HF) F&F) DHG .G/G G	G GG -G.G GG GG H&F) )GHGHG 	G G G G G 	H&HHHHHz /api/settings/pollinations/videoc                  K   	 | j                          d{   }|j                  dd      j	                         }|j                  dd	      j	                         }|j                  d
d      j	                         }|j                  dd      j	                         }|t
        j                  d<   |t
        j                  d<   |t
        j                  d<   |r|t
        j                  d<   	 t        d|d       d{    t        d|d       d{    t        d|d       d{    |rt        d|d       d{    t        ddd       d{    d |||d!S 7 F# t        $ r t        ddid      cY S w xY w7 7 o7 \7 G7 4# t        $ r1}t        j                  d       t        dd| id      cY d}~S d}~ww xY ww)"z#Update Pollinations Video settings.Nr   r   r   r   r   r  duration5aspect_ratio16:9r   r?   r  POLLINATIONS_VIDEO_DURATIONPOLLINATIONS_VIDEO_ASPECTr  r  r  pollinations_video_durationzPollinations video durationpollinations_video_aspectzPollinations video aspect ratior  r  rP  r  rR  z*Failed to save Pollinations Video settingsr"  r   r   )r{   r   r  r  r  )r   r   r   r  r  r   r`   s          ra   "update_pollinations_video_settingsr  0  s    H\\^# HHWj)//1Exx
C(..0H88NF399;Lhhy"%++-G-2BJJ)*08BJJ,-.:BJJ*+-4

)*	R4e=WXXX7C`aaa5|Efggg4g?UVVV*N<STTT
  %XWcdd5 $ HWn53GGH 	YagVT REFW(8&>?SQQRr  z/api/settings/pollinations/testc                   K   t        d       d{   xs  t        j                  j                  dd      } | sddddS 	 ddl}|j                  d	
      4 d{   }|j                  ddd|  i       d{   }|j                  dk(  r7|j                         }dd|j                  dd      dcddd      d{    S |j                  dk(  rdddcddd      d{    S t        dd|j                   i|j                        cddd      d{    S 7 7 7 7 h7 E7 # 1 d{  7  sw Y   yxY w# t        $ r7}t        j                  d       t        dt        |      id      cY d}~S d}~ww xY ww)z6Test Pollinations API key by checking account balance.r  Nr  r?   Tz/No API key configured - using limited free tier)r]  limitedr1  r   r  r[  z+https://gen.pollinations.ai/account/balancer   r   r  r  Fbalancer  )r]  r  r  r_  r  r  r   r  r   zPollinations API test errorr   )r%   r   r   rU   r  rb  r   rP   r   rY   rW   r   rS   )r   r  rc  rd  r_   r`   s         ra   test_pollinations_apir  Q  s       677e2::>>J`bd;eG H
 	
B$$R$0 	 	F=#wwi%8 $  D 3&yy{!$#xx	9=	 	 	 !!S(!&1BC!	 	 	$ $D,<,<+=>? $ 0 0%	 	 	 8		 	 	 	 	 	.  B67Wc#h/SAABs   FD".FE D%E D/;D'<8D/4E  D)E FD/E %D+&E *F+%D/E D-E !F%E 'D/)E +E -E /E5D86E=E  FE 	F,E?9F:F?FFz/api/settingsc                   K   dId} 	 t                d{   }|j                  d      xs  t        j                  j                  dd      }|j                  d      xs  t        j                  j                  dd      }|j                  d	d
      }|j                  dd      }|j                  dd      }|j                  d      xs  t        j                  j                  dd      }|j                  d      xs  t        j                  j                  dd      }|j                  d      xs  t        j                  j                  dd      }	|j                  d      xs  t        j                  j                  dd      }
|j                  d      xs  t        j                  j                  dd      }|j                  dd      }t        |      dk(  r|d    nd!}t        |      dk(  r|d   n|d    }|j                  d"      xs  t        j                  j                  d#d      }|j                  d$      xs  t        j                  j                  d%d      }|| | |       | |      d&t        j                  j                  d'd(      t        j                  j                  d)d*      t        j                  j                  d+d,      t        j                  j                  d-d.      d/t        |j                  d0d            t        |j                  d1d            |j                  d2d3      d4d5d6d7i | |      |t        |      d8 | |      ||	|
d7t        |      d9||| | t        j                  j                  d:d            t        j                  j                  d;d      t        j                  j                  d<d=      d> | t        j                  j                  d?d            t        j                  j                  d@dA      dBt        j                  j                  dCdD      t        j                  j                  dEdF      dGdHS 7 <# t        $ r i }Y Hw xY ww)Jz/Return all configurable settings (keys masked).c                d    | r| j                  d      ryt        |       dkD  r| d d dz   | dd  z   S y)Nzyour-r?         r  z***)
startswithr   )vals    ra   _maskz(get_all_settings_endpoint.<locals>._mask  s<    cnnW-s8b=r7U?SX--rv   Nr  r  r?   r  r  r  rP  rQ  r  r   r  
chatterboxr  r  r  r  r  r  r  r  r  r  r  r   r   r   rr   r   r   r   r   r   r   r   r   )r   r   r   r   IMAGE_MODELzdall-e-3
IMAGE_SIZE	1792x1024IMAGE_QUALITYhdIMAGE_STYLEnatural)r   sizequalitystyler  r  google_flow_aspect_ratioportraitnano_banana_pro)has_sessionhas_csrfr  r   accounts_configuredT)r   r  
configured)r   r  r  r  r  has_api_keyELEVENLABS_API_KEYELEVENLABS_VOICE_IDELEVENLABS_MODEL_IDeleven_multilingual_v2)elevenlabs_keyvoice_idmodel_idRUNWAY_API_KEYRUNWAY_MODELgen3a_turbo)
runway_keyrunway_model
OUTPUT_DIRrn   TARGET_PLATFORMtiktok)dirplatform)llmimager   rQ  r  r  rP  r  r  ttsvideorn   )r  rS   returnrS   )r   rY   rU   r   r   r   r   r   )r  r   leonardo_keyr  rP  r  r  pollinations_keyr  r  r  r   r   r   r   r   r   s                    ra   get_all_settings_endpointr  ~  s    /11
 ??#56`"**..I[]_:`L%//*?@pBJJNNShjoDp __%5v>N __%5}EN??><@L #'=>l"**..QgikBl*/IJ   Abjjnn]wy  OA*/IJ   Ebjjnn]w  zD  OE(__-EFz"**..YqsyJz,\

{O0\IOOC#Eu:?uQxHE
aE!HU1XE!12ZbjjnnEUWY6ZJOO$78cBJJNNK^`b<cM !
+"=1	
 ZZ^^M:>JJNN<=zz~~ot<ZZ^^M9=	
  0KR PQ[__-ErJK'OO,F
S&	
 "4
 \*-|,
 -.33/ 01
 )($#BJJNN3G$LM

'<bA

'<>VW
  

/? DEJJNN>=I

 ::>>,9

'8(C
_3 33 2 s8   Q&Q QQ P7Q&Q Q#Q&"Q##Q&c                  K   	 | j                          d{   }dddd	}g }|j                         D ]f  \  }\  }}}||v st	        ||         j                         }|s.t        |||       d{    |t        j                  |<   |j                  |       h d
dddddddddddd}	i }
|	j                         D ].  \  }}||v st	        ||         j                         }|s*||
|<   0 |
rt        |
       |t        |
j                               z   }|st        ddid      S d|dS 7 # t        $ r t        ddid      cY S w xY w7 ܭw)zGUpdate one or more settings (DB-backed for LLM, env-backed for others).Nr   r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   r  r  r  r  GOOGLE_FLOW_ASPECT_RATIOr  r  r  r  r  r  r  )r  
image_sizeimage_qualityimage_styler  r  elevenlabs_voice_idelevenlabs_model_idr  r  
output_dirtarget_platformzNothing to updater   )r{   keys)rP   rY   r   r   rS   r   r&   r   r   r   r   r$  r  )r   r   DB_KEYS
db_updatedfrontend_keydb_keyenv_keydescr  ENV_KEY_MAPenv_updatesall_keyss               ra   update_settingsr    s    H\\^# MXGG
 J18 +--vw4d<()//1C!&#t444&)

7#!!'*+ %"($$>.44&&",K K!,!2!2!4 +g4d<()//1C'*G$	+ %D!1!1!344HW&9:LL22c $ HWn53GGH 5s]   ED1 D.D1 &EE"E2E3AE	E(AE.D1 1E	EEEz/api/settings/providerc                h  K   	 | j                          d{   }|j                  dd      }|j                  dd      }d	d
dd}||vrt        dd| did      S |st        ddid      S t	        ||   |d| d       d{    d||dS 7 x# t        $ r t        ddid      cY S w xY w7 *w)z>Update the active provider for a given type (image/video/tts).Nr   r   r   r   typer?   r   r  rP  r  r  r  r  zInvalid type 'z '. Must be image, video, or tts.zprovider is requiredzActive z	 providerr/  )r{   r  r   )rP   rY   r   rU   r&   )r   r   provider_typeprovider_namekey_maps        ra   update_provider_selectionr"    s     H\\^# HHVR(MHHZ,M(3CN[GG#}o5UVW
 	
 W&<=3OO
gm,mw}oU^=_
```M}MM# $ HWn53GGH asD   B2B BB A)B2B0
B2B B-*B2,B--B2z/api/providers/healthc                   K   	 t                d{   } | j                  dd      }d}d}|dk(  r(t        | j                  dd            }|rdnd}|rdnd	}nD|d
k(  rd}d}n:|dk(  r5t        t        j
                  j                  dd            }|rdnd}|rdnd}| j                  dd      }d}d}|dk(  r=	 t                d{   }	t        d |	D              }
|
dkD  rdnd}|
 d|
dk7  rdnd }nX|dk(  rJt        | j                  dd      xs  t        j
                  j                  dd            }|rdnd}|rdnd}n	|d
k(  rd}d}| j                  dd      }d}d}|dk(  rd}nD|dk(  r6t        t        j
                  j                  d d            }|rdnd}|rdnd}n	|d
k(  rd}d}d!|||d"|||d"|||d"d#iS 7 # t        $ r i } Y w xY w7 # t        $ r d}d}Y w xY ww)$z*Health check for all configured providers.Nr  r   not_configuredr?   r  r  zCookies presentzNo session tokenr  zFree cloud providerdalle3r   zAPI key setz
No API keyrP  rQ  c              3  D   K   | ]  }|j                  d       sd  ywr?  r  r@  s     ra   rC  z)check_providers_health.<locals>.<genexpr>I  s     Cqk0BCs     r   z active accountr   sr   zFailed to query accountsr  r  r  r  r  zLocal provider
elevenlabsr  	providers)r=   r{   detailsr  )r   rY   rU   r   r   r   r-   rH  )r   r  image_statusimage_detailsr  has_keyrP  video_statusvideo_detailsrD  rF  r  
tts_statustts_detailss                 ra   check_providers_healthr2  *  sQ    /11
 !__%5}EN#LM&;??+FKL'2|8H-8)>P	>	)#-	8	#rzz~~&6;<'.|4D)0l !__%5v>N#LM	7/11HCHCCF+1A:<;KL%hoVq[cb5QRM 
:	%{'92>h"**..QcegBhi'.|4D)0l	>	)#- ??><@LJK|#&		%rzz~~&:B?@%,\2B
'.mL		'!
+ 	,Q^_,Q^_(J;W
 o 2 2 2  	7"L6M	7so   G.G GG B"G.9G G-G 4CG.G GG.GG.G G+(G.*G++G.z/api/projectsc                 :   K   t                d{   } d| iS 7 w)zList all projects (summary).Nprojects)r.   )r4  s    ra   api_list_projectsr5  n  s"      #_$H!! %r   z/api/projects/{project_id}c                   K   ddl }t        |        d{   }|t        ddid      S t        dz  | z  }|j	                         r|j                  |d	       t        |        d{    d
| dS 7 \7 w)z*Delete a project and its images (cascade).r   Nr   Project not foundr   r   rn   T)ignore_errorsr   r   )shutilr!   r   rL   rM   rmtreer   )r+  r9  projr  s       ra   api_delete_projectr<  u  s      Z((D|W&9:LL)J6Jj5

$$$z22 ) %s"   A6A2AA6(A4)
A64A6c                   K   t        |        d{   }|t        ddid      S t        |        d{   }||d<   t        |        d{   }||d<   t	        |        d{   }||d<   |S 7 _7 =7 '7 w)	z5Get full project details including result and images.Nr   r7  r   r   imagesvideosaudios)r!   r   r"   r#   r$   )r+  r;  r>  r?  r@  s        ra   api_get_projectrA    s      Z((D|W&9:LL%j11FDN%j11FDN%j11FDNK ) 211sC   A9A1#A9A3A9A5A9%A7&A93A95A97A9z!/api/projects/{project_id}/assetsc                p  K   t        |        d{   }|t        ddid      S |j                  d      }|r|j                  dg       ng }t        |      }t	        |        d{   }t        |        d{   }t        |        d{   }g }|xs g D ]  }	|	j                  dd	      }
t        j                  j                  |
      rt        |
      nt        |
z  }|j                         }|j                  |	d
   |
||r|j                         j                  nd|	j                  dd      d        g }|xs g D ]  }|j                  dd	      }
t        j                  j                  |
      rt        |
      nt        |
z  }|j                         }|j                  |d
   |
||r|j                         j                  nd|j                  d      |j                  dd      d        g }|xs g D ]  }|j                  dd	      }
t        j                  j                  |
      rt        |
      nt        |
z  }|j                         }|j                  |d
   |
||r|j                         j                  nd|j                  d      |j                  dd      d        |D cg c]  }|d   dv s| }}|D cg c]  }|d   dk(  s| }}|D cg c]  }|d   dk(  s| }}t!        d |D              t!        d |D              z   t!        d |D              z   }t!        d |D              }| ||||d|t        |      |t        |      z
  |t        |      |t        |      z
  |t        |      |t        |      z
  |t#        |d      ddS 7 7 77 '7 c c}w c c}w c c}w w)z2Return detailed asset metadata for CLI inspection.Nr   r7  r   r   r4  scenes	file_pathr?   scene_numberr   r{   pending)rE  rD  rM   file_size_bytesr{   duration_seconds)rE  rD  rM   rG  rH  r{   r   approvedr   c              3  &   K   | ]	  }|d      ywrG  Nru   )rA  is     ra   rC  z%get_project_assets.<locals>.<genexpr>  s     6QA 6   c              3  &   K   | ]	  }|d      ywrL  ru   rA  r   s     ra   rC  z%get_project_assets.<locals>.<genexpr>       8qa!"8rN  c              3  &   K   | ]	  }|d      ywrL  ru   r@  s     ra   rC  z%get_project_assets.<locals>.<genexpr>  rQ  rN  c              3  F   K   | ]  }|j                  d       xs d  yw)rH  r   Nr  rP  s     ra   rC  z%get_project_assets.<locals>.<genexpr>  s"     MA127a7Ms   !r>  r?  r@  r   )total_imagesgenerated_imagesmissing_imagestotal_videosgenerated_videosmissing_videostotal_audiosgenerated_audiosmissing_audiostotal_disk_size_bytestotal_duration_seconds)r+  total_scenesassetssummary)r!   r   rU   r   r"   r#   r$   r   r]   isabsr   rL   rM   r   statst_sizerH  round)r+  r;  r4  rC  r`  	images_db	videos_db	audios_dbimages_listimgfp	full_pathrM   videos_listvidaudios_listaudrM  
gen_imagesr   
gen_videosrB  
gen_audios
total_disktotal_durations                            ra   get_project_assetsrw    s     Z((D|W&9:LLXXhF)/VZZ"%RFv;L(44I(44I(44I KR 
WW["% "b 1DH}r7I	!!#/;Ay~~/77qggh	2
 		
 KR WW["% "b 1DH}r7I	!!#/;Ay~~/77q #(: ;ggh	2
 		 KR WW["% "b 1DH}r7I	!!#/;Ay~~/77q #(: ;ggh	2
 		 )UAhK;T,T!UJU(GAhK;,F!GJG(GAhK;,F!GJG6+66
8K8
8	9
8K8
8	9 
 MMMN !$!!!
 ) #J*S_<( #J*S_<( #J*S_<%/&+NA&>
 A ) 544X VGGs   N6NAN6'N(N6:N!;N6N$H N6.N';N'?N6N,N,N6N1+N1/B-N6N6!N6$N6'N6z,/api/projects/{project_id}/generation-statusc                6  K   t        |        d{   }|t        ddid      S |j                  d      }|r|j                  dg       ng }t        |        d{   }t	        |        d{   }t        |        d{   }|xs g D ci c]  }|d   |j                  d	d
       }}|xs g D 	ci c]  }	|	d   |	j                  d	d
       }
}	|xs g D ci c]  }|d   |j                  d	d
       }}g }|D ]Z  }|j                  dd      }|j                  ||j                  |d
      |
j                  |d
      |j                  |d
      d       \ t        |      }t        d |D              }t        d |D              }t        d |D              }| |j                  d	d      ||||rt        |dz  |z        ndd|||rt        |dz  |z        ndd|||rt        |dz  |z        nddddS 7 7 7 7 c c}w c c}	w c c}w w)uI   Non-SSE status polling — return current generation state as plain JSON.Nr   r7  r   r   r4  rC  rE  r{   rF  r   )rE  r  r  audioc              3  0   K   | ]  }|d    dv sd  yw)r  rI  r   Nru   rA  r'  s     ra   rC  z(get_generation_status.<locals>.<genexpr>  s     X'
>W0W1Xs   c              3  2   K   | ]  }|d    dk(  sd  yw)r  r   r   Nru   r{  s     ra   rC  z(get_generation_status.<locals>.<genexpr>       J'
k0I1J   c              3  2   K   | ]  }|d    dk(  sd  yw)ry  r   r   Nru   r{  s     ra   rC  z(get_generation_status.<locals>.<genexpr>  r}  r~  r  d   )donerE  percentrT  )r+  project_statusrC  progress)
r!   r   rU   r"   r#   r$   r   r   rH  rf  )r+  r;  r4  rC  rg  rh  ri  rk  
img_statusro  
vid_statusrq  
aud_statusscene_statusesscenesnrE  img_donevid_doneaud_dones                       ra   get_generation_statusr    sm     Z((D|W&9:LLXXhF)/VZZ"%RF(44I(44I(44I O 	NSWWXy99J  O 	NSWWXy99J  O 	NSWWXy99J 
 N YY~q)^^B	2^^B	2^^B	2	
 	 KEXnXXHJnJJHJnJJH !((8Y7  !<A5C%!78q !<A5C%!78q !<A5C%!78q
	 O ) 544sq   HG>A
HHH/H0HHHH
,
H6H
HH:DHHHH
Hz&/output/{project_id}/assets/{filename}c                  K   d|v sd|v sd|v rt        ddid      S t        dz  | z  d	z  |z  }|j                         st        dd
id      S |j                         }t        dz  | z  d	z  j                         }t	        |      j                  t	        |            st        ddid      S t        t	        |            S w)z:Serve a generated image from per-project output directory.z..rr   \r   zInvalid filenamer   r   rn   ra  zFile not foundr   zInvalid path)r   rL   rM   resolverS   r  r   )r+  filename
asset_pathresolvedexpected_parents        ra   serve_assetr  2  s      x3(?dh.>W&89sKK)J6AHLJW&67SII!!#H$x/*<xGPPROx=##C$89Wn53GGH&&s   C Cz5/api/projects/{project_id}/scenes/{scene_num}/approvec                   K   t        |        d{   }|t        ddid      S t        | |d       d{    d|dS 7 /7 w)zMark a scene image as approved.Nr   r7  r   r   rJ  r{   rE  )r!   r   r1   )r+  	scene_numr;  s      ra   approve_scener  C  sV      Z((D|W&9:LL
j)Z
@@@ )<<	 ) As   AA%AA
AAz3/api/projects/{project_id}/scenes/{scene_num}/imagec                   K   t        |        d{   }|t        ddid      S t        dz  | z  dz  }|d|d	d
z  }|j                         r|j	                          t        | |       d{    d|dS 7 g7 w)z2Delete a generated image so it can be regenerated.Nr   r7  r   r   rn   ra  frame_02dr   r   r  )r!   r   rL   rM   r   r   )r+  r  r;  r  img_paths        ra   delete_scene_imager  M  s      Z((D|W&9:LL )J6AJfYsO488H z9
---;; ) .s"   A=A9AA=/A;0
A=;A=z8/api/projects/{project_id}/scenes/{scene_num}/regeneratec           	       K   t        |        d{   }|t        ddid      S |j                  d      }|st        ddid      S |j                  d	g       }t        fd
|D        d      }|t        ddid      S |j                  dd      }|st        ddid      S d}	 |j	                          d{   }	|	j                  dd      j                         }|r| d| }t        dz  | z  dz  }
|
j                  dd       |
dddz  }	 t                d{   }|j                  dd      }	 |dk(  rddl
m} j                  dd      }t        |j                  dd             }t        |j                  d!d             }|j                  d"d      } |d|xs d#      }t        j                  |j                  |||||$       d{    ndd%lm}m}m}  |j                  d&d      |j                  d'd      (       d{    |j                  |j                  d)t(        j*                  j                  d*d+            j-                         d,      } ||||-       d{    t/        | t1        |             d{    ddl}d}|j5                         r.|j7                  |j9                               j;                  d.      }d/d0|  d1dd||d2S 7 7 3# t        $ r Y w xY w7 # t        $ r d}Y w xY w7 @7 7 7 # t        $ r3}t<        j?                  d3|        t        dd4| id5      cY d}~S d}~ww xY ww)6z:Regenerate a single scene image, optionally with feedback.Nr   r7  r   r   r4  No plan result foundr   rC  c              3  4   K   | ]  }|d    k(  s|  ywrE  Nru   rA  r'  r  s     ra   rC  z#regenerate_scene.<locals>.<genexpr>m       Fq'8I'E!F   Scene not foundimage_promptr?   zNo image prompt for scenefeedbackz

Additional direction: rn   ra  Tro   r  r  r   r  r   r  r   )get_image_providerr  r  r  r  r  r  r   )r   output_pathr   r  r  generate_image
get_engineASPECT_RATIOSr  r  r%  r&  r  r	  r  IMAGE_ASPECT_RATIO_PORTRAIT)r  r:   regenerated/output//assets/frame_)r{   rE  	image_urlimage_base64r   z+Regeneration failed for project %s scene %dzRegeneration failed: r   ) r!   r   rU   nextrP   r   rY   rL   r   r   r)  r  intr   r   r   providers.flow_browser_enginer  r  r  r   r   lowerr0   rS   base64rM   	b64encode
read_bytesdecoderW   r   )r+  r  r   r;  r4  rC  r  r  r  r   r  r  r   image_provider_prefr  pollinations_modelpollinations_widthpollinations_heightr  img_provr  r  r  aspectr  r  r`   s    `                         ra   regenerate_scener  `  s     Z((D|W&9:LLXXhFW&<=3OO ZZ"%FFVFME}W&78cJJ99^R0LW&ABPSTT H\\^#88J+113 &'A(L)J6AJTD1fYsO488H,/11)oo.>N6W.04!,1KV!T!$[__5OQW%X!Y"%koo6QSY&Z"[*/ErJ).BRBZVZ[H##!!#$((*   `_ )oo.I2N&??+CRH   #&& :JJNN#=zJLLQEG-F
 !xfMMM  
Is8}EEE 	??!++H,?,?,ABII'RL $%#J<~i_DQ(+
 	
g )* $  2 ,+, N 	F  W9:y	
 W(=cU&CDRUVV	Ws   MK+BM(K1 ;K.<$K1  5ML #L$L ;BL  L<L  LA L  4L5L  LAL  *M.K1 1	K>:M=K>>ML LMLML  L  L  L   	M)(MMMMMz*/api/projects/{project_id}/generate-imagesc                   	
K   t                d{   }|t        ddid      S |j                  d      }|st        ddid      S |j                  d	g       }|st        dd
id      S t                d{   }|xs g D ch c]  }|j                  d      dv r|d    }}|D cg c])  }|j                  dd      |vr|j                  d      r|+ c}		st        ddid      S t        dz   z  dz  

j                  dd       t        |      	
 fd}t         |       dddd      S 7 (7 c c}w c c}w w)zSGenerate images for missing scenes in a completed plan, streaming progress via SSE.Nr   r7  r   r   r4  r  r   rC  No scenes in planr{   rI  rE  r   r  zAll scenes already have imagesrn   ra  Tro   c                   K   t              } i }t                d {   }|j                  dd      }t        d      D ]  \  }}|j                  d|      }|j                  dd      }|j                  d      }|j                  dd	      }	|j                  d
d      }
 d|ddz  }t	        j
                  || "|d||
d      }d| d 	 |dk(  r'd	dlm}m}m	} |j                  |j                  dt        j                  j                  dd            j                         d      }d }|rL|	d	kD  rG|j                  |      }|rt        j                  d||	|
|d d        nt        j                  d||	        |||||       d {    |ru|	d	k(  ro	  ||j                  dd      |j                  dd             d {   }|j                   }|r|||<   t        j                  d||d d        n|d k(  rd	d!lm} |j                  d"d      xs  t        j                  j                  d#d      }|j                  d$d%      }t)        |j                  d&d'            }t)        |j                  d(d'            } ||xs d )      }|j+                  |||||*       d {    nZ|d+k(  r(d	d,lm}  |       }|j+                  ||       d {    n-t        j                  d-|       d	d.lm}  |||       d {    t1        !||t3        |      d/0       d {    t	        j
                  || "|d1! d2|ddd3||
d4      }d| d  d7 y 7 G7 7 # t"        $ r }t        j                  d|       Y d }~d }~ww xY w7 7 7 7 w# t"        $ rP}t        j5                  d5!|       t	        j
                  || "|t3        |      |d6      }d| d Y d }~d }~ww xY ww)8Nr  r   r   rE  r  r?   coverage_group_idcoverage_angle_indexr   coverage_angle_typer  r  r   
generating)rE  rE  r`  r   r{   coverage_group
angle_typedata: 

r  r  r	  r  r  u6   Coverage ref: group=%s angle=%d type=%s media_id=%s…   uD   No master reference for %s angle %d — generating without reference)r  reference_media_idr  r  r  u1   Coverage master captured: group=%s media_id=%s…z%Could not capture master media_id: %sr  )PollinationsImageProviderr  r  r  r  r  r  r  r  )r   r  r  r%  )DallE3ImageProviderz8Unknown image provider '%s', falling back to google_flow)r  r   r+  rE  r  rD  r{   r  r  r  )rE  rE  r`  r   r  r{   r  r  z/Image generation failed for project %s scene %d)rE  rE  r`  r   r   r  event: done
data: {}

)r   r   rU   	enumeraterP   dumpsr  r  r  r  r   r   r  rW   rX   rZ   last_media_idrY   %providers.pollinations_image_providerr  r  r   providers.image_providerr  r4   rS   r   )#total_missingcoverage_master_media_idsr   image_provider_nameidxr  r  r  r  angle_indexr  r  start_payloadr  r  r  r  r  engine
master_midmid_excr  r  r   r  r  r  r  payloadr`   err_payloadmissing_scenesr  r+  r`  s#                                  ra   event_streamz)generate_images_sse.<locals>.event_stream  s    N+ 57!/11)oo.>N#NA6 O	1JC		.#6I 99^R8L"YY':;N))$:A>K%rJ "fYsO4$@@H !JJ$-*$0"*&4",
M =/..v1&-7  +..#(BJJNN+EzRTTYTYT[5F 6:&%+/-F-J-J>-Z*-"KK X .Z 23B 7 #NN f .
 )$h%++=   &+*:]+5.9oo>Y[].^+6??;SUW+X, &F *0)=)=J)LV 9. I &$W$2JsO!" )N:_'27Mr'R  (AVXV`V`VdVde{}  WA$'OO,FOE0JF STE 1Lf!UVF8AQAYUYZH"++$h#5 ,   
 )H4L24H"++L(CCC NN#]_rsL(x@@@")!*!-!(m&   **(1!.(4#&'/
|>)TWX\%]"(*8&0	 wit,,{O	1b *)i 2v&  ) ]"NN+RT[\\] D A,  1  E
 #jj(1!.(4#&!$S*8	 {m4000!1s   O>M%B2O>B=N"M(N"-M.M+1M.=B/N",N-,N"N-N"N N"(N )3N"
O>(N"+M..	N7NN"NN"N"N" N""	O;+AO60O>6O;;O>text/event-streamno-cachenozCache-ControlzX-Accel-Buffering
media_typer   )r!   r   rU   r"   rL   r   r   r   )r+  r;  r4  rC  existing_imagesrk  existing_scene_numsr'  r  r  r  r`  s   `        @@@ra   generate_images_sser    s     Z((D|W&9:LLXXhFW&<=3OOZZ"%FW&9:LL /z::O $)r778 99 	N  55#+>>155CX 	
N 67S
 	
 )J6AJTD1v;LZ*x &'!%
 C ) ;sA   ED=A(E>E ?EE*E0.EA E E
Ez*/api/projects/{project_id}/generate-videosc           
        K   t                d{   }|t        ddid      S |j                  d      }|st        ddid      S |j                  d	g       }|st        dd
id      S t                d{   }|xs g D ch c]  }|j                  d      dv r|d    }}t	                d{   }|xs g D 	ch c]  }	|	j                  d      dk(  r|	d    }
}	|D cg c],  }|j                  dd      |v r|j                  dd      |
vr|. c}st        ddid      S t
        dz   z  dz  	 t                d{   }|j                  dd      |j                  dd      |j                  dd      |j                  dd      |j                  dd      |j                  dd      	 t        |j                  j                  dd            t        d t        d!             f
d"}t         |       d#d$d%d&'      S 7 7 c c}w 7 qc c}	w c c}w 7 # t        $ r ddddddY w xY w# t        t        f$ r d Y w xY ww)(zGenerate videos for scenes that have images but no videos, streaming progress via SSE.

    Query params:
        parallel (int): Number of concurrent Grok browser workers (default 1 = sequential).
    Nr   r7  r   r   r4  r  r   rC  r  r{   rI  rE  r   r   z*All scenes with images already have videosrn   ra  rP  rQ  r  r?   r  r  r  r  r  r  r  parallel1r   rZ  c            
    $
  
K   t              } d }d}xs  t        j                  j                  dd      }%dk(  r#	 ddlm}  | xs d #t        "      !      }d}n*%d	k(  r%|r#	 dd
l
m} |t        j                  d<    |       }d	}|d u }|r<t                d {   }|s&t        j                  ddi      }	d|	 d d y d}t        j                  d|       |rdkD  rddlm t%        j&                         	 d5	 	 	 	 	 	 	 	 	 	 	 d6fdd7$fd}
t%        j(                   |
             }d}	 	 j                          d {   }|n|d   dk(  r,|dz  }t        j                  |d   | |dd      }d| d n|d   dk(  r<|dz  }t        j                  |d   | ||j                  dd      d      }d| d ng|d   d k(  r't        j                  |d   | |d d      }d| d n8|d   dk(  r0t        j                  d|j                  dd!      i      }d| d 	 | d {    dt        j                  dd"       d d y 	 d }t+        d      D ]C  \  }}|j                  d|      }|j                  d#d      }d$|d%d&z  }d$|d%d'z  }t        j                  || |d d      }d| d 	 |rt                d {   }|st-        d(      |d)   |k7  rX|	 |j/                          d {    dd*lm}  ||d+   |d,   |d-   .      }|d)   }t        j                  d/|d)   |d0   |       |j5                  |||1       d {    t7        $||t9        |      d23       d {    t        j                  || |dd      }d| d F 	 |r	 |j/                          d {    d y # t        $ r!}t        j                  d|       Y d }~d }~ww xY w# t        $ r!}t        j                  d|       Y d }~d }~ww xY w7 7 7 # | d {  7   w xY w7 j7 =# t        $ r Y Gw xY w7 7 # t        $ rN}t        j;                  d4$|       t        j                  || |t9        |      d      }	d|	 d Y d }~Hd }~ww xY w7 # t        $ r Y w xY w# |r*	 |j/                          d {  7   w # t        $ r Y w w xY ww xY ww)8Nr  r  r?   r  r   PollinationsVideoProviderr   r   r  r  3Pollinations video provider failed: %s, trying Grokr  LeonardoVideoProvider)Leonardo provider failed: %s, trying Grokr   6No Grok accounts configured. Add accounts in Settings.r  r  r  rQ  zUsing video provider: %sr   )GrokWorkerPoolr{   c                P   K   j                  | ||||d       d {    y 7 w)N)rE  r{   r   rE  r   )put)r  r{   r   rE  r   progress_queues        ra   _on_pool_progresszDgenerate_videos_sse.<locals>.event_stream.<locals>._on_pool_progress  s2      %(($-&*   s   &$&c                   K   	        4 d {   } | j                          d {    t        
d      D cg c]n  \  }}|j                  d|      t        d|j                  d|      ddz        |j                  dd      t        d|j                  d|      dd	z        d
p }}}| j	                  |	       d {   }|D ]Y  j
                  st        fd
D        d      }t        j                  |t        j                        d       d {    [ d d d       d {    j                  d        d {    y 7 E7 0c c}}w 7 7 >7 .# 1 d {  7  sw Y   >xY w# t        $ rI}t        j                  d       j                  ddt        |      ddd       d {  7   Y d }~d }~ww xY w7 # j                  d        d {  7   w xY ww)N)max_workersr   rE  r  r  r   video_promptr?   .mp4)rE  
image_pathr  r  )rC  on_progressc              3  ~   K   | ]4  }|j                  d       j                  k(  r|j                  dd       6 yw)rE  r  r?   N)rU   rE  )rA  scrs     ra   rC  zOgenerate_videos_sse.<locals>.event_stream.<locals>._run_pool.<locals>.<genexpr>3  s:      %RB(*~(>!..(P &(VVNB%? %Rs   :=r   r+  rE  r  rD  r{   z"Parallel pool error for project %sr   r   )rE  r{   r   r   rE  )startr  rU   rS   generate_batchsuccessr  r5   rE  r  rY   rW   r   r  )poolrM  r'  scenes_dataresults
vid_promptr`   r  r  r  r  r  r  r  r+  s          @ra   	_run_poolz<generate_videos_sse.<locals>.event_stream.<locals>._run_pool"  s    3-(C " "t"jjl** )2.!(D' !%1 12na0H.1*n^_H`adGeei?j2j.k01nb0I/2:&~_`IabeHffj@k3k/l	' ' )-(;(;;\m(;(n"n!( "A yy-1%R. %RSU."
 '3/9121;.1!--.@+6'" !" !""" ": ),,T222;"*' #o!"%" " " "2 ! B$$%I:V(,,a7]`ad]ers~  .A  B  B  BB 3.,,T222s   G5E? EE? E*EE*A3E2E*E$E*"AE*'E&(E*.E? 9E(:E? >G5GG5E? E*E*&E*(E? *E<0E31E<8E? ?	G9GGGG GG G5G2+G.,G22G5T	completedrE  r  )rE  rE  r   r{   failedUnknown)rE  rE  r   r   r  z
Pool error)parallel_modeworkersr  r  r  r   r  z!No active Grok accounts availablerI   GrokPlaywrightProviderrN  rO  r8  rN  rO  r8  z'Using Grok account %d (%s) for scene %dr7  r  r  r  r   r  /Video generation failed for project %s scene %dN)r  r  r{   rS   r   r  rE  r  r   z
str | Noner  Noner  r!  )r   r   r   rU   %providers.pollinations_video_providerr  r  rY   rW   rZ   !providers.leonardo_video_providerr  r    rP   r  rX   providers.grok_worker_poolr  r   Queuecreate_taskr  RuntimeErrorrx  "providers.grok_playwright_providerr  r   r5   rS   r   )&r  
video_provr   r  r  r`   r  use_grok_rotationtest_accountr  r  	pool_task
done_counteventr  current_account_idr  r  r  r  r  vid_pathr  rU  GrokVideoProviderr  r  r  leonardo_key_dbr  r  r  pollinations_key_dbr  r  r  r+  video_provider_prefs&                            @@@ra   r  z)generate_videos_sse.<locals>.event_stream  sC    N+
! 'P"**..9KR*P.0
[[6/742 !<=!:	
 !/ !J.<QS1=

-.24
 *
 '$.!6!88L"jj'3k)lm{m40011"M.> AA9@N \`(+69BENX3 3B  ++IK8IJ "0"4"4"66E}X+5"a
"&**eN>S^k  yC  OU  .V  #W &wit44xH4"a
"&**eN>S^k  yC  NS  NW  NW  X_  aj  Nk  .l  #m &wit44xL8"&**eN>S^k  yC  O[  .\  #] &wit44xG3"&**guyy,7W-X"Y &wit44#     4::&RSTTXYY--X	!%': P5
U!IInc:	$yy<%&3t(DD%&3t(DD !%

(1!.#&".	! }oT22>5((=(?"?&"./R"SS #4=,>>)5!)*4*:*:*<$<$< w):*1+*>-4^-D(/	(:*J
 29."KK(Q'.t}gg6F	S %--#+%1$, .    '#-%.%1"%h-*   #jj,5%2'*&,	G #7)400AP5d $**,,, *)  [TVYZZ[  QJCPPQ 9| 7$  i8 #@ %='0 !)$(!)$ ! 5$$I"!
 #'**,5%2'*%(X	#K #;-t4445$ -   $**,,,   s  9T !O' !T*"P TQ B"TQ
 QC'Q
  TQ)T0A0S !Q40Q1Q4Q  Q!Q %AQ49Q0: Q4Q2'Q4S T	S SS !T'	P0PTPT	P>P93T9P>>TQ
 T
QQQTQ4Q  	Q-)Q4,Q--Q42Q44	S=AS S SS S 	STSTT#S=6S97S=<T=	T	TT		TTr  r  r  r  r  )r!   r   rU   r"   r#   rL   r   rY   r  query_params
ValueError	TypeErrormaxminr   )r+  r   r;  r4  rC  r  rk  image_scene_numsexisting_videosro  video_scene_numsr'  r   r  r3  r  r  r  r4  r  r  r  r5  s   `             @@@@@@@@@ra   generate_videos_sser>    s     Z((D|W&9:LLXXhFW&<=3OOZZ"%FW&9:LL /z::O $)r778 99 	N  /z::O $)r778+ 	N  55#'77EE.!$,<< 	
N BCQT
 	
 )J6AJ+/11)oo.>G%//*<bA)oo.DbI#.??3Mz#Z &1oo6SUX&Y#$/OO4OQW$X!w++//
C@A 1c(B'(HQ* Q*f &'!%
 o ) ; ;  2  +$ #- &)#$*!+ 	" s   I2H&A(I2H)I2H,0I2 H1I2 H4-I231H9$#I2I  H>A0I  %I ,;I2)I2,I24
I2>I   II2II2I/,I2.I//I2z*/api/projects/{project_id}/generate-audiosc                   	
K   t                d{   }|t        ddid      S |j                  d      

st        ddid      S 
j                  d	g       }|st        dd
id      S t                d{   }|xs g D ch c]  }|j                  d      dk(  r|d    }}|D cg c]8  }|j                  dd      |vr"|j                  dd      j	                         r|: c}st        ddid      S t
        dz   z  dz  		j                  dd       	 
fd}t         |       dddd      S 7 -7 c c}w c c}w w)zRGenerate TTS audio for all scenes in a completed plan, streaming progress via SSE.Nr   r7  r   r   r4  r  r   rC  r  r{   r   rE  r   tts_textr?   r1  zAll scenes already have audior  rn   ra  Tro   c                
  K   t        $      } d }d}	 ddlm} ddlm} 	 t                d {   }|j                  dd       }|j                  dd      }|j                  dd	      }|j                  d
d      }	|j                  dd      }
|j                  dd      }'j                  di       }|xs |j                  dd      } |||j                  dd      |j                  dd      |j                  dd      |j                  dd      ||t        |	      |
|xs d 
      } ||      }dd l}ddlm} |dk(  rd}d }n*|d!k(  r!d"|
 }d#d$d%d&d d'd(}|j                  |
d#      }nd)}d#}g }g }$D ]:  }|j                  d*d      dk(  r|j                  |       *|j                  |       < i }t        |      t        |      z   }d}|D ]  }|d+z  }|j                  d,d      }|j                  d-d      }%d.|d/| z  }t        j                  |d0|||d1      }d| d 	 |j                  ||       d {    |j                  d2      } | r||| <   d }!	 |j!                  |      }!t#        &|||t%        |      |j'                         ||!d34	       d {    t        j                  |d3||d5& d6|d/| ||!|d7      }"d|" d  |D ]L  }|d+z  }|j                  d,d      }|j                  d-d      }%d.|d/| z  }|j                  d2d      } t        j                  |d0|||d1      }d| d 	 |j                  |       }#|#r#|#j-                         r|j/                  |#|       n1t(        j1                  d:| |       |j                  ||       d {    d }!	 |j!                  |      }!t#        &|||t%        |      |j'                         ||!d34	       d {    t        j                  |d3||d5& d6|d/| ||!|d7      }"d|" d O d y 7 # t        $ r d }d}d	}d}	d}
d}Y w xY w# t        $ r2}t        j                  dd| i      }d| d d Y d }~y d }~ww xY w7 L# t        $ r Y *w xY w7  # t        $ rO}t(        j+                  d8&|       t        j                  |dt%        |      ||d9      }d| d Y d }~'d }~ww xY w7 S# t        $ r Y Iw xY w7 # t        $ rO}t(        j+                  d8&|       t        j                  |dt%        |      ||d9      }d| d Y d }~d }~ww xY ww);Nr  r   get_tts_providerVoiceSettingsr  r  r   r  r  r  r  r  r  r  r?   voice_settingsr  JBFqnCBsd6RMkjVDRZzbr  r  chatterbox_languageptchatterbox_voice_ref
r  r  r  rH  rJ  r  pollinations_voicepollinations_speedpollinations_formatr  r   TTS provider not available: r  r  r  r   .wav	audio/wavr  .
audio/mpeg
audio/opus	audio/aac
audio/flac	audio/pcmr  opusaacflacwavpcm.mp3r  r   rE  r@  r  r  r  )rE  r{   r  rE  r   r  r   	r+  rE  r@  r  rD  
audio_data	mime_typerH  r{   r  r  )rE  r{   r  rE  	audio_urlra  r  r   -TTS generation failed for project %s scene %d)rE  r{   r   r  rE  z@Master audio not found for group %s, generating TTS for scene %d)r   r)  rC  r	  rE  r   rU   rY   floatrP   r  r9  pathlibr   r   r   get_audio_durationr6   rS   r  rW   r   rM   copy2rZ   )(r  tts_provr   rC  rE  r   db_tts_providerr  rL  rM  rN  r  rF  settingsr`   r  r9  _Pathextra  format_mime_mapmasterssecondariesr'  master_audio_pathstotal_to_process	processedr  r  r@  
audio_pathr  	cov_groupr  done_payloadmaster_pathr  r  r+  r4  s(                                       ra   r  z)generate_audios_sse.<locals>.event_stream  s    N+$,	2,*$7$99"-//.$"G%0__5Mx%X"%0__5Mv%V"%0__5Mu%U"&1oo6OQV&W#'27Mr'R$ $ZZ(8"=N+_~/A/A.R^/_M$*'++J8NO'++J8PQ$2$6$67Ld$S%3%7%78NPR%S#5#5#();#<$7%9%ATH (1H 	)L(C#In,)*+C#$"$""O (++,?NIC$I  	&Auu+Q/14q!""1%		& 02w<#k*::	  K	1ENI		.!4IyyR0H#yocU&CCJ JJ$-* )- -M =/..:1''*=== "II&9:	4>&y1  ':::FH
 #)!*%!.!*o)446'%-&
 
 
  $zz(1"-$-!1'/
|>)TWY\X]%^%.$,$1	  |nD11uK	1\ ! Q	1ENI		.!4IyyR0H#yocU&CCJ		"5r:I JJ$-* )- -M =/..?1044Y?;#5#5#7LLj9 NNZ!!
 #++HjAAA  ':::FH
 #)!*%!.!*o)446'%-&
 
 
  $zz(1"-$-!1'/
|>)TWY\X]%^%.$,$1	  |nD11AQ	1f *)[ :  *"&%-"%+"%*"&+#')$*6  	**g1McU/S%TUK;-t,,--		z > ! 
4  1  C
 #jj(1")!$S$-!1 {m40001` B ! 
4  1  C
 #jj(1")!$S$-!1 {m40001s@  U,Q P0 P-A0P0 BQ .C:U,)R >R
?R R/.R R4R A3U,A"T(S;)T0S>.T/T04T$	U,-P0 0Q	Q Q		Q 	R(R=U,RU,
R 	RR RR  	S8)AS3-U,3S88U,;T>	TT
TT	U)AU$U,$U))U,r  r  r  r  r  )r!   r   rU   r$   r   rL   r   r   )r+  r;  rC  existing_audiosrq  audio_scene_numsr'  r  r  r  r4  s   `       @@@ra   generate_audios_ssery    s     Z((D|W&9:LLXXhFW&<=3OOZZ"%FW&9:LL /z::O $)r778+ 	N  55#+;;EE*b!'') 	
N 78c
 	
 )J6AJTD1x*t &'!%
 } ) ;sA   EEA(E>E?E E+E1=E.AEE
Ez>/api/projects/{project_id}/scenes/{scene_num}/regenerate-audioc                  K   t        |        d{   }|t        ddid      S |j                  d      }|st        ddid      S |j                  d	g       }t        fd
|D        d      }|t        ddid      S |j                  dd      }|j	                         st        ddid      S t
        dz  | z  dz  }|j                  dd       	 t                d{   }|j                  dd      }	|j                  dd      }
|j                  dd      }|j                  dd      }|j                  dd      }|j                  dd      }	 ddl	m
} ddlm} |j                  d i       }|	xs |j                  dd!      } |||j                  d"d#      |j                  d$d%      |j                  d&d'      |j                  d(d      |
|t        |      ||xs d)
      } ||      }|d!k(  rd+}n|d,k(  rd-| }nd.}|d/d0| z  }	 |j                  ||       d{    d}	 |j                  |      }|d!k(  rd1}n#|d,k(  rd2d3d4d5d1d6d7}|j                  |d2      }nd2}ddl}|j#                         }|j%                  |      j'                  d8      }t)        | ||t+        |      |||d9:	       d{    d;d<|  d=d0| ||||d>S 7 7 # t        $ r d}	d}
d}d}d}d}Y w xY w# t        $ r}t        dd*| id      cY d}~S d}~ww xY w7 # t        $ r Y w xY w7 r# t        $ r3}t,        j/                  d?|        t        dd@| idA      cY d}~S d}~ww xY ww)Bz4Generate or regenerate TTS audio for a single scene.Nr   r7  r   r   r4  r  r   rC  c              3  4   K   | ]  }|d    k(  s|  ywr  ru   r  s     ra   rC  z#regenerate_audio.<locals>.<genexpr> 
  r  r  r  r@  r?   zNo TTS text for this scenern   ra  Tro   r  r  r   r  r  r  r  r  r  r  r   rB  rD  rF  r  r  rG  r  r  rH  rI  rJ  rK  rO  rP  r  rR  r^  r  r  rQ  rS  rT  rU  rV  rW  rX  r:   r   r_  r  r  r  )r{   rE  rb  audio_base64ra  r  r   rc  zTTS generation failed: r   )r!   r   rU   r  r   rL   r   r   rY   r)  rC  r	  rE  rd  r   rf  r  r  r  r  r6   rS   rW   r   )r+  r  r;  r4  rC  r  r@  r  r   ri  r  rL  rM  rN  r  rC  rE  rF  r   rj  rh  r`   rl  rs  r  ra  rm  r  audio_bytesr|  s    `                            ra   regenerate_audior~  	  s,     Z((D|W&9:LLXXhFW&<=3OOZZ"%FFVFME}W&78cJJyyR(H>>W&BCQTUU)J6AJTD1"/11%//.$?(__-ExP(__-EvN(__-EuM)oo.GO*/ErJ
.($4b9'[>+=+=nl+[ &#''
4JK#''
4LM . 2 23H$ O!/!3!34JB!O11$%78 3!5!=
 $H- $	.	(%&'yocU;;J7Y*555	22:>H
 L(#In,#$"$""O (++,?NI$I 	 ++-''4;;GD!"&*o"%

 
	
 
	
 $%#J<~i_SER(" %
 	
g ), 2  "%#"#!"<  
4SE:;
 	

 	6
  		0
	
*  Y;Z	
 W(?u&EFTWXX	Ys   M2KCM2K #K$A0K BK8 0 M2L3 &L 'L3 .L" ?A?L3 >L1?L3 M2K K51M24K55M28	LLLM2LM2 L3 "	L.+L3 -L..L3 3	M/<(M*$M/%M2*M//M2z>/api/projects/{project_id}/scenes/{scene_num}/regenerate-videoc                  K   t        |        d{   }|t        ddid      S |j                  d      }|st        ddid      S |j                  d	g       }t        fd
|D        d      }|t        ddid      S t        dz  | z  dz  }|dddz  }|dddz  }|j                         st        ddid      S |j                  dd      }		 t                d{   }
|
j                  dd      }|
j                  dd      }|
j                  dd      }|
j                  dd      }|
j                  dd      }|
j                  dd      }d}d}|xs  t        j                  j                  d d      }|d!k(  r#	 d"d#l
m}  ||xs d|t        |      |$      }d!}n*|d&k(  r%|r#	 d"d'lm} |t        j                  d <    |       }d&}|@	 d"d)lm} t'                d{   }|st        dd*id      S  ||d+   |d,   |d-   .      }d}t        j)                  d0|       	 |j+                  ||	|1       d{    t-        | |	t/        |      d23       d{    d4d5	 |j1                          d{    S 7 r7 # t        $ r d}d}d}d}d}d}Y Mw xY w# t        $ r }t        j                  d%|       Y d}~d}~ww xY w# t        $ r!}t        j                  d(|       Y d}~(d}~ww xY w7 # t        $ r}t        dd/| id      cY d}~S d}~ww xY w7 7 7 # t        $ r Y S w xY w# t        $ r\}t        j3                  d6|        t        dd7| id8      cY d}~	 |j1                          d{  7   S # t        $ r Y S w xY wd}~ww xY w# 	 |j1                          d{  7   w # t        $ r Y w w xY wxY ww)9z2Generate or regenerate a video for a single scene.Nr   r7  r   r   r4  r  r   rC  c              3  4   K   | ]  }|d    k(  s|  ywr  ru   r  s     ra   rC  z#regenerate_video.<locals>.<genexpr>
  r  r  r  rn   ra  r  r  r   r  zImage not found for this scener  r?   rP  rQ  r  r  r  r  r  r  r  r  r  r  r  r   r  r  r  r  r  r  r  r  rN  rO  r8  r  zNo video provider configured: z%Using video provider: %s for scene %dr  r   r  r  r  r  zVideo generation failed: r   )r!   r   rU   r  rL   rM   r   rY   r   r   r#  r  r  rW   rZ   r$  r  r)  r  r    rX   r   r5   rS   rx  r   )r+  r  r;  r4  rC  r  r  r  r1  r  r   r5  r3  r4  r  r  r  r*  r   r  r  r`   r  r2  rU  s    `                       ra   regenerate_videor  z
  sr     Z((D|W&9:LLXXhFW&<=3OOZZ"%FFVFME}W&78cJJ)J6AJfYsO488HfYsO488H??67S
 	
 99^R0L+/11)oo.>G%//*<bA)oo.DbI#.??3Mz#Z &1oo6SUX&Y#$/OO4OQW$X! JM"Lbjjnn5G&LLn,
	WW2+3t.896	J +M 

	*|	MO-9BJJ)*.0J&M 	f133G#VW #  +!+.$^4	*J
 #M KK7	R!!%  " 
 	
 	
 !"%(m
 	
 	
 $%
	""$$$m )4 2  +$ #- &)#$*!+.  	WNNPRUVV	W  	MNNFLL	M 4  	:3%@A 		
	
* % 		  
=z9	
 1#78c
 	
	""$$$ 		
	""$$$ 		s  OJCOJ
 $J%A0J
 -O!J& $O-"K OL %K?&L :O;L O)L?  L* L? !L,"L? +L0>L.?L0OJ
 
J#O"J##O&	K/K
O
KO	K<K71O7K<<O?L 	L'L"L'O"L''O*L? ,L? .L00	L<9O;L<<O?	N$(N0N$1N' 6N	N
NO	NONON$$N' 'O)O<N?=OO	OOOOOc                     t         Cddl} ddl}| j                  j	                         rdnd}|dk(  rdnd}|j                  d||      a t         S )	zZLoad and cache the stable-whisper faster-whisper model (large-v3 for Portuguese accuracy).Nr   cudacpufloat16int8zlarge-v3)devicecompute_type)_stable_whisper_modeltorchstable_whisperr  is_availableload_faster_whisper)r  r  _device_computes       ra   _get_whisper_modelr  
  s\     $!JJ335&5 '6 19v . B B! !C !

 ! rv   c                t    t        j                  d| j                               }t        dt	        |            S )z@Estimate relative duration based on syllable count (Portuguese).u$   [aeiouáéíóúâêîôûãõàü]+r   )refindallr  r9  r   )wordvowel_groupss     ra   _estimate_word_durationr    s+    ::Etzz|TLq#l#$$rv   c           
         | D cg c]  }t        |       }}t        |      }|}g }t        |       D ]B  \  }	}|||	   |z  z  }
|j                  ||t	        |d      t	        ||
z   d      d       ||
z  }D |S c c}w )zADistribute duration among words proportionally to syllable count.   r  r  r  end)r  rH  r  r   rf  )wordsrv  
time_startr  wweightstotal_weightcursorr4  rM  word_durs              ra   _syllable_weighted_subtitlesr    s     499a&q)9G9w<LFF%  1!WQZ,%>?61%(*A.	
 	 	( M :s   A:z-/api/projects/{project_id}/generate-subtitlesc                	  K   t        |        d{   }|t        ddid      S |j                  d      }|st        ddid      S |j                  d	g       }t        d
z  | z  dz  }g }|D ]  }|d   }|j                  dd      }|sd}	dD ]!  }
|d|d|
 z  }|j	                         s|}	 n |	s|j                         }|s[|j                  dd      }t        |t              rJ|j                  d      }t        |      dk(  r t        |d         dz  t        |d         z   n
t        |      }|j                  dd      }|j                  t        ||||             	 t               }|j                  t        |	      |dddddddddddd       }|j                  dd      }t        |t              rJ|j                  d      }t        |      dk(  r t        |d         dz  t        |d         z   n
t        |      }|j                  D ]o  }|j                   D ]^  }|j#                  ||j$                  j'                         t)        ||j*                  z   d!      t)        ||j,                  z   d!      d"       ` q  |t        |      d'S 7 # t.        $ r t0        j3                  d#       	 dd$lm} |j9                  t        |	            }t        |      d%z  }n!# t:        $ r |j                  dd      }Y nw xY w|j                         }|sY |j                  dd      }t        |t              rJ|j                  d      }t        |      dk(  r t        |d         dz  t        |d         z   n
t        |      }|j                  t        ||||             Y 9t:        $ r}t0        j=                  d&||       |j                         }|sY d}~p|j                  dd      }t        |t              rJ|j                  d      }t        |      dk(  r t        |d         dz  t        |d         z   n
t        |      }|j                  dd      }|j                  t        ||||             Y d}~d}~ww xY ww)(zGenerate word-level subtitle timestamps from TTS audio files.
    
    Uses stable-ts for forced alignment of known TTS text with audio.
    Falls back to simple word-duration estimation if stable-ts unavailable.
    Nr   r7  r   r   r4  r  r   rC  rn   ra  rE  r@  r?   rP  r^  .opus.aac.flacr  r  r  r   :r   <   r   rH        @rI  TF皙?皙?      ?language	fast_modestream
token_stepnonspeech_skipvadvad_thresholdsuppress_silencesuppress_word_tsmin_word_durmax_word_durregroupr  r  z8stable-ts not installed, using duration-based estimation)AudioSegmentg     @@z*Subtitle alignment failed for scene %d: %s)	subtitlesr[   )r!   r   rU   rL   rM   r   r#  rS   r   r  rd  extendr  r  alignsegmentsr  r   r  r   rf  r  r  r3  rW   rZ   pydubr  	from_filerY   r   )r+  r;  r4  rC  r  r  r  r  r@  rs  rl  	candidater  r  r   r  r   	result_tssegment	word_datar  ry  audio_durationr`   s                           ra   generate_subtitlesr  )  s     Z((D|W&9:LLXXhFW&<=3OOZZ"%F)J6AJI J\>"99Z, 
= 	C"vbXcU%;;I!&
		 NN$E<3J*c*"((-EHZST_Sq]R/%a/AZ_`jZk
yy!3S9H9%:WYZ[.	\&(EC
OXX\ejwx  JN  TX  hl  C  VZ  im  |  IN  OI<3J*c*"((-EHZST_Sq]R/%a/AZ_`jZk
$-- !( I$$!# ) 4 4 6!&zIOO'CQ!G$Z)--%?C	& KJ\X #S^<<s )t  	bNNUVD.$..s:?!$Uf!4 D!&+=s!CD NN$E<3J*c*"((-EHZST_Sq]R/%a/AZ_`jZk
9%Q[]_`a 	\I2sSNN$E<3J*c*"((-EHZST_Sq]R/%a/AZ_`jZk
yy!3S9H9%:WYZ[[	\s   RJBR/B6R&DJRR6.K%$R%L RLRRB	R$R'R/)Q?RBQ?9R?RRz(/api/projects/{project_id}/subtitles.srtc                  K   t        |        d{   }|t        ddid      S |j                  d      }|st        ddid      S |j                  d	g       }|st        dd
id      S dd}g }t        |d      D ]  \  }}|j                  dd      j	                         }|s)|j                  dd      }	|j                  dd      }
|j                  t        |             |j                   ||	       d ||
              |j                  |       |j                  d        dj                  |      }t        |dddi      S 7 ;w)z4Export subtitles in SRT format from production plan.Nr   r7  r   r   r4  r  r   rC  r  c                   	 | j                  d      }t        |      dk(  rbt        |d         }|d   j                  d      }t        |d         }t        |      dkD  r!t        |d   j                  dd      dd       nd}nUd}|d   j                  d      }t        |d         }t        |      dkD  r!t        |d   j                  dd      dd       nd}|d	z  }|d	z  }|d
d|d
d|d
d|dS # t        t
        f$ r Y yw xY w)z;Convert 'MM:SS.ss' or 'MM:SS' to SRT format 'HH:MM:SS,mmm'.r  r   r   r   rR  r  0Nr  r  ,03dz00:00:00,000)r   r   r  ljustr7  
IndexError)time_strr   minutes	sec_partssecondsmillishourss          ra   _time_to_srtz*export_subtitles_srt.<locals>._time_to_srt  s"   	"NN3'E5zQeAh-!!HNN3/	il+@CIQR@RYq\//37;<XY!!HNN3/	il+@CIQR@RYq\//37;<XYrMElGC['#a}AfS\JJJ' 	"!	"s   C0C3 3DDr   r@  r?   r  z00:00time_endz00:03z --> r   z
text/plainzContent-Dispositionz$attachment; filename="subtitles.srt")r   r  r   )r  rS   r  rS   )	r!   r   rU   r  r   r   rS   r   r   )r+  r;  r4  rC  r  	srt_linesr  r  r@  r  r  srt_contents               ra   export_subtitles_srtr    sa     Z((D|W&9:LLXXhFW&<=3OOZZ"%FW&9:LL"( I* 	
U99Z,224YY|W5
99Z1S"L45U<;Q:RST"	 ))I&K&(NO [ )s   EED;Ez'/api/projects/{project_id}/export-videoc                T  5K   t        |        d{   }|t        ddid      S 	 |j                          d{   }t        dz  | z  }|d	z  }|d
z  }|j                  dd       |j                  dg       }i }t        |t              rB|D ]<  }	|	j                  d      xs |	j                  dd      }
|	j                  dg       ||
<   > nt        |t              r|}|j                  dg       }|j                  dg       }|j                  dg       }|j                  dd      }|j                  dg       }i }	 t        |        d{   }|D ]+  }|j                  dd      }|j                  dd      }|||<   - 	 |rt        |j                               nd}t        j                  d|dd       t!        |d        }|st        dd!id      S 	 ddl5dd"lm} dd#lm}m}m}m}m} d$}d%\  }} }!i d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6d7d8d9d:d;d<dd'd'd9d9d;d;d=d=d>d>i d)d)d+d+d-d-d/d/d7d7d?d?d@d@dAdAdBdBdCdCdDdDdEdEd1d1d3d3d5d5dFdFdGdGi dHdHdIdIdJdJdKdKdLdLdMdMdNdNdOdOdPdPdQdQdRdRdSdSdTdTdUdUdVdVdWdWdXdXi dYdYdZdZd[d[d\d\d]d]d^d^d_d_d`d`dadadbdbdcdcdddddededfdfdgdgdhdhdididjdkdl}"i dmdndodpdqdrdsdtdudvdwdxdydzd{d|d}d~dddddddddddddd}#dd}$|j                  di       }%|%j                  dd      }&|%j                  di       }'|'j                  dd      }(|'j                  dd      })|'j                  ddB      }*|'j                  dd      }+|j                  dd      },|,dkD  r|)dkD  r|,|)dz
  |+z  z   |)z  }-n|'j                  dd      }-|%j                  di       }.|.j                  dd      }/|.j                  dd      }0|.j                  dd      }1|.j                  dd      }2|%j                  di       }3|3j                  dd      }4|3j                  dd      }5|3j                  dd      }6|3j                  dd      }7|3j                  dd<      }8|3j                  dd      }9|%j                  di       }:|:j                  dd      };|:j                  dd      }<|:j                  dd      }=|:j                  dd      }>|%j                  di       }?|?j                  dd      }@|?j                  dd      }A|?j                  dd      }Bdd}Ct5        j6                  dt4        j8                        }Di }E|j                  di       }Ft        |Ft              rFj                  dg       ng }G|GD ]  }H|Hj                  dd      }I|Hj                  dd      }J|Idk(  r
ddJdEI<   7|/rDj;                  Jj=                               }K|KrKj?                  d      j=                         }L|LjA                  dd      }MtC        |M      dk(  r CMd         }N|NdN }LJKjE                         d j=                         }OdL|Kj?                  d      j=                         |OdEI<   ddJdEI<   ddJdEI<   	 t        j                  dEjG                         D PQci c]  \  }P}Q|P|Qd    c}Q}P        t        dz  | z  d	z  }Ri }S|/r)|4dkD  r#EjG                         D ]  \  }T}U|Ud   dk7  rd}VGD ]*  }W|Wj                  d      Tk(  sWj                  dd      }V n VsCdD ]  }XRdTd|X z  }Y|YjI                         s	 tK               }Z|ZjM                  tO        Y      Vddddddddddddū      }[|[jP                  D ]F  }\|\jR                  D ]/  }]d|]jT                  j=                         v s ]jD                  ST<    n TSv sF n  n TSvsdST<    t        j                  dS        tW               }_EjG                         D ]/  \  }`}a|ad   dk(  s`dkD  s`dz
  }b|b|v s_jY                  b       1 tW               }c|/rZ_D ]  }d||dxx   |5z  cc<    EjG                         D ]   \  }d}e|ed   dk(  sd|v s|dxx   |4z  cc<   " |D ]  }d|d_vs|dxx   |6z  cc<    t!        |j[                               }ft]        |f      D ][  \  }g}h|gdk(  rfgdz
     }i|i_vsEj                  hi       j                  d      dk7  s>|hxx   |7z  cc<   cjY                  |h       ] t        |j                               }t        j                  dtC        _       d|5 dt        d΄ Ej                         D               d|4 d|6 d|7 dtC        c       d|dd       g }jg }kt!        |dԄ        }t!        |dՄ        }ld}mg }ng }og }pg }q5fdք}rt]        |      D ]  \  }s}t|tj                  d׫      xs% tj                  dث      xs tj                  dd      }u|usBt        uj_                  dګ      z  }v|vjI                         st        j                  dv       tj                  ddܫ      }w|w}x|r;tj                  d      }|sdz   }|j                  |d      }y|ydkD  rta        wy      }wstC        |      dz
  k(  r5tO        v      jc                  dݫ      r rv      nd}z|zdkD  rta        wz      }wdm }{tO        v      jc                  dݫ       }|tj                  d߫      }}te        ||xr }xr }j                  d            }~|s(jjg                  dtO        w      dtO        v      g       nH~rjjg                  dtO        v      g       n)jjg                  dddtO        w      dtO        v      g       ~rti        w|!z        }}j                  dd      }|}j                  dd      }|}j                  dd      }|}j                  dd      }|}j                  dd      }|}j                  dd      }kjk                  djm                  g dm d|dz   d| dz   d| d| d| d| d| d| d| d| d| d| d| d| d| d| d| d|  d|! d{ d             n|r(kjk                  dm d| d|  d| d|  d|! d{ d       nv rv      }|dkD  r<wkD  r7wz  }kjk                  dm d| d|  d| d|  d|! d|dd|wd d{ d       n-kjk                  dm d| d|  d| d|  d|! dwd d{ d       njk                  {       ojk                  w       pjk                  tj                  dd             qjk                  | m|wf       |mdz  }m |(rEj                  di       j                  d      dk(  rtC        n      dkD  rg }t]        |dd d      D ]  \  }}tC              |)k\  r nwj                  d׫      xs% j                  dث      xs j                  dd      }|sQt        j_                  dګ      z  }|jI                         szjk                          rH|j                  dd      }|dkD  r-ta        dtC              |-z  tC        |      dz
  |+z  z
  z
        nd}g }t]              D ]  \  }}tO        |      jc                  dݫ      }d| }|-}|tC              dz
  k(  r
dkD  rz  }r,jjg                  dddtO              dtO              g       n)jjg                  dddtO              dtO              g       kjk                  dm d| d|  d| d|  d|! d d       jk                  |       |mdz  }m tC              dk(  rd   }|-z   }nd   }|-}to        dtC        |            D ]  }ta        d|+z
        }|tC              dz
  k  rd nd}kjk                  d d    d	|* d
|+d dd d| d       |}|tC        |      dz
  k(  r|-z   |+z
  z  }z|-|+z
  z  } }}d}kD cg c]  }|jc                  d d      r c}kdd nd<   od<   t        j                  dtC               d|dd       i }t]        o      D ]  \  }}||dz   <    ort        o      nd}|r|D ]  }|j                  dd      dz  z  } t        j                  ddd       d}ta        d||z
        }tC        n      }|dk(  rt        ddid      S i }|D ]M  }|j                  dd'      |j                  dd      d|j                  d      |j                  d      f<   O to        dtC        p            D ]\  }|dz   }Ej                  |i       j                  d      dk(  s-pdz
     |p|   f}dBdd|<   t        j                  d        ^ to        dtC        p            D ]_  }|dz   }Ej                  |i       j                  d      dk7  s-pdz
     |p|   f}|8|9d|<   t        j                  d|8 d        a dk(  rnd   }nod   }nd   }to        d      D ]  }p|dz
     |p|   f}j                  |d'dd      }|d   }|d   }|"j                  |      }|d'}d}ta        dz
        }dz
  k  rd nd}kjk                  d dn    d	 d
d dd d| d       |}o|   |z
  z  } }|%j                  dd      }||#v r!|#   }kjk                  d d| d       d}kjk                  d dd d d d!       d"}i }d}t]        o      D ]  \  }}|dz   }|<   d}|tC        o      dz
  k  s$d#}tC        p      k  rDdz   tC        p      k  r3p   |p|dz      f}j                  |      }|rj                  dd#      }z
  z  } dd$l8m9} d%d&d'd(}|%j                  d)i       }d*|vrj                  |&d%      d*<   g }|sp	 |j                  di       }t        |t              rj                  dg       ng }t        dz  | z  d	z  }R|D ]  }|j                  dd      }P|Psj                  Pd      }j                  dd      }|s@Ej                  Pi       }|j                  dd      }|dk(  r%j                  d+      rĐd+   }|/rd|1z   dz   nd}n
}Pcv r|7nd}|j                  Pj                  ddܫ            }sjA                         }|sd}ʐd,D ]  }RdPd|˛ z  }|jI                         s	 tK               }dk(  rn}jM                  tO        ̫      |ddddddddddddū      }|jP                  D ]l  }|jR                  D ][  }dk(  r|/r|4nd}jk                  jT                  j=                         |z   |jt                  z   ||z   |jD                  z   d-       ] n d} n rz   }|z
  }tw        ta        |d      |P      }|D ]$  }jk                  |אd/   |אd0   |אd1   d-       &  r$t        j                  d2tC               d3       |D ]  }|j                  d5d      }|j                  d6g       D ]d  }|j                  d/d      j=                         }|s'jk                  j                  d5d      z   ||j                  d7d      z   d-       f  rjy                  d8         to        dtC        |            D ]R  }|   d0   ||dz
     d1   k  rdz
     d1   ||   d0<      d1   ||   d0   k  s@   d0   dz   ||   d1<   T to        tC              dz
        D ]Y  }|dz      d0   }||   d1   |kD  r	   d1<      d1   ||   d0   z
  d9k  s<t{           d0   d9z   ݫ      ||   d1<   [ |dkD  rta        |      n}r_|d:z  } |dkD  rnd;|| <       |/r|0d=k7  rdd>l8m>} g }|dz  | d?z  }}EjG                         D ]  \  }}|d   dk7  sj                  d@      s!j                  d      }||1z   }d@   j                         }|j                  dAdB      j                  dCdD      j                  dEdF      } |      } ||      }dG}jk                  dH| d| dI d dJ| dE|         rj                  dKL      }dM|2 dN}|j                  dOdP| dO      }|jc                  dP      sdPz  }dPjm                        dPz   z  }j                  |dKL       t        j                  dQtC        |       dR       tO        ߫      j                  ddS      j                  dTdU      }tO        t        dVz  dWz        j                  ddS      j                  dTdU      }kjk                  d dX| dY| dZ       d[}t        j                  d\|j                  d*d&             g }g }g }t]        l      D ]  \  }}t|tj                  dd      }u|ust        uj_                  dګ      z  }v|vjI                         sDtj                  d      }|8ddl}|j                  d]u      }|rti        j?                  d            ndz   }jjg                  dtO        v      g       jk                  m       jk                  tj                  dd             jk                         |mdz  }m d}rg }to        tC                    D ]W  }|tC              k  r   ndz   }|/xr$ Ej                  i       j                  d      dk(  }_v }    d^}|rSv rS   }d_ }d`| } da| }db| }dc| }dd| }de}kjk                  d df| d|  d       |kjk                  d| dg|d dh| d| d	       |kjk                  di|4d dj| d       |kjk                  d|  dk|d dh| d| d	       |kjk                  d| d| d| dl| d	       |}t        j                  dm|4 dn|ddo| dp       cv r|7dkD  rdq }dr| }ds| }de}	kjk                  di|7d dj| d       |kjk                  d d|	 d| d       |kjk                  d| d| dt| d       |}t        j                  du|7 dv dp       j                  |j                  |dw            }
dx }kjk                  d dy|
d d| d       |}jk                  |       Z tC              dk(  rd   }n|sAdjm                  dz D              }kjk                  | d{tC        |       d|       d}}nd   }to        dtC                    D ]  }d}|dz
  tC        p      k  rLtC        p      k  r>pdz
     |p|   f}j                  |      }|rd   }|"j                  |      d   }nd}tC              dz
  k  rd~ nd}}kjk                  d d    dd d| d	       |} d}}t        d qD              }|rta        dt{        dt        |%j                  dd                        }g }t]        q      D ]  \  }\  }}}d| }|dz   }ti        j                  |d      dz        }|r2kjk                  d dddd d d| d d       nkjk                  did dj d       jk                          tC              dk(  rd   }nCdjm                  d D              }kjk                  | dtC        |       d       d}rDkjk                  d d d       d}t        j                  dti        dz               n(}t        j                  dti        dz               |;rPrMt        dVz  dz  }g }d}|=rŐdz  }|jI                         rEjG                         D ]  \  }}|d   dk7  rti        j                  d      dz        }d } jjg                  dtO              g       kjk                  dm d|>dd| d| d|  d       jk                  |        |dz  }|mdz  }m |<r|(rEj                  di       j                  d      dk(  rΐdz  }!|!jI                         rt{        |)ta        dtC        |      dz
              }"to        d|"      D ]  }#ti        |#|-z  dz        }$d } jjg                  dtO        !      g       kjk                  dm d|>dd|$ d|$ d|  d       jk                  |        |dz  }|mdz  }m ryd ddjm                  d D              z   }%dtC        |      z   }&kjk                  |% d|& d       d}t        j                  dtC        |       d|> d       @rrd}'Brt        Bz  }(|(jI                         r(}''t        dVz  dz  dz  }''jI                         rjjg                  dtO        '      g       m d^})d}*kjk                  d|) dd dAd dta        d|d?z
        d d|* d       |kjk                  d d|* d       d}|mdz  }mt        j                  d|Adz  dd|dd       nt        j                  d'        d}lr6|r4t]        l      D ]&  \  }}+|+j                  d|      }||v s|||   z  }( |dk(  r|rt        |j                               }|dkD  r6t        j                  d|dd       t        j                  ddd       |dkD  rFrD|kD  r?},kjk                  d dy|,d d       d}t        j                  d|,dd       djm                  k      }-ddg}.|.jg                  j       |.jg                  d|-g       |.jg                  dd dg       r.jg                  dd dg       .jg                  g dddddddddddddddddddddÑdđdődƑdǑdđdȑdɑdʑdˑd̑d͑dΑdϑdБdёdґdӑtO        |             t        j                  dԫ       t        j                  ddd       t        j                  d|dd       t        j                  dtC        |              t        j                  dtC        l              t        j                  dtC        |              |rt        j                  d|        t        j                  dېdjm                  .             t        j                  |.t        j"                  j                  t        j"                  j                  dݜ d{   }/|/j                          d{   \  }0}1/j                  dk7  rI1j                  dސdߐ      dd }2t        j                  d|2       t        dd|2 id      S d|  d}3d|3|j                         j                  dS 7 (7 (# t        $ r t        ddid      cY S w xY w7 '# t        $ r#}t        j                  d|        Y d}~'d}~ww xY wc c}Q}Pw # t        $ r&}^t        j                  dT d^        Y d}^~^!d}^~^ww xY wc c}w # t        $ r#}t        j                  d.Pӫ       Y d}~Ӑd}~ww xY w# t        $ r$}t        j                  d4؛        Y d}~ؐ}d}~ww xY w7 7 # t        $ r t        ddid      cY S t        $ r;}4t        j                  d|        t        dd4 id      cY d}4~4S d}4~4ww xY ww(  zExport final video using FFmpeg server-side composition.
    
    Receives editor project JSON with clip timings, effects, and settings.
    Composes all video/image/audio clips into a single MP4.
    Returns download URL when complete.
    Nr   r7  r   r   zInvalid JSON bodyr   rn   ra  final_export.mp4Tro   tracksrI   r  r?   clipsr  ry  subtitler  r   transitionsrE  rH  z!Could not fetch audio durations:         zTotal audio duration from DB: z.2fr'  c                &    | j                  dd      S N	startTimer   r  r   s    ra   r  zexport_video.<locals>.<lambda>  s    155a;P rv   )r   zNo video clips in project)DurationReconciler)fetch_scene_audio_durationscalculate_total_video_durationbuild_audio_filter_chain"apply_audio_sync_to_ffmpeg_commandlog_sync_detailsz(/usr/share/fonts/TTF/DejaVuSans-Bold.ttf)i8  i  r  	crossfadefadez
slide-left	slideleftzslide-right
sliderightzslide-upslideupz
slide-down	slidedownzoomsmoothupz
cross-zoom
smoothdownspin
circleopenzcircle-wipe
circlecropz	wipe-leftwipeleftz
wipe-right	wiperightcutwipeupwipedownrectcropdistance	fadeblack	fadewhiteradial
smoothleftsmoothrightcircleclosevertopen	vertclosehorzopen	horzclosedissolvepixelizediagtldiagtrdiagbldiagbrhlslicehrslicevuslicevdslicehblur	fadegrayswipetlwipetrwipeblwipebrsqueezehsqueezevzoominfadefastfadeslowhlwindhrwindvuwindvdwind	coverleft
coverrightcoverup	coverdown
revealleftrevealrightrevealup
revealdown)r'  r(  warmz9eq=brightness=0.04:saturation=1.3:gamma_r=1.1:gamma_b=0.9coolz9eq=brightness=0.02:saturation=1.1:gamma_r=0.9:gamma_b=1.1	cinematicz/eq=brightness=-0.05:contrast=1.2:saturation=0.9vibrantzeq=saturation=1.5:contrast=1.1bwzeq=saturation=0vintagez+eq=brightness=0.06:saturation=0.7:gamma=0.9z
film-grainz8noise=alls=20:allf=t+u,eq=brightness=-0.02:contrast=1.05vignettezvignette=PI/4bloomzgblur=sigma=5,eq=brightness=0.1zhigh-contrastz/eq=contrast=1.5:brightness=-0.05:saturation=1.1mutedz/eq=saturation=0.5:brightness=0.03:contrast=0.95sepiazBcolorchannelmixer=.393:.769:.189:0:.349:.686:.168:0:.272:.534:.131zteal-orangezPcolorbalance=rs=0.1:gs=-0.1:bs=-0.1:rm=0.1:gm=0.0:bm=-0.1:rh=0.0:gh=-0.05:bh=0.1noirzHeq=saturation=0:contrast=1.4:brightness=-0.1,curves=preset=cross_processdreamyz<gblur=sigma=2,eq=brightness=0.08:saturation=1.2:contrast=0.9horrorzGeq=brightness=-0.15:contrast=1.3:saturation=0.4:gamma_r=1.2:gamma_b=0.8c                    | j                  dd      } | j                  dd      } | j                  dd      } | j                  dd      } | S )	z)Escape special chars for FFmpeg drawtext.r  \\'z'\''r  \:%z%%)replace)texts    ra   _sanitize_drawtextz(export_video.<locals>._sanitize_drawtextQ  sG    <<f-D<<W-D<<U+D<<T*DKrv   effectssubtitleModesingle_wordintroenabled	clipCount   
transitiontransitionDurationg?r   clipDurationg?timeMarkersr  slamg333333?fontSizetiming	markerGapg      ?preMarkerGapg      ?sceneEndSilenceg      ?sceneStartSilencestandardTransitionstandardTransitionDurationgMbP?sfxmarkersvolumebgMusicgffffff?filec                N   dddddddddddd	d
}dddddddddddd}ddddddddd}i dd d!d d"d#d$d#d%d&d'd&d(d)d*d)d+d,d-d,d.d/d0d/d1d2d3d2d4d5d6d5d7d8d9d8i}d:d;i}| j                  d<d=      j                         D cg c]1  }|j                         s|j                         j                         3 }}|sy>d?}d?}	|D ]H  }||v r	|	||   z  }	||v r	|	||   z  }	||v r	|	||   z  }	*||v r	|	||   z  }	7||v r|	r|	nd||   z  }	H y> ||	z  }|d?kD  r|S d>S c c}w )@zLConvert Portuguese written number to integer. Returns None if not parseable.r   r   r     rD        r  	   )umumadoisduasu   trêstresquatrocincoseisseteoitonoverZ     r        r   r           )dezonzedozetrezecatorzequatorzequinze	dezesseis	dezessetedezoitodezenover  r  (   2   r  F   P   Z   )vintetrintaquarenta	cinquentasessentasetentaoitentanoventacemr  centoduzentosr  duzentas	trezentosi,  	trezentasquatrocentosr   quatrocentas
quinhentosr   
quinhentas
seiscentosiX  
seiscentas
setecentosi  
setecentas
oitocentosi   
oitocentas
novecentosi  
novecentasmil  z e r   Nr   )r;  r   r   r  )
r<  UNITSTEENSTENSHUNDREDSSPECIALr  r  rE  r   s
             ra   _pt_words_to_numberz)export_video.<locals>._pt_words_to_number  s*   Q1qRS 1aAWXZEBPR`b!PR`bdE22B "rbRQD>s >GS >*c >:s >#S>*5s><JC>Q_ad>$c>+7>>JC>Q]_b> %c> ,8> ?KC> R^_b> %c	> ,8	>H
 dmG04UC0H0N0N0P^1TUT[T[T]QWWY__&^E^EG  :uQx'G%ZuQx'G$YtAw&G(]x{*G'\*1wqGAJFG  WE!AI5/4/' _s   D" D"z^(Dia\s+[\w\s]+?)\.\s*r4  rC  r@  )r  marker_textnarrative_textr   zDia time_marker)r  r  original_marker_textr  	narrativezScene types detected: )r^  rP  r  r  r  r  r  rI  Fr  r  r  r  rR  z+Marker boundary detection failed for scene z: g?zMarker voice boundaries: zExtended audio: z pre-marker scenes (+zs), c              3  2   K   | ]  }|d    dk(  sd  yw)r  r  r   Nru   r{  s     ra   rC  zexport_video.<locals>.<genexpr>  s     [Q!F)]BZq[r~  z markers (+zs), standard scenes (+zs end, +zs start on z scenes), total: c                &    | j                  dd      S r  r  r  s    ra   r  zexport_video.<locals>.<lambda>      quu[RS?T rv   c                &    | j                  dd      S r  r  r  s    ra   r  zexport_video.<locals>.<lambda>  r  rv   c                    	  j                   ddddddt        |       gddd	      }t        t        j                  |j
                        d
   d         S # t        $ r Y yw xY w)Nffprobez-vquietz-print_formatrP   z-show_formatTrZ  )capture_outputr<  r  r  r  r  )runrS   rd  rP   rQ   stdoutrY   )r]   r  
subprocesss     ra   _get_video_durationz)export_video.<locals>._get_video_duration"  sn    "JNNgX[\`Xab#'dB TZZ1(;JGHH s   AA 	A#"A#videoUrlimageUrlsrcrr   zExport: missing file %sr  r  r   kenBurnsz-tz-iz-loopr  
startScaleendScalegffffff?startXstartYendXendY[z	:v]scale=r  z,zoompan=z='min(z+(-z)*on/r  z
)':x='iw*(z)-iw/zoom/2':y='ih*(z)-ih/zoom/2':d=z:s=xz:fps=z
,setsar=1[]z*:force_original_aspect_ratio=decrease,pad=z(:(ow-iw)/2:(oh-ih)/2:black,setsar=1,fps=z,setpts=PTS/z.4fz
,trim=end=z.3fz<,setpts=PTS-STARTPTS,tpad=stop_mode=clone:stop_duration=0.5[)r  montagez-ssz0.3mxfmontage_finalz][z]xfade=transition=z
:duration=z:offset=v0zIntro montage: z clips, zs totalz+Adjusted video duration (with audio sync): g       @zNo valid video sources found)r  r  
fromClipIdtoClipIdg333333?z5Forced fadewhite transition before TIME_MARKER scene zForced z" transition before standard scene xfvxfadecolorGradingz	[vgraded]vgradedz]fade=t=out:st=z:d=z[vfade]vfadeg      ?)generate_asssingle_word_poptiktok_karaokebold_center)r@  karaokegroupedsubtitleStylepresetr  r  )r<  r  r  z)Whisper alignment failed for scene %d: %sr  r  r  zAuto-generated z subtitle wordsz!Auto-subtitle generation failed: r  r  endTimec                    | d   | d   fS )Nr  r  ru   )r  s    ra   r  zexport_video.<locals>.<lambda>  s    !G*ah)? rv   g{Gz?zsubtitles.assi'  )word_timingsr  video_durationr  video_widthvideo_heightnone)_fmt_ass_timer  r  r  r7  {z\{}z\}z*\fscx180\fscy180\t(0,100,\fscx100\fscy100)zDialogue: 1,z,Marker,,0,0,0,,{\pos(z=)\an5\blur0.8\bord8\3c&H000000&\1c&HFFFFFF&\shad3\4c&H000000&z	utf-8-sigr;   zStyle: Marker,Anton,zQ,&H00FFFFFF,&H00FFFFFF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,8,3,5,0,0,0,1z


[Events]r   z	Injected z! marker ASS events (3-layer glow)r9  r8  z\'webfontsz]ass=z
:fontsdir=z:shaping=complex[vsub]vsubz(ASS subtitles generated at %s (style=%s)zframe_(\d+)z:aas1_as2_amp_asil_anp_agap_z/aformat=sample_rates=44100:channel_layouts=monoz]asplit[z	]atrim=0:z,asetpts=PTS-STARTPTS,zaevalsrc=0:d=z:s=44100:c=mono[z]atrim=z]concat=n=3:v=0:a=1[z	Inserted zs silence at zs in scene z audioapresil_afmt_aprecat_z]concat=n=2:v=0:a=1[z
Prepended zs silence to scene g      @afinal_z]apad=whole_dur=c              3  (   K   | ]
  }d | d  ywr  r  Nru   )rA  lbls     ra   rC  zexport_video.<locals>.<genexpr>(  s     Cs!C5
C   z	concat=n=z:v=0:a=1[aout]aoutaxfz]acrossfade=d=c              3  (   K   | ]
  \  }}}|  y wr   ru   )rA  is_vid_s      ra   rC  zexport_video.<locals>.<genexpr>@  s     JAfJr  videoVolumevar  z
:a]volume=z	,atrim=0:z,asetpts=PTS-STARTPTS,adelay=|c              3  (   K   | ]
  }d | d  ywr  ru   )rA  ls     ra   rC  zexport_video.<locals>.<genexpr>V  s     !>qAaS(!>r  zamix=inputs=z=:duration=longest:dropout_transition=0:normalize=0[vid_audio]	vid_audiozH]amix=inputs=2:duration=longest:dropout_transition=0:normalize=0[amixed]amixedz.Mixed video audio (%s%% volume) with TTS audior  z,Using video audio only (%s%% volume, no TTS)zding.mp3z,adelay=zcamera_flash.mp3c              3  (   K   | ]
  }d | d  ywr  ru   )rA  sls     ra   rC  zexport_video.<locals>.<genexpr>  s     ;["at1I;[r  z8:duration=longest:dropout_transition=0:normalize=0[asfx]asfxzMixed z SFX into audio (volume=r`  z	music.mp3bgmz"]aloop=loop=-1:size=2e+09,atrim=0:z,volume=z$,afade=t=in:st=0:d=2,afade=t=out:st=z:d=3[zD]amix=inputs=2:duration=first:dropout_transition=0:normalize=0[abgm]abgmzMixed background music at z.0fz%% volume, looped to z.1fz!Background music file not found: zTotal audio duration: zCalculated video duration: z	[apadded]apaddedzPadded audio with silence to ;ffmpegz-yz-filter_complexz-mapz-c:vlibx264z
-profile:vhighz-level:vz4.2z-presetslowz-crf18z-pix_fmtyuv420pz-color_rangetvz-colorspacebt709z-color_primariesz
-color_trcz-r30z-g60z-keyint_minz-sc_thresholdr  z-c:arZ  z-b:a192kz-ar48000z-ac2z	-movflagsz
+faststartzExport config:z  Video duration: z  Audio duration: z  Video clips: z  Audio clips: z  Transitions: z  Scene audio durations: zFFmpeg export command: %sr   )r  stderrr:   r;  )errorsizFFmpeg export failed: %szFFmpeg export failed: r   r  z/final_export.mp4r  r{   download_url	file_sizez5FFmpeg not found. Install it: sudo apt install ffmpegz"Video export failed for project %szExport failed: )r<  rS   r  rS   )r<  rS   r  z
int | None)Qr!   r   rP   rY   rL   r   rU   r#  r$  dictr$   rW   rZ   rH  valuesrX   rN   r  providers.audio_syncr  providers.export_utilsr  r  r  r  r  r  compile
IGNORECASEmatchr   groupr   r   r  r   rM   r  r  rS   r  r  r  r   r   r  r  lstripr9  endswithr   r  r  r   r   rangeweb.subtitle_enginer  r  r  sortr:  r  upperr;  rR   r   searchanyrd  r   create_subprocess_execPIPEcommunicate
returncoder  r   rd  re  FileNotFoundErrorr   (6  r+  r   r;  editor_datar  
assets_direxport_path
raw_tracks	track_mapttidvideo_clipsaudio_clipssubtitle_clipsr  r  audio_durationsproject_audiosry  r  duration_secetotal_audio_durationvideo_clips_sortedr  r  r  r  r  r  DEFAULT_FONTWHFPS	XFADE_MAPCOLOR_PRESETSr=  r>  subtitle_mode	intro_cfgintro_enabledintro_clip_countintro_transitionintro_transition_duration_intro_audio_durintro_clip_duration
marker_cfgmarkers_enabledmarker_stylemarker_durationmarker_font_size
timing_cfg
marker_gappre_marker_gapscene_end_silencescene_start_silencestandard_transitionstandard_transition_dursfx_cfgsfx_enabledsfx_transitionssfx_markers
sfx_volumebgm_cfgbgm_enabled
bgm_volumebgm_filer  TIME_MARKER_REscene_typesproj_result_stproj_scenes_stscene_stsn_sttts_text_stmatch_stmarker_text_st	day_wordsnumrest_str  stoutput_dir_assetsmarker_voice_endssn_mvst_mvtts_mvscene_mvext_mvaf_mvmodel_mvres_mvseg_mvwd_mve_mvpre_marker_scenessn_pmst_pmprev_snscene_start_silence_scenessn_extst_extsorted_scenesidx_sssn_ss
prev_sn_ssinputsfilter_partsaudio_clips_sorted	input_idxvideo_labelsclip_durationsclip_idsvideo_audio_infor  
clip_indexclipr  rD  clip_durationeditor_clip_duration	audio_duractual_last_vid_durr7  is_imagekbuse_ken_burnsframess_scalee_scales_xs_ye_xe_yactual_vid_durspeed_factormontage_sourcesmc_idxmc_clipmc_srcmc_pathintro_audio_durintro_extramontage_labelsmimc_is_videomc_labelmc_durmontage_outmontage_total_durmc_prevmc_cummci	mc_offsetmc_outold_v0_labelfscene_to_clip_durcicdcalculated_video_durationtrvid_fade_durvid_fade_startntrans_lookupci_trtr_scene_numtr_key	vid_labelcum_durprevrM  r   tr_typetr_durffmpeg_nameoffsetoutcolor_preset	eq_filterscene_start_timestm_cumsiscene_num_for_time
tr_overlaptr_infor  _subtitle_mode_presetssubtitle_style	all_wordsproj_resultrC  r  cum_timer@  st_infost_typesub_texttiming_offset	scene_durr  alignedrl  
audio_filer   
align_textr  r  wd_audio_offsetwhisper_exc	sub_startsub_dursubsr'  sub_excsub_clip
clip_startr  	word_text
next_startfinal_durationass_path_fmt_marker_timemarker_ass_eventspos_xpos_ytm_sntm_infotm_starttm_endtm_textts_startts_end	slam_animass_contentmarker_style_defass_path_escaped	fonts_diraudio_inputsaudio_clip_idsrx  ai_clipa_scene_num	_re_audio_m_sn	aud_labelaudio_labelsai_idxa_snis_tmis_precurrent_labelmv_ends1s2mpsilnp_gapfmtpre_silpre_fmtpre_catfmt_str
target_durpaddedarefsprev_aout_ahas_video_audio	video_vol	va_labelsva_ir  vid_idxva_durva_labelva_sceneva_start_msvid_audio_labelva_refssfx_dir
sfx_labelssfx_input_count	ding_pathtm_start_mssfx_lbl
flash_pathmontage_src_countfliflash_time_msall_audio_refs	total_mixbgm_pathbgm_candidatebgm_input_lbl
bgm_stream
audio_clippad_durfilter_complexcmdprocr  r  	error_msgr  r`   r  s6                                                                                                                                                                                                                                                                                                                       @ra   export_videor2    sw5     Z((D|W&9:LLM#LLN* )J6Jh&J11KTD1 2.JI*d# 	0A%%+2vr!2CUU7B/IcN	0 
J	%	--,K--,K]]:r2Nz1-H//-4K O@1*==# 	6E		.!4I 99%7;L)5OI&	6 =L35578QT
KK01Ec0J!LM  1PQW&ABPSTT^
;	
 	
 B"	1c(
(
 +(
 (5l(
 		(
 $0	(

 J(

 !-l(
 L(
 #0(
 (
 &2;(
 4(
 F(
 
(
 %0(
 h(
 !+J(
 (
 '3L(
 y(
 #.{(
 ,(
 )3J(
  
!(
  %0!(
" #(
" '/#(
$ ,%(
$ )6}%(
& 
'(
& %1,'(
( ,)(
( )6})(
* 
+(
* %0+(
, 
-(
, %0-(
. 
/(
. %/
/(
0 h1(
0 !)(1(
2 h3(
2 !)(3(
4 y5(
4 #,Y5(
6 y7(
6 #,Y7(
8 W9(
8 *;9(
: h;(
: !)(;(
< h=(
< !)(=(
> 
?(
> %/
?(
@ hA(
@ !+JA(
B 
C(
D hE(
D !)(E(
F hG(
F !)(G(
H I(
H '3LI(
J yK(
J #.{K(
L ,M(
L )6}M(
N #,O(
	T
T
T
 J
 9	

 *
 F
 W
 _
 >
 N
 N
 a
 o
 g
 [
  f!
&	 //)R0  NMB KK,	!i6$==a8$=={C$-MM2F$L! +..q!4a$4q$8#37G!7KOh6h#hl|"|"+--"D [[3
$..D9!~~gv6$..S9%>>*c:[[2.
^^K6
#<&NN+<cB(nn-@#F(nn-A5I",..1Mu"U ++eR(kk)T2!++mT:kk)T2[[3/
 ++i,kk)T2[[40
;;vt,"	0J $=r}}M(B/=GX\=]++Hb9ce& 	oHLL3E",,z26Kz.5d^i%jE" )//0A0A0CD%-^^A%6%<%<%>N . 4 4T1 =I9~*1)A,??/3C5\N)(,,./:@@BG2?P^  yA  yG  yG  HI  yJ  yP  yP  yR  fm  *nK&2=dfq)rK&.9$bm%nE")	o* 	,KL]L]L_.`&"br2f:~.`,bcd *H4zAHLzA~ + 1 1 3 3u=M1 . H||N3u<!)j"!= H F-&sF80LLE||~j'9';H%-^^CJQUaens  AB  SW  ]a  qu  HL  _c  rv  EH  RW^  &XF*0// *-3\\ !.E'*ejj.>.>.@'@CH99(9%(@(-!. $),=#=$)*    11/2%e,738 KK34E3FGH  E'--/ 	3LE5V}-%!)!)o-%))'2		3 &)U"+ :'>9':"-"3"3"5 :&>]2v7P#F+z9+: * A!22#F+/@@+A #?#7#7#9:M!*=!9 :Q;*6A:6
%66;??5RT;U;Y;YZ`;aer;r#E*.AA*.2259: $''='='?#@ KK*3/@+A*BBWXfWggk[+*<*<*>[[\\ghrgs t-->,?xH[G\\ghk  mG  iH  hI I""6s!;1> ?  $K5TU#K5TU		 !**< = \	J((:&U$((:*>U$((5RTBUC%

37I##%8)D HHZ5M#0   HH^4	$ *QI+//	1=	q=$'y$AMS!34q88HKIH_H_`fHg&9)&Dmn#&*$'7J$KM	{OEy>226::H*%B !Fb!FRVVI5FGMtS%7s9~NOtS^45 wT3}3EtSQZ^\]]S01&&s3&&T2ffXs+ffXs+ffVS)ffVS)##) )a )	{ )) )AaC5 ) )!A# ) 7& )&-Y).0)18	)9:);B))CH)IO)PQ)RYQZ)[)"e)#%)&)U)*+),/5)05)6<X)>)  #e) $&) '*U) +,) -05) 16) 7=X)>) !	) "%	) &'C	) ()	) *+	) ,1	) 25	)6 	)
 !&w)
 '() ##	{)A3as 3#Qqc "$$'5%3 "5Y!?!A%-.*H#1M#AL ''I;is!A3 7 c1# &((+u -&&23%7 8$$1##6 7BBGK !''I;is!A3 7 c1# &((+u -$$1##6 7BBG	K &!!-0OODHHT2./##\9m$LMNIy\	~ [__Q377?7JsS_O`cdOd O#,-?-C1#M 8'+;; Z0eGKK
4Kew{{[`bdOe+fmmC.@@G~~''..w78 "1"5"5a"; bq  tu  buc!_O8LOb8bfijyfz}~f~  C\  f\  9\  &]  ^  {|!##,_#= #KB"%g,"7"7"?K!(~H0FS1A55+/+-"ueT3v;cRYl&[\wT3v;cRYl&[\ ''I;is!A3 7 c1# &((+uAhZq:
 #))(3NI##$ ~&!+"0"3K(;k(I%,Q/G0F$QN(;< V$'64M+M$N	03c.6IA6M0M3seSb$++y>#+>*??QRbQc()B3(GxPYZ]^_`f_gghj #)#n"5"99"':['HLe&eeF"&9<U&UUFV #*K(.%#.:"b!**qQ]P^^_M`Ba1"bQ"-Q$5q!oc/.B-C8L]^aKbbijk / 	+FB(*b1f%	+ <JC$7s!! K)RVVJ-Ds-JJ)KAB[\_A``abc Q 9L HI6*H IWZ[[  	Bvv.FF:s3HL"&&.z0BCD	 1c(m, 	dE 19L|R044V<M"519-x?0;'MV$ST`Sabc	d 1c(m, 	mE 19L|R044V<M"519-x?0CQh'iV$g&9%::\]i\jkl	m 6$QI$Q'G?D1a[ 6A4!%%cF+LMV*J'mmG4&"(K"FQ& 01"#a!e)1#h##vRQ00B;- HVCL#aI >!,v55'6( I {{>26=(%l3I!I;a	{) DE!I 	a	{/.9MSQ]^aPbbijk	 / 	*FB!#a4:01JC'!++!
H%"q&3x=*@&rlHR!V,<=F*..v6G%,[[T%B
"z/)	*  	5 -'$"

 !_b9>)'='A'A-Qb'cN8$	EN"hhx4:D[RV:W26]_$1H$<z$IH$T! $ :E>15B 044R;H$yyR8H# )oob"5G%kk&+>G-/GKK@P4Q#*+;#<JY)>)E_` $,?AE_?_(;ef / 3 3B		BTVY8Z [I# $NN,E  #GI "%66"S#9O%O
%,,.m(:(<9@M9QXW_
,1KKJ^bnr  |A  NO  `d  jn  ~B  UY  lp  C  RU  _dK  -e	/8/A/A 	!+G.5mm %+ HOR_G_ds
z{(1(8(846GGMMO5=5MPRPXPX5X3;m3Kbff3T:* )+	%+	!+ +/ "+", #$,}$<	"+m";;E3wPSCTV_acd!% A%,,()&	)*7'(x. k:v KK/#i.1A QR ' 
	H!k15J\\'2. EE&"-335	   %'!%%Q*??%i(;;" 	
	 NN?N@1c)n- GQ<(9QU+;E+BB,5a!e,<U,CIaL)Q<&)A,w*??*3A,w*?$*FIaL'G 3y>A-. X&q1u-g6
Q<&3*4IaL'Q<&1g)>>E*-il7.Cd.JJ*WIaL'X RfhiQi68LM  pI!O3H&$1?!1C~$ <6#9Q$&! AvqAvu&1&7&7&9 NE7v-7w{{=?Y 044UA>H%7F%m4::<G%oodF;CCCOWWX[]bcG/9H-f5F MI &,,&xj& :##('5' 2IIRSUV]U^`$ %"*"4"4k"4"JK //?.@ A? @ %
 #."5"5&-.l;#K '//5#t+499->#?$#FFK''k'JKK)C0A,B+CCd ef"8}44S%@HHfUME1G;<DDS%PXXY\^deI!I;e4D3EZPY{Zp qrIKKBHnN`N`aik{N|} &'9: 	MGT((5"%C%

37I##%((>2K"&!((=5:c%++a.1!MM4Y01	*!!$((4"45##K0NI#	& 	LL 12 '339C@P<Q3Q'/W]`aWa'bKOOD",E,I,I&,QUb,b!22#/#7"8 ; T%66.t4FxBfX"xB%x0@# /C51A3KC ''!M?(2$bA(NO ''!B4yDZ[^Z__`ac`dde(fg ''-
37GGWX[W\\](^_ ''!B4wvclBXY\X]]^_b^ccd(ef ''!B4r#b=QRUQVVW(XY$'MKK)J<}VCLP[\`[aag hi 55:MPQ:Q (1G %fX.G (1GOG ''-8KC7PP`ah`iij(kl ''!M?!G9AgYa(PQ ''!G9Bwi?ST[S\\](^_$+MKK*-@,AATUYTZZ` ab /2249L9LTSV9WX
"6(+##a6FzRUFVVWX^W__`$ab &##M2O'3R < A%(O	 ClCC##ugYs<7H6I$XY"	%aq#l"34 #A F1us8},S]1B'A<)--c2&(jG(}}W5A)+J).)*S->-B)Bc!IE ''F82l1o%6nVCLPQRWQXXYZ #F#  #	 J9IJJCS%M30O*P!QRII3<=M3N +//vwv;!8!"3"7"7!"Dt"KL ''G9JyoYvcl S""-a}AhZqJ
 !'''s|3CH:QO   *+ 9~""+A,''!>I!>>##i|C	N+; <C D #.##	{"_$55}~ %	LcR[^aRaNbc+	JCPY\_P_L`a 9#e+e3GJO #j0	##%*5*;*;*= 'w"6?m;$&)*;*?*?q*ID*P&Q$''8"9tS^&<=$++	{*Z4D E&&1]!K='!M #))'2'1,!Q	' =[__Q5K5O5OPV5W[b5b$'99
$$&(+,<c!SI[E\_`E`>a(b%$Q(9: '(+C2E,E,L(M$''8"9tS_&=>$++	{*Z4D E&&3_Am_AgYaQ #))'2'1,!Q	' #$YKq!1BGG;[PZ;[4[![J/	##%&l9+ >> ? #	fS_$55Mj\YZ[\ 9H - 8 ''),H(5058;F tS]34#,+R 0"
## '8= >(- .&&)!-F-J&KC%P Q"|1& ##	{"ZL 1> ? #	Q	8C8LLab{|  bA  AB  C  D!B8*MN  #/!*+=!> G:&NN>1=	/(OI,FF(G
  1$#&'='='?#@ !#KK01Ec0J!LMKK56OPS5TTUVW  !#	6ORf6f/G!I;.>wsm9 UV!IKK7}AFG ,/
 

6

%~67

Fa	{!,-.JJ!I;a 012

 



 
 
 
 	
 	

 

 
 
 "
 
 !
 
 #
 
 !(
 
 "
 
 
 
 
 
  
 
 !
 
 
  !
  !
" #
" #
$ %
$ %
& '
& &'
* +
 	2 	n&()B3(GqIJ()=c(B!DEoc*<&=%>?@oc*<&=%>?@oc+&6%789KK3O3DEF/#?33%%**%%**
 

  $//11 ??agi@GILL3Y?29+>?S  "*->?!($))+33
 	
G" )
 + MW&9:LLM8 >
  @:1#>??@h /a:  ) j"NN-XY^X__abfag+hiij| #cZ $- m &/Z\^`k l lm  N!B7)LMMNB

 2"  
MN
 	
  
=zJu-.C
 	

s  BiBc<BiBd Bc?Bd C=Bi Bd# Bd 4Bd# ABiS6Bg4 Be!ABg4  8Bg4 :A,Be'Be>BeBg4 	ABg4 Bg4 	Bg4 !ABg4 4Bg4 9Bg4 ABg4 $Bg4 UBg4 (Bg4 HBg4 CBf
C'Bf
C+CBg4 F=BiF>BBg4 IA3Bg4 KFBg4 QB$Bg4 S:D:Bf> X6B8Bf[.Bf> [5A4Bf> ])C>Bg4 a(A'Bg4 crBg4 U K5Bg4 aBg.aBg4 a/Bg1a0A!Bg4 cBic)Bg4 c;Bic?Bd dBddBidBddBid Bd# d#	Bed,Be
eBie
BeeBieBg4 e	Bfe!Bfe<Bg4 fBffBg4 f	Bf;fBf6f0Bf> f6Bf;f;Bf> f>	Bg+gBg&g Bg4 g&Bg+g+Bg4 g1Bg4 g4BihBih	Bih+BiiBiiBiiBiiBiz/api/variantsc                 (   K   ddl m}  d |        iS w)zu[DEPRECATED] List available editing variant presets. Use /api/projects/{id}/export-video with effects config instead.r   list_variantsvariants)web.variant_presetsr5  r4  s    ra   api_list_variantsr8  %  s      2((r  z*/api/projects/{project_id}/export-variantsc                  K   ddl m}m} ddl}t	        |        d{   }|st        ddid      S t        |        d{   |d<   t        |        d{   |d	<   t        |        d{   |d
<   	 |j                          d{   }|j                  dt        |j                                     }|j                  dd      }t        dz  | z  }	i }
|D ]  }||vrdd| i|
|<   	  ||||      }ddl}|j!                  dd      4 d{   }|j#                  d|  d|       d{   }ddd      d{    j$                  dk(  r|j                         }|	dz  }|	d| dz  }|j'                         r$|j)                  t+        |      t+        |             dd|  d| d|j'                         r|j-                         j.                  ndd|
|<   nd|j0                  dd  d!|
|<   ! d|
iS 7 7 7 7 7 # t        $ r i }Y w xY w7 7 7 # 1 d{  7  sw Y   xY w# t        $ r}dt+        |      dd  d!|
|<   Y d}~d}~ww xY ww)"z[DEPRECATED] Generate multiple video exports. Use POST /api/projects/{id}/export-video with different effects payloads instead.r   )generate_variant_payloadVARIANT_PRESETSNr   r7  r   r   r>  r?  r@  r6  seed*   rn   zUnknown variant: )r<  zhttp://127.0.0.1:8000g     @)base_urlr  z/api/projects/z/export-video)rP   r  r  final_export_r  r  r  z/final_export_r  r  r   )r{   r   )r7  r:  r;  r9  r!   r   r"   r#   r$   rP   rY   rU   r$  r  rL   r  rb  postr   rM   moverS   rd  re  r<  )r+  r   r:  r;  r9  projectr   variant_namesr<  r  r  vnamer  r  rc  rd  r_   default_pathvariant_pathr`   s                       ra   api_export_variantsrG  ,  s     N  
++GW&9:LL0<<GH0<<GH0<<GH\\^# HHZo.B.B.D)EFM88FBD)J6JG K'%):5''BCGEN	K.wDIG((2ISX(Y  ]c#[[$ZL>  )    3&yy{),>>)mE7$,GG&&(KKL 13|3DE)&.zl.t$T@L@S@S@U!2!2!4!<!<[\" -5tyy#!O9KB   e , =<< $ "   *  	K(03s8DS>JGEN	Ks  I'G?#I'HI'HI'-H.I'6H 	H
H AI'-&H<H H<H'2H#3H'7H<H%B5H<8I'I'I'I'H HI'HI' H<#H'%H<'H9	-H0.H9	5H<<	I$II'I$$I'z/api/subtitle-presetsc                 (   K   ddl m}  d |        iS w)Nr   list_presetspresets)r  rJ  rI  s    ra   api_subtitle_presetsrL  h  s     0|~&&r  z(/api/projects/{project_id}/export-statusc                J  K   t        |        d{   }|t        ddid      S t        dz  | z  }|dz  |dz  |d	z  dz  g}|D ]P  }|j                         s| d
t	        |j                  t                    |j                         j                  d
dc S  | dddddS 7 w)z3Check if an exported video exists and its metadata.Nr   r7  r   r   rn   r  zfinal_video.mp4ra  T)r+  exportedrD  rG  export_availableFr   )r!   r   rL   rM   rS   relative_tord  re  )r+  r;  r  
candidatesr]   s        ra   get_export_statusrR  n  s      Z((D|W&9:LL)J6J 	''&&X 11J  ;;=(  !1!1-!@A#'99;#6#6$(  !! / )s   B#B!AB#AB#z/ws/pipeline/{project_id}c                
  "#$%&K   | j                          d {    dd l}t        |j                               }	 | j	                          d {   }|j                  dd      &|j                  dd      }|j                  dd      }|j                  dd      }t        |j                  d	d
            }|j                  dd      }t        |j                  dd            }	|j                  dd      }
|j                  dd      }|j                  dd      }|j                  dd      }&j                         sO| j                  ddd       d {    | j                          d {    	 	 | j                          d {    y d }|rt        |       d {   }|s|rt        |       d {   }t        t        dz  |z        }t                d {   }|j                  d      r|d   t        j                   d<   |j                  d      r|d   t        j                   d<   |j                  d      r|d   t        j                   d<   	 dd lm} d }|r8 |d@i |j'                         D ci c]  \  }}||j(                  v r|| c}}}t+        ||s|nd |||||	|
|||!      "|r|d"   n|}t-        |d#|d$|&d d% &       d {    t/        j0                         #dA#fd'}t3        "|(      $"#$&fd)}t/        j4                   |             }	 #j                          d {   }|n|j7                  d*+      }|j8                  d,k(  rX|j:                  rLd-|j:                  d.d/}t        t=        |      d0z  |z        }t?        ||j:                  |d12       d {    	 | j                  |       d {    | d {   }|j7                         }tE        |d3       d {    tG        |||jH                  4       d {    |jJ                  D ]  %tM        |       d {   } tO        %fd5| D        d       }!|!r3t?        |%jP                  %jR                  |!d6   |!d7   8       d {    `t?        |%jP                  %jR                  d9:       d {     | j                  d;|d<       d {    	 | j                          d {    y 7 7 7 7 7 t# t        $ r Y y w xY w7 n7 Z7 6c c}}w # t        $ rr}| j                  dt        |      d       d {  7   | j                          d {  7   Y d }~	 | j                          d {  7   y # t        $ r Y y w xY wd }~ww xY w7 7 g7 7 # t@        $ r< |jC                          Y 	 | j                          d {  7   y # t        $ r Y y w xY ww xY w7 7 7 7 7 t7 K7 0# t@        $ r/ tT        jW                  d=|       tE        |d>       d {  7   Y et        $ r~}tT        jY                  d?|       	 tE        |d       d {  7   n# t        $ r Y nw xY w	 | j                  dt        |      d       d {  7   n# t        $ r Y nw xY wY d }~d }~ww xY w7 # t        $ r Y y w xY w# 	 | j                          d {  7   w # t        $ r Y w w xY wxY ww)BNr   storyr?   modeplancharacter_id	characterskeletonframes_per_minute   enable_coverage_shotsFcoverage_angles_per_scener  coverage_modern  r  r  rH  rI  rJ  r   zNo story provided)
event_typer1  rn   r   r   r   r   r   r   )CharacterTemplate)rU  rX  character_templater  rZ  r\  r]  r^  r  rH  rJ  r=   runningr  r  )rI   r{   rU  r  rX  story_previewc                (    j                  |        y)z/Callback invoked from the sync pipeline thread.N)
put_nowait)r/  event_queues    ra   on_eventzws_pipeline.<locals>.on_event  s    ""5)rv   )rg  c                   K   	 t        j                  j                         d {   } t        | j                         t        | j                         | j                  d        S 7 C# j                  d        w xY wwr   )r   r   r  r   r  r   re  )rV  cfgrf  pipelinerT  s    ra   run_in_threadz"ws_pipeline.<locals>.run_in_thread  sk     -$..x||UCCdCNN3$/ &&t, D &&t,s,   B#A. A,1A. B,A. .BBT)exclude_noneimage_generatedr  r  r   ra  r   )r+  rE  rD  r{   r  )rf   c              3  H   K   | ]  }|d    j                   k(  s|  ywr  )rE  )rA  rM  r  s     ra   rC  zws_pipeline.<locals>.<genexpr>0  s#     Nqa&75;M;M&MNs   ""rD  r{   r  rF  )r+  rE  r  r{   r4  )r_  r_   zWebSocket disconnected: %sdisconnectedzPipeline error for project %sru   )r/  r   r  r!  )-r  rK   rS   rT   receive_jsonrU   r  r   	send_jsonrx  rY   r   r   rL   r   r   r   r	  r`  r   model_fieldsr   r+   r   r&  r   r'  
model_dumpr_  image_scene_numberr   r4   r
   cancelr3   r2   rf   rC  r"   r  rE  r  rW   rX   r   )'wsr+  rK   config_datarU  rW  character_namerZ  r\  r]  r^  r  rH  rJ  	char_dataproject_output_dirr   r`  char_templater   r   r`   resolved_namerg  rk  pipeline_taskr/  evt_dictimg_fileimg_full_pathrV  	plan_dictr>  img_rowri  rf  rj  r  rT  s'                                     @@@@@ra   ws_pipeliner    s    
))+ TZZ\"JOO-- __Wb1OOFF3'OONB?)ook:F!$[__5H"%M!N&1oo6Mu&U),OO7;*
! )___eD'OONLI#.??3H$#O$/OO4JB$O{{},,gBUVWWW((*L	((*I 	+L99I^3NCCI !!9J!FG 011??;'&1+&>BJJ{#??+,+67G+HBJJ'(??./.9:M.NBJJ*+	0 M 1 ! %.OO$5 Aq 1 > >> 1! 0=.4#0-"3&;*C+)$7%9C( .7	&)N#+
 	
 	
 <C==?	* C(3		-  ++MO< %//++E}''T':H #449Q9Q#E$<$<S#AF #D);$<x$G($R S")!&!9!9+&	  ll8,,,' 2 #" OO%	#J<<<#J	LLL [[ 	E-j99FNFNG ")!&!3!3!&!3!3%k2"8,   #)!&!3!3!&!3!3$	  !	0 ll&!
 	
 	
*	((*I  .$ XP  		G :C 2(  	,,g#c(KLLL((*f	((* 		q		
D , -& $$&p	((* 		y
 # 	=L :	
  @0*=#J??? 	8*E	'
G<<< 			,,g#c(KLLL 			  			((* 		s[  \S/!\X S2DX S5X -S8.X 4S> S;S> \X T X 6T7&X TA9X !T 9T T 4 X VA!X 6V7A;X 2V 3X 8V& V#V& X W.#X ;W1<X W4!X =W7>AX W:+X 2W=3X X X [ )[*[ .\2X 5X 8X ;S> >	T
\	T

\X X X T 	V% VUVU!V$X )V <U?=V \	V\V\VX X  X #V& &W+?X W WW \	W'$\&W''\*W++X 1X 4X 7X :X =X  X .[ 1X42[ 7[ :[ Z;Y/(Y+)Y/.Z;/	Y;8Z;:Y;;Z;? Z&Z" Z&%Z;&	Z2/Z;1Z22Z;5[ ;[  [ [ 	[\[\\ [1*[-+[10\ 1	[=:\ <[==\  \r"  )rd   r   )r   rS   )r   r   )r   rS   r   r   )r   zdict[str, str]r  r!  )r   )r   rS   )rT  r  )r+  rS   )r+  rS   r  rS   )r+  rS   r  r  )r+  rS   r  r  r   r   )r+  rS   r   r   )r  rS   r  rd  )
r  r$  rv  rd  r  rd  r  r  r  r$  )rv  r	   r+  rS   )__doc__
__future__r   r   rP   loggingr   r  r  sys
contextlibr   re  r   fastapir   r   r	   r
   fastapi.middleware.corsr   fastapi.responsesr   r   r   r   fastapi.staticfilesr   __file__r  parentrL   rS   r]   insertconfigr   r   r	  r   r   output_formatterr   r   rj  r   web.database_pgr   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   	getLogger__name__rW   _WEB_DIRrt   rb   re   rd   add_middlewaremount_OUTPUT_DIRr   rU   rw   r}   r   r   r   r@  r   r  r   deleter   r   r   r   r   r   r  r  r(  r5  rI  rV  rX  re  r  r  r  r  r  r  r  r  r  r  patchr"  r2  r5  r<  rA  rw  r  r  r  r  r  r  r>  ry  r~  r  r  r  r  r  r  r  r2  r8  rG  rL  rR  	websocketr  ru   rv   ra   <module>r     s   #    	  	 
 *  D D 2 U U + X&&(//66}SXX%HHOOAs=)* 9 . 5                  D 
		8	$ >!!#**! NF   /8T   %%%   		)[3{+;<8	 L h&   $  . 		)[3{+;<8	 L 9 9 ; ; 	5 5 	! ! 	$% & 
$/ $/N 	$%#( &#(L '(0 )0 
89+U :+U\ 	./) 0) 4 	 ( 
'; ';T 	#$BH %BHT 	 !
 "
 
!"1 #1h 
)*3B +3Bv 	%& ', 
&'C (CL 56; 7; 
/02B 12Bj 	%&FB 'FBX 
"#  $ F 	&')B ()BX 
&'$ ($N 
,-S .S@ 
*+ c , cF 
,-e .e@ 	*+)B ,)BX X Xv /43 43n #$N %N. 	 !@ "@F " " ()3 *3  	%& ' 	,-W .Wt 	78> 9>B 	12' 3'  
AB= C= AB< C<$ 
DE`W F`WP 
67J 8Jd 
67d 8dX	 
67g 8gT	 
JKBY LBYJ 
JKz LzB  ! %!&49FI	( 
9:_= ;_=D 	343 53v 
34Y
 5Y
x" ) ) 
678! 88!v 	 !' "'
 	34 5L *+G ,Grv   