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
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)
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})
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})
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__})
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__})
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
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))
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__ })
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.
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))
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)
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()
def setUp(self): self.database_conn = get_database() self.cursor = self.database_conn.cursor()
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})