
    <h[                       S SK r S SKrS SKrS SKrS SKrS SKrS SKrS SKrS SKrS SK	r	S SK
r
S SKrS SKJrJr  S SKJrJr  S SKJr  S SK
Jr  S SKJrJrJrJr  S SKJr  S SKJr  S S	KJr  S SKrS S
K J!r!J"r"  S SK#J$r$J%r%J&r&J'r'J(r(  SSK)J*r*J+r+J,r,J-r-J.r.  SSK/J0r0J1r1  SSK2J3r3J4r4  SSK)J5r5  \3" 5       (       a  S SK6r6S SKJ7r7J8r8J9r9J:r:  \%" 5       (       a  S SK;r;\'" 5       =(       a#    \$" 5       =(       a    \(" 5       =(       a    \&" 5       r<\<(       a  S SK=r=S SK>J?r?J@r@  S SKAJBrB  S SKCJDrDJErE  S SKFJGrG  S SKHJIrI  S SKJJKrK  S SKLJMrMJNrNJOrOJPrPJQrQ  S SKRJSrS  S SKTJUrUJVrVJWrWJXrXJYrYJZrZJ[r[J\r\J]r]J^r^J_r_J`r`JaraJbrbJcrc  S SKdJere  S SKfJgrgJhrhJiri   " S S\eS S!9rj " S" S#\SS S!9rk " S$ S%\IS S!9rl\h" \j5      rm\h" \k5      rn\h" \l5      ro1 S&krp1 S'krq1 S(krr\4R                  " \t5      ruS)S*S+S,.0rv\w" \vR                  5       5      ry " S- S.\R                  5      r{S/\4S0 jr|S1\}S2S3S4S34S5 jr~ " S6 S75      r " S8 S95      r\ " S: S;5      5       r " S< S=\55      r\tS>:X  a  \" 5       r\GR	                  5         gg)?    N)ArgumentParser	Namespace)	dataclassfield)BytesIO)Thread)	GeneratorIterableOptionalUnion)
model_info)HF_HUB_OFFLINE)Image)!MODEL_FOR_CAUSAL_LM_MAPPING_NAMES*MODEL_FOR_IMAGE_TEXT_TO_TEXT_MAPPING_NAMES)is_fastapi_availableis_librosa_availableis_openai_availableis_pydantic_availableis_uvicorn_available   )
AutoConfigLogitsProcessorListPreTrainedTokenizerFastProcessorMixinTextIteratorStreamer)ContinuousBatchingManagerRequestStatus)is_torch_availablelogging   )BaseTransformersCLICommand)AutoProcessorBitsAndBytesConfigGenerationConfigPreTrainedModel)FastAPIHTTPException)CORSMiddleware)JSONResponseStreamingResponse)Transcription)TranscriptionCreateParamsBase)ChatCompletionMessageParam)ChatCompletionChunkChoiceChoiceDeltaChoiceDeltaToolCallChoiceDeltaToolCallFunction)CompletionCreateParamsStreaming)ResponseResponseCompletedEventResponseContentPartAddedEventResponseContentPartDoneEventResponseCreatedEventResponseErrorResponseErrorEventResponseFailedEventResponseInProgressEventResponseOutputItemAddedEventResponseOutputItemDoneEventResponseOutputMessageResponseOutputTextResponseTextDeltaEventResponseTextDoneEvent)ResponseCreateParamsStreaming)	BaseModelTypeAdapterValidationErrorc                   $    \ rS rSr% Sr\\S'   Srg))TransformersResponseCreateParamsStreamingr   zo
OpenAI's ResponseCreateParamsStreaming with an additional field for the generation config (as a json string).
generation_config N__name__
__module____qualname____firstlineno____doc__str__annotations____static_attributes__rL       U/var/www/html/shao/venv/lib/python3.13/site-packages/transformers/commands/serving.pyrI   rI   r       	 rV   rI   F)totalc                   $    \ rS rSr% Sr\\S'   Srg)+TransformersCompletionCreateParamsStreamingy   zq
OpenAI's CompletionCreateParamsStreaming with an additional field for the generation config (as a json string).
rK   rL   NrM   rL   rV   rW   r[   r[   y   rX   rV   r[   c                   B    \ rS rSr% Sr\\S'   \\S'   Sr\	\
   \S'   Srg)	%TransformersTranscriptionCreateParams   zo
OpenAI's TranscriptionCreateParamsBase with an additional field for the generation config (as a json string).
filerK   FstreamrL   N)rN   rO   rP   rQ   rR   bytesrT   rS   ra   r   boolrU   rL   rV   rW   r^   r^      s"    	 !&&rV   r^   >   textuserstorepromptinclude	reasoning
background
truncationtool_choiceservice_tiertop_logprobsmax_tool_callsprevious_response_id>   nstopre   audiorf   logprobsmetadata	functions
modalities
predictionrl   rm   rn   function_callstream_optionsresponse_formatpresence_penaltyreasoning_effortweb_search_optionsparallel_tool_callsmax_completion_tokens>   rg   rh   languager{   chunking_strategytimestamp_granularitiesqwenz<tool_call>z</tool_call>)startendc                   $    \ rS rSrSrSrSrSrSrg)Modality   LLMVLMSTTTTSrL   N)	rN   rO   rP   rQ   r   r   r   r   rU   rL   rV   rW   r   r      s    
C
C
C
CrV   r   argsc                     [        U 5      $ )zr
Factory function used to instantiate serving server from provided command line arguments.

