Collections

Blog Python Model code and SQLite Database.

For this project, I have created a database called activities that stores the data for the locations and names of therapies. I have also added columns to the user database.

From VSCode using SQLite3 Editor, show your unique collection/table in database, display rows and columns in the table of the SQLite database.

Therapy SQLite Database:

image.png
Above shows therapy database with columns:

  • Name: The name of the therapy
  • Location: Where the Therapy is located
  • Special: The specialization of the therapy (ex. PTSD, Family Therapy, Relationship Therapy)

Therapy Database Code:

from random import randrange 
import json  

from __init__ import app, db  
from sqlalchemy.exc import IntegrityError

class Therapy(db.Model):  # Defining Therapy class as a subclass of db.Model from SQLAlchemy
    __tablename__ = 'therapies'  # Table name in the database

    # Defining columns of the table
    id = db.Column(db.Integer, primary_key=True)  
    _name = db.Column(db.String(255), unique=False, nullable=False)  
    _location = db.Column(db.String(255), unique=False, nullable=False)  
    _special = db.Column(db.String(255), unique=False, nullable=False) 

    def __init__(self, name, location, special):  # Constructor method for Therapy class
        self._name = name  
        self._location = location  
        self._special = special  

    @property
    def name(self):  # Getter method for name attribute
        return self._name
    
    @name.setter
    def name(self, name):  # Setter method for name attribute
        self._name = name
    
    @property
    def location(self):  # Getter method for location attribute
        return self._location
    
    @location.setter
    def location(self, location):  # Setter method for location attribute
        self._location = location
    
    @property
    def special(self):  # Getter method for special attribute
        return self._special
    
    @special.setter
    def special(self, special):  # Setter method for special attribute
        self._special = special
    
    def __str__(self):  # String representation of Therapy object
        return json.dumps(self.read())  # Converting Therapy object to JSON string

    def create(self):  # Method to create a new Therapy record in the database
        try:
            db.session.add(self)
            db.session.commit()
            return self  # Returning the created Therapy object
        except IntegrityError:  # Handling IntegrityError (e.g., duplicate key)
            db.session.remove()
            return None  # Returning None if creation fails


    def read(self):  # Method to read Therapy object attributes
        return {
            "id": self.id,  # Therapy ID
            "name": self.name,  # Therapy name
            "location": self.location,  # Therapy location
            "special": self.special,  # Therapy specialization
        }

From VSCode model, show your unique code that was created to initialize table and create test data.

Therapy Initialization Code (Testing Data):

def initTherapies():
    with app.app_context():
        db.create_all()
        therapies = [
            Therapy(name="Tranquil Haven Counseling Center", location="Suburban Retreat", special="General Counseling"),
            Therapy(name="Healing Waters Retreat", location="Riverside Sanctuary", special="Trauma Recovery"),
            Therapy(name="Family Harmony Center", location="Urban Oasis", special="Family Counseling"),
            Therapy(name="Sunrise Serenity Therapy Spa", location="Coastal Resort", special="Wellness Retreat"),
            Therapy(name="Inner Peace Sanctuary", location="Mountain Retreat", special="Mindfulness Therapy"),
            Therapy(name="Empowerment Pathways Center", location="Downtown Hub", special="Personal Growth Workshops"),
            Therapy(name="Whispering Winds Wellness Retreat", location="Countryside Haven", special="Stress Management"),
            Therapy(name="Safe Harbor Trauma Center", location="Seaside Refuge", special="PTSD Treatment"),
            Therapy(name="Hope Springs Counseling Oasis", location="Desert Sanctuary", special="Grief Counseling"),
            Therapy(name="Bright Horizons Counseling Collective", location="Community Center", special="Youth Counseling"),
            Therapy(name="Serenity Falls Therapy Retreat", location="Forest Hideaway", special="Addiction Recovery"),
            Therapy(name="Lighthouse Healing Institute", location="Lakeside Sanctuary", special="Depression Support"),
            Therapy(name="Tranquility Cove Wellness Center", location="Island Escape", special="Anxiety Relief"),
            Therapy(name="Phoenix Rising Counseling Center", location="Metropolitan Haven", special="Life Coaching"),
            Therapy(name="Golden Pathways Therapy Haven", location="Retreat Center", special="Spiritual Counseling")
        ]
        for therapy in therapies:
            try:
                therapy.create()
            except IntegrityError:
                db.session.rollback()
                print(f"Record exists")

