import numpy as np import librosa from pathlib import Path import hashlib from cryptography.fernet import Fernet import os import json class VoicePrint: def __init__(self, hive_home): self.hive_home = Path(hive_home) self.vp_dir = self.hive_home / "users" / "voiceprints" self.vp_dir.mkdir(parents=True, exist_ok=True) self.key = os.getenv("VP_KEY", Fernet.generate_key().decode()) self.cipher = Fernet(self.key.encode()) self.users_file = self.hive_home / "users" / "profiles.json" self.users = self.load_users() def load_users(self): if self.users_file.exists(): return json.loads(self.users_file.read_text()) return {} def save_users(self): self.users_file.write_text(json.dumps(self.users, indent=2)) def extract_features(self, audio_path): try: y, sr = librosa.load(str(audio_path), sr=16000) mfcc = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=20) return np.hstack([np.mean(mfcc, axis=1), np.std(mfcc, axis=1)]) except: return np.zeros(40) def enroll(self, audio_path, user_id): features = self.extract_features(audio_path) encrypted = self.cipher.encrypt(features.tobytes()) fp = self.vp_dir / f"{user_id}.vp" fp.write_bytes(encrypted) # Update user profile if user_id not in self.users: self.users[user_id] = {"id": user_id, "voice_enrolled": True} else: self.users[user_id]["voice_enrolled"] = True self.save_users() return True def verify(self, audio_path, user_id): stored_fp = self.vp_dir / f"{user_id}.vp" if not stored_fp.exists(): return 0.0 try: encrypted = stored_fp.read_bytes() decrypted = self.cipher.decrypt(encrypted) stored = np.frombuffer(decrypted, dtype=np.float64) current = self.extract_features(audio_path) if np.linalg.norm(current) == 0 or np.linalg.norm(stored) == 0: return 0.0 return np.dot(stored, current) / (np.linalg.norm(stored) * np.linalg.norm(current)) except: return 0.0 def identify(self, audio_path): current = self.extract_features(audio_path) if np.linalg.norm(current) == 0: return None best_score = 0.0 best_user = None for fp in self.vp_dir.glob("*.vp"): user_id = fp.stem score = self.verify(audio_path, user_id) if score > best_score and score >= 0.7: best_score = score best_user = user_id return best_user