Initial commit: SmallWhisper - web app per trascrizione audio con faster-whisper
This commit is contained in:
commit
98b0e8f198
6 files changed
+274
No files matched your search
@@ -0,0 +1,126 @@
|
||||
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/<job_id>')
|
||||
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/<job_id>.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)
|
||||
Reference in new issue
Block a user