Lists and Dictionaries

Blog Python API code and use of List and Dictionaries.

In VSCode using Debugger, show a list as extracted from database as Python objects.

Therapy Read List in Debugger: image.png When the frontend code fetches the data from the therapy database it sends a list of all the therapies from the database as shown above. The list returns all the information about the therapies as python objects.

In VSCode use Debugger and list, show two distinct example examples of dictionaries, show Keys/Values using debugger.

User Model Dictionary: image.png All the users registered are stored in the backend as dictionaries. In the debugger on the left [purple] there are keys (uid, name, sleep, diary, exercise, etc.) and the values are stored on the right [orange].

Therapy Model Dictionary: image.png The therapy data is stored in the backend also as dictionaries. There are less keys [purple] in this database (name, location, special). Values of the keys are on the right [orange]

APIs and JSON

Blog Python API code and use of Postman to request and respond with JSON.

In VSCode, show Python API code definition for request and response using GET, POST, UPDATE methods. Discuss algorithmic condition used to direct request to appropriate Python method based on request method.

Within the two APIs, user_api and activity_api, there are resources that direct to the appropriate request methods. With the appropriate link, and with the right prefix, the right function will be called when a request is sent from the frontend.

User API:

user_api = Blueprint('user_api', __name__,
                   url_prefix='/api/users')

api = Api(user_api)

class UserAPI:        
    class _CRUD(Resource):
        # Code here

    class _Security(Resource):
        # Code here
    
    class _Create(Resource):
        # Code here
    
    class _Logout(Resource):
        # Code here
    
    class _UD(Resource):
        # Code here

    class _Diary(Resource):
        # Code here

# building RESTapi endpoint
api.add_resource(_CRUD, '/')
api.add_resource(_Create, '/create')
api.add_resource(_Security, '/authenticate')
api.add_resource(_Diary, '/diary')
api.add_resource(_UD, '/<int:user_id>') 
api.add_resource(_Logout, '/logout') 

Therapy API:

therapy_api = Blueprint('therapy_api', __name__,
                   url_prefix='/api/therapy')

api = Api(therapy_api)

class TherapyAPI:     
    class _Read(Resource):
        # Code here
    
    class _Create(Resource):
        # Code here

# building RESTapi endpoint, method distinguishes action
api.add_resource(_Read, '/')
api.add_resource(_Create, '/create')

Demonstrate the code for GET, POST, and PUT

GET, POST, and PUT Code:

# Get Code for Activities
def get(self):
    therapies = Therapy.query.all()
    json_ready = [therapy.read() for therapy in therapies]
    return jsonify(json_ready)
# Get Code for Diary
def get(self):
    token = request.cookies.get("jwt")
    data = jwt.decode(token, 
                    current_app.config["SECRET_KEY"], 
                    algorithms=["HS256"])
    users = User.query.all()
    for user in users:
        if user.uid == data["_uid"]:    
            jsonData = user.diary
            print(jsonData)
            return user.diary
        return jsonify(jsonData)
# Post Code
def post(self):
    body = request.get_json()
    # Fetch data from the form
    name = body.get('name')
    if name is None or len(name) < 2:
        return {'message': f'Name is missing, or is less than 2 characters'}, 400
    # validate location
    location = body.get('location')
    if location is None or len(location) < 2:
        return {'message': f'Location is missing, or is less than 2 characters'}, 400
    # validate location
    special = body.get('special')
    if special is None or len(special) < 2:
        return {'message': f'Specialty is missing, or is less than 2 characters'}, 400
    new_therapy = Therapy(name=name, location=location, special=special)
    therapy = new_therapy.create()
    # success returns json of user
    if therapy:
            #return jsonify(user.read())
            return therapy.read()
        # failure returns error
    return {'message': f'Record already exists'}, 400
