
    hJJjY                        d dl Z d dlZd dlmZmZmZmZ d dlmZ	 d dl
Zd dlZddlmZmZmZmZmZmZmZ ddlmZmZ ddlmZ ddlmZ ddlmZmZ d	efd
Z dee!   dee   fdZ" G d d      Z#dddddddddddddddee$ejJ                  e	jL                  f   de$dee'   deeeedf   f   d ee   d!ee   d"ee   d#e'd$ee$   d%e'd&e$d'e$d(ee$ee   f   d)ee   fd*Z(y)+    N)ListOptionalTupleUnion   )FRAMES_PER_SECOND
HOP_LENGTHN_FRAMES	N_SAMPLESSAMPLE_RATElog_mel_spectrogrampad_or_trim)DecodingOptionsDecodingResult)
load_model)add_word_timestamps)	LANGUAGESget_tokenizersecondsc                     | dk\  sJ d       t        | dz        }|dz  }||dz  z  }|dz  }||dz  z  }|dz  } || dz  z  }|dkD  r|ddnd	}| |dd| dd
|dS )Nr   znon-negative timestamp expectedg     @@i6 i`  i  02d: .03d)round)r   millisecondshoursminuteshours_markers        `/Users/ahmed/devFolder/claude-voice/.venv/lib/python3.12/site-packages/mlx_whisper/transcribe.py_format_timestampr"      s    a<:::<6)*LI%EEI%%Lf$GGf$$Le#GGeO#L&+aieC[?RL^GC='#aS7IJJ    segmentsreturnc                 V    t        d t        |       D        | r| d   d         S d       S )Nc              3   L   K   | ]  }t        |d          D ]	  }|d      yw)wordsendN)reversed).0sws      r!   	<genexpr>z_get_end.<locals>.<genexpr>-   s)     L-ax'
7K!57K-s   "$r)   )nextr*   r$   s    r!   _get_endr2   +   s7    L8H-L'U -1 r#   c                   B    e Zd ZdZdZededej                  fd       Z	y)ModelHolderN
model_pathdtypec                     | j                   || j                  k7  rt        ||      | _         || _        | j                   S )N)r6   )modelr5   r   )clsr5   r6   s      r!   	get_modelzModelHolder.get_model6   s6    99
cnn <":U;CI'CNyyr#   )
__name__
__module____qualname__r8   r5   classmethodstrmxDtyper:    r#   r!   r4   r4   2   s0    EJ3 rxx  r#   r4   zmlx-community/whisper-tiny)        g?g?333333?g?      ?g333333@g      rD   TFu   "'“¿([{-u   "'.。,，!！?？:：”)]}、0)path_or_hf_repoverbosetemperaturecompression_ratio_thresholdlogprob_thresholdno_speech_thresholdcondition_on_previous_textinitial_promptword_timestampsprepend_punctuationsappend_punctuationsclip_timestampshallucination_silence_thresholdaudiorG   rH   rI   .rJ   rK   rL   rM   rN   rO   rP   rQ   rR   rS   c                >  RSTUVW j                  dd      rt        j                  nt        j                  }t        j                  ||      Rt        | Rj                  j                  t              }|j                  d   t        z
  }t        |t        z  t        z        }|r"t        j                          UUdk7  rUfd}nd }j                  dd	      Rj"                  sd
