
    PL
jI                       U d Z ddlmZ ddlZddlZddlmZmZmZm	Z	m
Z
 ddlmZmZmZ  ej        e          Z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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d0dd1d2dddd%d%dd3Zd4ed5<   d6ZdVd;ZdWd@ZdXdAZdYdEZdZdOZdad8edP<   d[dQZ G dR dSe          Zd\dUZdS )]u  FAL.ai video generation backend.

User-facing surface: pick a **model family** (e.g. "Pixverse v6",
"Veo 3.1", "Seedance 2.0", "Kling v3 4K", "LTX 2.3", "Happy Horse").
The plugin auto-routes to the family's text-to-video endpoint when
called without ``image_url``, and to its image-to-video endpoint when
``image_url`` is provided. The agent never sees the routing — it just
calls ``video_generate(prompt=..., image_url=...)``.

Model families (each with t2v + i2v endpoints):

  Cheap tier:
    ltx-2.3       fal-ai/ltx-2.3-22b/text-to-video               /  fal-ai/ltx-2.3-22b/image-to-video
    pixverse-v6   fal-ai/pixverse/v6/text-to-video               /  fal-ai/pixverse/v6/image-to-video

  Premium tier:
    veo3.1        fal-ai/veo3.1                                  /  fal-ai/veo3.1/image-to-video
    seedance-2.0  bytedance/seedance-2.0/text-to-video           /  bytedance/seedance-2.0/image-to-video
    kling-v3-4k   fal-ai/kling-video/v3/4k/text-to-video         /  fal-ai/kling-video/v3/4k/image-to-video
    happy-horse   fal-ai/happy-horse/text-to-video               /  fal-ai/happy-horse/image-to-video

Selection precedence for the active family:
    1. ``model=`` arg from the tool call
    2. ``FAL_VIDEO_MODEL`` env var
    3. ``video_gen.fal.model`` in ``config.yaml``
    4. ``video_gen.model`` in ``config.yaml`` (when it's one of our family IDs)
    5. ``DEFAULT_MODEL``

Authentication via ``FAL_KEY``. Output is an HTTPS URL from FAL's CDN; the
gateway downloads and delivers it.
    )annotationsN)AnyDictListOptionalTuple)VideoGenProvidererror_responsesuccess_responsezLTX 2.3 (22B)z~30-60scheapz322B model with native audio generation. Affordable.z fal-ai/ltx-2.3-22b/text-to-videoz!fal-ai/ltx-2.3-22b/image-to-videoT)displayspeedprice	strengthstiertext_endpointimage_endpointaspect_ratiosresolutions	durationsaudionegativezPixverse v6z~30-90sz.Affordable. Negative prompts. 1-15s durations.z fal-ai/pixverse/v6/text-to-videoz!fal-ai/pixverse/v6/image-to-video360p540p720p1080p)      zVeo 3.1z~60-120spremiumzBGoogle DeepMind. Cinematic, native audio, strong prompt adherence.zfal-ai/veo3.1zfal-ai/veo3.1/image-to-video)16:99:16)r   r   )         zSeedance 2.0z;ByteDance. Cinematic, synchronized audio + lip-sync, 4-15s.z$bytedance/seedance-2.0/text-to-videoz%bytedance/seedance-2.0/image-to-video)z21:9r!   z4:31:1z3:4r"   )480pr   r   )r#   r   FzKling v3 4Kz	~120-300sz14K output, native audio (Chinese/English), 3-15s.z&fal-ai/kling-video/v3/4k/text-to-videoz'fal-ai/kling-video/v3/4k/image-to-videostart_image_urlr!   r"   r&   )   r   )r   r   r   r   r   r   r   image_param_keyr   r   r   r   r   zHappy Horse 1.0uA   Alibaba. New model, sparse public docs — conservative defaults.z fal-ai/happy-horse/text-to-videoz!fal-ai/happy-horse/image-to-video)zltx-2.3pixverse-v6zveo3.1zseedance-2.0zkling-v3-4kzhappy-horsezDict[str, Dict[str, Any]]FAL_FAMILIESr,   r   r   returnboolc                    t          | t                    rt          |           dk    rdS t          d | D                       sdS | d         | d         z
  dk    S )zIHeuristic: a 2-tuple of ints with a gap > 1 is treated as ``(min, max)``.   Fc              3  @   K   | ]}t          |t                    V  d S N)
