yufii commited on
Commit
ff9511c
·
verified ·
1 Parent(s): 0974625

Upload 10 files

Browse files
Files changed (10) hide show
  1. .gitattributes +36 -36
  2. README.md +12 -12
  3. app.py +57 -26
  4. forms.py +9 -0
  5. main.py +85 -0
  6. models.py +28 -0
  7. requirements.txt +9 -5
  8. test.py +23 -0
  9. test_audio.mp3 +0 -0
  10. utils.py +117 -0
.gitattributes CHANGED
@@ -1,36 +1,36 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
36
- cnn_1_v6_final_model.keras filter=lfs diff=lfs merge=lfs -text
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.keras filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,12 +1,12 @@
1
- ---
2
- title: Speech Model
3
- emoji: 🏢
4
- colorFrom: yellow
5
- colorTo: blue
6
- sdk: streamlit
7
- sdk_version: 1.38.0
8
- app_file: app.py
9
- pinned: false
10
- ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
+ ---
2
+ title: Speech Model
3
+ emoji: 🏢
4
+ colorFrom: yellow
5
+ colorTo: blue
6
+ sdk: streamlit
7
+ sdk_version: 1.38.0
8
+ app_file: app.py
9
+ pinned: false
10
+ ---
11
+
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py CHANGED
@@ -1,26 +1,57 @@
1
- from fastapi import FastAPI, File, UploadFile, HTTPException
2
- import librosa
3
- import torch
4
- import io
5
- from fastapi.responses import JSONResponse
6
- import os
7
- import requests
8
-
9
- app = FastAPI()
10
-
11
-
12
- @app.post("/save-audio")
13
- async def save_audio(file: UploadFile = File(...)):
14
- if not file.content_type.startswith('audio/'):
15
- raise HTTPException(status_code=400, detail="Invalid file type")
16
-
17
- file_path = os.path.join("audio", file.filename)
18
- os.makedirs("audio", exist_ok=True)
19
-
20
- try:
21
- with open(file_path, "wb") as f:
22
- content = await file.read()
23
- f.write(content)
24
- return JSONResponse(content={"message": "File saved successfully", "filePath": file_path}, status_code=200)
25
- except Exception as e:
26
- return JSONResponse(content={"error": str(e)}, status_code=500)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, File, UploadFile, HTTPException
2
+ from models import User, Course, connection
3
+ from forms import UserRegistration, UserLoginForm
4
+ from fastapi.responses import JSONResponse
5
+ from utils import create_cnn_model, get_features, extract_features, pad_or_trim, noise, stretch, pitch
6
+ from peewee import *
7
+ import numpy as np
8
+ import tensorflow as tf
9
+ import keras
10
+ import requests
11
+ import io
12
+ import os
13
+
14
+ app = FastAPI()
15
+
16
+
17
+ @app.post("/save-audio")
18
+ async def save_audio(file: UploadFile = File(...)):
19
+ if not file.content_type.startswith("audio/"):
20
+ raise HTTPException(status_code=400, detail="Invalid file type")
21
+
22
+ file_path = os.path.join("audio", file.filename)
23
+ os.makedirs("audio", exist_ok=True)
24
+
25
+ try:
26
+ with open(file_path, "wb") as f:
27
+ content = await file.read()
28
+ f.write(content)
29
+ return JSONResponse(
30
+ content={"message": "File saved successfully", "filePath": file_path},
31
+ status_code=200,
32
+ )
33
+ except Exception as e:
34
+ return JSONResponse(content={"error": str(e)}, status_code=500)
35
+
36
+ model = tf.keras.models.load_model("cnn_1_v6_final_model.keras", compile=False)
37
+
38
+ @app.post("/process-audio")
39
+ async def process_audio(audio: UploadFile = File(...)):
40
+ if audio.content_type != "audio/mpeg":
41
+ raise HTTPException(
42
+ status_code=400, detail="Invalid file type. Please upload an MP3 file."
43
+ )
44
+
45
+ audio_bytes = await audio.read()
46
+
47
+ features = get_features(audio_bytes)
48
+
49
+ if features is None:
50
+ raise HTTPException(
51
+ status_code=400,
52
+ detail="Invalid audio file. Please upload a valid MP3 file.",
53
+ )
54
+
55
+ prediction = model.predict(np.expand_dims(features, axis=0))
56
+
57
+ return {"prediction": prediction}
forms.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+
3
+ class UserRegistration(BaseModel):
4
+ login: str
5
+ password: str
6
+
7
+ class UserLoginForm(BaseModel):
8
+ login: str
9
+ password: str
main.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, File, UploadFile, HTTPException
2
+ from models import User, Course, connection
3
+ from forms import UserRegistration, UserLoginForm
4
+ from fastapi.responses import JSONResponse
5
+ from utils import create_cnn_model, get_features, extract_features, pad_or_trim, noise, stretch, pitch
6
+ from peewee import *
7
+ import numpy as np
8
+ import tensorflow as tf
9
+ import keras
10
+ import requests
11
+ import io
12
+ import os
13
+
14
+ from fastapi.middleware.cors import CORSMiddleware
15
+
16
+ app = FastAPI()
17
+
18
+ app.add_middleware(
19
+ CORSMiddleware,
20
+ allow_origins=["*"],
21
+ allow_credentials=True,
22
+ allow_methods=["*"],
23
+ allow_headers=["*"],
24
+ )
25
+
26
+ UPLOAD_DIR = 'audio'
27
+ os.makedirs(UPLOAD_DIR, exist_ok=True)
28
+
29
+ MODEL_SERVER_URL = "http://model-server-url/predict"
30
+
31
+ @app.post("/save-audio")
32
+ async def save_audio(file: UploadFile = File(...)):
33
+ if not file.content_type.startswith('audio/'):
34
+ raise HTTPException(status_code=400, detail="Invalid file type")
35
+
36
+ file_path = os.path.join(UPLOAD_DIR, file.filename)
37
+
38
+ try:
39
+ with open(file_path, "wb") as f:
40
+ content = await file.read()
41
+ f.write(content)
42
+ return JSONResponse(content={"message": "File saved successfully", "filePath": file_path}, status_code=200)
43
+ except Exception as e:
44
+ return JSONResponse(content={"error": str(e)}, status_code=500)
45
+
46
+
47
+ model = tf.keras.models.load_model("cnn_1_v6_final_model.keras", compile=False)
48
+
49
+ @app.post("/process-audio")
50
+ async def process_audio(audio: UploadFile = File(...)):
51
+ if audio.content_type != "audio/mpeg":
52
+ raise HTTPException(status_code=400, detail="Invalid file type. Please upload an MP3 file.")
53
+
54
+ audio_bytes = await audio.read()
55
+
56
+ features = get_features(audio_bytes)
57
+
58
+ if features is None:
59
+ raise HTTPException(status_code=400, detail="Invalid audio file. Please upload a valid MP3 file.")
60
+
61
+ prediction = model.predict(np.expand_dims(features, axis=0))
62
+
63
+ return {"prediction": prediction}
64
+
65
+
66
+ '''
67
+ @router.post("/login")
68
+ async def login(user_data: UserLoginForm):
69
+ user = User.get(User.login == user_data.login)
70
+ if not user or user_data.password != user.password:
71
+ return {"message": "Invalid login or password"}
72
+ token_content = {"user_id": user.user_id}
73
+ jwt_token = jwt.encode(token_content, SECRET_KEY, algorithm=ALGORITHM)
74
+ return {"token": jwt_token}
75
+
76
+
77
+ @router.post("/registration")
78
+ async def registration(user_data: UserRegistration):
79
+ try:
80
+ new_user = User.create(login=user_data.login, password=user_data.password)
81
+ new_user.save()
82
+ return {"message": "User registered successfully"}
83
+ except IntegrityError:
84
+ return {"message": "User with this login already exists"}
85
+ '''
models.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from peewee import *
2
+
3
+ connection = SqliteDatabase('database.db')
4
+
5
+
6
+
7
+ class BaseModel(Model):
8
+ class Meta:
9
+ database = connection
10
+
11
+ class User(BaseModel):
12
+ user_id = AutoField()
13
+ login = CharField(unique=True)
14
+ password = CharField()
15
+
16
+ class Meta:
17
+ db_table = 'Users'
18
+ order_by = ('user_id',)
19
+
20
+
21
+ class Course(BaseModel):
22
+ course_id = AutoField()
23
+ name = CharField()
24
+ progress = IntegerField()
25
+
26
+ class Meta:
27
+ db_table = 'Courses'
28
+ order_by = ('course_id',)
requirements.txt CHANGED
@@ -1,5 +1,9 @@
1
- fastapi
2
- uvicorn
3
- torch
4
- librosa
5
- requests
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ torch
4
+ librosa
5
+ requests
6
+ keras
7
+ requests
8
+ io
9
+ os
test.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import httpx
2
+ import asyncio
3
+
4
+ def test_get_answer(audio_file_path: str):
5
+ url = "http://127.0.0.1:8000/process-audio"
6
+ headers = {
7
+ "accept": "application/json",
8
+ }
9
+
10
+ # Загрузить файл
11
+ with open(audio_file_path, "rb") as audio_file:
12
+ files = {
13
+ "audio": ("test.mp3", audio_file, "audio/mpeg")
14
+ }
15
+
16
+ response = httpx.post(url, headers=headers, files=files)
17
+
18
+ print("Status Code:", response.status_code)
19
+ print("Response JSON:", response.json())
20
+
21
+
22
+ audio_file_path = "test_audio.mp3"
23
+ test_get_answer(audio_file_path)
test_audio.mp3 ADDED
Binary file (2.71 kB). View file
 