# Put Code
def put(self):
    body = request.get_json()
    token = request.cookies.get("jwt")
    data = jwt.decode(token, 
                    current_app.config["SECRET_KEY"], 
                    algorithms=["HS256"])
    diary = body.get('diary')
    users = User.query.all()
    for user in users:
        if user.uid == data["_uid"]:    
            print(data["_uid"])
            user.update("", "", "", user._diary + "///" + diary, "", "")
            return user.read()

In VSCode, show algorithmic conditions used to validate data on a POST condition.

Algorithmic Conditions to validate Post:

name = body.get('name')
if name is None or len(name) < 2:
    return {'message': f'Name is missing, or is less than 2 characters'}, 400
# validate location
location = body.get('location')
if location is None or len(location) < 2:
    return {'message': f'Location is missing, or is less than 2 characters'}, 400
# validate location
special = body.get('special')
if special is None or len(special) < 2:
    return {'message': f'Specialty is missing, or is less than 2 characters'}, 400

In Postman, show URL request and Body requirements for GET, POST, and UPDATE methods.

GET Requirements:
image.png
Get function does not expect a body, thus no body is required. The API waits for a get request to be sent then sends data.

POST Requirements:
image-2.png
This post function requires the name, location, and specialization of the therapy.

PUT Requirements:
image-3.png
This put function only updates the diary column, and thus only requires diary.

In Postman, show the JSON response data for 200 success conditions on GET, POST, and UPDATE methods.

GET Request:
image.png
Successful GET request displays the data from the database for therapy.

POST Request:
image-2.png
Successful POST displays the new therapy location added into the database.

