
    (HJj\                     X   U 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mZm	Z	 d dl
mZ d dlmZ d dlmZ d dlmZmZ d dlmZ d dlmZ d dlmZ g d	Zg d
Zg dZ G d dee      Ze G d d             Zej@                   edg ddd      ejB                   edg ddd      ejD                   edg ddd      ejF                   edg ddd       iZ$i Z%e&ee'e   f   e(d!<   i Z)e&ee&f   e(d"<   d#ed$e'e   fd%Z*d#ed$e'e   fd&Z+d$e'e   fd'Z,d#ed$e&fd(Z-d#ed$e&fd)Z.dPd*ed+ee   d$efd,Z/d-ed$e&fd.Z0d/ed$ee   fd0Z1d1e&d$efd2Z2d1e&d$ee3eef      fd3Z4d-ed$ee3eef      fd4Z5d1e&d-ed$efd5Z6d1e&d-ed#ed$efd6Z7d/ed#efd7Z8d8ed9ed#ed$e3e9e   ef   fd:Z:d;ed8ed9ed#efd<Z;	 dPd=ee   d$eee<ge=f   fd>Z>d?ed@efdAZ?d-ed$e&fdBZ@	 	 	 	 	 	 	 	 	 	 	 dQd9edCedDe=dEeeA   dFeeA   dGee   d8ee   d+ee   dHe=dIee   dJedKee   fdLZBd$e j                  fdMZDdN ZEeFdOk(  r eE        yy)R    N)	dataclassfieldsis_dataclass)Enum)Path)dedent)CallableOptional)snapshot_download)tree_flatten)float16bfloat16float32)	mixed_2_6	mixed_3_4	mixed_3_6	mixed_4_6)affinemxfp4nvfp4mxfp8c                        e Zd ZdZdZdZdZdZy)DomainzSupported model domains.ttssttstslidN)__name__
__module____qualname____doc__TTSSTTSTSLID     [/Users/ahmed/devFolder/claude-voice/.venv/lib/python3.12/site-packages/mlx_audio/convert.pyr   r      s    "
C
C
C
Cr'   r   c                   @    e Zd ZU dZeed<   ee   ed<   eed<   eed<   y)DomainConfigz$Configuration for a specific domain.nametagscli_examplepython_exampleN)r   r   r    r!   str__annotations__listr&   r'   r(   r*   r*   #   s    .
I
s)Or'   r*   r"   )ztext-to-speechspeechzspeech generationzvoice cloningr   zOpython -m mlx_audio.tts.generate --model {repo} --text "Hello, this is a test."aS  
        from mlx_audio.tts.utils import load_model
        from mlx_audio.tts.generate import generate_audio

        model = load_model("{repo}")
        generate_audio(
            model=model,
            text="Hello, this is a test.",
            ref_audio="path_to_audio.wav",
            file_prefix="test_audio",
        )
        )r+   r,   r-   r.   r#   )zspeech-to-textr2   transcriptionasrr   zCpython -m mlx_audio.stt.generate --model {repo} --audio "audio.wav"a  
        from mlx_audio.stt.utils import load_model
        from mlx_audio.stt.generate import generate_transcription

        model = load_model("{repo}")
        transcription = generate_transcription(
            model=model,
            audio_path="path_to_audio.wav",
            output_path="path_to_output.txt",
            format="txt",
            verbose=True,
        )
        print(transcription.text)
        r$   )zspeech-to-speechr2   audiozspeech enhancementzaudio separationr   zCpython -m mlx_audio.sts.generate --model {repo} --audio "audio.wav"z
        from mlx_audio.sts.utils import load_model
        model = load_model("{repo}")
        # Usage depends on the specific STS model type
        # See model documentation for details
        r%   )zaudio-classificationr2   zlanguage-identificationr   z_python -c "from mlx_audio.lid import load; model = load('{repo}'); print(model.predict(audio))"aT  
        from mlx_audio.lid import load
        from mlx_audio.utils import load_audio

        model = load("{repo}")
        audio = load_audio("path_to_audio.wav", sample_rate=16000)  # LID requires 16kHz
        results = model.predict(audio, top_k=5)
        for lang, prob in results:
            print(f"{lang}: {prob:.1%}")
        _model_types_cache_detection_hints_cachedomainreturnc                 J   t        t              j                  | z  dz  }|j                         s