d<   n|rt%        d       t'        |t        d      j)                  |      }Rj+                  |      \  }}t-        ||j                         d<   |&t%        dt.        d      j1                                 d   }j                  dd      }t3        Rj"                  Rj4                  ||      Vt7        |t8              r+|r|j;                  d      ng D cg c]  }t        |       }}|D cg c]  }t=        |t>        z         }}tA        |      dk(  r|jC                  d       tA        |      dz  dk(  r|jC                  |       ntE        ||d         |d<   tG        tI        |d	d	d   |dd	d               }dS|	r|dk(  rtK        jL                  d       dt        jN                  dtP        fRfd}d}||   d   Tt        Rj                  jR                  z  }|t        z  t        z  }g } g }!d}"|4VjU                  d|jW                         z         }#| jY                  |#       ng }#dt        dt        d t        jN                  d!tP        fTVfd"}$t[        jZ                  |d#|d$u%      5 }%d&}&|D ]  \  }'}(T|(k  st        Tt        z  t        z        })t        Tt        z   t        z  t        z        }*tE        t        |Tz
  |(Tz
        }+|TT|+z    }|+t        z  t        z  },t'        |t        d      j)                  |      }| |"d	 d'<    ||      }-t]        jN                  |-j^                        }.*|-j`                  kD  }/|-jb                  kD  rd$}/|/rT|+z  TT}0g }1d(td        dt        fd)Wdtf        td           dth        fSWfd*}2d+tj        td           dtf        td           fd,}3|.Vjl                  k\  }4|4dd	 jo                         d$dgk(  }5t]        jp                  t]        jr                  |4d	d |4dd	             d   }6|6dz  }6tA        |6      dkD  r|6jo                         }7|5r|7jC                  tA        |.             d}8|7D ]p  }9|.|8|9 }:|:d   ju                         Vjl                  z
  };|:d   ju                         Vjl                  z
  }<|1jC                   |$|)|;|z  z   |)|<|z  z   |:|--             |9}8r |5rT|+z  Tn|.|8dz
     ju                         Vjl                  z
  }=T|=|z  z  Tn|,}>|.|4jw                         d      }?tA        |?      dkD  rE|?d   ju                         Vjl                  k7  r%|?d   ju                         Vjl                  z
  }=|=|z  }>|1jC                   |$|)|)|>z   |.|--             T|+z  T|	rty        |1RV||+|
||&.       |5s$t{        |1      }@|@@|)kD  rt=        @t>        z        T|@|}A|5s4t{        |1      }@|@'@|)kD  r"|*@z
  }B|BAkD  rt=        @t>        z        Tn|0|+z   T |3|1      }C|C, |2C      r$Cd   |)z
  }D|DAkD  r|0t=        Dt>        z        z   T|&}Et}        tA        |1            D ]  }F|1|F   }G|Gd/   s |2G      r |3|1Fdz   d	       }H|HHd/   d   d   }In|)|,z   }IGd   Ez
  AkD  xs Gd   Ak  xs Gd   |)z
  d0k  }JIGd   z
  AkD  xs  |2H      xs |*Gd   z
  d0k  }KJr8Kr6t=        t-        |)dz   Gd         t>        z        T||Gd   z
  Ak  r|Tg |1Fd	  nGd   }E t{        |1      }@|@@}&|rD|1D ]?  }G|Gd   |Gd   |Gd1   }N}M}Ld2t        |L       d3t        |M       d4|N }Ot%         |O             A t        |1      D ]6  \  }P}G|Gd   |Gd   k(  sGd1   jW                         d5k(  s(d5Gd1<   g |Gd <   g |Gd/<   8 |!jY                  t        |1tA        |!      6      D PGcg c]  \  }P}Gd7|Pi|G c}G}P       | jY                  |1D GQcg c]  }G|Gd    D ]  }Q|Q  c}Q}G       |r|-j                  d8kD  rtA        |       }"|%j                  tE        |T      |0z
         T|(k  r 	 d	d	d	       te        Vj                  | tA        |#      d	       |!|9      S c c}w c c}w c c}G}Pw c c}Q}Gw # 1 sw Y   HxY w):a  
    Transcribe an audio file using Whisper

    Parameters
    ----------
    audio: Union[str, np.ndarray, mx.array]
        The path to the audio file to open, or the audio waveform

    path_or_hf_repo: str
        The localpath to the Whisper model or HF Hub repo with the MLX converted weights.

    verbose: bool
        Whether to display the text being decoded to the console. If True, displays all the details,
        If False, displays minimal details. If None, does not display anything

    temperature: Union[float, Tuple[float, ...]]
        Temperature for sampling. It can be a tuple of temperatures, which will be successively used
        upon failures according to either `compression_ratio_threshold` or `logprob_threshold`.

    compression_ratio_threshold: float
        If the gzip compression ratio is above this value, treat as failed

    logprob_threshold: float
        If the average log probability over sampled tokens is below this value, treat as failed

    no_speech_threshold: float
        If the no_speech probability is higher than this value AND the average log probability
        over sampled tokens is below `logprob_threshold`, consider the segment as silent

    condition_on_previous_text: bool
        if True, the previous output of the model is provided as a prompt for the next window;
        disabling may make the text inconsistent across windows, but the model becomes less prone to
        getting stuck in a failure loop, such as repetition looping or timestamps going out of sync.

    word_timestamps: bool
        Extract word-level timestamps using the cross-attention pattern and dynamic time warping,
        and include the timestamps for each word in each segment.

    prepend_punctuations: str
        If word_timestamps is True, merge these punctuation symbols with the next word

    append_punctuations: str
        If word_timestamps is True, merge these punctuation symbols with the previous word

    initial_prompt: Optional[str]
        Optional text to provide as a prompt for the first window. This can be used to provide, or
        "prompt-engineer" a context for transcription, e.g. custom vocabularies or proper nouns
        to make it more likely to predict those word correctly.

    decode_options: dict
        Keyword arguments to construct `DecodingOptions` instances

    clip_timestamps: Union[str, List[float]]
        Comma-separated list start,end,start,end,... timestamps (in seconds) of clips to process.
        The last end timestamp defaults to the end of the file.

    hallucination_silence_threshold: Optional[float]
        When word_timestamps is True, skip silent periods longer than this threshold (in seconds)
        when a possible hallucination is detected

    Returns
    -------
    A dictionary containing the resulting text ("text") and segment-level details ("segments"), and
    the spoken language ("language"), which is detected when `decode_options["language"]` is None.
    fp16T)n_melspaddingzutf-8c                 H    | j                  d      j                        S )Nreplace)errors)encodedecode)xsystem_encodings    r!   <lambda>ztranscribe.<locals>.<lambda>   s     !((?9("M"T"T#r#   c                     | S NrB   )r_   s    r!   ra   ztranscribe.<locals>.<lambda>   s    !r#   languageNenzoDetecting language using up to the first 30 seconds. Use the `language` decoding option to specify the language)axis)keyzDetected language: task
transcribe)num_languagesrd   rh   ,r      r   r/   u*   "'“¿([{-"'.。,，!！?？:：”)]}、	translatez:Word-level timestamps on translations may not be reliable.segmentr%   c                    t        t        t        f      rgn}d }|D ]  }i }|dkD  r%|j                  dd        |j                  dd        n|j                  dd        t	        di |d|i}
j                  | |      }d}|j                  kD  rd}	|j                  	k  rd}|j                  kD  rd}|r |S  |S )	Nr   	beam_sizepatiencebest_ofrI   FTrB   )	
isinstanceintfloatpopr   r^   compression_ratioavg_logprobno_speech_prob)rn   temperaturesdecode_resulttkwargsoptionsneeds_fallbackrJ   decode_optionsrK   r8   rL   rI   s          r!   decode_with_fallbackz(transcribe.<locals>.decode_with_fallback   s    'c5\B[M 	 A''F1u

;-

:t, 

9d+%>>A>G!LL':M"N+7!336QQ!%!-!--0AA!%#/!003FF!&!A @ r#    startr)   tokensresultc           
          |j                         }|D cg c]  }|j                  k  s| }}| |j                  |      ||j                  |j                  |j
                  |j                  d	S c c}w )N)	seekr   r)   textr   rI   rx   rw   ry   )tolisteotr^   rI   rx   rw   ry   )r   r)   r   r   tokentext_tokensr   	tokenizers         r!   new_segmentztranscribe.<locals>.new_segment  s}     *0J&EIMM4Iu&J$$[1!--!--!'!9!9$33

 
	
 Ks
   A4A4framesF)totalunitdisablerC   promptwordc                     | j                  dd      }| d   | d   z
  }d}|dk  r|dz  }|dk  r|d|z
  dz  z  }|d	kD  r||d	z
  z  }|S )
NprobabilityrC   r)   r   g333333?rE   g/$?          @)get)r   r   durationscores       r!   word_anomaly_scorez&transcribe.<locals>.word_anomaly_scoreA  sp    "&((=#">K#E{T']:HE"T)%'%("2b!88#~C/ Lr#   c                     | | d   sy| d   D cg c]  }|d   vs| }}|d d }t        fd|D              }|dk\  xs |dz   t        |      k\  S c c}w )Nr(   Fr      c              3   .   K   | ]  } |        y wrc   rB   )r+   r-   r   s     r!   r.   z9transcribe.<locals>.is_segment_anomaly.<locals>.<genexpr>T  s     Eu! 21 5us      g{Gz?)sumlen)rn   r-   r(   r   punctuationr   s       r!   is_segment_anomalyz&transcribe.<locals>.is_segment_anomalyM  s}    gg.>$#*7#3#3aqy7S#3   ""1IEEuEEE A:CU)CCs
   AAr$   c                 (    t        d | D        d       S )Nc              3   ,   K   | ]  }|d    s	|  yw)r(   NrB   )r+   r,   s     r!   r.   z9transcribe.<locals>.next_words_segment.<locals>.<genexpr>X  s      CHq'
Hs   
)r0   r1   s    r!   next_words_segmentz&transcribe.<locals>.next_words_segmentW  s     CH CTJJr#   )r   r)   r   r   )r$   r8   r   mel
num_framesrP   rQ   last_speech_timestampr(   r   r   [z --> z] r   )r   idg      ?)r   r$   rd   )Dr   r@   float16float32r4   r:   r   dimsrW   r   shaper
   ru   r	   r   sysgetdefaultencodingis_multilingualprintr   astypedetect_languagemaxr   titler   rj   rs   r?   splitr   r   r   appendminlistzipwarningswarnarrayr   n_audio_ctxr]   stripextendtqdmnpr   ry   rx   dictr   boolr   timestamp_beginr   wherelogical_anditemnonzeror   r2   ranger"   	enumeraterI   updater^   )XrT   rG   rH   rI   rJ   rK   rL   rM   rN   rO   rP   rQ   rR   rS   r   r6   r   content_framescontent_duration	make_safemel_segment_probsrd   rh   tsseek_points
seek_clipsr   clip_idxinput_stridetime_precision
all_tokensall_segmentsprompt_reset_sinceinitial_prompt_tokensr   pbarr   seek_clip_startseek_clip_endtime_offsetwindow_end_timesegment_sizesegment_durationr   r   should_skipprevious_seekcurrent_segmentsr   r   timestamp_tokenssingle_timestamp_endingconsecutiveslices
last_slicecurrent_slicesliced_tokensstart_timestamp_posend_timestamp_poslast_timestamp_posr   
timestampslast_word_end	thresholdremaining_durationfirst_segmentgaphal_last_endsirn   next_segmenthal_next_startsilence_beforesilence_afterr   r)   r   lineir   r8   r   r   r`   r   r   sX      ````       `                                                                   @@@@@@r!   ri   ri   >   sU   h ),,VT:BJJ

E!!/59E eEJJ,=,=y
QCYYr]X-N^j8;FG002g%I $I*d+3$$)-N:&Q &c8"=DDUKK,,[9HAu),U		)BN:&"))N:4N*O*U*U*W)XY #:.H""6<8D))	I /3'?N!6!6s!;TV!V
!V"E"I!V 	 
 GVVoeB):$:;oKV
;11
;!q >*nk"o>B(,SSqS1A;qtRStCT-U(VJ@K4;.RS&bhh &> & &P Hh"Duzz555Lz!K/  JL! ) 0 0~7K7K7M1M N/0 "

#
-/XX
?M
$ 
8WE5I
	 #.8*O]&#D:$5$CD"'J(F(T"U"nt3]T5I  "$)<=#/*#<{#J )+xbIPPQVW+56H6I+Jx()=k)J&--0&2"("7"7:M"MK)5"..1BB ',"( ! $#% 
!T 
!e 
!D D4 DKd K K $*Y-F-F#F *:23*?*F*F*HM +'
 !hhNN#3CR#8:J12:NO q {#a'(//1F.c&k2!"J)/(.z-(H)!,113i6O6OO , *"-224y7P7PP * )//'&1"5"F'G$/2Cn2T$T'4'- &3
# *0& /, #:>2779I<U<UU +  2\ AA/H!'(8(@(@(B1(E!FJJ!+&rN//1Y5N5NN 'rN//1I4M4MM + $6#F$++#"- +h 6#)#)	 L(D"'!1#"+'#/-A,?.C	 3(01A(B(49T#(9J)J#KD 7B$C	6,45E,FM - 9$1K$?5D}5T 2#5	#A+0AR1R+SD+8<+GD );;K(L(49K): #0"8;"FC"Y'4uSCT=T7U'U ( (="',<(=">B&6r&:G#*7#3 (1':/A$4R!VX$>0" $0#;5A'5J15Mg5VN5@CS5SN$+G$4|$Ci$O %L'.w'7)'C%L'.w'7+'E'K !/ %3WU^$Ci$O %N'9,'G%N'6'G#'M !.
 $2m+0(+K!OWW=M(N*;)<,&D (8'%.'H9'T/=<>$4RS$9$)+25>L? #?B %--=$>M$00=-#3#G,#EN#FO %)s
 "##4U#;"<EBSTWBXAYY[\`[abio. $4 #,,<"=JAw(GEN:"6?002b8*,,.)+-( #> ## +4,C4E++JAw q,G,+ !! (8'7G%,X%6E %6 '7 2V5G5G#5M),Z& C5EFw & /9	
D j-B)C)EFG {

 WH
i
 
sJ   e=.f5fTf5fff,f?Affff))r   r   typingr   r   r   r   mlx.corecorer@   numpyr   r   rT   r   r	   r
   r   r   r   r   decodingr   r   load_modelsr   timingr   r   r   r   ru   r"   r   r2   r4   r?   ndarrayr   r   ri   rB   r#   r!   <module>r
     s     / /      6 # ' /Ku K"tDz huo 	 	 8"3Q36)-+.'+$(! .A/27;abjj"((*+a a d^	a
 ueE3J//0a "*%a  a "%a !%a SMa a a a 3U+,a &.e_ar#   