89 lines
2.9 KiB
Python
89 lines
2.9 KiB
Python
import argparse
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
import joblib
|
|
|
|
from audio_utils import SUPPORTED_AUDIO_EXTENSIONS, convert_to_wav
|
|
from features import LABEL_PD, LABEL_TPD, extract_features
|
|
|
|
|
|
BASE_DIR = Path(__file__).resolve().parent
|
|
MODEL_PATH = BASE_DIR / "models" / "svm_voice_confidence_model.joblib"
|
|
CONFIDENCE_THRESHOLD = 0.60
|
|
|
|
LABEL_DESCRIPTION = {
|
|
LABEL_PD: "Percaya Diri",
|
|
LABEL_TPD: "Tidak Percaya Diri",
|
|
}
|
|
|
|
|
|
def prepare_audio_for_prediction(audio_path):
|
|
"""
|
|
Menyiapkan audio prediksi menjadi WAV mono 22050 Hz.
|
|
Path hasil konversi dikembalikan bersama flag apakah file temporer perlu dihapus.
|
|
"""
|
|
audio_path = Path(audio_path)
|
|
extension = audio_path.suffix.lower()
|
|
|
|
if extension not in SUPPORTED_AUDIO_EXTENSIONS:
|
|
allowed = ", ".join(sorted(SUPPORTED_AUDIO_EXTENSIONS))
|
|
raise ValueError(f"Format audio tidak didukung: {extension}. Format yang didukung: {allowed}")
|
|
|
|
temp_wav_path = Path(tempfile.NamedTemporaryFile(delete=False, suffix=".wav").name)
|
|
convert_to_wav(audio_path, temp_wav_path)
|
|
return temp_wav_path
|
|
|
|
|
|
def predict_audio(audio_path, model_path=MODEL_PATH):
|
|
"""
|
|
Memprediksi satu file audio.
|
|
Audio diproses dengan preprocessing dan ekstraksi fitur yang sama seperti training.
|
|
"""
|
|
model = joblib.load(model_path)
|
|
|
|
temp_wav_path = prepare_audio_for_prediction(audio_path)
|
|
try:
|
|
features = extract_features(temp_wav_path).reshape(1, -1)
|
|
predicted_label = model.predict(features)[0]
|
|
probabilities = model.predict_proba(features)[0]
|
|
class_probabilities = dict(zip(model.classes_, probabilities))
|
|
confidence = class_probabilities[predicted_label]
|
|
finally:
|
|
temp_wav_path.unlink(missing_ok=True)
|
|
|
|
return predicted_label, LABEL_DESCRIPTION[predicted_label], confidence, class_probabilities
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Prediksi tingkat percaya diri dari audio")
|
|
parser.add_argument("audio_path", help="Path file audio yang ingin diprediksi")
|
|
args = parser.parse_args()
|
|
|
|
audio_path = Path(args.audio_path)
|
|
if not audio_path.exists():
|
|
raise FileNotFoundError(f"File tidak ditemukan: {audio_path}")
|
|
|
|
label, description, confidence, probabilities = predict_audio(audio_path)
|
|
|
|
probability_pd = probabilities.get(LABEL_PD, 0.0)
|
|
probability_tpd = probabilities.get(LABEL_TPD, 0.0)
|
|
|
|
print("=== Hasil Prediksi ===")
|
|
print(f"File : {audio_path}")
|
|
print(f"Prediksi : {label}")
|
|
print(f"Keterangan : {description}")
|
|
print(f"Confidence : {confidence * 100:.2f}%")
|
|
print(f"Probabilitas PD : {probability_pd * 100:.2f}%")
|
|
print(f"Probabilitas TPD : {probability_tpd * 100:.2f}%")
|
|
|
|
if confidence < CONFIDENCE_THRESHOLD:
|
|
print(
|
|
"Peringatan : Model belum yakin, suara perlu direkam ulang "
|
|
"atau data training perlu ditambah."
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|