dhruv2842 commited on
Commit
1f7ec3b
·
verified ·
1 Parent(s): 8dee43f

Upload 10 files

Browse files
app.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ from flask import Flask, request, jsonify
3
+ from flask_cors import CORS
4
+ from config.database import db
5
+ import numpy as np
6
+ import tempfile
7
+ import os
8
+ from voice_embedder import get_embedding, cosine_match
9
+
10
+ app = Flask(__name__)
11
+ CORS(app)
12
+
13
+ users_collection = db["users"]
14
+
15
+ # ---------------- Upload PIN audio ----------------
16
+ @app.route("/upload_pin", methods=["POST"])
17
+ def upload_pin():
18
+ if "pin_audio" not in request.files:
19
+ return jsonify({"error": "No audio file found"}), 400
20
+
21
+ audio_file = request.files["pin_audio"]
22
+ temp_path = tempfile.mktemp(suffix=".wav")
23
+ audio_file.save(temp_path)
24
+
25
+ try:
26
+ emb = get_embedding(temp_path).tolist()
27
+ except Exception as e:
28
+ return jsonify({"error": str(e)}), 500
29
+ finally:
30
+ os.remove(temp_path)
31
+
32
+ return jsonify({"message": "PIN processed successfully", "embedding": emb})
33
+
34
+ # ---------------- Signup ----------------
35
+ @app.route("/signup", methods=["POST"])
36
+ def signup():
37
+ data = request.json
38
+ required = ("name", "email", "password", "embedding")
39
+ if not all(k in data for k in required):
40
+ return jsonify({"error": "Missing fields"}), 400
41
+
42
+ if users_collection.find_one({"email": data["email"]}):
43
+ return jsonify({"error": "Email already exists"}), 400
44
+
45
+ new_user = {
46
+ "name": data["name"],
47
+ "email": data["email"],
48
+ "password": data["password"],
49
+ "embedding": data["embedding"]
50
+ }
51
+ users_collection.insert_one(new_user)
52
+ return jsonify({"message": "Signup successful!"})
53
+
54
+ # ---------------- Login ----------------
55
+ @app.route("/login", methods=["POST"])
56
+ def login():
57
+ if "pin_audio" not in request.files:
58
+ return jsonify({"error": "Audio file missing"}), 400
59
+
60
+ email = request.form.get("email")
61
+ user = users_collection.find_one({"email": email})
62
+ if not user:
63
+ return jsonify({"error": "User not found"}), 404
64
+
65
+ audio_file = request.files["pin_audio"]
66
+ temp_path = tempfile.mktemp(suffix=".wav")
67
+ audio_file.save(temp_path)
68
+
69
+ try:
70
+ new_emb = get_embedding(temp_path)
71
+ saved_emb = np.array(user["embedding"], dtype=np.float32)
72
+ score, status = cosine_match(saved_emb, new_emb)
73
+ except Exception as e:
74
+ return jsonify({"error": str(e)}), 500
75
+ finally:
76
+ os.remove(temp_path)
77
+
78
+ return jsonify({"score": score, "status": status})
79
+
80
+ # ---------------- Home ----------------
81
+ @app.route("/")
82
+ def home():
83
+ return jsonify({"message": "VoiceAuth Backend Running"})
84
+
85
+ if __name__ == "__main__":
86
+ app.run(port=5000, debug=True)
config/__pycache__/database.cpython-313.pyc ADDED
Binary file (960 Bytes). View file
 
config/database.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pymongo import MongoClient
2
+ import certifi
3
+
4
+ MONGO_URI = "mongodb+srv://kataricoder_db_user:katari@cluster0.bfn51lm.mongodb.net/?retryWrites=true&w=majority"
5
+
6
+ try:
7
+ client = MongoClient(
8
+ MONGO_URI,
9
+ tls=True,
10
+ tlsCAFile=certifi.where() # Fix SSL handshake
11
+ )
12
+
13
+ db = client["mydatabase"]
14
+
15
+ client.admin.command("ping")
16
+
17
+ # FIXED: Correct PyMongo update query
18
+ db.users.update_many({}, {"$unset": {"voiceEmbedding": ""}})
19
+
20
+ print("🚀 MongoDB Connected Successfully!")
21
+
22
+ except Exception as e:
23
+ print("❌ MongoDB Connection Failed:", e)
models/__pycache__/user_model.cpython-313.pyc ADDED
Binary file (331 Bytes). View file
 
models/user_model.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # This file only defines your User schema structure
2
+
3
+ def user_schema(name, email, password, embedding):
4
+ return {
5
+ "name": name,
6
+ "email": email,
7
+ "password": password,
8
+ "embedding": embedding # vector (list of floats)
9
+ }
10
+
requirements.txt ADDED
Binary file (418 Bytes). View file
 
routes/__pycache__/user_routes.cpython-313.pyc ADDED
Binary file (1.72 kB). View file
 
