Exemple #1
0
def validate_username(username):
    if username is None:
        return error("Username required.", "No username was provided.")

    if not isinstance(username, str):
        return error("Username is not a string.",
                     "Username must be text, not only numbers.")

    if len(username) < 8:
        return error("Username is not long enough.",
                     "Username must be at least 8 characters.")

    database_conn = get_database()
    cursor = database_conn.cursor()

    cursor.execute(
        """
                    SELECT COUNT(*) 
                    FROM public."User"
                    WHERE username=(%s);
                    """, (username, ))

    count = cursor.fetchone()[0]
    cursor.close()
    database_conn.close()

    if count is not 0:
        return error(
            "Username already exists.",
            "A user with the username {} already exists.".format(username))

    return True
Exemple #2
0
def create_user(username, password, role):
    auth_token, auth_expiry = get_auth_token()

    database_conn = get_database()
    cursor = database_conn.cursor()

    cursor.execute(
        """
                    INSERT INTO
                    public."User"
                    (username, password, role, auth_token, auth_expiry)
                    VALUES (%s, %s, %s, %s, %s)
                    RETURNING id, username;
                    """, (username, PasswordHasher().hash(password), role,
                          auth_token, auth_expiry))

    # Commit the transaction.
    database_conn.commit()

    # Close connections.
    attrs = cursor.fetchone()[0]
    cursor.close()
    database_conn.close()

    # Return the user object.
    return User(attrs[0], attrs[1], auth_token, role)
Exemple #3
0
def post(participant_id, data_file, activity_name, trial_num):
    # Validate the input.
    if participant_id is None:
        return error("participant_id is required.", "We need a participant ID to link the trial to.")

    if activity_name is None:
        return error("activity_name is required.", "We need to know the activity so that we can train the AI.")

    if data_file is None:
        return error("file is required.", "There was no file associated with the request."
                                          "The file should contain the raw accelerometer data.")

    if trial_num is None:
        return error("trial_num is required.", "We need a trial number link the trial to.")

    # Convert trial file to bytes.
    data = data_file.read()

    # Store the data in the database.
    database_conn = get_database()
    cursor = database_conn.cursor()
    cursor.execute("""
                    INSERT INTO 
                    public."Trial" 
                    (participant_id, filename, data, trial_num) 
                    VALUES (%s, %s, %s, %s) 
                    RETURNING id;
                    """, (participant_id, data_file.filename, data, trial_num))

    # Commit the transaction.
    database_conn.commit()

    # Get the ID of the new trial.
    idx = cursor.fetchone()[0]

    # Get the targets for the activity.
    targets = Target.get_targets(activity_name)

    # Make an entry for each target.
    for target in targets:
        cursor.execute("""
                        INSERT INTO 
                        public."Target" 
                        (trial_id, activity_id) 
                        VALUES (%s, %s);
                        """, (idx, target))

    # Commit the transaction.
    database_conn.commit()

    # Close the connections.
    cursor.close()
    database_conn.close()

    return success("Trial added for participant: {}, activity: {}.".format(participant_id, activity_name))
def get():
    models = []
    database_conn = get_database()
    cursor = database_conn.cursor()
    cursor.execute("""
                    SELECT name, description 
                    FROM public."Model"
                    ORDER BY name ASC;
                    """)

    for model in cursor.fetchall():
        models.append({"name": model[0], "description": model[1]})

    cursor.close()
    database_conn.close()
    return jsonify({"models": models})
Exemple #5
0
def get():
    activities = []
    database_conn = get_database()
    cursor = database_conn.cursor()
    cursor.execute("""
                    SELECT id, name 
                    FROM public."Activity" 
                    ORDER BY id ASC;
                    """)

    for activity in cursor.fetchall():
        activities.append(Activity(activity[0], activity[1]).__dict__)

    cursor.close()
    database_conn.close()
    return jsonify({"activities": activities})
Exemple #6
0
def get(user):
    trials = []
    database_conn = get_database()
    cursor = database_conn.cursor()
    cursor.execute("""
                    SELECT id, participant_id, filename, data
                    FROM public."Trial";
                    """)

    for attrs in cursor:
        trials.append(Trial(attrs[0], attrs[1], attrs[2], attrs[3]).__dict__)

    cursor.close()
    database_conn.close()

    if user is None:
        return jsonify({"trials": trials})
    else:
        return jsonify({"trials": trials, "user": user.__dict__})
