Update app.py
Browse files
app.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
| 1 |
import os
|
| 2 |
import tempfile
|
|
|
|
|
|
|
| 3 |
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
|
| 4 |
from fastapi.middleware.cors import CORSMiddleware
|
| 5 |
from faster_whisper import WhisperModel
|
|
@@ -15,7 +17,6 @@ app.add_middleware(
|
|
| 15 |
allow_headers=["*"],
|
| 16 |
)
|
| 17 |
|
| 18 |
-
import sys
|
| 19 |
print("Loading Whisper model...", flush=True)
|
| 20 |
model = WhisperModel("large-v3", device="cpu", compute_type="int8")
|
| 21 |
print("Whisper model ready!")
|
|
@@ -24,10 +25,39 @@ print("Loading DeepFilterNet model...", flush=True)
|
|
| 24 |
df_model, df_state, _ = init_df()
|
| 25 |
print("DeepFilterNet model ready!")
|
| 26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
@app.get("/health")
|
| 28 |
async def health():
|
| 29 |
return {"status": "ok", "message": "SubFlow backend is running"}
|
| 30 |
|
|
|
|
| 31 |
@app.websocket("/transcribe")
|
| 32 |
async def transcribe(websocket: WebSocket):
|
| 33 |
await websocket.accept()
|
|
@@ -46,9 +76,12 @@ async def transcribe(websocket: WebSocket):
|
|
| 46 |
print(f"Step 3: saved to {tmp_path}")
|
| 47 |
|
| 48 |
await websocket.send_json({"status": "cleaning"})
|
| 49 |
-
print("Step 3.5: cleaning audio with DeepFilterNet")
|
| 50 |
|
| 51 |
audio_data, _ = load_audio(tmp_path, sr=df_state.sr())
|
|
|
|
|
|
|
|
|
|
| 52 |
enhanced_audio = enhance(df_model, df_state, audio_data, atten_lim_db=20)
|
| 53 |
enhanced_path = tmp_path.replace(".wav", "_enhanced.wav")
|
| 54 |
save_audio(enhanced_path, enhanced_audio, df_state.sr())
|
|
@@ -67,7 +100,7 @@ async def transcribe(websocket: WebSocket):
|
|
| 67 |
speech_pad_ms=200,
|
| 68 |
),
|
| 69 |
)
|
| 70 |
-
|
| 71 |
print("Step 5: transcription done")
|
| 72 |
|
| 73 |
await websocket.send_json({"status": "processing"})
|
|
@@ -117,5 +150,4 @@ async def transcribe(websocket: WebSocket):
|
|
| 117 |
try:
|
| 118 |
await websocket.close()
|
| 119 |
except Exception:
|
| 120 |
-
pass
|
| 121 |
-
|
|
|
|
| 1 |
import os
|
| 2 |
import tempfile
|
| 3 |
+
import numpy as np
|
| 4 |
+
import torch
|
| 5 |
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
|
| 6 |
from fastapi.middleware.cors import CORSMiddleware
|
| 7 |
from faster_whisper import WhisperModel
|
|
|
|
| 17 |
allow_headers=["*"],
|
| 18 |
)
|
| 19 |
|
|
|
|
| 20 |
print("Loading Whisper model...", flush=True)
|
| 21 |
model = WhisperModel("large-v3", device="cpu", compute_type="int8")
|
| 22 |
print("Whisper model ready!")
|
|
|
|
| 25 |
df_model, df_state, _ = init_df()
|
| 26 |
print("DeepFilterNet model ready!")
|
| 27 |
|
| 28 |
+
|
| 29 |
+
def compress_dynamic_range(audio, sr, threshold_db=-28, ratio=4.0, makeup_gain_db=8, block_ms=20):
|
| 30 |
+
"""
|
| 31 |
+
صدای آروم رو نسبت به صدای بلند بلندتر میکنه (یکسانسازی حجم صدا)،
|
| 32 |
+
تا صدای یه نفر که از میکروفون دوره به صدای کسی که میکروفون دستشه نزدیکتر بشه.
|
| 33 |
+
"""
|
| 34 |
+
audio = audio.astype(np.float32)
|
| 35 |
+
block_size = max(1, int(sr * block_ms / 1000))
|
| 36 |
+
n_blocks = int(np.ceil(len(audio) / block_size))
|
| 37 |
+
pad_len = n_blocks * block_size - len(audio)
|
| 38 |
+
padded = np.pad(audio, (0, pad_len))
|
| 39 |
+
blocks = padded.reshape(n_blocks, block_size)
|
| 40 |
+
|
| 41 |
+
rms = np.sqrt(np.mean(blocks ** 2, axis=1) + 1e-10)
|
| 42 |
+
rms_db = 20 * np.log10(rms + 1e-10)
|
| 43 |
+
|
| 44 |
+
target_db = np.where(rms_db > threshold_db, threshold_db + (rms_db - threshold_db) / ratio, rms_db)
|
| 45 |
+
gain_db = target_db - rms_db + makeup_gain_db
|
| 46 |
+
gain = 10 ** (gain_db / 20)
|
| 47 |
+
|
| 48 |
+
kernel = np.ones(5, dtype=np.float32) / 5
|
| 49 |
+
gain_smooth = np.convolve(gain, kernel, mode="same")
|
| 50 |
+
|
| 51 |
+
gain_per_sample = np.repeat(gain_smooth, block_size)[:len(audio)].astype(np.float32)
|
| 52 |
+
compressed = audio * gain_per_sample
|
| 53 |
+
return np.clip(compressed, -1.0, 1.0).astype(np.float32)
|
| 54 |
+
|
| 55 |
+
|
| 56 |
@app.get("/health")
|
| 57 |
async def health():
|
| 58 |
return {"status": "ok", "message": "SubFlow backend is running"}
|
| 59 |
|
| 60 |
+
|
| 61 |
@app.websocket("/transcribe")
|
| 62 |
async def transcribe(websocket: WebSocket):
|
| 63 |
await websocket.accept()
|
|
|
|
| 76 |
print(f"Step 3: saved to {tmp_path}")
|
| 77 |
|
| 78 |
await websocket.send_json({"status": "cleaning"})
|
| 79 |
+
print("Step 3.5: leveling volume + cleaning audio with DeepFilterNet")
|
| 80 |
|
| 81 |
audio_data, _ = load_audio(tmp_path, sr=df_state.sr())
|
| 82 |
+
audio_np = compress_dynamic_range(audio_data.numpy()[0], df_state.sr())
|
| 83 |
+
audio_data = torch.from_numpy(audio_np).unsqueeze(0)
|
| 84 |
+
|
| 85 |
enhanced_audio = enhance(df_model, df_state, audio_data, atten_lim_db=20)
|
| 86 |
enhanced_path = tmp_path.replace(".wav", "_enhanced.wav")
|
| 87 |
save_audio(enhanced_path, enhanced_audio, df_state.sr())
|
|
|
|
| 100 |
speech_pad_ms=200,
|
| 101 |
),
|
| 102 |
)
|
| 103 |
+
|
| 104 |
print("Step 5: transcription done")
|
| 105 |
|
| 106 |
await websocket.send_json({"status": "processing"})
|
|
|
|
| 150 |
try:
|
| 151 |
await websocket.close()
|
| 152 |
except Exception:
|
| 153 |
+
pass
|
|
|