Returns: ServeCommand
)ServeCommand)r   s    rW   serve_command_factoryr      s     rV   reqmodel_generation_configr%   returnc                 ~   U R                  S5      b#  [        S0 [        R                  " U S   5      D6nO[        R
                  " U5      nUR                  " S0 UD6nUR                  5        H  u  pVUc  M
  [        X5U5        M     U R                  S5      b  [        U S   5      Ul
        U R                  S5      b  [        U S   5      Ul
        U R                  S5      b  [        U S   5      Ul        U R                  S5      b
  U S   Ul        U R                  S5      b
  U S   Ul        U R                  S5      b,  [        U S   5      Ul        [        U S   5      S:X  a  S	Ul        U R                  S
5      b  [        U S
   5      Ul        U R                  S5      b  [$        R&                  " U S   5        U$ )ax  
Creates a generation config from the parameters of the request. If a generation config is passed in the request,
it will be used as a baseline for parameterization. Otherwise, we will use the model's default generation config.
Other parameters in the request will be applied on top of the baseline.

Args:
    req (`dict`):
        The request which may optionally contain generation parameters.
    model_generation_config (`GenerationConfig`):
        The model's default generation config.
    kwargs (`dict`):
        Additional parameters to set in the generation config.

Returns:
    The prepared `GenerationConfig` object.
rK   max_output_tokens
max_tokensfrequency_penalty
logit_biasrr   temperatureg        Ftop_pseedrL   )getr%   jsonloadscopydeepcopyupdateitemssetattrintmax_new_tokensfloatrepetition_penaltysequence_biasstop_stringsr   	do_sampler   torchmanual_seed)r   r   kwargsrK   non_standard_kwargskvs          rW   !create_generation_config_from_reqr      s   . ww"#/,Ttzz#>Q:R/ST MM*AB+22<V<#))+=%!, ,
 ww"#/+.s3F/G+H( ww|(+.s</@+A(
ww"#//4S9L5M/N,
ww|(*-l*;'
wwv"),V&
ww})(-c-.@(A%]#$+*/'
www#"'G"5
wwv"#f+&rV   c                   $    \ rS rSrSrS rS rSrg)	ToolStatei  z7Lightweight class to keep track of the tool call state.c                 $    U R                  5         g N)resetselfs    rW   __init__ToolState.__init__  s    

rV   c                 <    SU l         SU l        SU l        SU l        g)z>Reset the tool call state (assumes we're outside a tool call).Fr    N)inside_tool_callhas_tool_name_definedarg_nesting_levelbufferr   s    rW   r   ToolState.reset  s!     %%*"!"rV   )r   r   r   r   N)rN   rO   rP   rQ   rR   r   r   rU   rL   rV   rW   r   r     s    ArV   r   c            	       R    \ rS rSrSr SSSS\S\\S      4S	 jjrS
 r	S r
S rSrg)
TimedModeli'  z
A class that holds a PreTrainedModel instance and its associated processor.
Automatically deletes the instances after a specified timeout.
Nmodelr&   timeout_seconds	processor)r   r   c                     Xl         [        UR                  5      U l        X0l        X l        [        R                  " U R
                  U R                  5      U l	        U R                  R                  5         g r   )r   rS   name_or_path_name_or_pathr   r   	threadingTimer_delete_model_timerr   )r   r   r   r   s       rW   r   TimedModel.__init__-  sU     
 !3!34".ood&:&:D<N<NOrV   c                     U R                   R                  5         [        R                  " U R                  U R
                  5      U l         U R                   R                  5         g)z2Reset the timer for the deletion of the instances.N)r   cancelr   r   r   r   r   r   s    rW   reset_timerTimedModel.reset_timer:  s@    ood&:&:D<N<NOrV   c                 r   [        U S5      (       a  U R                  b  U ?U ?SU l        SU l        [        R                  " 5         [
        R                  R                  5       (       a  [
        R                  R                  5         [        R                  U R                   SU R                   S35        ggg)z>Delete the wrapped model and processor and clean up resources.r   Nz was removed from memory after z seconds of inactivity)hasattrr   r   gccollectr   cudais_availableempty_cacheloggerinfor   r   r   s    rW   r   TimedModel._delete_model@  s    4!!djj&<
DJ!DNJJL zz&&((

&&(KK%%&&EdFZFZE[[qr '=!rV   c                 N    [        U S5      (       + =(       d    U R                  SL $ )z)Check if the instances have been deleted.r   N)r   r   r   s    rW   
is_deletedTimedModel.is_deletedQ  s     4))?TZZ4-??rV   )r   r   r   r   r   r   )rN   rO   rP   rQ   rR   r   r   r   r   r   r   r   rU   rL   rV   rW   r   r   '  sJ     SW	   E"MNO	"@rV   r   c                      \ rS rSr% Sr\" SSS0S9r\\S'   \" SS/ S	QS
.S9r	\
\   \S'   \" SSS0S9r\\S'   \" SSS0S9r\
\   \S'   \" SSS0S9r\\S'   \" SSS0S9r\\S'   \" SSSS/S
.S9r\\S'   \" SSS0S9r\\S'   \" SSS0S9r\\S'   \" SSS 0S9r\\S!'   \" S"SS#0S9r\\S$'   \" S%SS&0S9r\\S''   \" SSS(0S9r\
\   \S)'   \" SSS*0S9r\\S+'   \" SSS,0S9r\\S-'   \" SSS.0S9r\
\   \S/'   S0rg)1ServeArgumentsiV  z
Arguments for the serve CLI.

See the metadata arg for each argument's description -- the metadata will be printed with
`transformers serve --help`
autohelpzfDevice to use for inference; will default to `auto` andplace the model on an accelerator if available.)defaultru   devicezOverride the default `torch.dtype` and load the model under this dtype. If `'auto'` is passed, the dtype will be automatically derived from the model's weights.)r   bfloat16float16float32)r   choicestorch_dtypeFz2Whether to trust remote code when loading a model.trust_remote_codeNzWhich attention implementation to use; you can run --attn_implementation=flash_attention_2, in which case you must install this manually by running `pip install flash-attn --no-build-isolation`.attn_implementationzIWhether to use 8 bit precision for the base model - works only with LoRA.load_in_8bitzIWhether to use 4 bit precision for the base model - works only with LoRA.load_in_4bitnf4zQuantization type.fp4bnb_4bit_quant_typez#Whether to use nested quantization.use_bnb_nested_quant	localhostz$Interface the server will listen to.hosti@  zPort the server will listen to.porti,  z@Time in seconds after which a model will be removed from memory.model_timeoutr   z8Logging level as a string. Example: 'info' or 'warning'.	log_levelz1The default seed for torch, should be an integer.default_seedztWhether to enable CORS. Some apps that make requests from external domains (e.g. Cursor) require CORS to be enabled.enable_corsz+Whether to turn on strict input validation.input_validationzName of the model to be forced on all requests. This is useful for testing Apps that don't allow changing models in the request.force_modelrL   )rN   rO   rP   rQ   rR   r   r   rS   rT   r   r   r   rc   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rU   rL   rV   rW   r   r   V  s
     >
FC  "'PA
"K#  $)] ^t  */ r
*#  efL$  efL$   %UFZhmotgu=vww!&uHm?n!o$o kV=c4deD#edf6W-XYD#Y\]M3  &*d!eIs  #(([\#L(3-  &
K  #B
d  "'2
"K# rV   r   c                   r   \ rS rSr\S\4S j5       rS\4S jrS\	SSS	S
S\
4S jrS\	4S jrS\	4S jrS\	4S jr      S2S\\   S\\   S\\   S\\   S\\   S\\S      S\4S jjrSSS\4S jrS r\R,                  " SS9S\\	\\4      4S j5       rS \	S\\SS4   4S! jr\S\S\4S" j5       r\S#\4S$ j5       rS \	S\\SS4   4S% jrS \	S\\SS4   4S& jr S \	S\\SS4   4S' jr!S \	S\"4S( jr#\S\S\S)   4S* j5       r$S+\S\4S, jr%S-\4S. jr&S-\S\'\\(4   4S/ jr)S-\S\'\\*4   4S0 jr+S1r,g)3r   i  parserc                 X    [         4nU R                  SUS9nUR                  [        S9  g)z
Register this command to argparse so it's available for the transformer-cli

Args:
    parser: Root parser to register command-specific arguments
serve)dataclass_types)funcN)r   
add_parserset_defaultsr   )r   r  serve_parsers      rW   register_subcommand ServeCommand.register_subcommand  s3     *+((/(R!!'<!=rV   r   c                    [         (       d  [        S5      eXl        U R                  R                  S:H  U l        U R                  R
                  U l        U R                  R                  b*  [        R                  " U R                  R                  5        [        R                  " S5      nUR                  [        R                  U R                  R                  R                  5          5        [        R                  " S5      nUR                  [        R                  U R                  R                  R                  5          5        0 U l        S U l        S U l        S U l        S U l        g )NzaMissing dependencies for the serving CLI. Please install with `pip install transformers[serving]`
sdpa_pagedtransformersz+transformers.generation.continuous_batching)serve_dependencies_availableImportErrorr   r   use_continuous_batchingr   r   r   r   r    
get_loggersetLevel
log_levelsr   lowerloaded_models#running_continuous_batching_managerlast_messageslast_kv_cache
last_model)r   r   transformers_logger	cb_loggers       rW   r   ServeCommand.__init__  s   ++s 
 	'+yy'D'D'T$990099!!-dii445 &00@$$W%7%7		8K8K8Q8Q8S%TU&&'TU	7--dii.A.A.G.G.IJK 57X\0 "!rV   requestschema_TypedDictMeta	validatorrF   unused_fieldsc                 :   [         R                  SU 35        [        UR                  5       5      nUR                  nXV-
  nU(       a%  [         R                  SU 35        [        SSU 3S9eU R                  R                  (       aC   UR                  U5        XT-  n	U	(       a%  [         R                  SU	 35        [        SSU	 3S9egg! [         aC  n[         R                  SUR                  5        35        [        SUR                  5       S9eSnAff = f)a&  
Validates the request against the schema, and checks for unexpected keys.

Args:
    request (`dict`):
        The request to validate.
    schema (`_TypedDictMeta`):
        The schema of the request to validate. It is a `TypedDict` definition.
    validator (`TypeAdapter`):
        The validator to use to validate the request. Built from `schema`.
    unused_fields (`set`):
        Fields accepted by `schema`, but not used in `transformers serve`.

Raises:
    HTTPException: If the request is invalid or contains unexpected or unused fields.
zValidating request: z Unexpected keys in the request: i  )status_codedetailzValidation error: NzUnused fields in the request: )r   debugsetkeys__mutable_keys__errorr(   r   r   validate_pythonrG   errors)
r   r  r  r  r  
input_keyspossible_keysunexpected_keyseunused_fields_in_requests
             rW   _validate_requestServeCommand._validate_request  s   . 	+G956 (
//$4LL;O;LMNC:Z[jZk8lmm99%%H))'2 (2'A$'=>V=WXY# #.LMeLf,g  ( & # H1!((*>?#AHHJGGHs   
C 
D>DDc                 @    U R                  U[        [        [        S9  g N)r  r  r  r  )r.  rI   response_validatorUNUSED_RESPONSE_FIELDSr   r  s     rW   validate_response_request&ServeCommand.validate_response_request  s!    <(0	 	 	
rV   c                 @    U R                  U[        [        [        S9  g r1  )r.  r[   completion_validatorUNUSED_CHAT_COMPLETION_FIELDSr4  s     rW    validate_chat_completion_request-ServeCommand.validate_chat_completion_request  s!    >*7	 	 	
rV   c                 @    U R                  U[        [        [        S9  g r1  )r.  r^   transcription_validatorUNUSED_TRANSCRIPTION_FIELDSr4  s     rW   validate_transcription_request+ServeCommand.validate_transcription_request  s!    8-5	 	 	
rV   N
request_idcontentr   rolefinish_reason
tool_callsr2   r   c                     [        U[        [        R                  " 5       5      U[        [	        UUUS9SUS9/SSS9nSUR                  SS	9 S
3$ )aO  
Builds a chunk of a streaming OpenAI Chat Completion response.

IMPORTANT: The serialized chunk won't contain empty fields (fields with `None`). Some downstream apps,
like Cursor, assume that when the field exists, it has data.

Args:
    request_id (`str`):
        The request ID.
    content (`str`, *optional*):
        Content of the response from the model.
    model (`str`, *optional*):
        The model that generated the content.
    role (`str`, *optional*):
        The role of the next content, until a new role is defined.
    finish_reason (`str`, *optional*):
        The reason the generation by the model has finished.
    tool_calls (`list[ChoiceDeltaToolCall]`, *optional*):
        Data about the tool calls, when they are triggered.

Returns:
    `str`: The built chunk, a string containing a JSON string with the payload.
)rB  rC  rE  r   )deltaindexrD  r   zchat.completion.chunk)idcreatedr   r   system_fingerprintobjectdata: Texclude_none

)r/   r   timer0   r1   model_dump_json)r   rA  rB  r   rC  rD  rE  chunks           rW   build_chat_completion_chunk(ServeCommand.build_chat_completion_chunk'  sq    @ $		$% '!#-
 "/
  "*!
$ --4-@AFFrV   responserE   c                 (    SUR                  SS9 S3$ )a  
Builds a event of a streaming OpenAI Response response.

IMPORTANT: The serialized chunk won't contain empty fields (fields with `None`). Some downstream apps,
like Cursor, assume that when the field exists, it has data.

Args:
    response (`BaseModel`):
        The response to build an event from. One of the multiple OpenAI Response output types

Returns:
    `str`: The built chunk, a string containing a JSON string with the payload.
rM  TrN  rP  )rR  )r   rV  s     rW   build_response_event!ServeCommand.build_response_event[  s"     00d0CDDIIrV   c                 B  ^  [        5       nT R                  (       a  UR                  [        S/SS/S/S9  UR	                  S5      S[
        4U 4S jj5       nUR	                  S5      S[
        4U 4S jj5       nS	S
KJn  UR	                  S5      SU4U 4S jj5       nUR                  S5      UR                  S5      U 4S j5       5       n[        R                  " UT R                  R                  T R                  R                  T R                  R                  S9  g )N*T)allow_originsallow_credentialsallow_methodsallow_headersz/v1/chat/completionsr  c                    > TR                  U S9  TR                  (       a  TR                  U 5      nOTR                  U 5      n[	        USS9$ Nr  text/event-stream
media_type)r:  r  #continuous_batching_chat_completiongenerate_chat_completionr+   r  outputr   s     rW   chat_completion)ServeCommand.run.<locals>.chat_completiony  sK    11'1B++AA'J66w?$V8KLLrV   z/v1/responsesc                 X   > TR                  U S9  TR                  U 5      n[        USS9$ ra  )r5  generate_responser+   rh  s     rW   	responses#ServeCommand.run.<locals>.responses  s2    **7*;++G4F$V8KLLrV   r   )Requestz/v1/audio/transcriptionsc           
        >#    U R                  5        IS h  vN n[        US   R                  5       I S h  vN US   S9n[        R	                  SUS   R
                   SUS   R                   SUS   R                  S-  S S	35        S S S 5      IS h  vN   TR                  WS
9  TR                  U5      n[        USS9$  N N N2! , IS h  vN  (       d  f       NG= f7f)Nr`   r   )r`   r   zReceived file: z; MIME type: z; size:    z.2fz KiBrb  rc  rd  )formr^   readr   r"  filenamecontent_typesizer?  generate_transcriptionr+   )r  rs  parsed_requestri  r   s       rW   audio_transcriptions.ServeCommand.run.<locals>.audio_transcriptions  s      ||~~!F#F|0022w-"
 %d6l&;&;%<M$v,JcJcId e!&\..5c:$@ &~ ///G00@F$V8KLL &2 &~~~sU   C'CC'CC	
ACC'C/C'	CC'C$CC$ C'z
/v1/modelsc                  <   > [        ST R                  5       S.5      $ )Nlist)rL  data)r*   get_gen_modelsr   s   rW   get_all_models(ServeCommand.run.<locals>.get_all_models  s      64;N;N;P QRRrV   )r   r   r   )r'   r   add_middlewarer)   postdictfastapirp  optionsr   uvicornrunr   r   r   r   )r   apprj  rn  rp  rz  r  s   `      rW   r  ServeCommand.runk  s   i "e"&"e"e   
(	)	MT 	M 
*	M 
/	"	Mt 	M 
#	M 	$	,	-	M 	M 
.	M" 
\	"			S 
 
#	S 	Cdiinn499>>TYYM`M`arV   )maxsizec           	         / SQn[         (       aS  U Vs/ sHF  nUS[        R                  R                  5       R                  5       UR	                  S5      S   S.PMH     sn$ U Vs/ sH  n[        U5      PM     nnU Vs/ sH6  nUR                  SUR                  R                  5       UR                  S.PM8     sn$ s  snf s  snf s  snf )a  
This is by no means a limit to which models may be instantiated with `transformers serve`: any chat-based
model working with generate can work.

This is a limited list of models to ensure we have a discoverable /v1/models endpoint for third-party
integrations.
)zMenlo/Jan-nanozMenlo/Jan-nano-128kzQwen/Qwen2.5-0.5B-InstructzQwen/Qwen2.5-3B-InstructzQwen/Qwen2.5-7B-InstructzQwen/Qwen2.5-14B-Instructz meta-llama/Llama-3.1-8B-Instructz meta-llama/Llama-3.2-1B-Instructz!meta-llama/Llama-3.3-70B-InstructzHuggingFaceTB/SmolVLM-Instructz!ibm-granite/granite-vision-3.2-2bzQwen/Qwen2.5-VL-7B-Instructr   /r   )rI  rL  rJ  owned_by)	r   datetimenow	timestampsplitr   rI  
created_atauthor)r   modelsr   model_infoss       rW   r  ServeCommand.get_gen_models  s    
 > $ $E  %'00446@@B %C 0 3	 $  ;AA&:e,&KA ) )E  ((%$//99; %	 )  Bs   AC 'C<C
r   c                   ^ ^^^	 T R                  TS   5      m	T	T R                  :g  nT	T l        U(       a.  T R                  b!  T R                  R                  SSS9  ST l        T R	                  T	5      u  p4[        US5      (       a  UR                  OUn[        TUR                  UR                  UR                  SSS	SS
SS9
mT R                  cH  UR                  TSS9T l        [        5       T R                  l        T R                  R                  5         UR                  TS   SSS9R!                  UR"                  5      nUU	UU 4S jnU" US   5      $ )z
Generates an OpenAI Chat Completion using continuous batching.

Args:
    req (`dict`): The request to generate an OpenAI Chat Completion for.

Returns:
    `Generator[str, None, None]`: A generator that yields the OpenAI Chat Completion chunks.
r   NTr   )blocktimeout	tokenizerFr!   rr  
   fifo)	r   eos_token_idpad_token_id	use_cache
num_blocks
block_sizer   max_batch_tokens	scheduler)rK   	streamingmessagespt)return_tensorsadd_generation_promptc              3     >#     T	R                   R                  U TR                  S5      TR                  S9nSnT	R	                  USTS9v   T	R                    H  nUR
                  U:w  a  M  TR                  S5      b)  U(       d"  UR                  [        R                  :X  a  MN  SnUR                  [        R                  :X  a  SOS nUR                  [        R                  :X  a  T	R	                  XTS9v     g T	R	                  XR                  TS	9v   M     g ! [         a9  n[        R                  [        U5      5        S
[        U5       S3v    S nAg S nAff = f7f)NrA  )rA  r   F	assistantrC  r   Trr   rD  r   )rA  rB  r   data: {"error": ""})r  add_requestr   r   rT  rA  statusr   FINISHED
next_token	Exceptionr   r&  rS   )
_inputsrA  queue_is_flushedresultrD  r,  rK   model_id_and_revisionr   r   s
         rW   stream_chat_completionPServeCommand.continuous_batching_chat_completion.<locals>.stream_chat_completion  sV    !7!EEQQ(=N_NnNn R 
 $)  66z[p6qq"FFF((J6 ww|,8AQ!==M,B,BB$/3,.4mm}?U?U.UF[_M}}(>(>>">>&K` ?   ">>'1;L;LTi ?  ! G(  7SV$*3q6(#667s;   E%C8D =E%> D E%
E")/EE%E""E%r   )process_model_namer  r  rr   load_model_and_processorr   r  r   rK   r  r  init_continuous_batchingr   logit_processorr   apply_chat_templatetor   )
r   r   must_discard_cacher   r   r  inputsr  rK   r  s
   ``      @@rW   rf  0ServeCommand.continuous_batching_chat_completion  si    !% 7 7G E2dooE/77C88==DRS=T;?8889NO+29k+J+JI''PY	=$)$;$;"//"//
 33;7<7U7U"3t 8V 8D4 H[G\D44D44::< ..s:tko.pssLL
"	7 "	7H &fQi00rV   c                     U R                   R                  nU[        R                  " 5       ;   a  [        R
                  nU$ U[        R                  " 5       ;   a  [        R                  nU$ [        SU 35      e)NzUnknown modality: )		__class__rN   r   valuesr   r   r   r   
ValueError)r   model_classnamemodalitys      rW   get_model_modalityServeCommand.get_model_modality,  sm    //22HOOQQ||H   A H H JJ||H  1/1BCDDrV   r  c           	      >   / nU  GH  nUS   / S.nU[         R                  :X  a+  [        US   [        5      (       a  US   OUS   S   nXTS'   GO7U[         R                  :X  Ga"  [        US   [        5      (       a  US   R                  SUS   S.5        OUS    H  nUS   S:X  a  US   R                  U5        M"  US   S:X  d  M-  SUS   S	   ;   a  [        R                  " S
SUS   S	   5      n[        R                  " [        [        R                  " U5      5      5      n[        R                  " SSS9nUR                  n	UR!                  UR                  5        OUS   S	   n	US   R                  SU	S.5        M     UR                  U5        GM     U$ )NrC  rC  rB  rB  rd   )typerd   r  	image_urlbase64urlz^data:image/.+;base64,r   z.pngF)suffixdeleteimage)r  r  )r   r   
isinstancerS   r   appendresubr   openr   r  	b64decodetempfileNamedTemporaryFilenamesave)
r  r  processor_inputsmessageparsed_messagerB  
image_datar  r`   r  s
             rW   *get_processor_inputs_from_inbound_messages7ServeCommand.get_processor_inputs_from_inbound_messages8  s   G&-fo"EN8<<'0:79;Ms0S0S'),Y`ajYklrYs,3y)X\\) gi0#66"9-44fgV_N`5ab#*9#5"6?f4*95<<WE$V_;'7;+?+FF-/VV4LbRYZeRfglRm-n
(-

76;K;KJ;W3X(Y'/'B'B&Y^'_&*ii %

499 5&-k&:5&A*95<<gVY=Z[ $6  ##N3=  >  rV   c           	        ^ ^^^^^ T R                   R                  b  T R                   R                  US'   US   nUS   S   S:X  a  gT R                  US   5      mTT R                  :g  nTT l        T R	                  T5      u  mnT R                  T5      nT R                  X%5      nSm[         H2  nUTR                  R                  S   R                  5       ;   d  M0  Um  O   UR                  USUR                  S	S5      S
SSS9nUR                  TR                  5      nUR                  SS5      mSn	STR                  R                  S   R                  5       ;   a  Sn	[        UU	SS9n
[!        UTR"                  S9nSnT R%                  U5      (       a  U(       d  T R&                  n0 UEU
USUS.EmUUUUU U4S jnU" U
T5      $ )z
Generates an OpenAI Chat Completion using `generate`.

Args:
    req (`dict`): The request to generate an OpenAI Chat Completion for.

Returns:
    `Generator[str, None, None]`: A generator that yields the OpenAI Chat Completion chunks.
Nr   r  rC  r  r   Ttoolsr  )r  r  r  return_dicttokenizerA  req_0gptossFskip_special_tokensskip_promptr   )streamerrK   return_dict_in_generatepast_key_valuesc              3     >#    SnS nSTR                   R                  S   R                  5       ;   a  SnSnUU4S jn[        UTS9nSn UR	                  5         [        5       nTR                  TS	TS
9v   U  GHF  nSTR                   R                  S   R                  5       ;   a%  UR                  S5      (       a  US [        S5      *  nXh-  nU(       a  X6;   a  SnMh  Mj  TGb  UR                  5       [        T   S   :X  a	  SUl        M  UR                  5       [        T   S   :X  a&  UR                  5         TR                  US STS9v   M  UR                  (       Ga@  U=R                  U-  sl        UR                  (       dV  [        R                   " SUR                  5      n	U	c  GM8  U	R#                  S5      n	SUl        [%        ['        U	S9SSUS-   S9n
OUS:X  a  GMp  SUR                  ;  a  GM  U=R(                  UR+                  S5      -  sl        U=R(                  UR+                  S5      -  sl        UR(                  S:  a&  SR-                  UR/                  S5      S S 5      S-   n[%        ['        US9SSS9n
TR                  US U
/TS9v   GM+  US:w  d  GM4  TR                  XTS9v   GMI     TR                  USTS9v   UR-                  5         UR-                  5         g ! [0         a9  n[2        R5                  [7        U5      5        S [7        U5       S!3v    S nANOS nAff = f! UR-                  5         f = f7f)"NFr  r   T<|channel|>final<|message|>c                  L   > TR                   " S0 U D6nUR                  Tl        g NrL   generater  r  r   generate_outputr   r   s     rW   generate_with_cachebServeCommand.generate_chat_completion.<locals>.stream_chat_completion.<locals>.generate_with_cache  "    "'..":6":%4%D%D"rV   targetr   r   r  r  
<|return|>r   r   rE  )rA  rC  rD  r   z\"name\": \"(.*?)\"r!   )r  function
_tool_call)r  rH  r  rI  z"arguments": {{})	arguments)r  rH  r  )rA  rC  rE  r   )rB  r   rr   r  r  r  )configarchitecturesr  r   r   r   rT  endswithlenstrip_TOOL_CALL_TOKENSr   r   r   r   r  searchgroupr2   r3   r   countjoinr  r  r   r&  rS   )r  _request_id
filter_cotcot_trace_endr  threadresults
tool_stater  	tool_nametoolr,  generation_kwargsr   r  rA  r   tool_model_familys               rW   r  EServeCommand.generate_chat_completion.<locals>.stream_chat_completion  sW     J M5<<55a8>>@@!
 =E #6?PQFGh&[
 66z[p6qq&F5<<#=#=a#@#F#F#HH!??<88%+,@s</@.@%AF%G "(3).J$$ )4!<<>->?P-QRY-ZZ:>J7$ "<<>->?P-QRW-XX&,,."&"B"B+6%).:&;	 #C #  %%666&--7- $.#C#C,.II6LjN_N_,`	#,#4$,090BICG
 @':-Hi-X*+)3'2\'A	(" $*R<$, $4:;L;L#L$, !+ < <S@Q Q < * < <S@Q Q <#-#?#?!#C-/WWV\\#5Fs5K-Ls-RF':-HSY-Z*+)3(" #'"B"B+6Ttf\q #C #  % |">>'?T ?  k 'p 66{RX`u6vv   7SV$*3q6(#667
 sC   AMIK9 .:K9 (M9
L</L72L? 7L<<L? ?MM)r   r   r  r  r  r  r  _MODELS_WITH_TOOL_SUPPORTr  r  r  r  r   r  r   r   r   rK   is_continuationr  )r   r   r  r  r   r  r  supported_model_familiesr  r  generation_streamerrK   r  r  r  r   r  rA  r  s   `             @@@@@rW   rg  %ServeCommand.generate_chat_completion]  s    99  ,9900CL9<Z B<;. $ 7 7G E2dooE/889NOy**51JJ8^ !(A$'5<<+E+Ea+H+N+N+PP$<! )B .."&'''4( / 
 5<<(WW\73
 #u||11!4::<<"'2 3

 >c[`[r[rs$$-? ..M

+!2'+,
y	 y	v &&9:FFrV   c                   ^ ^^
^^^ T R                  TS   5      mTT R                  :g  nTT l        T R                  T5      u  mn[        TS   [        5      (       a)  ST;   a	  STS   S./O/ nUR                  STS   S.5        O[        TS   [        5      (       a;  ST;   a/  TS   S   S   S:w  a  STS   S./TS   QnO`TS   nTS   US   S	'   OOTS   nOI[        TS   [        5      (       a&  ST;   a	  STS   S./O/ nUR                  TS   5        O[        S
5      eUR                  USSS9nUR                  TR                  5      nTR                  SS5      mSnSTR                  R                  S   R                  5       ;   a  Sn[!        UUSS9n[#        TTR$                  S9nSnT R'                  T5      (       a  U(       d  T R(                  nU[*        R,                  " U5      UUSUS.m
U
UUUUU 4S jn	U	" UT5      $ )z
Generates an OpenAI Response using `generate`.

Args:
    req (`dict`): The request to generate an OpenAI Response for.

Returns:
    `Generator[str, None, None]`: A generator that yields the OpenAI Response events.
r   inputinstructionssystemr  re   r   rC  rB  z%inputs should be a list, dict, or strTr  )r  r  rp   r  r  Fr  r  N)r  attention_maskr  rK   r  r  c              3     >#    SnS nSTR                   R                  S   R                  5       ;   a  SnSnUU4S jn[        UTS9nSnSnSn UR	                  5         [
        R
                  " 5       n	[        SU[        S	T 3U	S
TTR                  S5      SSS00S/ / TR                  SS5      STR                  S5      S9S9n
US-  nTR                  U
5      v   [        SU[        S	T 3U	STTR                  S5      SSS00S/ / TR                  SS5      STR                  S5      S9S9nUS-  nTR                  U5      v   [        SUU[        ST 3SSS/ S9S9nUS-  nTR                  U5      v   [        SST 3UUU[        SS / S!9S"9nUS-  nTR                  U5      v   S nU  H  nSTR                   R                  S   R                  5       ;   a%  UR                  S#5      (       a  US [!        S#5      *  nX-  nU(       a  X>;   a  SnS nMi  Mk  [#        S$ST 3UUUUS S%S&./S'9nUS-  nTR                  U5      v   M     [%        S(ST 3UUSUS S%S&./S)9nUS-  nTR                  U5      v   ['        S*ST 3UUU[        SUR(                  / S!9S"9nUS-  nUS-  nTR                  U5      v   [+        S+UU[        ST 3SS,SUR,                  // S-9S9nUS-  nUS-  nTR                  U5      v   [/        S.U[        S	T 3U	S,TTR                  S5      SSS00UR0                  /S/ TR                  SS5      STR                  S5      S/9S9nUS-  nTR                  U5      v   UR3                  5         UR3                  5         g ! [4         a  n[6        R9                  S0[;        U5       35        [=        S1U[;        U5      S29nUS-  nTR                  U5      v   [?        S3U[        S	T 3W	S4TTR                  S5      SSS00/ S/ SSTR                  S5      [A        S5[;        U5      S69S79S9nUS-  nTR                  U5      v    S nANS nAff = f! UR3                  5         f = f7f)8NFr  r   Tr  c                  L   > TR                   " S0 U D6nUR                  Tl        g r  r  r  s     rW   r  TServeCommand.generate_response.<locals>.stream_response.<locals>.generate_with_cachen  r  rV   r  zresponse.createdresp_queuedr#  formatr  rd   rV  r   r   ru   )rI  r  r  r   r#  rd   rL  r  ri  r   rl   ru   )r  sequence_numberrV  r!   zresponse.in_progressin_progresszresponse.output_item.addedmsg_r  r  )rI  r  r  rC  rB  )r  r,  output_indexitemzresponse.content_part.addedoutput_textr   )r  rd   annotations)r  item_idr,  r/  content_indexpartr   zresponse.output_text.deltagX@)tokenlogprob)r  r3  r,  r/  r4  rG  rt   zresponse.output_text.done)r  r3  r,  r/  r4  rd   rt   zresponse.content_part.donezresponse.output_item.done	completed)rI  r  r  rC  rB  r2  zresponse.completed)rI  r  r  r   r#  rd   ri  rL  r  r   rl   ru   z"Exception in response generation: r&  )r  r,  r  zresponse.failedfailedserver_error)coder  )rI  r  r  r   r#  rd   ri  rL  r  r   rl   ru   r&  )!r  r  r  r   r   rQ  r9   r5   r   rX  r=   r>   r@   r7   rA   r	  r
  rB   rC   r8   rd   r?   r5  r6   r0  r  r  r   r&  rS   r;   r<   r:   )r  r  r  r  r  r  r,  r/  r4  r  response_createdresponse_in_progressresponse_output_item_addedresponse_content_part_addedr  r  response_output_text_deltaresponse_output_text_doneresponse_content_part_doneresponse_output_item_doneresponse_completedr,  error_eventresponse_failedr  r   r  r   rA  r   s                           rW   stream_response7ServeCommand.generate_response.<locals>.stream_responsed  s     J M5<<55a8>>@@!
 =E #6?PQFOLMN!YY[
 $8+$3%":,/#-'3%(WW^%<&(89) !,/GG4I5,Q$*!$!4$ $  1$//0@AA'>/$3%":,/#-,3%(WW^%<&(89) !,/GG4I5,Q$*!$!4($$  1$//0DEE .J5$3!-.!*.Y}[fpr	.*  1$//0JKK /L6":,/$3!-"/+RUWX/+  1$//0KLL &F5<<#=#=a#@#F#F#HH!??<88%+,@s</@.@%AF%G "(3).J&(G$$1G9"&zl 3(7%1&3$,.4"@!A2. $q(O334NOO5 ': -B4":,/$3!-"# (*t<=-)  1$//0IJJ .J5":,/$3!-"/+E^EcEcqst.*  1$"//0JKK -H4$3!-.!*.&*(!;!@!@ A$&	-)  1$!//0IJJ &<-$3%":,/#-*3%(WW^%<&(89 9 > >?) ,/GG4I5,Q$*!$!4&"$  1$//0BCCJ I  !AA#a&JK0 $3F
  1$//<<"5*$3%":,/#-'3%(WW^%<&(89!) ,1$*!$!4+!/$'F#,  1$//@@C!AH s>   AQ:L5N Q:
Q"B9QQ% Q""Q% %Q77Q:)r  r  r  r  rS   r  r}  r  r  r  r  r   r   r  r  r  r   r   rK   r  r  r   	ones_like)r   r   r  r   r  r  r  rK   r  rG  r  r   r  rA  s   ``        @@@@rW   rm  ServeCommand.generate_response%  s=    !% 7 7G E2dooE/889NOyc'lC((M[_bMbxC4GHIhjFMM6c'lCDGd++$w<?6*h6'/C<OP`SVW^S_`F \F+.~+>F1Ii(WGd++M[_bMbxC4GHIhjFMM#g,'DEE..vTbf.g5<<(WW3W=
 #u||11!4::<<"'2 3

 >c[`[r[rs$$-? ..M #oof5+!2'+,
a	 a	F 2J??rV   c                   ^
^^^ [        5       (       d  [        S5      eU R                  US   5      nU R                  U5      u  mm[	        TR
                  SSS9n[        UTR                  S9nTR                  R                  n[        R                  " US   5      n[        R                  " XeSS9u  pxT" XuSS	9R                  TR                  5      m
T
S
   R                  TR                   5      T
S
'   UUSS.mU
UUU4S jn	U	" 5       $ )z
Generates an OpenAI Transcription using the audio file.

Args:
    req (`dict`): The request containing the audio file and model information.

Returns:
    `Generator[str, None, None]`: A generator that yields the transcription result.
z]Missing librosa dependency for audio transcription. Please install with `pip install librosa`r   Tr  r  r`   )srmonor  )sampling_rater  input_features)r  rK   r  c               3      >#    TR                   " S0 TDTD6n TR                  U R                  SS9S   n[        US9nUR	                  SS9 v   g 7f)NT)r  r   )rd   rN  rL   )r  batch_decode	sequencesr,   rR  )generated_idstranscription_texttranscriptionaudio_inputsaudio_modelaudio_processorr  s      rW   _generate_transcriptionDServeCommand.generate_transcription.<locals>._generate_transcriptionq  sd     '00U<UCTUM!0!=!=m>U>Uko!=!pqr!s)/ABM"222EFGs   AA)r   r  r  load_audio_model_and_processorr   r  r   rK   feature_extractorrN  ior   librosaloadr  r   dtype)r   r   r  r  rK   model_sampling_rateaudio_bytesaudio_array_rY  rV  rW  rX  r  s             @@@@rW   rx  #ServeCommand.generate_transcriptionI  s#    $%%o  !% 7 7G E'+'J'JK`'a$_2%%4T
 >)F)F

 .??MMjjV- kPTU&{fjknn
 *66F)G)J)J;K\K\)]%& ,!2'+
	H 	H '((rV   c                 N   UR                  S5      =(       d    UR                  S5      nSnU R                  c  SnOc[        U R                  5      [        U5      :  a  SnO>[        [        U R                  5      5       H  nU R                  U   X$   :w  d  M  Sn  O   X l        U$ )a  
Determines whether the current request is a continuation of the last request. In other words, if it is the
same chat session.

Args:
    req (`dict`): The request to check.

Returns:
    `True` if the request is a continuation of the last request, `False` otherwise.
r  r"  TF)r   r  r
  range)r   r   r  req_continues_last_messagesis        rW   r  ServeCommand.is_continuationy  s     77:&:#'''*:&*# %*/'##$H5*/' 3t1123%%a(HK727/ 4
 &**rV   r$   c                     U R                   (       a7  [        SU R                  U R                  U R                  U R                  S9nU$ U R
                  (       a  [        SS9nU$ SnU$ )z
Returns the quantization config for the given CLI arguments.

Args:
    args (`ServeArguments`): The serve arguments. May contain quantization settings, device, etc.

Returns:
    `Optional[BitsAndBytesConfig]`: The quantization config.
T)r   bnb_4bit_compute_dtyper   bnb_4bit_use_double_quantbnb_4bit_quant_storage)r   N)r   r$   r   r   r   r   )r   quantization_configs     rW   get_quantization_config$ServeCommand.get_quantization_config  sv     "4!'+'7'7$($<$<*.*C*C'+'7'7# #" "4!# #" #'""rV   model_idc                 v    U R                   R                  b  U R                   R                  nSU;   a  U$ U S3$ )a  
Applies the `force_model` CLI argument and canonicalizes the model name to the format "model_id@revision".
If the model_id DOESN'T contain an @, it defaults to "model_id@main".

Args:
    model_id (`str`): The model ID.

Returns:
    `str`: The canonicalized model name to be used
@z@main)r   r   )r   rr  s     rW   r  ServeCommand.process_model_name  s<     99  ,yy,,H(?O5!!rV   r  c                    U R                   n[        R                  SU 35        SU;   a  UR                  SS5      u  p4OUSpC[        R
                  " UUUR                  S9nUR                  S;   a  UR                  O[        [        UR                  5      nU R                  U5      nUUR                  USUR                  S.nUb  XxS
'   [        R
                  " U40 UD6n	[        [        U	R                  S   5      n
U
R
                  " U40 UD6n[        USS	5      c  UR                  UR                   5      nUR"                  R$                  S	L =(       a    UR"                  R&                  S:H  nUR"                  R$                  S	L=(       a    UR"                  R$                  S:  nU(       d  U(       a  SUR"                  l        [        R                  SU 35        X4$ )a  
Generic method to load a model and a data processor from a model ID and revision, making use of the serve CLI
arguments.

Args:
    model_id_and_revision (`str`):
        The model ID and revision to load.
    model_cls (`type[PreTrainedModel]`):
        The model class to load.

Returns:
    `tuple[PreTrainedModel, Union[ProcessorMixin, PreTrainedTokenizerFast]]`: The loaded model and
    data processor (tokenizer, audio processor, etc.).
zLoading rt  r!   main)revisionr   )r   Nr   )rx  r   r   
device_mapr   Nro  r   hf_device_map   rr  zLoaded model )r   r   r   r  r#   from_pretrainedr   r   getattrr   rp  r   r   r
  r  r  r   rK   r   
max_length)r   r  r   rr  rx  data_processorr   ro  model_kwargsr  architecturer   has_default_max_lengthhas_short_max_new_tokenss                 rW   _load_model_and_data_processor+ServeCommand._load_model_and_data_processor  s    yyh4567''!6!<!<S!!DHh!6h&66"44
 +/*:*:n*Ld&&RYZ_aeaqaqRr"::4@ !#'#;#;& !%!7!7
 *2E./++HEE|V-A-A!-DE,,XFF5/408HHT[[)E ##22d:gu?V?V?a?aeg?g 	 ##22$>p5CZCZCiCilpCp 	! "%=59E##2m$9#:;<$$rV   c                    XR                   ;  d"  U R                   U   R                  5       (       aB  U R                  U5      u  p#[        UU R                  R
                  US9U R                   U'   X#4$ U R                   U   R                  5         U R                   U   R                  nU R                   U   R                  nX#4$ )a$  
Loads the text model and processor from the given model ID and revision into the ServeCommand instance.

Args:
    model_id_and_revision (`str`):
        The model ID and revision to load.

Returns:
    `tuple[PreTrainedModel, PreTrainedTokenizerFast]`: The loaded text model and processor.
r   r   	r  r   r  r   r   r   r   r   r   )r   r  r   r   s       rW   r  %ServeCommand.load_model_and_processor  s     !(:(::d>P>PQf>g>r>r>t>t#BBCXYE8B $		 7 7#9D45 	 45AAC&&'<=CCE**+@AKKIrV   c                    XR                   ;  d"  U R                   U   R                  5       (       aB  U R                  U5      u  p#[        UU R                  R
                  US9U R                   U'   X#4$ U R                   U   R                  5         U R                   U   R                  nU R                   U   R                  nX#4$ )a  
Loads the audio model and processor from the given model ID and revision into the ServeCommand instance.

Args:
    model_id_and_revision (`str`):
        The model ID and revision to load.

Returns:
    `tuple[PreTrainedModel, ProcessorMixin]`: The loaded audio model and processor.
r  r  )r   r  rW  rX  s       rW   r[  +ServeCommand.load_audio_model_and_processor  s     !(:(::d>P>PQf>g>r>r>t>t+/+N+NOd+e(K8B $		 7 7)9D45 ++	 45AAC,,-BCIIK"001FGQQO++rV   )r   r   r  r  r  r  r  r  )r   NNNNN)-rN   rO   rP   rQ   staticmethodr   r  r   r   r  r#  r.  r5  r:  r?  r   rS   r}  rT  rX  r  	functools	lru_cacheanyr  r	   rf  r&   r   r  r  rg  rm  rx  rc   r  rp  r  r  tupler   r  r   r[  rU   rL   rV   rW   r   r     s   	>N 	> 	>^ @// !/ !	/
 /b
 

 

d 
 %'!%#"'+<@2GSM2G #2G }	2G
 sm2G  }2G T"7892G 
2GhJ[ JS J 8bt &+T#s(^ 4 + '+ZW1t W1	#tUY/@Z W1r 	/ 	h 	 	 " x "  " HFGD FGYsD$5O FGPb@T b@iT4.H b@H	.)$ .)9S$_3M .)`+4 +D +< #n #BV9W # #8"3 "3 "";%C ;%z c  eO]tLtFu  2,C ,ERacqRqLr ,rV   r   __main__)r  r   r  enumr  r   r]  r   r  r  r   rQ  argparser   r   dataclassesr   r   r   r   typingr	   r
   r   r   huggingface_hubr   huggingface_hub.constantsr   PILr   r
  &transformers.models.auto.modeling_autor   r   transformers.utils.import_utilsr   r   r   r   r   r   r   r   r   r   r   generation.continuous_batchingr   r   utilsr   r    r"   r   r#   r$   r%   r&   r^  r  r  r  r'   r(   fastapi.middleware.corsr)   fastapi.responsesr*   r+    openai.types.audio.transcriptionr,   .openai.types.audio.transcription_create_paramsr-   openai.types.chatr.   'openai.types.chat.chat_completion_chunkr/   r0   r1   r2   r3   *openai.types.chat.completion_create_paramsr4   openai.types.responsesr5   r6   r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   -openai.types.responses.response_create_paramsrD   pydanticrE   rF   rG   rI   r[   r^   r2  r8  r=  r3  r9  r>  r  rN   r   r  r}  r$  r  Enumr   r   r  r   r   r   r   r   r   r  rL   rV   rW   <module>r     sY        	 	  	    . (   7 7 & 4     V / (    k 4 6k;O;QkViVk   .6A>\<  [    " \@@4QY^ 6U]b '0MUZ ' %%NO&'RS)*OP %!.# 
		H	%
   !!2!7!7!9: tyy 	 8	8/8 	8v ,@ ,@^ W W WtA,- A,H$ zNE	IIK rV   