o
    +iC                     @   sJ  d 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
 ddlmZmZmZmZ ddlZe	G dd dZe	G dd	 d	Ze	G d
d dZG dd dZ	d?dedededefddZedkr!ddlZeejdk r~ed ed ejd Zdejdd ZeeeZ edd  ed ed  ede d   ed e d! d" ed#e d$ d% ed&e d' d% ed(e d) d% ed*e d+ d%d, e !d-red.e d-   dS ed/e d0  d1 e d2 dd3 D ]"Z"ed4e"d5 d6d7e"d8 d%d9e"d: d%d;e"d< d=d>	 q dS dS )@al  
IndicMFA Real Validator
=======================

Proper forced alignment using AI4Bharat's IndicMFA models.
Uses MFA (Montreal Forced Aligner) with G2G (grapheme-to-grapheme) dictionaries.

Provides:
- Character-level alignment timestamps
- Alignment quality metrics (log-likelihood, phone duration deviation)
- Per-word confidence scores

Requirements:
- MFA installed via conda/micromamba
- IndicMFA models downloaded from GitHub releases

Usage:
    validator = IndicMFARealValidator(language="te")
    result = validator.validate("audio.flac", "transcription text")
    print(f"Score: {result['alignment_score']}")
    N)Path)	dataclassfield)ListDictOptionalTuplec                   @   s<   e Zd ZU dZeed< eed< eed< edefddZdS )	CharAlignmentz!Alignment for a single character.char
start_timeend_timereturnc                 C      | j | j S Nr   r   self r   =/home/ubuntu/maya3_transcribe/src/validators/indicmfa_real.pyduration(      zCharAlignment.durationN)	__name__
__module____qualname____doc__str__annotations__floatpropertyr   r   r   r   r   r	   !   s   
 r	   c                   @   sR   e Zd ZU dZeed< eed< eed< eedZ	e
e ed< edefdd	Zd
S )WordAlignmentz5Alignment for a word (reconstructed from characters).wordr   r   default_factorychar_alignmentsr   c                 C   r   r   r   r   r   r   r   r   5   r   zWordAlignment.durationN)r   r   r   r   r   r   r   r   listr#   r   r	   r   r   r   r   r   r   r   -   s   
 r   c                   @   s   e Zd ZU dZeed< eed< dZeed< dZeed< dZ	eed< dZ
