
    (HJj7                     2   d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlmZ d dlm	Z	m
Z
mZ d dlmZ d dlmZ d dlmZ d dlmZ dde
e	e      fdZded	efd
Zded	efdZd ZdefdZdefdZdefdZdefdZ ej>                   ej@                               Z!ejD                  ddejF                  de
e	ejH                        fd       Z%	 	 	 	 	 	 dde
eeejF                  f      deeejL                  f   dedede'defdZ(d Z)e*dk(  r e)        yy)    N)pprint)ListOptionalUnion)tree_reduce)
load_modelargvc                 z   t        j                  d      }|j                  ddt        d       |j                  dt        dd	
       |j                  dt        dd
       |j                  dt        dg dd       |j                  ddd       |j                  dt        dd       |j                  ddt        d dd       |j                  dt        d d!       |j                  d"t
        d#d$       |j                  d%t        d&d'       |j                  d(dd)       |j                  d*t        d d+       |j                  d,t        d-d.       |j                  d/t        d d0       |j                  d1t        j                  d d2       |j                  d3t        d4d5       |j                  |       S )6Nz(Generate transcriptions from audio files)descriptionz--modelz$mlx-community/whisper-large-v3-turbozPath to the model)defaulttypehelpz--audioTzPath to the audio file)r   requiredr   z--output-pathzPath to save the outputz--formattxt)r   srtvttjsonz&Output format (txt, srt, vtt, or json))r   r   choicesr   z	--verbose
store_truezVerbose output)actionr   z--max-tokensi    z(Maximum number of new tokens to generate)r   r   r   z--max-parallel-segments
batch_sizeSEGMENTSzcMaximum number of audio segments to transcribe in parallel for models that support segment batching)destr   r   metavarr   z
--languageenz)Language code (e.g. en, es, fr, de, etc.)z--chunk-durationg      >@z)Chunk duration in seconds (default: 30.0)z--frame-threshold   zFrame threshold (default: 25)z--streamz<Stream the transcription as it is generated (default: False)z	--contextz?Context string with hotwords or metadata to guide transcriptionz--prefill-step-sizei   z!Prefill step size (default: 2048)z--promptz@Custom prompt for the model (e.g. 'Describe the audio content.')z--gen-kwargszGAdditional generate kwargs as JSON (e.g. '{"min_chunk_duration": 1.0}')z--text z+Text to align (for forced alignment models))	argparseArgumentParseradd_argumentstrintfloatr   loads
parse_args)r	   parsers     `/Users/ahmed/devFolder/claude-voice/.venv/lib/python3.12/site-packages/mlx_audio/stt/generate.pyr%   r%      s5   $$>F 6 	   d1I   cD7P   -5   L?OP
7	   !3  
 8	   8	   ,	   K  
 N	   0	   O	   ZZX	   :	   T""    secondsreturnc                     t        | dz        }t        | dz  dz        }| dz  } |dd|dd| dj                  dd      S )z2Convert seconds to HH:MM:SS,mmm format for SRT/VTTi  <   02d:z06.3f.,)r"   replace)r)   hoursminutess      r'   format_timestampr4   s   sV    4 E7T>b()GlGC['#a7??SIIr(   c                 8    t        |       j                  dd      S )z.Convert seconds to HH:MM:SS.mmm format for VTTr0   r/   )r4   r1   )r)   s    r'   format_vtt_timestampr6   {   s    G$,,S#66r(   c                 h   t        | d      r<| j                  D cg c]&  }|j                  |j                  |j                  d( c}S g }| j
                  D ]S  }|j                  |d   |d   |d   d       d|v s&|d   s,|d   D ]   }|j                  |d   |d   |d   d       " U |S c c}w )zExtract unified cues from any model's output (Parakeet or Whisper).

    Uses word-level cues when available, otherwise falls back to segment-level.
    	sentences)startendtextr9   r:   r;   wordsword)hasattrr8   r9   r:   r;   segmentsappend)r?   scuesws       r'   	_get_cuesrD      s    
 x%FNFXFX
FXaggaeeQVV<FX
 	
 Daj51V9MNa<AgJwZaj51V9UV   
 K
s   +B/output_pathc                     |dk7  rt        | ddd      n"t        j                  t        j                        5 }|j                  | j                         d d d        y # 1 sw Y   y xY w)N-z.txtrC   utf-8encoding)open
contextlibnullcontextsysstdoutwriter;   )r?   rE   fs      r'   save_as_txtrR      s]     # 	}D!39##CJJ/	0 
			0 	0 	0s   AA(c           
         |dk7  rt        | ddd      n"t        j                  t        j                        5 }t        t        |       d      D ]_  \  }}|j                  | d       |j                  t        |d          d	t        |d
          d       |j                  |d    d       a 	 d d d        y # 1 sw Y   y xY w)NrG   z.srtrC   rH   rI      
r9    --> r:   r;   

)	rK   rL   rM   rN   rO   	enumeraterD   rP   r4   r?   rE   rQ   icues        r'   save_as_srtr\      s     # 	}D!39##CJJ/	0 
	( 3Q7FAsGGqcHGG#CL12%8HU8T7UUWX GGs6{m4() 8		0 	0 	0s   A8B<<Cc           
         |dk7  rt        | ddd      n"t        j                  t        j                        5 }|j                  d       t        t        |       d      D ]_  \  }}|j                  | d       |j                  t        |d	          d
t        |d          d       |j                  |d    d       a 	 d d d        y # 1 sw Y   y xY w)NrG   z.vttrC   rH   rI   zWEBVTT

rT   rU   r9   rV   r:   r;   rW   )	rK   rL   rM   rN   rO   rP   rX   rD   r6   rY   s        r'   save_as_vttr^      s     # 	}D!39##CJJ/	0 
		( 3Q7FAsGGqcHGG'G56e<PQTUZQ[<\;]]_` GGs6{m4() 8	0 	0 	0s   B	CCc                    t        | d      r| j                  | j                  D cg c]w  }|j                  |j                  |j                  |j
                  |j                  D cg c]1  }|j                  |j                  |j                  |j
                  d3 c}dy c}}d}t        | j                        D ]'  \  }}t        |d      s|j                  |d   |   d<   ) nj| j                  g d}| j                  D ]L  }|d   |d   |d	   |d	   |d   z
  d}d