Exemple #7
0
def get(user):
    features = []
    database_conn = get_database()
    cursor = database_conn.cursor()
    cursor.execute("""
                    SELECT id, "meanXYZ", "stdXYZ"
                    FROM public."Featureset_1";
                    """)

    for attrs in cursor:
        features.append(Featureset1(attrs[0], attrs[1], attrs[2]).__dict__)

    cursor.close()
    database_conn.close()

    if user is None:
        return jsonify({"features": features})
    else:
        return jsonify({"features": features, "user": user.__dict__})
Exemple #8
0
def is_authenticated(auth_token):
    if auth_token is None:
        return False

    database_conn = get_database()
    cursor = database_conn.cursor()

    cursor.execute(
        """
                    SELECT COUNT(*)
                    FROM public."User"
                    WHERE auth_token=%s
                    AND auth_expiry > %s;
                    """, (auth_token, time()))
    count = cursor.fetchone()[0]

    cursor.close()
    database_conn.close()
    return count > 0
Exemple #9
0
def post(idx, dom_hand, watch_hand, gender):
    # Validate the input.
    if None in [idx, dom_hand, watch_hand, gender]:
        return error(
            "Missing attributes.",
            "id, dom_hand, watch_hand, and gender are all required Participant fields."
        )

    # Get a database connection.
    database_conn = get_database()
    cursor = database_conn.cursor()

    # Check if the participant already exists.
    cursor.execute(
        """
                    SELECT COUNT(*)
                    FROM public."Participant"
                    WHERE id=%s;
                    """, (idx, ))
    count = cursor.fetchone()[0]

    # Return if the participant exists.
    if count != 0:
        return error("Participant already exists.",
                     "A participant with that ID has already been added.")

    # Add the new participant.
    cursor.execute(
        """
                    INSERT INTO
                    public."Participant"
                    (id, dom_hand, watch_hand, gender)
                    VALUES (%s, %s, %s, %s);
                    """, (idx, dom_hand, watch_hand, gender))

    # Commit and close the connection.
    database_conn.commit()
    cursor.close()
    database_conn.close()

    return success("Participant {} added.".format(idx))
Exemple #10
0
def get(idx):
    # Get a database connection.
    database_conn = get_database()
    cursor = database_conn.cursor()

    # If there's no ID, select all participants.
    if idx is None:
        cursor.execute("""
                        SELECT id, dom_hand, watch_hand, gender
                        FROM public."Participant";
                        """)

        # Create a list of json participants.
        participants = []
        for attrs in cursor.fetchall():
            participants.append(
                Participant(attrs[0], attrs[1], attrs[2], attrs[3]).__dict__)

        # Return all participants.
        return jsonify({"participants": participants})

    else:
        # Find the specific participant.
        cursor.execute(
            """
                        SELECT id, dom_hand, watch_hand, gender
                        FROM public."Participant"
                        WHERE id=%s;
                        """, (idx, ))
        attrs = cursor.fetchone()

        if attrs is None:
            return jsonify({"participant": None})
        else:
            # Return the json participant.
            return jsonify({
                "participant":
                Participant(attrs[0], attrs[1], attrs[2], attrs[3]).__dict__
            })
Exemple #11
0
from scripts.analysis import get_train_test_data, plot_confusion, get_best_classifier, get_trained_classifiers, \
    get_accuracy
from utils.db_utils import get_database
from random import shuffle
import numpy as np
import pickle


# Define the model name.
model_name = "fs1_diff_hands"
description = "Classifies whether the watch is on the user's dominant hand."

database_conn = get_database()
cursor = database_conn.cursor()

# Get the participant's information alongside the features.
cursor.execute("""
                SELECT "meanXYZ", "stdXYZ", dom_hand, watch_hand
                FROM public."Featureset_1" feature, public."Participant" ptct, public."Trial" trial
                WHERE trial.participant_id = ptct.id
                AND trial.id = feature.trial_id;
                """)

# Create a matrix of feature data.
features = [[attrs[0][0], attrs[0][1], attrs[0][2], attrs[1][0], attrs[1][1], attrs[1][2], attrs[2] == attrs[3]]
            for attrs in cursor.fetchall()]

# Shuffle the features to distribute them more randomly between users and trials.
shuffle(features)

