import librosa
import tensorflow as tf
import numpy as np

SAVED_MODEL_PATH = "model_weights_acc_new.h5"
SAMPLES_TO_CONSIDER = 22050

class _modelFin:

    model = None
    _mapping = [
        "children_playing",
        "children_playing2",
        "children_playing3",
        "children_playing4",
        "children_playing5"
    ]

    _instance = None


    def predict(self, file_path):
        
        # extract MFCC
        MFCCs = self.preprocess(file_path)

        # 4-dim array to feed to the model for prediction: (# samples, # time steps, # coefficients, 1)
        MFCCs = MFCCs[np.newaxis, ..., np.newaxis]

        # get the predicted label
        predictions = self.model.predict(MFCCs)
        predicted_index = np.argmax(predictions)
        predicted_keyword = self._mapping[predicted_index]
        return predicted_keyword


    def preprocess(self, file_path, num_mfcc=40, n_fft=2048, hop_length=512):
        
        # load audio file
        signal, sample_rate = librosa.load(file_path)

        if len(signal) >= SAMPLES_TO_CONSIDER:
            # ensure consistency of the length of the signal
            signal = signal[:SAMPLES_TO_CONSIDER]

            # extract MFCCs
            MFCCs = librosa.feature.mfcc(signal, sample_rate, n_mfcc=num_mfcc, n_fft=n_fft,
                                         hop_length=hop_length)
        return MFCCs.T

def modelFin():
    
    # ensure an instance is created only the first time the factory function is called
    if _modelFin._instance is None:
        _modelFin._instance = _modelFin()
        _modelFin.model = tf.keras.models.load_model(SAVED_MODEL_PATH)
    return _modelFin._instance


if __name__ == "__main__":

    # create 2 instances of service
    kss = modelFin()
    kss1 = modelFin()

    # check that different instances of the service point back to the same object
    assert kss is kss1

    # make a prediction
    keyword = kss.predict("100263-2-0-117.wav")
    print(keyword)