t	               S |j                         D ch c]L  }|j                         r:|j                  j                  d      s|dz  j                         r|j                  N c}S c c}w )z@Discover available model types by scanning the models directory.models_z__init__.py)	r   __file__parentexistssetiterdiris_dirr+   
startswith)r8   
models_dirds      r(   _discover_model_typesrF   |   s    h&&/(:Ju ##%%A88:aff//4!m:K9S9S9U 	
%  s   AB c                 `    | j                   }|t        vrt        |      t        |<   t        |   S )z2Get the set of available model types for a domain.)valuer6   rF   r8   
domain_strs     r(   get_model_typesrK      s/    J++)>z)J:&j))r'   c                     t        |       r#t        |       D ch c]  }|j                   c}S t        | d      r"t	        t        |       j                               S t	               S c c}w )zEExtract field names from a config class (dataclass or regular class).__dict__)r   r   r+   hasattrr@   varskeys)config_classfs     r(   _get_config_keysrS      s^    L! &| 45 41 455*1,
*KD##%&QTQV 6s   A'c                    i i i d}t        t        |             D ]  }d|  d| }	 t        j                  |      }t	        |d      rU|j
                  }d|v rt        |d         |d   |<   d|v rt        |d         |d   |<   d|v rXt        |d         |d   |<   nCt	        |d      rt        |j                        }||d   |<   ||j                  d	d
      h|d   |<    |S # t        $ r Y w xY w)z
    Discover detection hints for all models in a domain.

    Each model can optionally define:
    - DETECTION_HINTS: dict with 'config_keys', 'architectures', 'path_patterns'
    - Or we infer from the ModelConfig class
    )config_keysarchitecturespath_patterns
mlx_audio..models.DETECTION_HINTSrU   rV   rW   ModelConfigr<    )rK   r   	importlibimport_modulerN   rZ   r@   rS   r[   replaceImportError)r8   hints
model_typemodule_pathmodulemodel_hintsrU   s          r(   _discover_detection_hintsrf      sA    E &fVn5
"6((:,?	,,[9F v01$44 K/7:;};U7VE-(4"k19<#O4:E/*:6 #k19<#O4:E/*:6
 6=1"263E3E"FK7BE-(4 &&sB/6o&z23 6B L  		s   B9C$$	C0/C0c                 `    | j                   }|t        vrt        |      t        |<   t        |   S )z*Get detection hints for a domain (cached).)rH   r7   rf   rI   s     r(   get_detection_hintsrh      s/    J//-Fz-Rz*!*--r'   path_or_hf_reporevisionc                 n    t        |       }|j                         st        t        | |g d            }|S )zx
    Ensures the model is available locally.

    Downloads from HuggingFace Hub if the path doesn't exist locally.
    )*.json*.safetensors*.py*.model
*.tiktoken*.txt*.jinjaz*.jsonl*.yaml*.wavz*.pth)rj   allow_patterns)r   r?   r   )ri   rj   
model_paths      r(   get_model_pathrw      s?     o&J! 

( r'   rv   c                     | dz  }|j                         r-t        |dd      5 }t        j                  |      cddd       S t	        d|        # 1 sw Y   xY w)z%Load model configuration from a path.config.jsonrzutf-8)encodingNzConfig not found at )r?   openjsonloadFileNotFoundError)rv   config_pathrR   s      r(   load_configr      sU    },K+sW599Q< 65
2:,?
@@ 65s   AArb   c                 B    | syt         D ]  }| t        |      v s|c S  y)z-Try to match a model_type string to a domain.N)r   rK   )rb   r8   s     r(   _match_by_model_typer      s+     00M  r'   configc                     | j                  dd      j                         xs  | j                  dd      j                         S )zFGet model identifier from config, checking model_type and name fields.rb   r\   r+   )getlower)r   s    r(   _get_model_identifierr   
  s5    ::lB'--/Q6::fb3I3O3O3QQr'   c                    t        | j                               }d}d}t        D ]f  }t        |      }|j	                  di       j                         D ]6  \  }}||z  }|st        |      t        |      z  }	|	|kD  s+|	dkD  s1|	}||f}8 h |S )z4Try to match config keys to a domain and model type.Nr   rU   333333?)r@   rP   r   rh   r   itemslen)