# Create training data for classifying a user's dominant hand.
Exemple #12
0
def post(trial_id, file):
    if file is None:
        return error(
            "Featureset 1 file is missing.",
            "The POST request is missing the file containing feature data.")

    if trial_id is None:
        return error(
            "Featureset 1 trial_id is missing.",
            "The POST request to add a new feature is missing the trial_id attribute."
        )

    database_conn = get_database()
    cursor = database_conn.cursor()
    ids = []
    index = 0
    try:
        for line in file:
            index += 1

            # Get the features from the line.
            features = line.split(",")

            # Validate the length.
            if len(features) != 7:
                remove_files(database_conn, cursor, ids)
                cursor.close()
                database_conn.close()
                return error(
                    "The wrong amount of features were sent.",
                    "On line {} there were {} values instead of 7. "
                    "There should be 6 features and one target.".format(
                        index, len(features)))

            # Store the data in the database.
            cursor.execute(
                """
                            INSERT INTO 
                            public."Featureset_1" 
                            (meanXYZ, stdXYZ, trial_id) 
                            VALUES (%s, %s, %s) 
                            RETURNING id;
                            """,
                ([features[0], features[1], features[2]
                  ], [features[3], features[4], features[5]], trial_id))

            # Commit the transaction.
            database_conn.commit()

            # Get the ID and target of the new feature.
            idx = cursor.fetchone()[0]
            ids.append(idx)

        cursor.close()
        database_conn.close()
        return success("{} features added.".format(len(ids)))

    # Delete any database entries if there was an error.
    except ():
        remove_files(database_conn, cursor, ids)
        cursor.close()
        database_conn.close()
        return error("Error storing featureset.",
                     "An unknown error occurred on line {}.".format(index))
Exemple #13
0
def script():
    # Get a list of activity ids to use as targets.
    # activities = ["Walking", "Jogging", "Cycling", "Idle"]
    activities = ["Walking", "Jogging", "Cycling", "Writing", "Typing", "Idle"]
    # activities = ["Walking", "Jogging", "Cycling", "Writing", "Typing", "Sitting",
    #               "Standing", "On Phone (sit)", "On Phone (stand)"]

    activity_ids = [name_id_map[activity] for activity in activities]

    # Get a connection to the database.
    database_conn = get_database()
    cursor = database_conn.cursor()

    # Get the features relating to these activities.
    features = get_same_hand_features(cursor, activity_ids, False)

    # Shuffle the features to distribute them more randomly between users and trials.
    shuffle(features)

    # # Ensure there are the same number of features for each class.
    # class_counts = []
    # for activity_id in activity_ids:
    #     class_count = sum([1 for row in features if row[6] == activity_id])
    #     class_counts.append([activity_id, class_count])
    #
    # min_count = min([class_count[1] for class_count in class_counts])
    #
    # print("Min feature count = {}".format(min_count))
    #
    # for activity_id, class_count in class_counts:
    #     if class_count > min_count:
    #         rows = [row for row in features if row[6] == activity_id]
    #
    #         for row in rows[:-min_count]:
    #             features.remove(row)

    # Split the features into training and testing.
    x_train, x_test, y_train, y_test = get_train_test_data(
        features, range(0, 6), 6)

    # Train the classifiers.
    trained_classifiers = get_trained_classifiers(x_train, y_train)

    # Plot confusion matrices.
    conf_matrix = None
    for classifier in trained_classifiers:
        cnf = plot_confusion(classifier, activities, x_test, y_test)
        if conf_matrix is None:
            conf_matrix = cnf
        else:
            conf_matrix += cnf

    # Plot the total conf matrix.
    plot_confusion(None,
                   activities,
                   x_test,
                   y_test,
                   conf_matrix,
                   title="Activity Set 2")

    # features = get_same_hand_features(cursor, activity_ids, False)

    # Close the database connections.
    cursor.close()
    database_conn.close()

    # Measure their accuracies using the testing data.
    accuracies = [
        get_accuracy(classifier, x_test, y_test)
        for classifier in trained_classifiers
    ]

    # Print the accuracies of each algorithm.
    for classifier, accuracy in zip(trained_classifiers, accuracies):
        print("{} is {}% accurate".format(classifier.__class__.__name__,
                                          accuracy))

    # Get the best classifier for these features.
    classifier, accuracy = trained_classifiers[accuracies.index(
        max(accuracies))], max(accuracies)

    # Print result.
    print("Best classifier is: {}, with accuracy {}".format(
        classifier.__class__.__name__, accuracy))

    # Plot the confusion matrix of the best performing.
    plot_confusion(classifier, activities, x_test, y_test)
