o
    PžŽj'D  ã                   @   sÔ  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Zd dlZd dl	m
Z
mZmZmZmZ G dd„ dƒZdad/dee defdd„Z				d0d
ededee dee deeef f
dd„Zedkrèejdd�Zejddeddd� ejdded	dd� ejddeddd� ejddeddd� e ¡ Zed ƒ eejejejejd!�Zed" rÙed#ƒ ed$ed% › �ƒ ed&ed' › �ƒ ed(ed) › �ƒ ed*e ed+ ƒ› d,�ƒ dS ed-ƒ ed.ed' › �ƒ dS dS )1é    N)ÚListÚOptionalÚDictÚAnyÚTuplec                   @   sÖ   e Zd ZdZddee dee fdd„Zdedefd	d
„Zdee fdd„Zdedee fdd„Z	de
e fdd„Zdee fdd„Zdedefdd„Z			ddedee dee dee deeef f
dd„ZdS )ÚSalesHubAudioGeneratorzó
    Standalone Audio Generator for Sales Hub.
    Uses Piper Neural TTS (the exact same TTS engine & ONNX model architecture used in Roleplay).
    Completely independent script with robust voice model resolution and fallback mechanisms.
    NÚpiper_binary_pathÚ
model_pathc                 C   sØ   t j t j t¡¡| _|p|  ¡ | _|pt  dd¡}|  	|¡| _
t j | j
¡s,|  ¡ | _
| j
r5|  | j
¡nd| _tdƒ | jsDtdƒ ntd| j› �ƒ | j
rVt j | j
¡satd| j
› d�ƒ dS td	| j
› d
�ƒ dS )zø
        Initialize the generator with automatic path resolution.

        Args:
            piper_binary_path: Optional path to the 'piper' binary executable.
            model_path: Optional path to a Piper ONNX voice model file (.onnx).
        ÚPIPER_MODEL_PATHz&assets/models/en_US-lessac-medium.onnxNu$   
ðŸŽ™ï¸� Piper TTS Diagnostic Check:u8      - Binary: â�Œ NOT FOUND (Check PIPER_EXECUTABLE_PATH)u      - Binary: âœ… FOUND at u,      - Default Model: â�Œ NOT FOUND (Checked: ú)u!      - Default Model: âœ… FOUND at Ú
)ÚosÚpathÚdirnameÚabspathÚ__file__Úbase_dirÚ_resolve_piper_executableÚpiper_binaryÚgetenvÚ_make_absoluter	   ÚexistsÚ_find_default_modelÚ_get_config_pathÚconfig_pathÚprint)Úselfr   r	   Ú	model_env© r   úO/var/www/eduai.edurigo.com/doc_train/edurigo_ai/Puru/saleshub_audio_generate.pyÚ__init__   s   

zSalesHubAudioGenerator.__init__r   Úreturnc                 C   s(   |sdS t j |¡r|S t j | j|¡S )z@Converts relative paths to absolute paths based on project root.Ú )r   r   ÚisabsÚjoinr   )r   r   r   r   r   r   1   s
   z%SalesHubAudioGenerator._make_absolutec                    sÌ   ddg}t  d¡}|r2t j |¡r||vrt j |¡r|S nt |¡‰ˆr2t‡fdd„|D ƒƒs2ˆS dD ]}t |¡‰ ˆ rLt‡ fdd„|D ƒƒsLˆ   S q4g d¢}|D ]‰ t j ˆ ¡rcˆ |vrcˆ   S qSd	S )
zž
        Strategically searches for the piper binary in common production paths.
        STRICTLY blocks /usr/bin/piper to avoid Ubuntu GTK conflict.
        z/usr/bin/piperz
/bin/piperÚPIPER_EXECUTABLE_PATHc                 3   ó   � | ]}|ˆ v V  qd S ©Nr   ©Ú.0Úb)Úresolvedr   r   Ú	<genexpr>H   ó   € zCSalesHubAudioGenerator._resolve_piper_executable.<locals>.<genexpr>)z	piper-ttsÚpiperc                 3   r&   r'   r   r(   )r   r   r   r,   N   r-   )z/usr/local/bin/piper-ttsz/usr/local/bin/piperz/opt/piper/piperz/opt/piper/piper/piperzC:\piper\piper.exez C:\Program Files\piper\piper.exeN)r   r   r   r#   r   ÚshutilÚwhichÚany)r   Ú	BLACKLISTÚenv_pathÚnameÚsearch_pathsr   )r   r+   r   r   9   s*   
€