r   rU   
best_match
best_scorer8   ra   rb   
model_keysintersectionscores
             r(   _match_by_config_keysr     s    fkkm$KJJ#F+&+iir&B&H&H&J"J
&3LL)C
O;:%%#+!&J"(*!5J 'K  r'   c                     t        |       j                         t        D ]Q  }t        |      }|j	                  di       j                         D ]!  \  }}t        fd|D              s||fc c S  S y)z6Try to match path patterns to a domain and model type.rW   c              3   &   K   | ]  }|v  
 y wNr&   .0patternpath_strs     r(   	<genexpr>z!_match_by_path.<locals>.<genexpr>,  s     ?h77h&h   N)r/   r   r   rh   r   r   any)rv   r8   ra   rb   patternsr   s        @r(   _match_by_pathr   %  sk    :$$&H#F+$)IIor$B$H$H$J J?h??
++ %K  r'   c                     t        |       }t        |      }|r|d   S t        |      }|r|S t        |       }|r|d   S t        j
                  S )z
    Detect whether a model is TTS, STT, or STS based on its configuration.

    Uses multiple heuristics in order of reliability:
    1. model_type or name field in config
    2. Config key matching
    3. Path pattern matching
    r   )r   r   r   r   r   r"   )r   rv   model_identifiermatchr8   s        r(   detect_model_domainr   2  s`     -V4 :&EQx ""23F "&)EQx ::r'   c                    | j                  dd      j                         }| j                  dd      j                         }||fD ]  }|s|t        |      v s|c S  t        |      }t	        | j                               }d}d}	|j                  di       j                         D ].  \  }
}|s	||z  }t        |      t        |      z  }||	kD  s+|}	|
}0 |r|	dkD  r|S t        |      j                         |j                  di       j                         D ]  \  }
}t        fd	|D              s|
c S  t        |      }|rt        t        |      d
      S d
S )z2Determine the specific model type within a domain.rb   r\   r+   Nr   rU   r   rW   c              3   &   K   | ]  }|v  
 y wr   r&   r   s     r(   r   z!get_model_type.<locals>.<genexpr>p  s     ;(ww("(r   unknown)r   r   rK   rh   r@   rP   r   r   r/   r   nextiter)r   rv   r8   rb   
model_name	candidatera   rU   r   r   mtr   r   r   r   model_typesr   s                   @r(   get_model_typer   P  sW    L"-335JFB'--/J !*-	of&== .
  'Efkkm$KJJ))M26<<>J&3L%J7Ez!"

 ? j3& :$$&H		/26<<>H;(;;I ?
 "&)K1<4[!9-K)Kr'   c                     d|j                    d|  }	 t        j                  |      S # t        $ r:}d|  d|j                   d| }t        j                  |       t        |      d}~ww xY w)z=Get the model class module for a given model type and domain.rX   rY   zModel type 'z' not supported for z	. Error: N)rH   r]   r^   r`   r+   loggingerror
ValueError)rb   r8   rc   emsgs        r(   get_model_classr   x  ss    v||nHZLAK&&{33 ZL(<V[[MSTRUVcos   ) 	A,5A''A,upload_repohf_pathc                    ddl m} t        |   }dg|j                  z   }|j	                  d       t        d|  d| d| d| d	| d
|j                  j                  |        d|j                  j                  |        d      }||fS )z4Generate README content and tags for the model card.r   )__version__mlx	mlx-audioz
        # z8

        This model was converted to MLX format from [`z`](https://huggingface.co/z) using mlx-audio version **zG**.

        Refer to the [original model card](https://huggingface.co/z) for more details on the model.

        ## Use with mlx-audio

        ```bash
        pip install -U mlx-audio
        ```

        ### CLI Example:
        ```bash
        )repozC
        ```

        ### Python Example:
        ```python        z
        ```
        )	mlx_audio.versionr   DOMAIN_CONFIGSr,   appendr   r-   formatr.   )r   r   r8   r   r   r,   contents          r(   generate_readme_contentr     s     .F#F7V[[ DKK- 77>i?YZaYbb~  @K  L LCCJ) 
L	 
			"	"	"	45 6	
 
			%	%;	%	78 9	)	G4 =r'   pathc                 H   ddl m}m} t        d|        t	        |||      \  }}	 |j                  |      }|j                  j                  |n|j                  j                  |z   |j                  _        d|j                  _        ||_
        |j                  | dz          |       }	|	j                  |d	       |	j                  t        |       |d
       t        d|        y# t        $ r-  |d      }||j                  _        d|j                  _        Y w xY w)z*Upload converted model to HuggingFace Hub.r   )HfApi	ModelCardz[INFO] Uploading to Nr   r\   z	README.mdT)repo_idexist_okmodel)folder_pathr   	repo_typez3[INFO] Upload complete! See https://huggingface.co/)huggingface_hubr   r   printr   r~   datar,   library_name	Exceptiontextsavecreate_repoupload_folderr/   )
r   r   r   r8   r   r   r,   readme_contentcardapis
             r(   upload_to_hubr     s   0	 
./2;PD.-~~g&!%!7TYY^^d=R		!,		 DIIId[ !
'COOK$O7I  
 
?}
MN  -}		!,		-s   A"C+ +3D! D!quant_predicate_namec                 z    t        | dd       dt        dt        ffd|sS ddlm}  |||       fdS )	z*Build the quantization predicate function.model_quant_predicatec                      y)NTr&   )pms     r(   <lambda>z'build_quant_predicate.<locals>.<lambda>  s    QUr'   r   r9   c                     t        |d      xr8 |j                  j                  d   dz  dk(  xr t        |d      xr	  | |      S )Nweight@   r   to_quantized)rN   r   shape)r   rd   r   s     r(   base_requirementsz0build_quant_predicate.<locals>.base_requirements  sS    FH% 4##B'",14/4 &dF3		
r'   r   )mixed_quant_predicate_builderc                 ,     | |      xr	  | |      S r   r&   )r   r   r   mixed_predicates     r(   r   z'build_quant_predicate.<locals>.<lambda>  s    )!Q/IOAq4IIr'   )getattrr/   boolmlx_lm.convertr   )r   r   r   r   r   r   s      @@@r(   build_quant_predicater     sJ     $E+BDUV
 
 
    <34H%POIIr'   sourcedestc                 r   g d}|D ]-  }t        j                   t        | |z              D ]U  }t        |      j                  }|dk(  s"|j	                  d      r|j                  d      r@t        j                  ||       W t        j                   t        | dz  |z        d      D ]  }t        |      j                  |       }t        |j                        dk  r6t        |      j                  }|dk(  rQ||j                  z  }|j                  dd	       t        j                  ||        0 y
)z1Copy supporting files from source to destination.)
rn   rl   rs   rp   ro   rq   rr   rt   z*.ptrm   zmodel.safetensors.index.jsonr   z.safetensorsz**T)	recursive   parentsr   N)globr/   r   r+   rC   endswithshutilcopyrelative_tor   partsr>   mkdir)r   r   r   r   filer+   rel_pathdest_dirs           r(   copy_model_filesr     s   H IIc&7"234D:??D55(T]]>-JKKd# 5 IIc&4-'"9:dKDDz--f5H8>>"a':??D55hoo-HNN4$N7KKh' L r'   c                 F   t        j                   t        | dz              }|st        d|        |D cg c])  }t        |      j                  j                  d      s(|+ }}|r|}i }|D ]+  }d|v r|j                  t        j                  |             - |S c c}w )z*Load model weights from safetensors files.rm   zNo safetensors found in consolidated	tokenizer)	r   r/   r   r   r+   rC   updatemxr~   )rv   weight_filesrR   r   weightswfs         r(   load_weightsr    s    99So!=>?L"::, GHH  ,W|!tAw||/F/F~/VA|LW#G"rwwr{# 
 N Xs   )B Bmlx_pathquantizeq_group_sizeq_bitsdtype