PUT Request:
image-3.png
Successful PUT displays the data on the specific user with the updated diary (I had a previous diary entry of keyboard spam seperated by /// to signify a new diary entry).

In Postman, show the JSON response for error for 400 when missing body on a POST request.

Missing Body POST:
image.png
Does not allow me to create a new entry into the database

In Postman, show the JSON response for error for 404 when providing an unknown user ID to a UPDATE request.

This can not be accomplished. In my code, I take the cookie from the user that is logged in and I decode the cookie in order to update the information for that user. Thus, I am not able to provide an unknown user ID to update.

def put(self):
    body = request.get_json()
    token = request.cookies.get("jwt")
    data = jwt.decode(token, 
                    current_app.config["SECRET_KEY"], 
                    algorithms=["HS256"])
    diary = body.get('diary')
    users = User.query.all()
    for user in users:
        if user.uid == data["_uid"]:    
            print(data["_uid"])
            user.update("", "", "", user._diary + "///" + diary, "", "")
            return user.read()

Frontend

Blog JavaScript API fetch code and formatting code to display JSON.

In Chrome inspect, show response of JSON objects from fetch of GET, POST, and UPDATE methods.

GET Response:
image.png
Fetching the therapy data from the backend JSON response in the frontend.

POST Response:
image-2.png
Sending data to the backend showing JSON response in the frontend.

PUT Response:
image-3.png
Sending data to the backend showing JSON response in the frontend.

In the Chrome browser, show a demo (GET) of obtaining an Array of JSON objects that are formatted into the browsers screen.

GET fetching from therapy database:
image.png
This is the array JSON response from the backend.

Describe fetch and method that obtained the Array of JSON objects:

  • GET request to backend to fetch the data when the function displayTherapyTable() is run
  • Sent request to http://127.0.0.1:8086/api/therapy/, which is the corresponds to the correct API link
  • When the API recieves this response, it retrieves data from the backend and sends the data back in an array of JSON objects.
function displayTherapyTable() {
    // Define options for the fetch request
    let options = {
        method: 'GET',
        headers: {
            'Content-Type': 'application/json;charset=utf-8'
        },
    };

    // Fetch therapy data from the API endpoint
    fetch("http://127.0.0.1:8086/api/therapy/", options)
    .then(response => {
        // Check if the response is successful
        if (response.ok) {
            // Parse the JSON response
            return response.json();
        } else {
            // If the response is not ok, throw an error
            throw new Error('Network response was not ok.');
        }
    })
    // Handle the JSON data in the next promise chain
    // You may want to add .then() for further processing
}

In JavaScript code, show code that performs iteration and formatting of data into HTML:

  • Iterates through each entry in the database and displays it onto a table
.then(data => {
    // Select the table body element
    const tableBody = document.querySelector("#therapy-table tbody");
    // Clear the existing table data
    tableBody.innerHTML = "";

    // Iterate over each therapy activity in the fetched data
    data.forEach(activity => {
        // Insert a new row into the table
        const row = tableBody.insertRow();
        // Insert cells into the row for each activity attribute
        const nameCell = row.insertCell(0);
        const locationCell = row.insertCell(1);
        const specialCell = row.insertCell(2);

        // Populate cells with activity attributes
        nameCell.textContent = activity.name;
        locationCell.textContent = activity.location;
        specialCell.textContent = activity.special;
    });
})
.catch(error => {
    // Log the error to the console
    console.error('Error:', error);
    // Alert the user about the error
    alert(error);
});

image

In the Chrome browser, show a demo (POST or UPDATE) gathering and sending input and receiving a response that show update. Repeat this demo showing both success and failure.

POST-

Success:
image.png
There is an alert message that pops up for the user to tell the user it was updated successfully. Once the message is clicked, the page reloads and the entry is displayed on the table.
image-3.png

Failure:
image-2.png
The length of the name, location, and specialization were too short so the entry could not be created.

In JavaScript code, show and describe code that handles success. Describe how code shows success to the user in the Chrome Browser screen:

if (response.status === 200) {
    alert("Entry added successfully!");
    window.location.reload();

If the resopnse from the backend is 200, meaning that it was successful, the code will continue and run an alert message that displays to the user that the entry was added successfully, then the page and the table will reload (as the table regenerates when the page loads), and display the new entry.

In JavaScript code, show and describe code that handles failure. Describe how the code shows failure to the user in the Chrome Browser screen:

else if (response.status === 400) {
    alert("There was a problem creating the entry.");
}

If the response given was 400 instead, this code will run giving an alert to the user that there was a problem creating the entry (so the user definitley knows there’s a problem).

Demonstrate a search feature.

Searching table code:

function searchTable() {
    // Declare variables for input field, filter value, table, table rows, table data, and text value
    var input, filter, table, tr, td, i, txtValue;
    // Get the input value from the search input field
    input = document.getElementById("searchInput");
    // Convert input value to uppercase for case-insensitive search
    filter = input.value.toUpperCase();
    // Get the table element
    table = document.getElementById("therapy-table");
    // Get all table rows
    tr = table.getElementsByTagName("tr");

    // Loop through all table rows
    for (i = 0; i < tr.length; i++) {
        // Get the first cell (column) of each row (change index to match the column you want to search)
        td = tr[i].getElementsByTagName("td")[0];
        // Check if cell exists
        if (td) {
            // Get the text content of the cell, or inner text if textContent is not supported
            txtValue = td.textContent || td.innerText;
            // Check if the text value matches the filter
            if (txtValue.toUpperCase().indexOf(filter) > -1) {
                // If match found, display the row
                tr[i].style.display = "";
            } else {
                // If no match found, hide the row
                tr[i].style.display = "none";
            }
        }
    }
}

The code above searches through the list of all entries in the table but only looks at the name column. Matches up the displayed entries with the letters typed in the input box.

Optional/ Extra ML Analysis:

Machine Learning Algorithm Analysis

Show algorithms and preparation of data for analysis. This includes cleaning, encoding, and one-hot encoding.

Depression Dataset: Cleaning, encoding, and one-hot encoding is not necessary for my dataset, as when I found the dataset, the data had already been cleaned for use for machine learning.

image This is the dataset formatted into a .csv file.

Show algorithms and preparation for predictions.

def train_model(self, data_path):
        # Load data
        data = pd.read_csv(data_path)

        # Split the data into features and labels
        X = data.drop('Probability of Developing Depression', axis=1)
        y = data['Probability of Developing Depression']

        # Standardize the features
        self.scaler = StandardScaler()
        X_scaled = self.scaler.fit_transform(X)

        # Split the data into training and testing sets
        X_train, self.X_test, y_train, self.y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)

        # Train a linear regression model
        self.model = LinearRegression()
        self.model.fit(X_train, y_train)

def predict_depression(self, age, stress_level, exercise_hours, sleep_hours):
        if self.model is None or self.scaler is None:
                raise ValueError("Model has not been trained yet. Please train the model first.")

        # Scale input data
        input_data = self.scaler.transform([[age, stress_level, exercise_hours, sleep_hours]])

        # Predict depression probability
        chance_of_depression = self.model.predict(input_data)[0]
        return chance_of_depression

Discuss concepts and understanding of Linear Regression algorithms.

Linear Regression Algorithms:

  • Used to model relationships between a dependant variable (what you intend to predict) and independant variables (factors that may contribute to changing the dependant variable).
  • Assumes linearity. Matches a linear equation (y=mx+b) to the relationship between the dependant variable and the independant variable.
  • Used to make predictions linear regression

Types of Linear Regression:

  • Simple Linear Regression- One independant variable. Linear regression only measures the relationship between that one independant variable and the dependant variable
  • Multiple Linear Regression- Multiple independant variables. Linear regression measures the relationship between multiple factors.
  • Polynomial Regression- Relationship between the independant variables and the dependant variables is no longer modeled with a line and is instead modeled as a nth degree polynomial. image

Discuss concepts and understanding of Decision Tree analysis algorithms.

Decision Trees:

  • Used for both classification and regression tasks
  • Flowchart-like structure. Each internal node represents a feature/ attribute, and each branch represents a decision based on that feature, and each leaf node represents the outcome/ class label. image

How They Work:

  1. Tree Generation- Starts from the root node with the entire dataset. Then, it recursivley splits the dataset into smaller subsets based on the most significant feature at each node. Stops when it reaches a stopping criterion (ex. maximum depth, minimum samples per leaf).
    • Maximum Depth- Each time a tree splits, it goes down one level. If you set a maximum depth, the tree can only grow a certain amount of levels before it is stopped.
    • Minimum Samples Per Leaf- When the tree splits, the dataset gets smaller and smaller and the samples (think of them as rows in the dataset). If the criteria is set with a minimum number of samples required for a node to become a leaf (a node without further splits) then nodes with fewer than the minimum number of samples become nodes.
  2. Decision Making- When making predictions, the algorithm traverses through the tree starting from the root and follows the decision rules at each node (Like for example, is the subject older than 30 years old? Yes or no) based on the data input into the algorithm. Once it reaches a leaf node, it reaches a decision (it reaches a prediction or classification).
  3. Pruning- Sometimes, branches of a tree are unnecessary, and are removed through several different processes of pruning.
    • Pre-Pruning- This is implimented during the tree building process, like setting stopping criteria (maximum depth, minimum samples per leaf, etc.)
    • Post-Pruning- Once a decision tree is fully grown, some branches are selectivley removed if they do not improve the trees performance on validation data. The algorithm iterates over every node and evaluates the effect of removing the node. If it improves validation data, the branch is removed and the previous node becomes a leaf. image