import os import uuid import threading from flask import Flask, request, render_template, send_file, url_for from faster_whisper import WhisperModel app = Flask(__name__) app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024 # 100 MB limit app.secret_key = os.urandom(24) # ── Whisper model ─────────────────────────────────────────────── # Modello small (1.5 GB) — ottimo per italiano, veloce su CPU. # Cambia in "base" o "tiny" se vuoi più velocità, "medium" per più accuratezza. WHISPER_MODEL = "small" print(f"[INFO] Caricamento modello Whisper '{WHISPER_MODEL}'...") whisper = WhisperModel(WHISPER_MODEL, device="cpu", compute_type="int8") print("[INFO] Modello caricato!") # ── Job tracking (in memoria) ─────────────────────────────────── jobs = {} # ── Routes ────────────────────────────────────────────────────── @app.route('/') def index(): return render_template('index.html') @app.route('/upload', methods=['POST']) def upload(): if 'audio' not in request.files: return {'error': 'Nessun file audio'}, 400 file = request.files['audio'] if file.filename == '': return {'error': 'Nome file vuoto'}, 400 job_id = str(uuid.uuid4()) os.makedirs('tmp', exist_ok=True) tmp_path = os.path.join('tmp', f'{job_id}.m4a') file.save(tmp_path) jobs[job_id] = { 'status': 'running', 'progress': 0, 'message': 'Caricato', 'download': None, } threading.Thread(target=job_worker, args=(job_id, tmp_path), daemon=True).start() return {'statusUrl': url_for('status', job_id=job_id)} @app.route('/status/') def status(job_id): job = jobs.get(job_id) if not job: return {'error': 'Job non trovato'}, 404 # Mentre whisper lavora, mostriamo "Trascrizione in corso..." con progress 50 if job.get('status') == 'running' and job.get('progress', 0) < 100: return { 'status': 'running', 'progress': 50, 'message': 'Trascrizione in corso...', 'download': None, } return { 'status': job.get('status'), 'progress': job.get('progress', 100), 'message': job.get('message'), 'download': job.get('download'), } @app.route('/download/.txt') def download(job_id): txt_path = os.path.join('tmp', f'trascrizione_{job_id}.txt') if not os.path.exists(txt_path): return {'error': 'File non trovato'}, 404 return send_file( txt_path, as_attachment=True, download_name='trascrizione.txt', mimetype='text/plain', ) # ── Worker (thread background) ────────────────────────────────── def job_worker(job_id, tmp_path): try: jobs[job_id]['message'] = 'Trascrizione in corso...' # Whisper trascrive direttamente dal file (supporta .m4a via ffmpeg) segments, info = whisper.transcribe(tmp_path, language="it", beam_size=5) transcript_parts = [] for segment in segments: transcript_parts.append(segment.text.strip()) transcription = "\n".join(transcript_parts) txt_path = os.path.join('tmp', f'trascrizione_{job_id}.txt') with open(txt_path, 'w', encoding='utf-8') as f: f.write(transcription) jobs[job_id]['download'] = f'/download/{job_id}.txt' jobs[job_id]['message'] = 'Completato' jobs[job_id]['progress'] = 100 jobs[job_id]['status'] = 'done' except Exception as e: jobs[job_id]['status'] = 'error' jobs[job_id]['message'] = str(e) finally: try: os.remove(tmp_path) except Exception: pass if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=True)