Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -10,9 +10,19 @@ import soundfile as sf
|
|
| 10 |
import numpy as np
|
| 11 |
|
| 12 |
# --- IMPORTS NEMO ---
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
# ----------------------------------------------------------------------
|
| 18 |
# CONSTANTES DE CONFIGURATION
|
|
@@ -79,6 +89,7 @@ def load_punct_model():
|
|
| 79 |
print("-> Modèle de ponctuation chargé avec succès.")
|
| 80 |
except Exception as e:
|
| 81 |
print(f"!!! AVERTISSEMENT: Échec du chargement du modèle de ponctuation {PUNCT_MODEL_NAME}. La sortie restera brute. Détail: {e}")
|
|
|
|
| 82 |
return punct_pipeline
|
| 83 |
|
| 84 |
# ----------------------------------------------------------------------
|
|
@@ -106,6 +117,7 @@ def transcribe_audio(model_name: str, audio_path: str):
|
|
| 106 |
# ----------------------------------------------------------------
|
| 107 |
yield f"**[1/4] CHARGEMENT AUDIO...** Préparation du fichier original (Mono @ 16kHz). ⚙️"
|
| 108 |
|
|
|
|
| 109 |
full_audio_data, sr = librosa.load(audio_path, sr=SR_TARGET, mono=True)
|
| 110 |
total_duration = len(full_audio_data) / SR_TARGET
|
| 111 |
|
|
@@ -128,7 +140,6 @@ def transcribe_audio(model_name: str, audio_path: str):
|
|
| 128 |
# --- BARRE DE PROGRESSION SIMULÉE ---
|
| 129 |
for progress_percent in range(0, 91, 10):
|
| 130 |
time.sleep(0.3)
|
| 131 |
-
# Utilisation de la syntaxe correcte : progress(valeur_flottante, description)
|
| 132 |
progress(progress_percent / 100, desc=f"Progression ASR ({progress_percent}%)")
|
| 133 |
|
| 134 |
yield f"**[3/4] FINALISATION...** Inférence en cours sur le GPU. 🚀"
|
|
@@ -138,10 +149,11 @@ def transcribe_audio(model_name: str, audio_path: str):
|
|
| 138 |
transcriptions = asr_model.transcribe([temp_full_path], batch_size=1)
|
| 139 |
|
| 140 |
# --- GESTION DE L'OBJET HYPOTHESIS ---
|
| 141 |
-
transcription_text_final = ""
|
| 142 |
if transcriptions and transcriptions[0]:
|
| 143 |
hyp_object = transcriptions[0]
|
| 144 |
|
|
|
|
| 145 |
if hasattr(hyp_object, 'text'):
|
| 146 |
transcription_text_final = hyp_object.text.strip()
|
| 147 |
elif isinstance(hyp_object, str):
|
|
@@ -162,6 +174,7 @@ def transcribe_audio(model_name: str, audio_path: str):
|
|
| 162 |
|
| 163 |
# --- POST-TRAITEMENT (PONCTUATION & CASSE) ---
|
| 164 |
punct_model = load_punct_model()
|
|
|
|
| 165 |
if punct_model and transcription_text_final != "[Transcription vide ou échec ASR]":
|
| 166 |
yield f"**[4/4] POST-TRAITEMENT...** Correction de la ponctuation et de la casse pour la lisibilité. ✨"
|
| 167 |
# Termine la barre de progression
|
|
@@ -173,21 +186,33 @@ def transcribe_audio(model_name: str, audio_path: str):
|
|
| 173 |
processed_text = corrected_list[0].strip()
|
| 174 |
except Exception as pc_error:
|
| 175 |
print(f"!!! Échec du post-traitement de ponctuation : {pc_error}")
|
|
|
|
| 176 |
yield "⚠️ Échec de la correction de ponctuation. Affichage du texte brut."
|
| 177 |
|
| 178 |
-
# 1. EN-TÊTE D'INFORMATION
|
| 179 |
output = f"**Modèle Utilisé :** `{model_short_name}` (NeMo)\n"
|
| 180 |
output += f"**Durée de l'Audio :** {total_duration:.1f} secondes\n"
|
| 181 |
output += f"**Temps de Traitement Total :** {duration:.2f} secondes\n"
|
| 182 |
output += f"***\n"
|
| 183 |
|
| 184 |
-
# 2. PRÉSENTATION LYRICS PROPRE
|
| 185 |
output += "**RÉSULTAT DE LA TRANSCRIPTION (Lyrics) :**\n"
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
|
| 190 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
|
| 192 |
# 3. NOTE FINALE
|
| 193 |
output += "\n\n*Traitement complet de l'audio sans découpage (chunking).* "
|
|
@@ -195,7 +220,7 @@ def transcribe_audio(model_name: str, audio_path: str):
|
|
| 195 |
yield output
|
| 196 |
|
| 197 |
except RuntimeError as e:
|
| 198 |
-
yield f"❌ Erreur critique lors du chargement : {str(e)}"
|
| 199 |
|
| 200 |
except Exception as e:
|
| 201 |
yield f"❌ Erreur générale lors de la transcription complète : {e}"
|
|
@@ -210,26 +235,38 @@ def transcribe_audio(model_name: str, audio_path: str):
|
|
| 210 |
# 3. PRÉ-CHARGEMENT ET INTERFACE GRADIO
|
| 211 |
# ----------------------------------------------------------------------
|
| 212 |
|
| 213 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 214 |
|
| 215 |
if ROBOTSMALI_MODELS:
|
| 216 |
default_model = ROBOTSMALI_MODELS[0]
|
|
|
|
| 217 |
try:
|
| 218 |
# Tente de charger le modèle par défaut au démarrage
|
| 219 |
load_pipeline(default_model)
|
| 220 |
-
|
| 221 |
INITIAL_DESCRIPTION = (
|
| 222 |
-
f"✅
|
| 223 |
-
f"
|
| 224 |
-
f"Téléchargez ou enregistrez votre audio pour transcrire."
|
| 225 |
)
|
| 226 |
except RuntimeError as e:
|
| 227 |
-
default_model_short_name = default_model.split('/')[-1]
|
| 228 |
INITIAL_DESCRIPTION = (
|
| 229 |
f"❌ ERREUR CRITIQUE AU DÉMARRAGE : Impossible de charger le modèle `{default_model_short_name}`. "
|
| 230 |
f"**Veuillez sélectionner un autre modèle dans la liste**. "
|
| 231 |
f"Détails de l'erreur : {str(e)}"
|
| 232 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 233 |
|
| 234 |
model_dropdown = gr.Dropdown(
|
| 235 |
label="1. Sélectionner un Modèle RobotsMali",
|
|
@@ -242,7 +279,7 @@ audio_input = gr.Audio(
|
|
| 242 |
label="2. Télécharger ou Enregistrer l'Audio",
|
| 243 |
type="filepath",
|
| 244 |
sources=["microphone", "upload"],
|
| 245 |
-
format="mp3")
|
| 246 |
|
| 247 |
text_output = gr.Markdown(
|
| 248 |
label="3. Résultat de la Transcription ASR")
|
|
|
|
| 10 |
import numpy as np
|
| 11 |
|
| 12 |
# --- IMPORTS NEMO ---
|
| 13 |
+
# Nécessite : pip install nemo_toolkit['asr'] nemo_toolkit['nlp']
|
| 14 |
+
try:
|
| 15 |
+
import nemo.collections.asr as nemo_asr
|
| 16 |
+
import nemo.collections.nlp as nemo_nlp
|
| 17 |
+
except ImportError:
|
| 18 |
+
print("!!! AVERTISSEMENT : NeMo ASR ou NLP n'est pas installé. Les modèles ne fonctionneront pas.")
|
| 19 |
+
# On définit des substituts pour permettre au script de s'exécuter jusqu'à l'interface
|
| 20 |
+
class DummyASRModel:
|
| 21 |
+
def from_pretrained(self, model_name): raise RuntimeError("NeMo ASR not installed.")
|
| 22 |
+
class DummyNLPModel:
|
| 23 |
+
def from_pretrained(self, model_name): raise RuntimeError("NeMo NLP not installed.")
|
| 24 |
+
nemo_asr = type('nemo_asr', (object,), {'models': type('models', (object,), {'ASRModel': DummyASRModel})})
|
| 25 |
+
nemo_nlp = type('nemo_nlp', (object,), {'models': type('models', (object,), {'PunctuationCapitalizationModel': DummyNLPModel})})
|
| 26 |
|
| 27 |
# ----------------------------------------------------------------------
|
| 28 |
# CONSTANTES DE CONFIGURATION
|
|
|
|
| 89 |
print("-> Modèle de ponctuation chargé avec succès.")
|
| 90 |
except Exception as e:
|
| 91 |
print(f"!!! AVERTISSEMENT: Échec du chargement du modèle de ponctuation {PUNCT_MODEL_NAME}. La sortie restera brute. Détail: {e}")
|
| 92 |
+
punct_pipeline = False # Marquer comme tentative échouée
|
| 93 |
return punct_pipeline
|
| 94 |
|
| 95 |
# ----------------------------------------------------------------------
|
|
|
|
| 117 |
# ----------------------------------------------------------------
|
| 118 |
yield f"**[1/4] CHARGEMENT AUDIO...** Préparation du fichier original (Mono @ 16kHz). ⚙️"
|
| 119 |
|
| 120 |
+
# NOTE : Utilisation de librosa pour garantir le 16kHz et mono
|
| 121 |
full_audio_data, sr = librosa.load(audio_path, sr=SR_TARGET, mono=True)
|
| 122 |
total_duration = len(full_audio_data) / SR_TARGET
|
| 123 |
|
|
|
|
| 140 |
# --- BARRE DE PROGRESSION SIMULÉE ---
|
| 141 |
for progress_percent in range(0, 91, 10):
|
| 142 |
time.sleep(0.3)
|
|
|
|
| 143 |
progress(progress_percent / 100, desc=f"Progression ASR ({progress_percent}%)")
|
| 144 |
|
| 145 |
yield f"**[3/4] FINALISATION...** Inférence en cours sur le GPU. 🚀"
|
|
|
|
| 149 |
transcriptions = asr_model.transcribe([temp_full_path], batch_size=1)
|
| 150 |
|
| 151 |
# --- GESTION DE L'OBJET HYPOTHESIS ---
|
| 152 |
+
transcription_text_final = "[Transcription vide ou échec ASR]"
|
| 153 |
if transcriptions and transcriptions[0]:
|
| 154 |
hyp_object = transcriptions[0]
|
| 155 |
|
| 156 |
+
# Tente d'extraire le texte de l'objet de retour de NeMo
|
| 157 |
if hasattr(hyp_object, 'text'):
|
| 158 |
transcription_text_final = hyp_object.text.strip()
|
| 159 |
elif isinstance(hyp_object, str):
|
|
|
|
| 174 |
|
| 175 |
# --- POST-TRAITEMENT (PONCTUATION & CASSE) ---
|
| 176 |
punct_model = load_punct_model()
|
| 177 |
+
|
| 178 |
if punct_model and transcription_text_final != "[Transcription vide ou échec ASR]":
|
| 179 |
yield f"**[4/4] POST-TRAITEMENT...** Correction de la ponctuation et de la casse pour la lisibilité. ✨"
|
| 180 |
# Termine la barre de progression
|
|
|
|
| 186 |
processed_text = corrected_list[0].strip()
|
| 187 |
except Exception as pc_error:
|
| 188 |
print(f"!!! Échec du post-traitement de ponctuation : {pc_error}")
|
| 189 |
+
# Le texte brut (transcription_text_final) reste dans processed_text
|
| 190 |
yield "⚠️ Échec de la correction de ponctuation. Affichage du texte brut."
|
| 191 |
|
| 192 |
+
# 1. EN-TÊTE D'INFORMATION - LE NOM DU MODÈLE EST MAINTENANT DYNAMIQUE ICI
|
| 193 |
output = f"**Modèle Utilisé :** `{model_short_name}` (NeMo)\n"
|
| 194 |
output += f"**Durée de l'Audio :** {total_duration:.1f} secondes\n"
|
| 195 |
output += f"**Temps de Traitement Total :** {duration:.2f} secondes\n"
|
| 196 |
output += f"***\n"
|
| 197 |
|
| 198 |
+
# 2. PRÉSENTATION LYRICS PROPRE (AMÉLIORÉE)
|
| 199 |
output += "**RÉSULTAT DE LA TRANSCRIPTION (Lyrics) :**\n"
|
| 200 |
+
output += "---\n" # Séparateur visuel pour la section lyrics
|
| 201 |
+
|
| 202 |
+
# Nettoyage et normalisation de base
|
| 203 |
+
clean_text = processed_text.replace('\n', ' ').strip()
|
| 204 |
+
|
| 205 |
+
# Remplacer les séparateurs de phrases par un double saut de ligne pour simuler des paragraphes/strophes
|
| 206 |
+
formatted_lyrics = clean_text.replace('. ', '.\n\n').replace('? ', '?\n\n').replace('! ', '!\n\n')
|
| 207 |
|
| 208 |
+
# Ajouter le bloc de citation (>) au début de chaque ligne pour un rendu plus clair en Markdown
|
| 209 |
+
final_lines = []
|
| 210 |
+
for line in formatted_lyrics.split('\n'):
|
| 211 |
+
if line.strip():
|
| 212 |
+
final_lines.append('> ' + line.strip())
|
| 213 |
+
|
| 214 |
+
output += '\n'.join(final_lines)
|
| 215 |
+
output += "\n---\n"
|
| 216 |
|
| 217 |
# 3. NOTE FINALE
|
| 218 |
output += "\n\n*Traitement complet de l'audio sans découpage (chunking).* "
|
|
|
|
| 220 |
yield output
|
| 221 |
|
| 222 |
except RuntimeError as e:
|
| 223 |
+
yield f"❌ Erreur critique lors du chargement ou de l'inférence : {str(e)}"
|
| 224 |
|
| 225 |
except Exception as e:
|
| 226 |
yield f"❌ Erreur générale lors de la transcription complète : {e}"
|
|
|
|
| 235 |
# 3. PRÉ-CHARGEMENT ET INTERFACE GRADIO
|
| 236 |
# ----------------------------------------------------------------------
|
| 237 |
|
| 238 |
+
# --- MODIFICATIONS APPLIQUÉES ICI ---
|
| 239 |
+
|
| 240 |
+
# 1. On donne une description initiale GÉNÉRALE
|
| 241 |
+
INITIAL_DESCRIPTION_BASE = (
|
| 242 |
+
"Sélectionnez un modèle ASR de RobotsMali, puis enregistrez ou téléchargez un fichier audio pour obtenir la transcription. "
|
| 243 |
+
"Attention : Le traitement se fait sur l'audio complet. Les longs fichiers peuvent planter la RAM."
|
| 244 |
+
)
|
| 245 |
+
INITIAL_DESCRIPTION = INITIAL_DESCRIPTION_BASE
|
| 246 |
|
| 247 |
if ROBOTSMALI_MODELS:
|
| 248 |
default_model = ROBOTSMALI_MODELS[0]
|
| 249 |
+
default_model_short_name = default_model.split('/')[-1]
|
| 250 |
try:
|
| 251 |
# Tente de charger le modèle par défaut au démarrage
|
| 252 |
load_pipeline(default_model)
|
| 253 |
+
# 2. On ajoute seulement le statut de préchargement au message d'information initial
|
| 254 |
INITIAL_DESCRIPTION = (
|
| 255 |
+
f"✅ Modèle par défaut `{default_model_short_name}` **préchargé et réchauffé** avec succès. "
|
| 256 |
+
f"{INITIAL_DESCRIPTION_BASE}"
|
|
|
|
| 257 |
)
|
| 258 |
except RuntimeError as e:
|
|
|
|
| 259 |
INITIAL_DESCRIPTION = (
|
| 260 |
f"❌ ERREUR CRITIQUE AU DÉMARRAGE : Impossible de charger le modèle `{default_model_short_name}`. "
|
| 261 |
f"**Veuillez sélectionner un autre modèle dans la liste**. "
|
| 262 |
f"Détails de l'erreur : {str(e)}"
|
| 263 |
)
|
| 264 |
+
except Exception as e:
|
| 265 |
+
INITIAL_DESCRIPTION = (
|
| 266 |
+
f"❌ ERREUR CRITIQUE : Problème de configuration (peut-être NeMo/CUDA). Détails : {str(e)}"
|
| 267 |
+
)
|
| 268 |
+
# -------------------------------------
|
| 269 |
+
|
| 270 |
|
| 271 |
model_dropdown = gr.Dropdown(
|
| 272 |
label="1. Sélectionner un Modèle RobotsMali",
|
|
|
|
| 279 |
label="2. Télécharger ou Enregistrer l'Audio",
|
| 280 |
type="filepath",
|
| 281 |
sources=["microphone", "upload"],
|
| 282 |
+
format="mp3")
|
| 283 |
|
| 284 |
text_output = gr.Markdown(
|
| 285 |
label="3. Résultat de la Transcription ASR")
|