€€z0SalesHubAudioGenerator._resolve_piper_executablec                 C   s$   |sdS |d }t j |¡r|S dS )z7Returns the .json config path for a model if it exists.Nú.json©r   r   r   )r   r	   r   r   r   r   r   `   s   z'SalesHubAudioGenerator._get_config_pathc                 C   s@   t j | jdd¡t j t j | j¡ddd¡ddg}dd„ |D ƒS )zYFinds all existing assets/models directories across local workspace and production paths.ÚassetsÚmodelsÚtestingzD:\testing\assets\modelszC:\piper\modelsc                 S   s   g | ]
}t j |¡r|‘qS r   r7   )r)   Údr   r   r   Ú
<listcomp>o   s    z;SalesHubAudioGenerator._get_models_dirs.<locals>.<listcomp>)r   r   r$   r   r   )r   Údirsr   r   r   Ú_get_models_dirsg   s   üz'SalesHubAudioGenerator._get_models_dirsc                 C   sB   |   ¡ D ]}t |¡D ]}| d¡rtj ||¡    S qqdS )z7Finds any available ONNX model file from assets/models.ú.onnxN)r>   r   ÚlistdirÚendswithr   r$   )r   Ú
models_dirÚfiler   r   r   r   q   s   
ÿÿz*SalesHubAudioGenerator._find_default_modelÚvoicec                 C   s6  |   ¡ }|r|s| j| jfS | ¡ }d|v }d|v o| }|D ]Ø}|rSt |¡D ]*}| d¡rRd| ¡ v rRtj ||¡}t	d|› d|› d�ƒ ||  
|¡f    S q(|r‹t |¡D ]0}| d¡rŠd| ¡ v rŠd| ¡ vrŠtj ||¡}t	d|› d|› d�ƒ ||  
|¡f    S qZ|| dd	¡| d	d¡g}	|	D ]}
tj ||
› d�¡}tj |¡r·||  
|¡f    S qštj |d
¡}t |¡}|D ]0}tj |¡ ¡ }|rád|v rá||  
|¡f    S |röd|v röd|vrö||  
|¡f    S qÆq| j�rtj | j¡�rt	d|› dtj | j¡› �ƒ | j| jfS dS )z¤
        Ultra-robust resolution for Piper voice models across all model directories.
        Guarantees gender matching for female vs male voice requests.
        ÚfemaleÚmaler?   u,   ðŸŽ™ï¸� [Voice Match] Matched female model 'z' for requested voice 'ú'u*   ðŸŽ™ï¸� [Voice Match] Matched male model 'Ú_Ú-z*.onnxu   âš ï¸� Piper voice 'z' fallback to default model: ©NN)r>   r	   r   Úlowerr   r@   rA   r   r$   r   r   Úreplacer   ÚglobÚbasename)r   rD   Ú
model_dirsÚv_lowerÚ	is_femaleÚis_maleÚmdirrC   Ú
match_pathÚvariantsÚvr   ÚpatternÚmatchesÚmatchÚbnamer   r   r   Ú_resolve_voice_modely   sX   €"€

ýÿ
€ûz+SalesHubAudioGenerator._resolve_voice_modelúsaleshub_output.wavÚtextÚoutput_filenameÚvoice_model_pathc              
   C   s  |r|  ¡ sdddddddœS | dd¡ dd¡  ¡ }|r+tj |¡r+|}|  |¡}n|r5|  |¡\}}n| j}| j}d}| j	sJd}t
d	|› �ƒ n|sVd
}t
d	|› �ƒ ntj |¡sid|› d�}t
d	|› �ƒ | j	�r„|�r„tj |¡�r„zëtjddd�}	|	j}
|	 ¡  | j	d|d|
g}|d }tj |¡rŸ| d|g¡ t
d|dd… › d�ƒ tj|tjtjtjddd�}|j|dd�\}}|jdk�r=tj |
¡�r=tj |
¡dk�r=t|
dƒ�}| ¡ }W d  ƒ n1 sìw   Y  t |¡ d¡}d}|�r.tjtj tj |¡¡dd� t|dƒ�}| |¡ W d  ƒ n	1 �s#w   Y  tj |¡}t |
¡ dd||dddœW S |�rD|  ¡ nd |j› �}t
d!|j› d"|› �ƒ tj |
¡�rat |
¡ W n! t �yƒ } zd#t!|ƒ› �}t
d$|› �ƒ W Y d}~nd}~ww z›dd%l"m#} t
d&ƒ ||d'd(�}tjd)dd�}|j}| ¡  | $|¡ t|dƒ�}| ¡ }W d  ƒ n	1 �s½w   Y  t |¡ d¡}d}|�r| %d)¡�sÛ| %d¡�rÝ|n|d) }tjtj tj |¡¡dd� t|dƒ�}| |¡ W d  ƒ n	1 �sw   Y  tj |¡}t |¡ dd*||d+|dœW S  t&�y)   Y n t �yB } zt
d,|› �ƒ W Y d}~nd}~ww zœddl'}t
d-ƒ | (¡ }tjddd�}	|	j}
|	 ¡  | )||
¡ | *¡  tj |
¡�rÞtj |
¡dk�rÞt|
dƒ�}| ¡ }W d  ƒ n	1 �s�w   Y  t |¡ d¡}d}|�rÏtjtj tj |¡¡dd� t|dƒ�}| |¡ W d  ƒ n	1 �sÄw   Y  tj |¡}t |
¡ dd.||d/|dœW S W n# t&�yé   Y n t �y } zt
d0|› �ƒ W Y d}~nd}~ww dd1ddd|dœS )2zd
        Converts text input into audio speech (.wav/.mp3) and returns Base64 audio string.
        Fz"Error: Input text cannot be empty.N)ÚsuccessÚmessageÚvoice_base64Ú	file_pathÚengineÚpiper_errorú"r"   rG   z@Piper binary executable not found in PATH or standard locations.u   âš ï¸� [Piper TTS Warning] zHPiper ONNX voice model path is not specified and no default model found.z/Piper ONNX model file does not exist at path: 'z.wav)ÚsuffixÚdeleteú--modelz--output_filer6   z--configu:   ðŸŽ™ï¸� [Piper Neural TTS] Synthesizing speech for text: "é<   z..."Tzutf-8)ÚstdinÚstdoutÚstderrr]   Úencodingé   )ÚinputÚtimeoutr   Úrb)Úexist_okÚwbz4Audio generated successfully using Piper Neural TTS.zPiper Neural TTS (ONNX Model)z&Piper process exited with return code u,   â�Œ [Piper TTS Error] Process Failed! Code: z | Detail: zPiper execution exception: u   â�Œ [Piper TTS Exception] )ÚgTTSu,   ðŸŽ™ï¸� [gTTS Engine] Synthesizing speech...Úen)r]   Úlangz.mp3z(Audio generated successfully using gTTS.zgTTS (Google Text-To-Speech)u   âš ï¸� gTTS notice: u/   ðŸŽ™ï¸� [pyttsx3 Engine] Synthesizing speech...z:Audio generated successfully using pyttsx3 offline engine.zpyttsx3 (Offline Native TTS)u   âš ï¸� pyttsx3 notice: z~No active TTS engine found. Please install piper binary/models, gTTS ('pip install gtts'), or pyttsx3 ('pip install pyttsx3').)+ÚstriprL   r   r   r   r   r[   r	   r   r   r   ÚtempfileÚNamedTemporaryFiler4   ÚcloseÚextendÚ
subprocessÚPopenÚPIPEÚcommunicateÚ
returncodeÚgetsizeÚopenÚreadÚbase64Ú	b64encodeÚdecodeÚmakedirsr   r   ÚwriteÚremoveÚ	ExceptionÚstrÚgttsru   ÚsaverA   ÚImportErrorÚpyttsx3ÚinitÚsave_to_fileÚ
runAndWait)r   r]   r^   r_   rD   Ú
clean_textÚactive_modelÚactive_configÚpiper_error_msgÚtemp_wavÚtemp_wav_pathÚcmdÚconfig_fileÚprocessrl   rm   ÚfÚ
audio_dataÚ	voice_b64Ú
saved_pathÚout_fÚeru   ÚttsÚtemp_mp3Útemp_mp3_pathÚout_pathr�   rd   r   r   r   Úgenerate_audio²   s6  
ú	ýú	,
ÿÿ
ú

€€þ

ÿ$ÿ
ú€ÿ 
ÿÿ
ú€€ÿúz%SalesHubAudioGenerator.generate_audiorJ   ©r\   NN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   rŒ   r    r   r   r   r   r>   r   Útupler[   r   r   r§   r   r   r   r   r      s.    '
<ûþýüû
úr   r	   r!   c                 C   s   t du r	t| d�a t S )zbReturns a cached singleton instance of SalesHubAudioGenerator to avoid re-initialization overhead.N©r	   )Ú_global_generator_instancer   r®   r   r   r   Úget_audio_generatorx  s   
r°   r\   r]   r^   rD   c                 C   s   t |d�}|j| ||d�S )Nr®   )r]   r^   rD   )r°   r§   )r]   r^   r	   rD   Ú	generatorr   r   r   Úgenerate_saleshub_audio€  s   
r²   Ú__main__z&Sales Hub Audio Generator (Standalone))Údescriptionz--textz-tz0Welcome to Sales Hub! Here is your audio script.z"Text script to generate audio from)ÚtypeÚdefaultÚhelpz--outputz-oz#Target output audio filename (.wav)ri   z-mz4Optional path to Piper ONNX voice model file (.onnx)z--voicez-vz8Optional voice model name (e.g. en_US-hfc_female-medium)z-
--- Sales Hub Standalone Audio Generator ---)r]   r^   r	   rD   r`   u   
âœ… SUCCESS!z   Engine Used: rd   z   Message: ra   z   Saved Audio File: rc   z   Base64 Length: rb   z charactersu   
â�Œ FAILED!z   Reason: r'   r¨   )!r   Úsysr…   Úargparser}   ry   r/   ÚrerM   Útypingr   r   r   r   r   r   r¯   rŒ   r°   r²   r©   ÚArgumentParserÚparserÚadd_argumentÚ
parse_argsÚargsr   r]   ÚoutputÚmodelrD   ÚresultÚlenr   r   r   r   Ú<module>   s^      l
üÿþýü

û
ì