|v r|d
   r|d
   |d
<   d|v r|d   |d<   |d   j                  |       N |dk7  rt        | ddd      n"t        j                  t        j                        5 }t!        j"                  ||dd       d d d        y c c}w c c}}w # 1 sw Y   y xY w)Nr8   )r;   r9   r:   duration)r;   r9   r:   r`   tokens)r;   r8   
speaker_id)r;   r?   r;   r9   r:   r<   r?   rG   z.jsonrC   rH   rI   F   )ensure_asciiindent)r>   r;   r8   r9   r:   r`   ra   rX   rb   r?   r@   rK   rL   rM   rN   rO   r   dump)r?   rE   rA   tresultrZ   segrQ   s           r'   save_as_jsonrj      s   x%MM" "++!  ,A FFWW55 !

 "# "*A %&FF%&WW#$55()

	 "* ,!
, h001DAqq,'78||{#A&|4 2
 MM
 ""A&	7xeHqz1	C !|'
 zGq $%lOL!:%%c* #" # 	}E"C':##CJJ/	0 
		&!%:		0 	0MX	0 	0s#   ?F4&6F/F4F:/F4:Gmodelstreamsc              #   b  K   t         j                  j                         s	 d yt        d | d      }t         j                  j	                         d   }|d|z  kD  r|dz  }|dz  }t        d| d| d	       t        j                  |      }	 d ||D ]  }t        j                  |        nt        j                          t        j                  |       y# w xY w# ||D ]  }t        j                  |        nt        j                          t        j                  |       w xY ww)
a  
    A context manager to temporarily change the wired limit.

    Note, the wired limit should not be changed during an async eval.  If an
    async eval could be running pass in the streams to synchronize with prior
    to exiting the context manager.
    Nc                 X    t        |t        j                        r| |j                  z   S | S N)
isinstancemxarraynbytes)accxs     r'   <lambda>zwired_limit.<locals>.<lambda>  s!    Z288-D3>M#Mr(   r    max_recommended_working_set_sizeg?i   z0[WARNING] Generating with a model that requires z6 MB which is close to the maximum recommended size of z MB. This can be slow. See the documentation for possible work-arounds: https://github.com/ml-explore/mlx-lm/tree/main#large-models)rq   metalis_availabler   device_infoprintset_wired_limitsynchronize)rk   rl   model_bytesmax_rec_sizemodel_mb
max_rec_mb	old_limitrA   s           r'   wired_limitr      s'     88  "	!MuVW
 xx++-.PQ|++"e+H%.JB8* MEEOL QNN &&|4		*" ANN1% !  y)1 & " ANN1% !  y)s6   D/C A)D/C" A	D/CD/"A
D,,D/audioformatverboser;   c                    ddl m} | t        d      t        | t              rt        |       } t        j                          t        j                         }|r5t        d       t        d|        t        d|        t        d|        |j                  d	d      }	|	r|j                  |	       |r||d
<   t        j                  | j                        }
|j                         D ci c]  \  }}||
j                   v s|| }}}|j#                  dd      rg }d}d}d}d} | j                  |fd|i|D ]  }|j$                  |j&                  |j(                  |j*                  d}|j-                  |       ||j$                  z  }|j.                  }t1        |d      r|j2                  dkD  r|j2                  }t1        |d      s|j4                  dkD  s|j4                  } t        j                         }||z
  } ||j7                         ||||||z   ||dkD  r||z  nd|dkD  r||z  nd	      }n | j                  |f|t8        d|}|rqt1        |d
      r&t        d       t        |j$                  dd  d       t1        |d      r3|j:                  't        d       t=        |j:                  dd dgz          t        j                         }|rt        d       t        d| d|        t        d ||z
  d!d"       t        ||      rNt        d#|j2                   d$|j>                  d%d&       t        d'|j4                   d$|j@                  d%d&       t        d(t        jB                         d)z  d!d*       tE        jF                  tD        jH                  jK                  tD        jH                  jM                  |            d+,       t1        |d      xr |j:                  du}t1        |d-      xr |jN                  du}|d.k(  s|s|s|s|st        d/       tQ        ||       |S |d0k(  rtS        ||       |S |d1k(  rtU        ||       |S |d2k(  rtW        ||       |S c c}}w )3a  Generate transcriptions from audio files.

    Args:
        model: Path to the model or the model instance.
        audio: Path to the audio file (str), or audio waveform (mx.array).
        output_path: Path to save the output.
        format: Output format (txt, srt, vtt, or json).
        verbose: Verbose output.
        text: Text to align (for forced alignment models).
        **kwargs: Additional arguments for the model's generate method.

    Returns:
        segments: The generated transcription segments.
    rT   )	STTOutputNz.Model path or model instance must be provided.z
==========z[94mAudio path:[0m z[94mOutput path:[0m z[94mFormat:[0m 
gen_kwargsr;   streamFr   r   r   r   )r;   r9   r:   is_finalprompt_tokensgeneration_tokens)	r;   r?   languager   r   total_tokens
total_time
prompt_tpsgeneration_tps)r   generation_streamz[94mTranscription:[0m
i  z...
r?   z[94mSegments:[0m
   z...z
==========z[94mSaving file to:[0m ./r/   z[94mProcessing time:[0m z.2fz secondsz[94mPrompt:[0m z	 tokens, z.3fz tokens-per-secz[94mGeneration:[0m z[94mPeak memory:[0m g    eAz GBT)exist_okr8   r   z2[WARNING] No segments found, saving as plain text.r   r   r   ),models.baser   
ValueErrorrp   r!   r   rq   reset_peak_memorytimer{   popupdateinspect	signaturegenerateitems
parametersgetr;   
start_timeend_timer   r@   r   r>   r   r   stripr   r?   r   r   r   get_peak_memoryosmakedirspathdirnameabspathr8   rR   r\   r^   rj   )rk   r   rE   r   r   r;   kwargsr   r   r   r   kvall_segmentsaccumulated_textr   r   r   rh   segment_dictstream_end_timestream_durationr?   r   has_segmentshas_sentencess                             r'   generate_transcriptionr     s   . '}IJJ%5!Jh+E734,[M:;'x01 L$/Jj! v!!%..1I%||~K~tq!i6J6J1Jad~FKzz(E"$ennUFGFvFF**"OO	L -+H v/F4H4H14L & 4 4v238P8PST8T$*$<$<!# G& ))+)J6!'')!'/&)::&:IA:M}6ST7F7J!O3PQ
 "5>>
"6G
KQ
 8V$34X]]4C()/08Z(X->->-J./8$$Ra(E723yy{Ho1+axHI0J1Fs0K8TUh	*)(*@*@)A&&s+?< -h.H.H-I**3/@ 	,R-?-?-AC-G,LCPQ KK <=M 8Z0RX5F5Fd5RLHk2Ux7I7IQU7UM|MMFGHk* O 
5Hk* O 
5Hk* O 
6	X{+Ow Ls   ,Q6Q6c                  @    t               } t        di t        |        y )N )r%   r   vars)argss    r'   mainr     s    <D(T$Z(r(   __main__ro   )NN
transcriptr   Fr   )+r   rL   r   r   r   rN   r   r   typingr   r   r   mlx.corecorerq   mlx.nnnn	mlx.utilsr   mlx_audio.stt.utilsr   r!   r%   r#   r4   r6   rD   rR   r\   r^   rj   
new_streamdefault_devicer   contextmanagerModuleStreamr   rr   boolr   r   __name__r   r(   r'   <module>r      s       	 
   ( (   ! *^#Xd3i( ^#BJe J J7% 7C 7
$s *s **s *4; 4;p "BMM"3""3"3"56  $*ryy $*8DO+D $* $*P .2"&#ME#ryy.)*MbhhM M 	M
 M M`)
 zF r(   