eed< dZeed	< eed
Zee ed< eed
Zee ed< dZeed< dZeed< dZeed< dZee ed< defddZdS )IndicMFAResultzResult of IndicMFA alignment.
audio_pathtranscription        overall_log_likelihoodspeech_log_likelihoodphone_duration_deviationsnralignment_scorer!   r#   word_alignmentsaudio_duration_secprocessing_time_secFsuccessNerrorr   c                 C   sz   | j | jt| jdt| jdt| jdt| jdt| jdt| j	t| j
dd | j	D t| jdt| jd| j| jdS )N   c                 S   s4   g | ]}|j t|jd t|jd t|jd dqS )   )r    r   r   r   )r    roundr   r   r   ).0war   r   r   
<listcomp>`   s    


z*IndicMFAResult.to_dict.<locals>.<listcomp>r4   )r&   r'   r-   r)   r*   r+   r,   
word_count
char_countr.   r/   r0   r1   r2   )r&   r'   r5   r-   r)   r*   r+   r,   lenr.   r#   r/   r0   r1   r2   r   r   r   r   to_dictU   s"   





	
zIndicMFAResult.to_dict)r   r   r   r   r   r   r)   r   r*   r+   r,   r-   r   r$   r#   r   r	   r.   r   r/   r0   r1   boolr2   r   r   r<   r   r   r   r   r%   :   s    
 r%   c                   @   s   e Zd ZdZdZddddddd	d
dddddZ			d/dededefddZdefddZ	dedefddZ
dedee dee fd d!Zd"edee fd#d$Zd%edefd&d'Zd(edefd)d*Zd+ed,edefd-d.ZdS )0IndicMFARealValidatorz
    Real IndicMFA validator using Montreal Forced Aligner.
    
    Requires:
    - micromamba with MFA environment
    - IndicMFA models for the target language
    zmodels/indicmfaTeluguHindiTamilKannada	MalayalamBengaliMarathiGujaratiPunjabiOdiaAssameseUrdu)tehitaknmlbnmrgupaorasurrK   Nmfalanguageproject_rootmfa_envc                 C   s   |  dd | _| j| j| j | _|du r ttjjj}t|| _	|| _
| j	d d | _| j	| j | j | _| j| j d | _| j| j d | _d| _dS )a  
        Initialize IndicMFA validator.
        
        Args:
            language: Language code (te, hi, ta, etc.)
            project_root: Path to project root (contains models/, bin/)
            mfa_env: Name of micromamba environment with MFA
        N   bin
micromambaz_Acoustic_Model.zipz_Dictionary_g2g.txtF)lowerrX   	LANGUAGESgettitle	lang_namer   __file__parentrY   rZ   r]   
MODELS_DIR
models_diracoustic_model
dictionary_setup_complete)r   rX   rY   rZ   r   r   r   __init__   s   

zIndicMFARealValidator.__init__r   c              
   C   s8  | j rdS | j std| j  dS z>tjt| jdd| jddgdddi tj	d	tt
 d
 id}|jdkrGtd| j d W dS td|j   W n tyl } ztd|  W Y d}~dS d}~ww | j std| j  td dS | j std| j  dS td| j  d| _ dS )z&Check if MFA and models are available.Tz#[IndicMFA] micromamba not found at Frun-nrW   version   MAMBA_ROOT_PREFIXr]   capture_outputtexttimeoutenvr   z [IndicMFA] MFA not available in z environmentz[IndicMFA] MFA version: z[IndicMFA] Error checking MFA: Nz%[IndicMFA] Acoustic model not found: zH[IndicMFA] Download from: https://github.com/AI4Bharat/IndicMFA/releasesz![IndicMFA] Dictionary not found: z[IndicMFA] Ready for )ri   r]   existsprint
subprocessrk   r   rZ   osenvironr   home
returncodestdoutstrip	Exceptionrg   rh   rb   )r   resulter   r   r   setup   s@   



zIndicMFARealValidator.setuprr   c                 C   s8   |  }g }|D ]}dt|}|| qd|S )z|
        Preprocess text for G2G alignment.
        Adds spaces between each character, double space between words.
           )splitjoinr$   append)r   rr   wordsspaced_wordsr    spaced_wordr   r   r   _preprocess_text   s   
z&IndicMFARealValidator._preprocess_textoriginal_textr#   c           
   	   C   s|   |  }g }d}|D ]1}t|}g }|D ]}	|t|k r'|||  |d7 }q|r;|t||d j|d j|d q
|S )z6Reconstruct word alignments from character alignments.r      )r    r   r   r#   )r   r$   r;   r   r   r   r   )
r   r   r#   r   r.   char_idxr    
word_charsword_char_alignments_r   r   r   _reconstruct_words   s(   z(IndicMFARealValidator._reconstruct_wordstextgrid_pathc           	   
   C   s   zDddl m} |jt|dd}g }dD ]-}||jv rA||}|jD ]}|j r<|jdkr<|	t
|j|j|jd q# |W S q|W S  ty_ } ztd|  g W  Y d	}~S d	}~ww )
z4Parse TextGrid file to extract character alignments.r   )textgridF)includeEmptyIntervals)r   phonesz<unk>)r
   r   r   z![IndicMFA] TextGrid parse error: N)praatior   openTextgridr   	tierNamesgetTierentrieslabelr}   r   r	   startendr~   rv   )	r   r   r   tg
alignments	tier_nametierintervalr   r   r   r   _parse_textgrid   s0   


z%IndicMFARealValidator._parse_textgridcsv_pathc              
   C   s   ddddd}z]t |dM}t|}|D ];}t|ddpd|d< t|ddp+d|d< t|ddp7d|d< t|ddpCd|d<  W d	   W |S W d	   W |S 1 s]w   Y  W |S  ty~ } ztd
|  W Y d	}~|S d	}~ww )z1Parse alignment_analysis.csv for quality metrics.r(   )r)   r*   r+   r,   rr)   r   r*   r+   r,   Nz[IndicMFA] CSV parse error: )opencsv
DictReaderr   r`   r~   rv   )r   r   metricsfreaderrowr   r   r   r   _parse_analysis_csv  s4   
z)IndicMFARealValidator._parse_analysis_csvr   c                 C   s\   | dd}| dd}tdtd|d d }tdtdd|d  }d	| d
|  }|S )z
        Compute normalized alignment score (0-1) from MFA metrics.
        
        Based on:
        - speech_log_likelihood: higher (less negative) is better
        - phone_duration_deviation: lower is better
        r*   ir+   
   r   r   d      gffffff?g333333?)r`   maxmin)r   r   sllpdd	sll_score	pdd_scorescorer   r   r   _compute_alignment_score1  s   z.IndicMFARealValidator._compute_alignment_scorer&   r'   c                 C   s  t   }|  st||ddS t .}t|}|d }|d }|  |  z|d }tjddd|d	d
ddt	|g	ddd ddl
}	|	t	|\}
}t|
| }|d }| |}|| i tjdt	t d i}tjt	| jdd| jddddt	|t	| jt	| jt	|gddd|d}|jdkrt||d|jr|jdd nd t   | d W W  d   S |d! }|d" }| r| |ng }| r| |ni }| ||}| |}t   | }t|||d#d|d$d|d%d|d&d|||||dd'W W  d   S  tyA } z#ddl}|   t||t	|t   | d W  Y d}~W  d   S d}~ww 1 sFw   Y  dS )(z
        Run IndicMFA alignment and return quality metrics.
        
        Args:
            audio_path: Path to audio file
            transcription: Text to align
            
        Returns:
            IndicMFAResult with alignment metrics
        zMFA not set up)r&   r'   r2   corpusoutputz	audio.wavffmpegz-yz-iz-ar16000z-ac1Trn   )rq   rs   r   Nz	audio.txtro   r]   rk   rl   rW   alignz--cleanz--single_speakerx   rp   zMFA failed: izUnknown error)r&   r'   r2   r0   zaudio.TextGridzalignment_analysis.csvr)   r*   r+   r,   )r&   r'   r)   r*   r+   r,   r-   r#   r.   r/   r0   r1   )!timer   r%   tempfileTemporaryDirectoryr   mkdirrw   rk   r   	soundfilereadr;   r   
write_textrx   ry   rz   r]   rZ   rh   rg   r{   stderrru   r   r   r   r   r`   r~   	traceback	print_exc)r   r&   r'   r   temp_dir	temp_path
corpus_dir
output_dirwav_pathsf
audio_datasraudio_durationtranscript_pathspaced_textrt   r   r   analysis_pathr#   r   r.   r-   processing_timer   r   r   r   r   validateH  s   




7




T
TzIndicMFARealValidator.validate)rK   NrW   )r   r   r   r   re   r_   r   rj   r=   r   r   r   r	   r   r   r   r   r   r   r   r   r%   r   r   r   r   r   r>   p   sZ    	
)
r>   rK   r&   r'   rX   r   c                 C   s   t |d}|| |}| S )zQuick IndicMFA validation.)rX   )r>   r   r<   )r&   r'   rX   	validatorr   r   r   r   indicmfa_validate  s   
r   __main__r4   z;Usage: python indicmfa_real.py <audio_path> <transcription>r   r   r[   
z<============================================================zINDICMFA ALIGNMENT RESULTz	Success: r1   zAlignment Score: r-   z.4fzSpeech Log-Likelihood: r*   z.2fzPhone Duration Deviation: r+   zSNR: r,   zProcessing Time: r0   sr2   zError: z
Word Alignments (r9   z words):r.   r   r   r    z<20z [r   -r   zs] (r   z.3fzs))rK   )#r   rx   r   shutilr   rw   pathlibr   dataclassesr   r   typingr   r   r   r   r   r	   r   r%   r>   r   r   r   sysr;   argvrv   exitr&   r   r'   r   r`   r7   r   r   r   r   <module>   sj    5  V






>