dequantizequant_predicateq_modemodel_domainc                 R   ddl m}m}m}m} |r|rt        d      t        d|         t        | |      }t        |      }|t        ||      }nt        |      }t        |||      }t        d|j                   d|        t        ||      }t        |d	      r|j                  j!                  |      n|}t        |d
      r||_        t%        |      }|j'                  |      }t        |d      r|j)                  |      }|j%                  t+        |j-                                      t/        t1        |j3                                     }|xs |j5                  d      }|rX|t6        v rPt        d|        t9        t:        |      }|j-                         D ci c]  \  }}||j=                  |       }}}|rEt?        ||	      }|j%                  t+        |j-                                       ||||||
|      \  }}|r5t        d        ||      }t/        t1        |j3                                     }tA        |      }|jC                  dd       tE        ||        |||d       ||d<    |||dz         t        d|        |rtG        ||| |       yyc c}}w )a  
    Convert a model from HuggingFace to MLX format.

    Automatically detects whether the model is TTS, STT, or STS and handles
    conversion appropriately.

    Args:
        hf_path: Path to the Hugging Face model or repo ID.
        mlx_path: Path to save the MLX model.
        quantize: Whether to quantize the model.
        q_group_size: Group size for quantization. Uses mode defaults when None.
        q_bits: Bits per weight for quantization. Uses mode defaults when None.
        dtype: Data type for weights (float16, bfloat16, float32).
        upload_repo: Hugging Face repo to upload the converted model.
        revision: Model revision to download.
        dequantize: Whether to dequantize a quantized model.
        quant_predicate: Mixed-bit quantization recipe.
        q_mode: Quantization mode (affine, mxfp4, nvfp4, mxfp8).
        model_domain: Force model domain ("tts", "stt", or "sts"). Auto-detected if None.
    r   )dequantize_modelquantize_modelsave_config
