ó
    �®žj#  ã            	       ó"  • S r SSKrSSKJrJr  SSKJr  SSKJr  SSK	r
\R                  " \5      rSr Sr Sr \ " S	 S
5      5       r\ " S S5      5       rS\
R&                  S\4S jr  SS\S\S-  S\S\4S jjrS\\   S\S\\   4S jrg)av  Speaker diarization using Resemblyzer embedding-based clustering.

Assigns speaker labels to transcript segments by:
1. Encoding sliding windows of audio into speaker embedding vectors
2. Estimating the optimal number of speakers via silhouette score
3. Clustering embeddings into speaker groups
4. Mapping each transcript segment to the dominant speaker in its time window
é    N)Ú	dataclassÚfield)ÚPath)ÚAnyé   é   g      à?c                   ó8   • \ rS rSr% Sr\\S'   \\S'   \\S'   Srg)ÚSpeakerSegmenté   z.A time segment attributed to a single speaker.Ú
start_timeÚend_timeÚspeaker© N)	Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__ÚfloatÚ__annotations__ÚstrÚ__static_attributes__r   ó    Ú^/home/mande/repo/quber/.venv/lib/python3.13/site-packages/docling/utils/speaker_diarization.pyr
   r
      s   ‡ á8àÓØƒOØ†Lr   r
   c                   ó`   • \ rS rSr% Sr\" \S9r\\   \	S'   Sr
\\	S'   \" \S9r\\   \	S'   Srg	)
ÚDiarizationResulté'   zOutput of speaker diarization.)Údefault_factoryÚsegmentsr   Únum_speakersÚspeaker_idsr   N)r   r   r   r   r   r   Úlistr   r
   r   r    Úintr!   r   r   r   r   r   r   r   '   s6   ‡ á(á%*¸4Ñ%@€Hˆd�>Ñ"Ó@Ø€L�#ÓÙ"°4Ñ8€K��c‘Ö8r   r   Ú
embeddingsÚreturnc           	      ój  • SSK Jn  SSKJn  [        SpC[        [        [        [        S-   [        U 5      5      5       H[  nU" US9R                  U 5      n[        [        U5      5      S:  a  M2  U" X5      n[        R                  SXW5        Xt:”  d  MW  UnUnM]     [        R                  S	X45        U$ )
z®Estimate optimal speaker count via silhouette score.

Args:
    embeddings: Per-window speaker embeddings.

Returns:
    The speaker count with the highest silhouette score.
r   ©ÚAgglomerativeClustering)Úsilhouette_scoreg      ð¿é   ©Ú
n_clustersr   zN=%d silhouette=%.4fz'Estimated %d speakers (silhouette=%.4f))Úsklearn.clusterr(   Úsklearn.metricsr)   Ú_MIN_SPEAKERSÚrangeÚminÚ_MAX_SPEAKERSÚlenÚfit_predictÚsetÚ_logÚdebugÚinfo)r$   r(   r)   Úbest_nÚ
best_scoreÚnÚlabelsÚscores           r   Ú_estimate_num_speakersr>   0   s›   € õ 8Ý0ä&¨ˆJÜ”=¤#¤m°aÑ&7¼¸Z»Ó"IÖJˆÙ(°AÑ6×BÑBÀ:ÓNˆÜŒs�6‹{Ó˜aÓÙÙ  Ó4ˆÜ�
‰
Ð)¨1Ô4ØÕØˆJØŠFñ Kô 	‡I�IÐ7¸ÔLØ€Mr   Úwav_pathr    Úaccelerator_devicec                 ó¦  •  SSK nSSKnSSKJn  SSKJnJnJn  SSKJ	n	  [        R                  SU 5        UR                  [!        U 5      SS	9u  p«U
R"                  S
:”  a  U
R%                  S
S9n
X¸:w  a  UR'                  X«US9n
U" X¦SS9n[)        U5      S:X  a  [        R                  S5        [        5       $ SSKJn  U" U5      nU" US9nUn[/        US-  5      n[/        [0        U-  5      n/ n/ nSnUU-   [)        U5      ::  aD  UR3                  UU-  5        UR3                  UUUU-    5        UU-  nUU-   [)        U5      ::  a  MD  U(       d  [        R                  S5        [        5       $ [        R                  S[)        U5      5        SSKnUR7                  5       nUR9                  [;        SU5      5         [<        R>                  " U Vs/ s H  nURA                  U5      PM     sn5      nUR9                  U5        Ub  UO
[C        U5      nU	" US9RE                  U5      n[G        U5       Vs/ s H	  nSUS 3PM     nn/ n[)        U5      S:”  aœ  UUS      nUS   nUS   [0        -   n [I        US
S US
S 5       HE  u  n!n"UU"   n#U#U:X  a  U![0        -   n M  UR3                  [K        UU U5      5        U#nU!nU![0        -   n MG     UR3                  [K        U[)        U5      U-  U5      5        [        UUUS9$ ! [         a"    [        R                  S5        [        5       s $ f = fs  snf ! UR9                  U5        f = fs  snf )a  Run speaker diarization on a WAV file.

Loads and resamples the audio to the rate Resemblyzer expects, encodes
fixed-size sliding windows into speaker embeddings, clusters the
embeddings by speaker, then merges consecutive same-speaker windows into
contiguous segments.

Args:
    wav_path: Path to a 16kHz mono WAV file.
    num_speakers: Number of speakers. None = auto-detect.
    accelerator_device: Device selector passed to decide_device(), e.g.
        "auto", "cpu", "cuda", "cuda:0", "mps".

Returns:
    Per-segment speaker labels.
r   N)ÚVoiceEncoder)Úaudio_norm_target_dBFSÚnormalize_volumeÚsampling_rater'   z¤Speaker diarization requires resemblyzer, soundfile, scikit-learn, and librosa. Speaker diarization disabled. Install with: pip install 'docling-slim[format-video]'z!Loading audio for diarization: %sÚfloat32)Údtyper*   )Úaxis)Úorig_srÚ	target_srT)Úincrease_onlyu$   Empty audio â€” skipping diarization)Údecide_device)Údeviceg      ø?zAudio too short for diarizationzEncoding %d audio windowsé   r+   ÚSPEAKER_Ú02d)r   r    r!   )&ÚlibrosaÚ	soundfileÚresemblyzerrB   Úresemblyzer.audiorC   rD   rE   r-   r(   ÚImportErrorr6   Úwarningr   r8   Úreadr   ÚndimÚmeanÚresampler3   Údocling.utils.accelerator_utilsrL   r#   Ú_WINDOW_STEPÚappendÚtorchÚget_num_threadsÚset_num_threadsr1   ÚnpÚarrayÚembed_utterancer>   r4   r0   Úzipr
   )$r?   r    r@   rQ   ÚsfrB   rC   rD   Ú_RESEMBLYZER_SRr(   ÚrawÚfile_srÚwavrL   rM   ÚencoderÚsrÚwindow_samplesÚstep_samplesÚ
timestampsÚ
wav_splitsÚir^   Úprev_threadsÚwr$   r;   r<   r!   r   Úcur_speakerÚ	cur_startÚcur_endÚtsÚlabelÚspks$                                       r   Údiarizery   J   sB  € ð*#ÛÛÝ,÷	
ñ 	
õ
 	<ô 	‡I�IÐ1°8Ô<à—7‘7œ3˜x›=°	�7Ð:�L€CØ
‡x�x�!ƒ|Ø�h‰h˜AˆhÐˆØÓ!Ø×Ñ˜s¸ÐÐOˆñ ˜3ÀdÑ
K€CÜ
ˆ3ƒx�1ƒ}Ü�‰Ð;Ô<Ü Ó"Ð"å=áÐ-Ó.€FÙ &Ñ)€Gà	€BÜ˜˜c™“]€NÜ”| bÑ(Ó)€Là €JØ#%€Jà	€AØ
ˆnÑ
¤ C£Ó
(Ø×Ñ˜!˜b™&Ô!Ø×Ñ˜#˜a ! nÑ"4Ð5Ô6Ø	ˆ\Ñˆð ˆnÑ
¤ C£Õ
(ö
 Ü�‰Ð6Ô7Ü Ó"Ð"ä‡I�IÐ)¬3¨z«?Ô;ó à×(Ñ(Ó*€LØ	×Ñœ#˜a Ó.Ô/ð,Ü—X’XÁ:ÓNÂ:¸a˜w×6Ñ6°qÖ9Á:ÑNÓOˆ
à×Ñ˜lÔ+à$Ñ0‰Ô6LÈZÓ6X€Aá$°Ñ2×>Ñ>¸zÓJ€FÜ/4°Q¬xÓ8ªx¨!�X˜a ˜WÓ%©x€KÐ8à%'€HÜ
ˆ:ƒ˜ÓØ! &¨¡)Ñ,ˆØ˜q‘Mˆ	Ø˜Q‘-¤,Ñ.ˆä˜Z¨¨˜^¨V°A°B¨ZÖ8‰IˆB�Ø˜eÑ$ˆCØ�kÓ!Øœ|Ñ+’à—‘¤¨y¸'À;Ó OÔPØ!�Ø�	Øœ|Ñ+’ñ 9ð 	�‰œ y´#°c³(¸R±-ÀÓMÔNäØØØñð øôm ó #Ü�‰ðEô	
ô
 !Ó"Ò"ð#üòt Oøà×Ñ˜lÕ+üò
 9s5   ‚L ÇL8 ÇL3Ç0L8 È:MÌ)L0Ì/L0Ì3L8 Ì8MÚtranscript_itemsÚdiarizationc           
      ór  • UR                   (       d  U $ U  H�  nUR                  =(       d    SnUR                  =(       d    UnSnSnUR                    HM  n[        S[	        XGR                  5      [        X7R                  5      -
  5      nX†:”  d  M?  UnUR
                  nMO     U(       d  M—  XRl        MŸ     U $ )a^  Assign speaker labels to transcript ConversationItems.

For each transcript segment, find the diarization segment with the
maximum time overlap and assign its speaker label.

Args:
    transcript_items: List of ConversationItem from ASR transcriber.
    diarization: Result from diarize().

Returns:
    The same list with .speaker set on each item.
g        N)r   r   r   Úmaxr1   r   )	rz   r{   ÚitemÚstartÚendÚbest_speakerÚbest_overlapÚsegÚoverlaps	            r   Úassign_speakersr…   Æ   sž   € ð  ××ØÐã ˆØ—‘×& 3ˆØ�m‰m×$˜uˆàˆØˆà×'Ô'ˆCÜ˜#œs 3¯©Ó5¼¸EÇ>Á>Ó8RÑRÓSˆGØÕ%Ø&�Ø"Ÿ{™{’ñ	 (÷ ˆ<Ø'ŽLñ !ð  Ðr   )NÚauto)r   ÚloggingÚdataclassesr   r   Úpathlibr   Útypingr   Únumpyra   Ú	getLoggerr   r6   r/   r2   r\   r
   r   Úndarrayr#   r>   r   ry   r"   r…   r   r   r   Ú<module>rŽ      sî   ðñó ß (Ý Ý ã à×Ò˜Ó"€à€Ø ;Ø€Ø ;Ø€Ø |ð ÷ð ó ðð ÷9ð 9ó ð9ð r§z¡zð °cô ð8  $Ø$ñyØðyà˜‘*ðyð ðyð õ	yðx#Ø˜3‘ið#à"ð#ð 
ˆ#�Yõ#r   