isinstanceint).0ds     B/home/kuhnn/.hermes/hermes-agent/plugins/video_gen/fal/__init__.py	<genexpr>z%_is_duration_range.<locals>.<genexpr>   s,      55az!S!!555555    r   r   )r4   tuplelenall)r   s    r8   _is_duration_ranger>      se    i'' 3y>>Q+>+>u55955555 uQ<)A,&**r:   familyDict[str, Any]durationOptional[int]c                    |                      d          }|sS |d         S t          |          r#|\  }}t          |t          |                    S |v rS t          |fd          S )Nr   r   c                (    t          | z
            S r3   )abs)r7   rA   s    r8   <lambda>z!_clamp_duration.<locals>.<lambda>   s    AL(9(9 r:   )key)getr>   maxmin)r?   rA   r   lohis    `   r8   _clamp_durationrM      s    

;''I |)$$ *B2s2x(()))9y9999::::r:   c                    	 ddl m}   |             }t          |t                    r|                    d          nd }t          |t                    r|ni S # t
          $ r'}t                              d|           i cY d }~S d }~ww xY w)Nr   )load_config	video_genz#Could not load video_gen config: %s)hermes_cli.configrO   r4   dictrH   	Exceptionloggerdebug)rO   cfgsectionexcs       r8   _load_video_gen_sectionrY      s    111111kmm*4S$*?*?I#''+&&&T$Wd33;ww;   :C@@@						s   AA 
B!B=BBexplicitOptional[str]Tuple[str, Dict[str, Any]]c                4   g }|                     |            |                     t          j                            d                     t	                      }t          |                    d          t                    r|                    d          ni }t          |t                    r(|                     |                    d                     |                    d          }t          |t                    r|                     |           |D ]k}t          |t                    rT|                                r@|                                t          v r%|                                }|t          |         fc S lt          t          t                   fS )z>Decide which FAL family to use. Returns ``(family_id, meta)``.FAL_VIDEO_MODELfalmodel)appendosenvironrH   rY   r4   rR   strstripr-   DEFAULT_MODEL)rZ   
candidatesrV   fal_cfgtopcfids          r8   _resolve_familyrl      sT   &(Jhbjnn%677888
!
#
#C *3775>>4 @ @HcggennnbG'4   0'++g..///
'''

C#s # * *a 	*!'')) 	*		\0I0I''))CS))))),}555r:   promptrd   	image_urlaspect_ratio
resolutionnegative_promptr   Optional[bool]seedc                  i }	|r||	d<   |r|                      d          pd}
||	|
<   |||	d<   |                      d          r|| d         v r||	d<   |                      d          r|| d         v r||	d	<   t          | |          }|'|                      d
          rt          |          |	d<   |                      d          r|t          |          |	d<   |                      d          r|r||	d<   |	S )zJBuild a family-specific payload, dropping keys the family doesn't declare.rm   r+   rn   Nrs   r   ro   r   rp   r   rA   r   generate_audior   rq   )rH   rM   rd   r/   )r?   rm   rn   rA   ro   rp   rq   r   rs   payloadrG   clampeds               r8   _build_payloadrx      s?    !G #" ! jj*++:{ zz/"" 36/222&2GN# zz-   /...$.GL! fh//Gvzz+66!'ll
zz' 0u0$(KK !zz* 5/ 5%4!"Nr:   _fal_clientc                 .    t           t           S dd l} | a | S )Nr   )ry   
fal_client)r{   s    r8   _load_fal_clientr|   #  s%    Kr:   c            
          e Zd ZdZed#d            Zed#d            Zd$dZd%d	Zd&dZ	d'dZ
d'dZdddddddddd	d(d"ZdS ))FALVideoGenProviderzFAL.ai multi-family video generation backend.

    Routes between text-to-video and image-to-video endpoints automatically
    based on whether ``image_url`` was provided.
    r.   rd   c                    dS )Nr_    selfs    r8   namezFALVideoGenProvider.name9      ur:   c                    dS )NFALr   r   s    r8   display_namez FALVideoGenProvider.display_name=  r   r:   r/   c                    t           j                            dd                                          sdS 	 dd l}n# t
          $ r Y dS w xY wdS )NFAL_KEY Fr   T)rb   rc   rH   re   r{   ImportError)r   r{   s     r8   is_availablez FALVideoGenProvider.is_availableA  sf    z~~i,,2244 	5	 	 	 	55	ts   ; 
A	A	List[Dict[str, Any]]c                   g }t                                           D ]\  }}g }|                    d          r|                    d           |                    d          r|                    d           |                    ||d         |d         |d         |d         |                    d	d
          |d           |S )Nr   textr   imager   r   r   r   r   r    )idr   r   r   r   r   
modalities)r-   itemsrH   ra   )r   outrk   metar   s        r8   list_modelszFALVideoGenProvider.list_modelsJ  s    $&%++-- 	 	IC$&Jxx(( *!!&)))xx()) +!!'***JJ	?g!+.g33(      
r:   r[   c                    t           S r3   )rf   r   s    r8   default_modelz!FALVideoGenProvider.default_model]  s    r:   r@   c                    dddddddgdS )	Nr   paidu^   LTX, Pixverse, Veo 3.1, Seedance 2.0, Kling 4K, Happy Horse — text-to-video & image-to-videor   zFAL.ai API keyzhttps://fal.ai/dashboard/keys)rG   rm   url)r   badgetagenv_varsr   r   s    r8   get_setup_schemaz$FALVideoGenProvider.get_setup_schema`  s4    s %.: 	
 
 	
r:   c           	     $    ddgg dg ddddddd	S )
Nr   r   r)   r   r   r   Tr   )r   r   r   max_durationmin_durationsupports_audiosupports_negative_promptmax_reference_imagesr   r   s    r8   capabilitiesz FALVideoGenProvider.capabilitiesn  s:    !7+444<<<"(,$%	
 	
 		
r:   Nr!   r   )	r`   rn   reference_image_urlsrA   ro   rp   rq   r   rs   rm   r`   rn   r   Optional[List[str]]rA   rB   ro   rp   rq   r   rr   rs   kwargsr   c       	           t           j                            dd                                          st	          ddd|          S 	 t                      }n## t          $ r t	          ddd|          cY S w xY w|pd                                }t          |          \  }}|pd                                pd }|r2|                    d	          }d
}|st	          d| ddd||          S n1|                    d          }d}|st	          d| ddd||          S |st	          ddd||          S t          ||||||||	|
	  	        }	 |	                    ||d          }nN# t          $ rA}t                              d|||d           t	          d| dd|||          cY d }~S d }~ww xY wt          |t                    r|pi                     d          nd }d }t          |t                    r|                    d          }nt          |t                    r|}|st	          dd d||          S d!|i}t          |t                    r@|                    d"          r|d"         |d"<   |                    d#          r|d#         |d#<   t!          ||||d$|v r|ndd%|v rt#          |d%                   nd&d|'          S )(Nr   r   uN   FAL_KEY not set. Run `hermes tools` → Video Generation → FAL to configure.auth_requiredr_   )error