routes/user_routes.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Blueprint, request, jsonify
2
+ from config.database import db
3
+
4
+ users_collection = db["users"]
5
+
6
+ user_routes = Blueprint("user_routes", __name__)
7
+
8
+ @user_routes.route("/signup", methods=["POST"])
9
+ def signup():
10
+ data = request.json
11
+
12
+ required = ("name", "email", "password", "embedding")
13
+ if not all(k in data for k in required):
14
+ return jsonify({"error": "Missing fields"}), 400
15
+
16
+ if users_collection.find_one({"email": data["email"]}):
17
+ return jsonify({"error": "Email already exists"}), 400
18
+
19
+ new_user = {
20
+ "name": data["name"],
21
+ "email": data["email"],
22
+ "password": data["password"],
23
+ "embedding": data["embedding"],
24
+ }
25
+
26
+ users_collection.insert_one(new_user)
27
+
28
+ return jsonify({"message": "Signup successful"})
routes/voice_routes.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Blueprint, request, jsonify
2
+ import numpy as np
3
+ import tempfile
4
+ import os
5
+
6
+ from voice_embedder import get_embedding, cosine_match
7
+ from config.database import db
8
+
9
+ users_collection = db["users"]
10
+
11
+ voice_routes = Blueprint("voice_routes", __name__)
12
+
13
+ # --------------------------------------------------------
14
+ # UPLOAD PIN AUDIO FOR SIGNUP
15
+ # --------------------------------------------------------
16
+ @voice_routes.route("/upload_pin", methods=["POST"])
17
+ def upload_pin():
18
+ if "pin_audio" not in request.files:
19
+ return jsonify({"error": "No audio file found"}), 400
20
+
21
+ audio_file = request.files["pin_audio"]
22
+
23
+ temp_path = tempfile.mktemp(suffix=".wav")
24
+ audio_file.save(temp_path)
25
+
26
+ emb = get_embedding(temp_path).tolist()
27
+
28
+ os.remove(temp_path)
29
+
30
+ return jsonify({
31
+ "message": "PIN processed successfully",
32
+ "embedding": emb
33
+ })
34
+
35
+
36
+ # --------------------------------------------------------
37
+ # LOGIN WITH VOICE MATCH
38
+ # --------------------------------------------------------
39
+ @voice_routes.route("/login", methods=["POST"])
40
+ def login():
41
+ if "pin_audio" not in request.files:
42
+ return jsonify({"error": "Audio file missing"}), 400
43
+
44
+ email = request.form.get("email")
45
+ user = users_collection.find_one({"email": email})
46
+
47
+ if not user:
48
+ return jsonify({"error": "User not found"}), 404
49
+
50
+ audio_file = request.files["pin_audio"]
51
+ temp_path = tempfile.mktemp(suffix=".wav")
52
+ audio_file.save(temp_path)
53
+
54
+ new_emb = get_embedding(temp_path)
55
+ saved_emb = np.array(user["embedding"], dtype=np.float32)
56
+
57
+ score, status = cosine_match(saved_emb, new_emb)
58
+
59
+ os.remove(temp_path)
60
+
61
+ return jsonify({
62
+ "score": score,
63
+ "status": status
64
+ })
voice_embedder.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from sklearn.metrics.pairwise import cosine_similarity
3
+ import librosa
4
+ import noisereduce as nr
5
+ import torch
6
+ from transformers import AutoModelForAudioXVector
7
+
8
+ device = "cpu"
9
+
10
+ # Load model globally once
11
+ model = AutoModelForAudioXVector.from_pretrained(
12
+ "microsoft/wavlm-base-plus-sv"
13
+ ).to(device)
14
+
15
+
16
+ # ------------------------------------------------------------
17
+ # PREPROCESS AUDIO
18
+ # ------------------------------------------------------------
19
+ def preprocess(path):
20
+ y, sr = librosa.load(path, sr=16000)
21
+ y = nr.reduce_noise(y=y, sr=sr)
22
+ y, _ = librosa.effects.trim(y, top_db=25)
23
+ y = librosa.util.normalize(y)
24
+ return y
25
+
26
+
27
+ # ------------------------------------------------------------
28
+ # GET EMBEDDING
29
+ # ------------------------------------------------------------
30
+ def get_embedding(path):
31
+ y = preprocess(path)
32
+ audio = torch.tensor(y).float().unsqueeze(0).to(device)
33
+
34
+ with torch.no_grad():
35
+ outputs = model(audio)
36
+ emb = outputs.embeddings.cpu().numpy().squeeze()
37
+
38
+ emb = emb / np.linalg.norm(emb)
39
+ return emb.astype(np.float32)
40
+
41
+
42
+ # ------------------------------------------------------------
43
+ # COSINE MATCH
44
+ # ------------------------------------------------------------
45
+ def cosine_match(saved, new, threshold=0.75):
46
+ """Returns similarity score + authentication status"""
47
+
48
+ score = float(cosine_similarity([saved], [new])[0][0])
49
+
50
+ if score >= threshold:
51
+ return score, "Authenticated"
52
+ elif score >= 0.55:
53
+ return score, "Ask for PIN"
54
+ else:
55
+ return score, "Failed"