Spaces:
Sleeping
Sleeping
added whisper operating
Browse files- __pycache__/app.cpython-311.pyc +0 -0
- __pycache__/utils.cpython-311.pyc +0 -0
- app.py +73 -43
- audio.mp3 +0 -0
- test.py +12 -1
__pycache__/app.cpython-311.pyc
ADDED
|
Binary file (9.12 kB). View file
|
|
|
__pycache__/utils.cpython-311.pyc
ADDED
|
Binary file (6.63 kB). View file
|
|
|
app.py
CHANGED
|
@@ -1,30 +1,29 @@
|
|
|
|
|
|
|
|
| 1 |
import logging
|
| 2 |
from contextlib import contextmanager
|
| 3 |
-
from fastapi import FastAPI, File, UploadFile, HTTPException
|
| 4 |
-
from fastapi.responses import JSONResponse
|
| 5 |
-
from fastapi.middleware.cors import CORSMiddleware
|
| 6 |
import tempfile
|
| 7 |
import os
|
|
|
|
| 8 |
import librosa
|
| 9 |
import numpy as np
|
| 10 |
-
import
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
from utils import (
|
| 12 |
-
create_cnn_model,
|
| 13 |
-
get_features,
|
| 14 |
extract_features,
|
| 15 |
pad_or_trim,
|
| 16 |
-
noise,
|
| 17 |
-
stretch,
|
| 18 |
-
pitch,
|
| 19 |
)
|
| 20 |
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
-
|
| 24 |
-
# "http://localhost:3000",
|
| 25 |
-
# "http://127.0.0.1:3000",
|
| 26 |
-
# # Add more origins if needed
|
| 27 |
-
# ]
|
| 28 |
|
| 29 |
app.add_middleware(
|
| 30 |
CORSMiddleware,
|
|
@@ -34,6 +33,25 @@ app.add_middleware(
|
|
| 34 |
allow_headers=["*"],
|
| 35 |
)
|
| 36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
@app.get("/")
|
| 38 |
async def read_root():
|
| 39 |
return {"message": "Welcome to the Defects_model API"}
|
|
@@ -73,21 +91,12 @@ logging.basicConfig(
|
|
| 73 |
)
|
| 74 |
|
| 75 |
|
| 76 |
-
@contextmanager
|
| 77 |
-
def temporary_audio_file(audio_bytes):
|
| 78 |
-
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp_file:
|
| 79 |
-
tmp_file.write(audio_bytes)
|
| 80 |
-
tmp_file.flush()
|
| 81 |
-
tmp_filename = tmp_file.name
|
| 82 |
-
try:
|
| 83 |
-
yield tmp_filename
|
| 84 |
-
finally:
|
| 85 |
-
if os.path.exists(tmp_filename):
|
| 86 |
-
os.remove(tmp_filename)
|
| 87 |
-
|
| 88 |
|
| 89 |
@app.post("/process-audio")
|
| 90 |
-
async def process_audio(
|
|
|
|
|
|
|
|
|
|
| 91 |
if audio.content_type != "audio/mpeg":
|
| 92 |
raise HTTPException(
|
| 93 |
status_code=400, detail="Invalid file type. Only MP3 files are supported."
|
|
@@ -95,36 +104,57 @@ async def process_audio(audio: UploadFile = File(...)):
|
|
| 95 |
|
| 96 |
try:
|
| 97 |
audio_bytes = await audio.read()
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
|
|
|
|
|
|
|
|
|
| 101 |
with temporary_audio_file(audio_bytes) as tmp_filename:
|
| 102 |
logging.info(f"Temporary file created: {tmp_filename}")
|
|
|
|
| 103 |
audio_data, sample_rate = librosa.load(tmp_filename, sr=None)
|
| 104 |
logging.info(
|
| 105 |
f"Audio loaded: sample rate = {sample_rate}, data shape = {audio_data.shape}"
|
| 106 |
)
|
| 107 |
if not audio_data.any() or sample_rate == 0:
|
| 108 |
raise ValueError("Empty or invalid audio data.")
|
| 109 |
-
|
|
|
|
| 110 |
features = extract_features(audio_data, sample_rate)
|
| 111 |
logging.info(f"Features extracted: shape = {features.shape}")
|
|
|
|
| 112 |
target_shape = (1, model.input_shape[1])
|
| 113 |
features = pad_or_trim(features, target_shape[1])
|
| 114 |
features = np.expand_dims(features, axis=0)
|
| 115 |
|
| 116 |
prediction = model.predict(features)
|
| 117 |
-
|
| 118 |
logging.info(f"Prediction: {prediction}")
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
except Exception as e:
|
| 128 |
-
logging.exception(f"Error processing audio: {e}")
|
| 129 |
raise HTTPException(status_code=500, detail="Internal server error")
|
| 130 |
-
|
|
|
|
| 1 |
+
from fastapi import FastAPI, File, UploadFile, Form, HTTPException
|
| 2 |
+
import whisper
|
| 3 |
import logging
|
| 4 |
from contextlib import contextmanager
|
|
|
|
|
|
|
|
|
|
| 5 |
import tempfile
|
| 6 |
import os
|
| 7 |
+
import keras
|
| 8 |
import librosa
|
| 9 |
import numpy as np
|
| 10 |
+
import re
|
| 11 |
+
import Levenshtein
|
| 12 |
+
from fastapi.responses import JSONResponse
|
| 13 |
+
|
| 14 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 15 |
from utils import (
|
|
|
|
|
|
|
| 16 |
extract_features,
|
| 17 |
pad_or_trim,
|
|
|
|
|
|
|
|
|
|
| 18 |
)
|
| 19 |
|
| 20 |
+
logging.basicConfig(
|
| 21 |
+
level=logging.INFO,
|
| 22 |
+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
| 23 |
+
handlers=[logging.StreamHandler()]
|
| 24 |
+
)
|
| 25 |
|
| 26 |
+
app = FastAPI(port=8000)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
app.add_middleware(
|
| 29 |
CORSMiddleware,
|
|
|
|
| 33 |
allow_headers=["*"],
|
| 34 |
)
|
| 35 |
|
| 36 |
+
filepath = os.path.abspath("cnn_1_v6_final_model.h5")
|
| 37 |
+
if not os.path.exists(filepath):
|
| 38 |
+
raise FileNotFoundError(f"Model file not found at {filepath}")
|
| 39 |
+
|
| 40 |
+
model = keras.models.load_model(filepath, compile=False)
|
| 41 |
+
whisper_model = whisper.load_model("tiny")
|
| 42 |
+
|
| 43 |
+
@contextmanager
|
| 44 |
+
def temporary_audio_file(audio_bytes):
|
| 45 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp_file:
|
| 46 |
+
tmp_file.write(audio_bytes)
|
| 47 |
+
tmp_file.flush()
|
| 48 |
+
tmp_filename = tmp_file.name
|
| 49 |
+
try:
|
| 50 |
+
yield tmp_filename
|
| 51 |
+
finally:
|
| 52 |
+
if os.path.exists(tmp_filename):
|
| 53 |
+
os.remove(tmp_filename)
|
| 54 |
+
|
| 55 |
@app.get("/")
|
| 56 |
async def read_root():
|
| 57 |
return {"message": "Welcome to the Defects_model API"}
|
|
|
|
| 91 |
)
|
| 92 |
|
| 93 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
|
| 95 |
@app.post("/process-audio")
|
| 96 |
+
async def process_audio(
|
| 97 |
+
audio: UploadFile = File(...),
|
| 98 |
+
phrase: str = Form(...)
|
| 99 |
+
):
|
| 100 |
if audio.content_type != "audio/mpeg":
|
| 101 |
raise HTTPException(
|
| 102 |
status_code=400, detail="Invalid file type. Only MP3 files are supported."
|
|
|
|
| 104 |
|
| 105 |
try:
|
| 106 |
audio_bytes = await audio.read()
|
| 107 |
+
|
| 108 |
+
if not audio_bytes:
|
| 109 |
+
raise HTTPException(status_code=400, detail="Received empty file")
|
| 110 |
+
|
| 111 |
+
logging.info(f"Received audio bytes: {len(audio_bytes)} bytes")
|
| 112 |
+
|
| 113 |
with temporary_audio_file(audio_bytes) as tmp_filename:
|
| 114 |
logging.info(f"Temporary file created: {tmp_filename}")
|
| 115 |
+
|
| 116 |
audio_data, sample_rate = librosa.load(tmp_filename, sr=None)
|
| 117 |
logging.info(
|
| 118 |
f"Audio loaded: sample rate = {sample_rate}, data shape = {audio_data.shape}"
|
| 119 |
)
|
| 120 |
if not audio_data.any() or sample_rate == 0:
|
| 121 |
raise ValueError("Empty or invalid audio data.")
|
| 122 |
+
|
| 123 |
+
# Извлекаем признаки из аудиоданных
|
| 124 |
features = extract_features(audio_data, sample_rate)
|
| 125 |
logging.info(f"Features extracted: shape = {features.shape}")
|
| 126 |
+
|
| 127 |
target_shape = (1, model.input_shape[1])
|
| 128 |
features = pad_or_trim(features, target_shape[1])
|
| 129 |
features = np.expand_dims(features, axis=0)
|
| 130 |
|
| 131 |
prediction = model.predict(features)
|
|
|
|
| 132 |
logging.info(f"Prediction: {prediction}")
|
| 133 |
+
|
| 134 |
+
transcription_result = whisper_model.transcribe(tmp_filename, language="russian")
|
| 135 |
+
transcribed_text = transcription_result["text"].lower().strip()
|
| 136 |
+
|
| 137 |
+
# Удаление знаков препинания из транскрибированного текста
|
| 138 |
+
transcribed_text_clean = re.sub(r'[^\w\s]', '', transcribed_text)
|
| 139 |
+
logging.info(f"Transcribed text (cleaned): {transcribed_text_clean}")
|
| 140 |
+
|
| 141 |
+
# Вычисление редакторского расстояния
|
| 142 |
+
lev_distance = Levenshtein.distance(transcribed_text_clean, phrase.lower().strip())
|
| 143 |
+
phrase_length = max(len(transcribed_text_clean), len(phrase))
|
| 144 |
+
|
| 145 |
+
# Допускаем различие в 40% длины исходной фразы
|
| 146 |
+
max_acceptable_distance = 0.5 * phrase_length
|
| 147 |
+
match_phrase = lev_distance <= max_acceptable_distance
|
| 148 |
+
|
| 149 |
+
logging.info(f"Expected phrase: {phrase}, Is correct: {match_phrase}, Transcribed text: {transcribed_text_clean}, Levenshtein distance: {lev_distance}")
|
| 150 |
+
|
| 151 |
+
return {
|
| 152 |
+
"prediction": prediction.tolist(),
|
| 153 |
+
"match_phrase": match_phrase,
|
| 154 |
+
"lev_distance": lev_distance,
|
| 155 |
+
"transcribed_text": transcribed_text_clean
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
except Exception as e:
|
| 159 |
+
logging.exception(f"Error processing audio: {e}")
|
| 160 |
raise HTTPException(status_code=500, detail="Internal server error")
|
|
|
audio.mp3
ADDED
|
Binary file (190 kB). View file
|
|
|
test.py
CHANGED
|
@@ -3,6 +3,7 @@ import numpy as np
|
|
| 3 |
import keras
|
| 4 |
import httpx
|
| 5 |
import librosa
|
|
|
|
| 6 |
|
| 7 |
from utils import (
|
| 8 |
extract_features,
|
|
@@ -48,4 +49,14 @@ model = keras.models.load_model(filepath, compile=False)
|
|
| 48 |
prediction = model.predict(features)
|
| 49 |
print(f"Prediction: {prediction.tolist()}")
|
| 50 |
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
import keras
|
| 4 |
import httpx
|
| 5 |
import librosa
|
| 6 |
+
import whisper
|
| 7 |
|
| 8 |
from utils import (
|
| 9 |
extract_features,
|
|
|
|
| 49 |
prediction = model.predict(features)
|
| 50 |
print(f"Prediction: {prediction.tolist()}")
|
| 51 |
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def transcribe_russian(audio_file, model_name="tiny"):
|
| 55 |
+
model = whisper.load_model(model_name)
|
| 56 |
+
result = model.transcribe(audio_file, language="russian")
|
| 57 |
+
return result["text"]
|
| 58 |
+
|
| 59 |
+
# Example usage:
|
| 60 |
+
audio_file = "audio.mp3"
|
| 61 |
+
text = transcribe_russian(audio_file)
|
| 62 |
+
print(text)
|