error_typeproviderrm   z@fal_client Python package not installed (pip install fal-client)missing_dependencyr   r   zFAL family us    has no image-to-video endpoint. Pick a family with image-to-video support via `hermes tools` → Video Generation.modality_unsupported)r   r   r   r`   rm   r   r   zq has no text-to-video endpoint. Pass an image_url to use its image-to-video endpoint, or pick a different family.zprompt is required.missing_prompt)rm   rn   rA   ro   rp   rq   r   rs   F)	arguments	with_logsz1FAL video gen failed (family=%s, endpoint=%s): %sT)exc_infozFAL video generation failed: 	api_error)r   r   r   r`   rm   ro   videor   z%FAL returned no video URL in responseempty_responseendpoint	file_sizecontent_typero   rA   r   )r   r`   rm   modalityro   rA   r   extra)rb   rc   rH   re   r
   r|   r   rl   rx   	subscriberS   rT   warningr4   rR   rd   r   r5   )r   rm   r`   rn   r   rA   ro   rp   rq   r   rs   r   r{   	family_idr?   image_url_normr   modality_usedrv   resultrX   r   r   r   s                           r8   generatezFALVideoGenProvider.generatez  s&    z~~i,,2244 		!, +   	)++JJ 	 	 	!X/	     	 ,B%%''+E22	6 $/r0022:d 	zz"233H#M 	%Di D D D  6")F   	 zz/22H"M 	%Pi P P P  6")F     	!++i    !$%!+

 

 

	))! *  FF
  
	 
	 
	NNC8S4     ";c;;&i)	        
	 0:&$/G/GQ2""7+++T!eT"" 	))E""CCs## 	C 	!=+i    ",X 6eT"" 	>yy%% 8%*;%7k"yy(( >(-n(=n%")77)B)B1;w1F1FS,---A	
 	
 	
 		
s0   A A65A6E& &
F106F,&F1,F1)r.   rd   )r.   r/   )r.   r   )r.   r[   r.   r@   )rm   rd   r`   r[   rn   r[   r   r   rA   rB   ro   rd   rp   rd   rq   r[   r   rr   rs   rB   r   r   r.   r@   )__name__
__module____qualname____doc__propertyr   r   r   r   r   r   r   r   r   r:   r8   r~   r~   2  s            X    X      &   
 
 
 


 

 

 

   $#'48"&" )- $"G
 G
 G
 G
 G
 G
 G
 G
r:   r~   Nonec                H    |                      t                                 dS )uF   Plugin entry point — wire ``FALVideoGenProvider`` into the registry.N)register_video_gen_providerr~   )ctxs    r8   registerr   	  s#    ##$7$9$9:::::r:   )r   r   r.   r/   )r?   r@   rA   rB   r.   rB   r   )rZ   r[   r.   r\   )r?   r@   rm   rd   rn   r[   rA   rB   ro   rd   rp   rd   rq   r[   r   rr   rs   rB   r.   r@   )r.   r   )r.   r   )r   
__future__r   loggingrb   typingr   r   r   r   r   agent.video_gen_providerr	   r
   r   	getLoggerr   rT   r-   __annotations__rf   r>   rM   rY   rl   rx   ry   r|   r~   r   r   r:   r8   <module>r      s    @ # " " " " "  				 3 3 3 3 3 3 3 3 3 3 3 3 3 3          
	8	$	$. #J;=  " !E;=8   Y(8)(  "R?A G0 " !HAC -0 $ %X;=  a`+ `+ ` ` ` `D + + + +; ; ; ;(	 	 	 	6 6 6 66/ / / /l        O
 O
 O
 O
 O
* O
 O
 O
n; ; ; ; ; ;r:   