save_modelz/Choose either quantize or dequantize, not both.z[INFO] Loading model from )rj   Nz
[INFO] Model domain: z, type: r[   rv   sanitizetorch_dtypez[INFO] Converting to )moder  z[INFO] DequantizingTr   )donate_modelrb   ry   )r   z+[INFO] Conversion complete! Model saved to )$mlx_lm.utilsr  r  r  r  r   r   rw   r   r   r   r   r+   r   rN   r[   	from_dictrv   r  Modelr  r1   r   dictr   
parametersr   MODEL_CONVERSION_DTYPESr   r  astyper   r   r   r   r   )r   r  r  r	  r
  r  r   rj   r  r  r  r  r  r  r  r  rv   r   r8   rb   model_classmodel_configr  r   target_dtypemx_dtypekvfinal_predicates                                r(   convertr'     s   D WVJJKK	&wi
01(;J$F $VZ8%
F;J	#FKK=
EF "*f5K ;. 	))&1  |\*", :&Gl+Euj!..)	tGMMO,-< 0 0 234G 5FJJ}5L(??%l^452|,5<]]_E_TQ1ahhx((_E /G401(+
 #$ '|E$4$4$678 H~HNN4$N/Z* xT2%F<H}$<=	7z
BChWf= A Fs   J#c                     t        j                  d      } | j                  dt        dd       | j                  dt        dd	
       | j                  dddd       | j                  dt        dd
       | j                  dt        dd
       | j                  dt
        t        dd       | j                  dt        t        d       | j                  dt        t        dd       | j                  dt        dd 
       | j                  d!t        dd"
       | j                  d#d$dd%       | j                  d&t        g d'dd(       | S ))z)Configure and return the argument parser.z:Convert HuggingFace model (TTS, STT, or STS) to MLX format)descriptionz	--hf-pathTz*Path to the Hugging Face model or repo ID.)typerequiredhelpz
--mlx-path	mlx_modelzPath to save the MLX model.)r*  defaultr,  z-qz
--quantize
store_truezGenerate a quantized model.)actionr,  z--q-group-sizeNz6Group size for quantization (mode default if omitted).z--q-bitsz;Bits per weight for quantization (mode default if omitted).z--q-moder   zQuantization mode.)choicesr*  r.  r,  z--quant-predicatezMixed-bit quantization recipe.)r1  r*  r,  z--dtypezData type for weights.)r*  r1  r.  r,  z--upload-repoz)Hugging Face repo to upload the model to.z
--revisionzModel revision to download.z-dz--dequantizezDequantize a quantized model.z--model-domain)r   r   r   r   z4Force model domain (auto-detected if not specified).)argparseArgumentParseradd_argumentr/   intQUANT_MODESQUANT_RECIPESr  )parsers    r(   configure_parserr9    s   $$PF 9	   *	   *	   E	   J	   !   -	   '%   8	   *	   ,	   ,C   Mr'   c                  `    t               } | j                         }t        di t        |       y )Nr&   )r9  
parse_argsr'  rO   )r8  argss     r(   mainr=    s'    FDd4jr'   __main__r   )r-  FNNNNNFNr   N)Gr2  r   r]   r}   r   r   dataclassesr   r   r   enumr   pathlibr   textwrapr   typingr	   r
   mlx.corecorer  r   r   	mlx.utilsr   r  r7  r6  r/   r   r*   r"   r#   r$   r%   r   r6   r  r@   r0   r7   rF   rK   rS   rf   rh   rw   r   r   r   tupler   r   r   r   r   r1   r   r   r   r   r   r   r  r5  r'  r3  r9  r=  r   r&   r'   r(   <module>rH     s"         7 7    %  - " = D3S$     JJVe	" JJHY	& JJ
 Z$ JJQw		oFT +- Dc#h' ,*, S$Y ,
# 
#c( 
*F *s3x *c#h /c /d /d. .4 .C 8C= D @AD AT A
S 
Xf-= 
R$ R3 R
$ 8E&#+4F+G ,
t 
vs{1C(D 
 $ 6 <%L4 %LT %L6 %Lc %LP V %%"%,2%
49c>%PO O3 O Of O> 26J!)#JsCj$J.$(T $( $(NT d 6  "& !%"%)"&q>q>q> q> 3-	q>
 SMq> C=q> #q> smq> q> c]q> q> 3-q>hR(11 Rj zF r'   