utils.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import librosa
2
+ import numpy as np
3
+ from keras import layers, models
4
+
5
+ def create_cnn_model(input_shape):
6
+ model = models.Sequential()
7
+
8
+ # First Convolutional Layer
9
+ model.add(layers.Conv1D(32, 3, activation='relu', input_shape=input_shape))
10
+ model.add(layers.MaxPooling1D(pool_size=2))
11
+
12
+ # Second Convolutional Layer
13
+ model.add(layers.Conv1D(64, 3, activation='relu'))
14
+ model.add(layers.MaxPooling1D(pool_size=2))
15
+
16
+ # Flatten layer
17
+ model.add(layers.Flatten())
18
+
19
+ # Dense layers
20
+ model.add(layers.Dense(128, activation='relu', input_shape=input_shape))
21
+ model.add(layers.Dense(256, activation='relu', input_shape=input_shape))
22
+ model.add(layers.Dense(512, activation='relu', input_shape=input_shape))
23
+ model.add(layers.Dense(512, activation='relu', input_shape=input_shape))
24
+ model.add(layers.Dense(256, activation='relu', input_shape=input_shape))
25
+ model.add(layers.Dense(128, activation='relu', input_shape=input_shape))
26
+
27
+ # Output layer
28
+ model.add(layers.Dense(1, activation='sigmoid'))
29
+
30
+ return model
31
+
32
+
33
+ def get_features(path, duration=6):
34
+ try:
35
+ # Load audio file with specific duration and offset to handle silent parts
36
+ data, sample_rate = librosa.load(path, duration=2.5, offset=0.6)
37
+ except Exception as e:
38
+ print(f"Error loading {path}: {e}")
39
+ return None # Skip the file if there's an error
40
+
41
+ # Without augmentation
42
+ res1 = extract_features(data, sample_rate)
43
+ result = np.array(res1)
44
+
45
+ # With noise
46
+ noise_data = noise(data)
47
+ res2 = extract_features(noise_data, sample_rate)
48
+ result = np.vstack((result, res2))
49
+
50
+ # Stretching and pitching
51
+ new_data = stretch(data)
52
+ data_stretch_pitch = pitch(new_data, sample_rate)
53
+ res3 = extract_features(data_stretch_pitch, sample_rate)
54
+ result = np.vstack((result, res3))
55
+
56
+ return result
57
+
58
+
59
+ def extract_features(data, sample_rate, target_shape=40):
60
+ result = np.array([])
61
+
62
+ # ZCR
63
+ zcr = librosa.feature.zero_crossing_rate(y=data)
64
+ zcr = np.mean(zcr.T, axis=0)
65
+ zcr = pad_or_trim(zcr, target_shape)
66
+ result = np.hstack((result, zcr))
67
+
68
+ # Chroma_stft
69
+ stft = np.abs(librosa.stft(data))
70
+ chroma_stft = librosa.feature.chroma_stft(S=stft, sr=sample_rate)
71
+ chroma_stft = np.mean(chroma_stft.T, axis=0)
72
+ chroma_stft = pad_or_trim(chroma_stft, target_shape)
73
+ result = np.hstack((result, chroma_stft))
74
+
75
+ # MFCC
76
+ mfcc = librosa.feature.mfcc(y=data, sr=sample_rate, n_mfcc=13)
77
+ mfcc = np.mean(mfcc.T, axis=0)
78
+ mfcc = pad_or_trim(mfcc, target_shape)
79
+ result = np.hstack((result, mfcc))
80
+
81
+ # Root Mean Square Value
82
+ rms = librosa.feature.rms(y=data)
83
+ rms = np.mean(rms.T, axis=0)
84
+ rms = pad_or_trim(rms, target_shape)
85
+ result = np.hstack((result, rms))
86
+
87
+ # MelSpectrogram
88
+ mel = librosa.feature.melspectrogram(y=data, sr=sample_rate)
89
+ mel = np.mean(mel.T, axis=0)
90
+ mel = pad_or_trim(mel, target_shape)
91
+ result = np.hstack((result, mel))
92
+
93
+ return result
94
+
95
+
96
+ def pad_or_trim(feature, target_shape):
97
+ """Pad or trim feature array to ensure a consistent shape."""
98
+ if len(feature) > target_shape:
99
+ feature = feature[:target_shape]
100
+ elif len(feature) < target_shape:
101
+ feature = np.pad(feature, (0, target_shape - len(feature)), mode='constant')
102
+ return feature
103
+
104
+
105
+ def noise(data, noise_factor=0.005):
106
+ noise_amp = noise_factor * np.random.uniform() * np.amax(data)
107
+ data = data + noise_amp * np.random.normal(size=data.shape[0])
108
+ return data
109
+
110
+ def stretch(data, rate=0.8):
111
+ return librosa.effects.time_stretch(data, rate=rate)
112
+
113
+ def pitch(data, sample_rate, pitch_factor=0.7):
114
+ return librosa.effects.pitch_shift(data, sr=sample_rate, n_steps=pitch_factor)
115
+
116
+
117
+