Exemple #14
0
def script():
    # Get a list of activity ids to use as targets.
    # activities = ["Walking", "Jogging", "Cycling", "Idle"]
    # activities = ["Walking", "Jogging", "Cycling", "Writing", "Typing", "Idle"]
    activities = [
        "Walking", "Jogging", "Cycling", "Writing", "Typing", "Sitting",
        "Standing", "On Phone (sit)", "On Phone (stand)"
    ]

    activity_ids = [name_id_map[activity] for activity in activities]

    targets = ["Idle", "Low", "Medium", "High"]

    # Get a connection to the database.
    database_conn = get_database()
    cursor = database_conn.cursor()

    # Get the features relating to these activities.
    features = get_features(cursor, activity_ids)

    # Shuffle the features to distribute them more randomly between users and trials.
    shuffle(features)

    # Split the features into training and testing.
    x_train, x_test, y_train, y_test = get_train_test_data(
        features, range(0, 6), 6)

    # Update the target values.
    y_train = [
        energy_id_map[name_id_map[activity_id]] for activity_id in y_train
    ]
    y_test = [
        energy_id_map[name_id_map[activity_id]] for activity_id in y_test
    ]

    # Train the classifiers.
    trained_classifiers = get_trained_classifiers(x_train, y_train)

    # Plot confusion matrices.
    conf_matrix = None
    for classifier in trained_classifiers:
        cnf = plot_confusion(classifier, targets, x_test, y_test)
        if conf_matrix is None:
            conf_matrix = cnf
        else:
            conf_matrix += cnf

    # Plot the total conf matrix.
    plot_confusion(None, targets, x_test, y_test, conf_matrix)

    # Measure their accuracies using the testing data.
    accuracies = [
        get_accuracy(classifier, x_test, y_test)
        for classifier in trained_classifiers
    ]

    # Print the accuracies of each algorithm.
    for classifier, accuracy in zip(trained_classifiers, accuracies):
        print("{} is {}% accurate".format(classifier.__class__.__name__,
                                          accuracy))

    # Get the best classifier for these features.
    classifier, accuracy = trained_classifiers[accuracies.index(
        max(accuracies))], max(accuracies)

    # Print result.
    print("Best classifier is: {}, with accuracy {}".format(
        classifier.__class__.__name__, accuracy))

    # Plot the confusion matrix of the best performing.
    plot_confusion(classifier, targets, x_test, y_test)

    idle_accuracy = conf_matrix[0][0] / sum(conf_matrix[0]) * 100
    low_accuracy = conf_matrix[1][1] / sum(conf_matrix[1]) * 100
    med_accuracy = conf_matrix[2][2] / sum(conf_matrix[2]) * 100
    high_accuracy = conf_matrix[3][3] / sum(conf_matrix[3]) * 100

    cnf_encoded = pickle.dumps(conf_matrix)
    classifier_encoded = pickle.dumps(classifier)
    accuracies_encoded = pickle.dumps({
        "Idle": idle_accuracy,
        "Low": low_accuracy,
        "Medium": med_accuracy,
        "High": high_accuracy
    })

    cursor.execute(
        """
                        INSERT INTO
                        public."Model" (data, name, description, target_accuracies, confusion_matrix)
                        VALUES (%s, %s, %s, %s, %s)
                        ON CONFLICT (name) DO UPDATE
                        SET data = %s,
                        target_accuracies = %s,
                        confusion_matrix = %s;
                        """,
        (classifier_encoded, model_name, description, accuracies_encoded,
         cnf_encoded, classifier_encoded, accuracies_encoded, cnf_encoded))
    database_conn.commit()

    # Close the database connections.
    cursor.close()
    database_conn.close()
Exemple #15
0
 def setUp(self):
     self.database_conn = get_database()
     self.cursor = self.database_conn.cursor()
