Spaces:
Sleeping
Sleeping
File size: 7,848 Bytes
d6cebe9 6d3487b d6cebe9 6d3487b d6cebe9 6dee894 d6cebe9 ec8fa7d d6cebe9 6dee894 ec8fa7d 6d3487b 476003d d6cebe9 6d3487b 476003d c2e5478 476003d d6cebe9 6d3487b 476003d 6d3487b a875366 6d3487b d71f113 6d3487b 476003d 217f9d2 2a52065 476003d 6dee894 476003d 6dee894 476003d d6cebe9 476003d d6cebe9 476003d c90cf25 476003d 6d3487b 476003d 6d3487b 476003d 6d3487b 476003d 6d3487b d71f113 6d3487b 476003d 6d3487b d6cebe9 476003d 6d3487b 476003d 6d3487b d6cebe9 476003d 6d3487b d6cebe9 476003d 6d3487b d6cebe9 476003d 6dee894 ec8fa7d 6d3487b d6cebe9 476003d 6dee894 59c18e6 6d3487b 59c18e6 6dee894 59c18e6 6dee894 59c18e6 6d3487b 6dee894 d6cebe9 476003d d6cebe9 476003d d6cebe9 476003d d6cebe9 476003d d6cebe9 476003d d6cebe9 6dee894 d71f113 d6cebe9 6d3487b d6cebe9 ec8fa7d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | from fastapi import FastAPI, File, UploadFile, Form, HTTPException
import whisper
import logging
from contextlib import contextmanager
import tempfile
import os
import keras
import librosa
import numpy as np
import re
import Levenshtein
import tensorflow as tf
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
from utils_api import get_features
#вывод в консоль для просмотри на hugging face
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
handlers=[logging.StreamHandler()]
)
# Установка временной директории для кэша Numba
os.environ['NUMBA_CACHE_DIR'] = '/tmp'
# Инициализация FastAPI приложения
app = FastAPI(port=8000)
# Настройка CORS (Cross-Origin Resource Sharing) для обработки запросов с разных доменов
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["GET, POST"],
allow_headers=["*"],
)
# Инициализация и загрузка модели Whisper для распознавания речи
cache_dir = "/tmp/whisper_cache"
os.makedirs(cache_dir, exist_ok=True)
whisper_model = whisper.load_model("tiny", download_root=cache_dir)
# загрузка параметров модели
filepath = "best_model.keras"
if not os.path.exists(filepath):
raise FileNotFoundError(f"Model file not found at {filepath}")\
model = tf.keras.models.load_model(filepath, compile=False)
logging.info(model.summary())
# Контекстный менеджер для временных аудио файлов
@contextmanager
def temporary_audio_file(audio_bytes):
"""
Создает временный файл для хранения аудио данных и автоматически удаляет его после использования
"""
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp_file:
tmp_file.write(audio_bytes)
tmp_file.flush()
tmp_filename = tmp_file.name
try:
yield tmp_filename
finally:
if os.path.exists(tmp_filename):
os.remove(tmp_filename)
# Корневой endpoint
@app.get("/")
async def read_root():
return {"message": "Welcome to the Defects_model API"}
# Endpoint для сохранения аудио файлов
@app.post("/save-audio")
async def save_audio(file: UploadFile = File(...)):
"""
Обработчик для сохранения загруженных аудио файлов
"""
if not file.content_type.startswith("audio/"):
raise HTTPException(status_code=400, detail="Invalid file type")
file_path = os.path.join("audio", file.filename)
os.makedirs("audio", exist_ok=True)
try:
with open(file_path, "wb") as f:
content = await file.read()
f.write(content)
return JSONResponse(
content={"message": "File saved successfully", "filePath": file_path},
status_code=200,
)
except Exception as e:
return JSONResponse(content={"error": str(e)}, status_code=500)
# Настройка пути для файла логов
log_file_path = os.path.join("/tmp", "server.log")
# Настройка логирования для отслеживания работы сервера
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
handlers=[logging.StreamHandler()]
)
# Основной endpoint для обработки аудио
@app.post("/process-audio")
async def process_audio(
audio: UploadFile = File(...),
phrase: str = Form(...)
):
"""
Главный обработчик для анализа аудио файлов:
- Делает предсказание моделью
- Прогоняет аудио через openai-whisper для проверки фразы
- Сравнивает полученный текст с ожидаемой фразой
"""
# Проверка формата файла
if audio.content_type != "audio/mpeg":
raise HTTPException(
status_code=400, detail="Invalid file type. Only MP3 files are supported."
)
try:
# Чтение аудио файла
audio_bytes = await audio.read()
if not audio_bytes:
raise HTTPException(status_code=400, detail="Received empty file")
logging.info(f"Received audio bytes: {len(audio_bytes)} bytes")
# Обработка аудио во временном файле
with temporary_audio_file(audio_bytes) as tmp_filename:
logging.info(f"Temporary file created: {tmp_filename}")
# Загрузка аудио данных
audio_data, sample_rate = librosa.load(tmp_filename, sr=None)
logging.info(
f"Audio loaded: sample rate = {sample_rate}, data shape = {audio_data.shape}"
)
if not audio_data.any() or sample_rate == 0:
raise ValueError("Empty or invalid audio data.")
# Извлечение признаков из аудио
features = get_features(tmp_filename)
# features = np.expand_dims(features, axis=0) # Add batch dimension
logging.info(f"Features extracted: shape = {features.shape}")
# Получение предсказания от модели
class_weights = {0: 0.5460790960451978, 1: 1.0068333333333332, 2: 1000.696369636963697}
prediction = model.predict(features)
logging.info(f"Prediction shape: {prediction.shape}")
#умножаем предикт на веса классов
for j in range(prediction.shape[1]):
prediction[0, j] *= class_weights.get(j, 1.0)
prediction[0, j] *= 10
logging.info(f"Prediction: {prediction}")
response_answer = np.argmax(prediction)
if (response_answer == 0):
response_answer = 1
else:
response_answer = 0
logging.info(f"Right or with defects: 1 or 0: {response_answer}")
# Транскрибация аудио с помощью Whisper
transcription_result = whisper_model.transcribe(tmp_filename, language="russian")
transcribed_text = transcription_result["text"].lower().strip()
# Очистка транскрибированного текста
transcribed_text_clean = re.sub(r'[^\w\s]', '', transcribed_text)
logging.info(f"Transcribed text (cleaned): {transcribed_text_clean}")
# Сравнение с ожидаемой фразой
lev_distance = Levenshtein.distance(transcribed_text_clean, phrase.lower().strip())
phrase_length = max(len(transcribed_text_clean), len(phrase))
# Определение допустимого расстояния Левенштейна
max_acceptable_distance = 0.5 * phrase_length
match_phrase = lev_distance <= max_acceptable_distance
logging.info(f"Expected phrase: {phrase}, Is correct: {match_phrase}, Transcribed text: {transcribed_text_clean}, Levenshtein distance: {lev_distance}")
# Возврат результатов
return {
"prediction": response_answer,
"match_phrase": match_phrase
}
except Exception as e:
logging.exception(f"Error processing audio: {e}")
raise HTTPException(status_code=500, detail="Internal server error") |