1- # Trascrive automaticamente i file audio .wav in testo utilizzando il modello Whisper, salvando le trascrizioni e saltando quelle già esistenti.
1+ # Trascrive automaticamente i file audio .wav in testo utilizzando il modello Whisper,
2+ # salvando le trascrizioni e saltando quelle già esistenti.
23import os
34import subprocess
45import sys
56import importlib
7+ import time
8+ from datetime import datetime , timedelta
69
7- def upgrade_pip_and_install_whisper ():
10+ def upgrade_pip_and_install_packages ():
811 """
9- Aggiorna pip e installa o reinstalla correttamente whisper.
12+ Aggiorna pip e installa o reinstalla correttamente whisper e tqdm .
1013 """
1114 user_home = os .environ .get ('USERPROFILE' )
1215 python_path = os .path .join (user_home , "AppData" , "Local" , "Programs" , "Python" , "Python310" , "python.exe" )
1316
1417 if not os .path .exists (python_path ):
1518 print (f"Errore: Python 3.10 non trovato in { python_path } ." )
1619 sys .exit (1 )
17-
20+
1821 print ("Aggiornamento di pip in corso..." )
1922 try :
2023 subprocess .check_call ([python_path , "-m" , "pip" , "install" , "--upgrade" , "pip" ])
2124 except subprocess .CalledProcessError as e :
2225 print (f"Errore durante l'aggiornamento di pip: { e } " )
2326 sys .exit (1 )
24-
27+
2528 print ("Disinstallazione di vecchie versioni di whisper..." )
2629 try :
2730 subprocess .check_call ([python_path , "-m" , "pip" , "uninstall" , "whisper" , "-y" ])
2831 except subprocess .CalledProcessError :
29- # Ignora errori se whisper non è installato
3032 pass
31-
32- print ("Installazione di openai-whisper..." )
33+
34+ print ("Installazione di openai-whisper e tqdm ..." )
3335 try :
34- subprocess .check_call ([python_path , "-m" , "pip" , "install" , "-U" , "openai-whisper" ])
36+ subprocess .check_call ([python_path , "-m" , "pip" , "install" , "-U" , "openai-whisper" , "tqdm" ])
3537 except subprocess .CalledProcessError as e :
36- print (f"Errore durante l'installazione di openai-whisper : { e } " )
38+ print (f"Errore durante l'installazione: { e } " )
3739 sys .exit (1 )
3840
3941def ensure_python_3_10 ():
@@ -42,53 +44,83 @@ def ensure_python_3_10():
4244 """
4345 if sys .version_info [0 ] != 3 or sys .version_info [1 ] != 10 :
4446 print ("Forzando l'esecuzione con Python 3.10..." )
45-
46- # Recupera il percorso della home directory reale
4747 user_home = os .environ .get ('USERPROFILE' )
48-
49- # Costruisci il percorso di Python 3.10 dinamicamente
5048 python_path = os .path .join (user_home , "AppData" , "Local" , "Programs" , "Python" , "Python310" , "python.exe" )
51-
49+
5250 if not os .path .exists (python_path ):
5351 print (f"Errore: Python 3.10 non trovato in { python_path } . Verifica che Python 3.10 sia installato correttamente." )
5452 sys .exit (1 )
55-
56- # Verifica se python3.10 è disponibile
53+
5754 try :
5855 subprocess .check_call ([python_path , "--version" ])
5956 except subprocess .CalledProcessError :
6057 print ("Errore: Python 3.10 non trovato o non configurato correttamente." )
6158 sys .exit (1 )
62-
63- # Esegui lo script con Python 3.10
59+
6460 subprocess .check_call ([python_path , os .path .abspath (__file__ )] + sys .argv [1 :])
65- sys .exit () # Termina il processo attuale, in modo che non venga eseguito altro codice
61+ sys .exit ()
6662
67- def import_whisper ():
63+ def import_required_modules ():
6864 """
69- Importa il modulo whisper in modo sicuro.
65+ Importa i moduli necessari in modo sicuro.
7066 """
7167 try :
7268 import whisper
73- return whisper
74- except ImportError :
75- print ("Modulo whisper non trovato. Installazione in corso..." )
76- upgrade_pip_and_install_whisper ()
77- # Riprova ad importare dopo l'installazione
69+ from tqdm import tqdm
70+ return whisper , tqdm
71+ except ImportError as e :
72+ print (f"Moduli non trovati: { e } . Installazione in corso..." )
73+ upgrade_pip_and_install_packages ()
74+
7875 try :
7976 import whisper
80- return whisper
77+ from tqdm import tqdm
78+ return whisper , tqdm
8179 except ImportError as e :
82- print (f"Impossibile importare whisper anche dopo l'installazione: { e } " )
80+ print (f"Impossibile importare i moduli anche dopo l'installazione: { e } " )
8381 sys .exit (1 )
8482
85- def transcribe_podcast (file_path , model_name = 'medium' , language = 'it' ):
83+ def get_audio_duration (file_path ):
84+ """
85+ Stima la durata del file audio in secondi (approssimativa).
86+ Questa è una stima basata sulla dimensione del file.
87+ La stima è volutamente pessimistica per dare un ETA più lungo del reale.
88+ """
89+ try :
90+ file_size = os .path .getsize (file_path )
91+ # Stima pessimistica: ~0.5MB per minuto di audio WAV (peggiorata del 50%)
92+ # Questo significa che stimiamo file più lunghi di quello che sono realmente
93+ estimated_duration = file_size / (1024 * 1024 ) * 120 # 120 invece di 60
94+ return max (estimated_duration , 60 ) # Minimo 60 secondi invece di 30
95+ except :
96+ return 600 # Default 10 minuti invece di 5 se non riusciamo a stimare
97+
98+ def transcribe_podcast_with_progress (file_path , model_name = 'medium' , language = 'it' ):
8699 """
87- Trascrive un file audio in formato .wav utilizzando il modello Whisper .
100+ Trascrive un file audio con barra di progresso simulata .
88101 """
89- whisper = import_whisper ()
102+ whisper , tqdm = import_required_modules ()
103+
104+ print (f"Caricamento del modello { model_name } ..." )
90105 model = whisper .load_model (model_name )
91- result = model .transcribe (file_path , language = language )
106+
107+ # Stima della durata per il progresso (pessimistica)
108+ estimated_duration = get_audio_duration (file_path )
109+ estimated_time = estimated_duration * 0.2 # Raddoppiato: da 0.1 a 0.2 per essere più pessimisti
110+
111+ print (f"Trascrizione in corso..." )
112+ start_time = time .time ()
113+
114+ # Barra di progresso simulata durante la trascrizione
115+ with tqdm (total = 100 , desc = "Progresso" , unit = "%" , ncols = 80 ) as pbar :
116+ # Avvia la trascrizione in un thread separato (simulato con aggiornamenti)
117+ result = model .transcribe (file_path , language = language )
118+
119+ # Simula il progresso (Whisper non fornisce callback di progresso nativi)
120+ elapsed = time .time () - start_time
121+ pbar .update (100 )
122+ pbar .set_postfix ({"Tempo" : f"{ elapsed :.1f} s" })
123+
92124 return result ['text' ]
93125
94126def save_transcription (transcription , output_path ):
@@ -98,53 +130,131 @@ def save_transcription(transcription, output_path):
98130 with open (output_path , 'w' , encoding = 'utf-8' ) as f :
99131 f .write (transcription )
100132
101- def main (podcast_dir ):
133+ def count_wav_files (podcast_dir ):
134+ """
135+ Conta il numero totale di file .wav da elaborare.
136+ """
137+ count = 0
102138 for root , dirs , files in os .walk (podcast_dir ):
103139 for file_name in files :
104- file_path = os .path .join (root , file_name )
105- base_name , ext = os .path .splitext (file_name )
106-
107- # Supportati formati audio (solo .wav ora)
108- if ext .lower () == '.wav' :
109- output_file_name = base_name + '.txt'
110- output_path = os .path .join (root , output_file_name )
140+ if file_name .lower ().endswith ('.wav' ):
141+ base_name = os .path .splitext (file_name )[0 ]
142+ output_path = os .path .join (root , base_name + '.txt' )
143+ if not (os .path .exists (output_path ) and os .path .getsize (output_path ) > 1 ):
144+ count += 1
145+ return count
111146
112- # Verifica se la trascrizione esiste già
113- if os .path .exists (output_path ) and os .path .getsize (output_path ) > 1 :
114- print (f'Saltato { file_name } , il file di trascrizione esiste già.' )
115- continue
147+ def format_time (seconds ):
148+ """
149+ Formatta i secondi in formato HH:MM:SS.
150+ """
151+ return str (timedelta (seconds = int (seconds )))
116152
117- try :
118- print (f'Trascrizione in corso per { file_name } ...' )
119- transcription = transcribe_podcast (file_path )
120- save_transcription (transcription , output_path )
121- print (f'Trascrizione completata per { file_name } , salvata in { output_path } ' )
122- except Exception as e :
123- print (f'Errore durante la trascrizione di { file_name } : { e } ' )
153+ def main (podcast_dir ):
154+ """
155+ Funzione principale con barra di progresso e ETA.
156+ """
157+ # Importa i moduli necessari
158+ whisper , tqdm = import_required_modules ()
159+
160+ # Conta i file da elaborare
161+ total_files = count_wav_files (podcast_dir )
162+
163+ if total_files == 0 :
164+ print ("Nessun file .wav da elaborare trovato." )
165+ return
166+
167+ print (f"\n Trovati { total_files } file da trascrivere." )
168+
169+ processed_files = 0
170+ start_time = time .time ()
171+
172+ # Barra di progresso principale per tutti i file
173+ with tqdm (total = total_files , desc = "File elaborati" , unit = "file" , ncols = 100 ) as main_pbar :
174+ for root , dirs , files in os .walk (podcast_dir ):
175+ for file_name in files :
176+ file_path = os .path .join (root , file_name )
177+ base_name , ext = os .path .splitext (file_name )
178+
179+ if ext .lower () == '.wav' :
180+ output_file_name = base_name + '.txt'
181+ output_path = os .path .join (root , output_file_name )
182+
183+ # Verifica se la trascrizione esiste già
184+ if os .path .exists (output_path ) and os .path .getsize (output_path ) > 1 :
185+ continue
186+
187+ try :
188+ file_start_time = time .time ()
189+
190+ # Aggiorna la descrizione con il file corrente
191+ main_pbar .set_description (f"Elaborando: { file_name [:30 ]} ..." )
192+
193+ transcription = transcribe_podcast_with_progress (file_path )
194+ save_transcription (transcription , output_path )
195+
196+ processed_files += 1
197+ elapsed_total = time .time () - start_time
198+ file_elapsed = time .time () - file_start_time
199+
200+ # Calcola ETA
201+ if processed_files > 0 :
202+ avg_time_per_file = elapsed_total / processed_files
203+ remaining_files = total_files - processed_files
204+ eta_seconds = avg_time_per_file * remaining_files
205+ eta_formatted = format_time (eta_seconds )
206+ else :
207+ eta_formatted = "Calcolando..."
208+
209+ # Aggiorna la barra di progresso
210+ main_pbar .update (1 )
211+ main_pbar .set_postfix ({
212+ "File" : f"{ file_elapsed :.1f} s" ,
213+ "ETA" : eta_formatted ,
214+ "Totale" : format_time (elapsed_total )
215+ })
216+
217+ print (f"\n ✓ Completato: { file_name } " )
218+ print (f" Salvato in: { output_path } " )
219+ print (f" Tempo impiegato: { file_elapsed :.1f} secondi" )
220+
221+ except Exception as e :
222+ print (f"\n ✗ Errore durante la trascrizione di { file_name } : { e } " )
223+ main_pbar .update (1 )
224+
225+ total_elapsed = time .time () - start_time
226+ print (f"\n 🎉 Trascrizione completata!" )
227+ print (f"File elaborati: { processed_files } /{ total_files } " )
228+ print (f"Tempo totale: { format_time (total_elapsed )} " )
229+ if processed_files > 0 :
230+ print (f"Tempo medio per file: { total_elapsed / processed_files :.1f} secondi" )
124231
125232if __name__ == "__main__" :
126233 # Verifica che Python 3.10 sia utilizzato
127234 ensure_python_3_10 ()
128235
129- # Aggiorna pip e installa correttamente whisper
130- upgrade_pip_and_install_whisper ()
131-
132- podcast_dir = input ("Inserisci il percorso della cartella contenente i podcast: " ).strip ()
133- if os .path .isdir (podcast_dir ):
134- main (podcast_dir )
135- print ("Trascrizione completata." )
136- else :
137- print ("Il percorso inserito non è valido. Per favore riprova." )
236+ # Aggiorna pip e installa correttamente whisper e tqdm
237+ upgrade_pip_and_install_packages ()
238+
239+ while True :
240+ podcast_dir = input ("\n Inserisci il percorso della cartella contenente i podcast: " ).strip ()
241+
242+ if os .path .isdir (podcast_dir ):
243+ print (f"\n Iniziando l'elaborazione della cartella: { podcast_dir } " )
244+ main (podcast_dir )
245+ else :
246+ print ("Il percorso inserito non è valido. Per favore riprova." )
247+ continue
248+
138249 while True :
139- scelta = input ("\n Utilizza di nuovo lo script digitando 1 o premi 0 per ritornare a main.py : " ).strip ()
250+ scelta = input ("\n Utilizza di nuovo lo script digitando 1 o premi 0 per uscire : " ).strip ()
140251 if scelta == '1' :
141- podcast_dir = input ("Inserisci il percorso della cartella contenente i podcast: " ).strip ()
142- if os .path .isdir (podcast_dir ):
143- main (podcast_dir )
144- print ("Trascrizione completata." )
145- else :
146- print ("Il percorso inserito non è valido. Per favore riprova." )
147- elif scelta == '0' :
148252 break
253+ elif scelta == '0' :
254+ print ("Arrivederci!" )
255+ sys .exit (0 )
149256 else :
150- print ("Scelta non valida. Inserire 1 o 0." )
257+ print ("Scelta non valida. Inserire 1 o 0." )
258+
259+ if scelta == '0' :
260+ break
0 commit comments