Exemple #16
0
def login(auth_token, authorization):

    # Check if the user is authenticated through a token.
    if not is_authenticated(auth_token):

        # Check if credentials were provided.
        if (authorization is None) or ("Basic " not in authorization):
            return error(
                "Authorization not provided.",
                "Using Basic Auth, a username and password must be "
                "included in the header.")

        # Decode the username & password.
        authorization = b64decode(
            authorization.split("Basic ")[1]).decode("utf-8")
        username, password = authorization.split(":")

        # Ensure there is a valid username.
        if username is None:
            return error("Username not provided.",
                         "A username must be included in the header.")

        if not isinstance(username, str):
            return error(
                "Username is not valid.",
                "A username must be constituted of text and numbers.")

        # Check the password validity.
        valid = validate_password(password)
        if valid is not True:
            return valid

        # There's a valid password.
        database_conn = get_database()
        cursor = database_conn.cursor()

        # Get the id and password of the user.
        cursor.execute(
            """
                        SELECT id, password, role
                        FROM public."User"
                        WHERE username=(%s);
                        """, (username, ))
        attrs = cursor.fetchone()

        # Check if there is a user with that username.
        if attrs is None:
            cursor.close()
            database_conn.close()
            return error(
                "User doesn't exist.",
                "No user exists with that username. You should register an account."
            )

        idx = attrs[0]
        hashed_pwd = attrs[1]
        role = attrs[2]

        # Verify the passwords match.
        try:
            PasswordHasher().verify(hashed_pwd, password)

        # Handle the passwords not matching.
        except VerifyMismatchError:
            cursor.close()
            database_conn.close()
            return error(
                "Passwords don't match.",
                "The password supplied doesn't match the one stored.")

        # The passwords match. Create an auth token for the user.
        auth_token, expiry = get_auth_token()

        # Store the auth token.
        cursor.execute(
            """
                        UPDATE
                        public."User"
                        SET auth_token = %s, 
                            auth_expiry = %s
                        WHERE id = %s;
                        """, (auth_token, expiry, idx))

        # Commit the transaction.
        database_conn.commit()

        # Close the connections.
        cursor.close()
        database_conn.close()

        # Return the logged in user.
        return User(idx, username, auth_token, role)

    # The user is authenticated. Update the expiry date.
    expiry = get_auth_token()[1]

    database_conn = get_database()
    cursor = database_conn.cursor()

    cursor.execute(
        """
                    UPDATE
                    public."User"
                    SET auth_expiry = %s
                    WHERE auth_token=(%s)
                    RETURNING id, username, role;
                    """, (expiry, auth_token))

    # Commit the transaction.
    database_conn.commit()

    attrs = cursor.fetchone()
    cursor.close()
    database_conn.close()

    return User(attrs[0], attrs[1], auth_token, attrs[2])
def classify(acceleration_data, model_name):
    if acceleration_data is None:
        return error("Acceleration data not provided.",
                     "Post acceleration data in the request.")

    if model_name is None:
        return error(
            "Model name not provided.",
            "Post model_name in the request to dynamically select a model.")

    # Get the features from the data.
    features, time_intervals = get_features(acceleration_data, FEATURE_SET)

    # Connect to the database.
    database_conn = get_database()
    cursor = database_conn.cursor()

    cursor.execute(
        """
                    SELECT data, target_accuracies
                    FROM public."Model"
                    WHERE name = %s;
                    """, (model_name, ))
    response = cursor.fetchone()

    # Decode the response.
    classifier = pickle.loads(response[0])
    accuracies = pickle.loads(response[1])

    # Close the database connection.
    cursor.close()
    database_conn.close()

    # Predict the activities.
    predictions = classifier.predict(features)

    return_values = []
    if model_name.startswith("as1") or model_name.startswith("as2"):
        for activity_id, time_interval in zip(predictions, time_intervals):
            # Get the model's accuracy for the target.
            accuracy = accuracies[name_id_map[activity_id]]

            # Create a wrapper object.
            activity = Activity(int(activity_id), name_id_map[activity_id],
                                time_interval[0], time_interval[1], accuracy)

            # Add a key-value dictionary representation.
            return_values.append(activity.__dict__)

    if model_name.startswith("energy"):
        for energy_id, time_interval in zip(predictions, time_intervals):
            # Get the confidence score.
            accuracy = accuracies[energy_id_map[energy_id]]

            # Append the data.
            return_values.append({
                "id": int(energy_id),
                "name": energy_id_map[energy_id],
                "start_time": time_interval[0],
                "end_time": time_interval[1],
                "confidence": accuracy
            })

    if model_name.startswith("watch_hand"):
        for hand_id, time_interval in zip(predictions, time_intervals):
            hand = "left" if hand_id == LEFT_TARGET else "right"

            # Get the confidence score.
            accuracy = accuracies[hand]

            # Append the data.
            return_values.append({
                "id": int(hand_id),
                "name": hand,
                "start_time": time_interval[0],
                "end_time": time_interval[1],
                "confidence": accuracy
            })

    # Return the activities in json.
    return jsonify({"predictions": return_values})