You will design and build a web-based appointment booking system using Python (Flask) for the backend, HTML/CSS/JavaScript for the frontend, and integrate a basic AI recommendation feature to enhance user experience. You will also learn UI design fundamentals to create a user-friendly interface.
This unit consists of two major components:Individual Exercises
- Listed below. 100/80/60 Quizzes will be given.
Group project (20% of final mark)
- In groups, you will develop a modern web app using Flask and Python. This project will continue throughout the whole unit. Details will be given soon.
You need to be comfortable using HTML and CSS in this unit.
Do the following tutorials:
- Code along with HTML and CSS Crash Course.
- Read how to include an external CSS file. For this unit, all CSS must be included in an external CSS file (separation of languages). The previous video does not do this, rather it shows you how to add CSS to the top of the HTML document.
- Code along with Simple Responsive Design. responsive design using tutorials like these: Simple Responsive Design
Lesson in class: How to utilize these resources now that you understand HTML, CSS and responsive design.
Useful HTML Resources- Valid HTML5 document (Explanation)
- Intro to HTML 5 Tutorials at w3Schools.
- HTML Validator
- HTML Reference
Lesson in class: How to utilize these resources now that you understand HTML, CSS and responsive design.
Useful HTML Resources- Valid HTML5 document (Explanation)
- Intro to HTML 5 Tutorials at w3Schools.
- HTML Validator
- HTML Reference
Flask is a lightweight, flexible, and free Python web framework that's commonly used to build web applications, APIs, and microservices. It's considered a microframework because it provides a minimal core set of functionalities and relies on extensions for more advanced features. Flask is suitable for both beginners and experienced developers, making it a popular choice for web development projects.
Jinja2 is a powerful and popular template engine for the Python programming language. It allows you to create dynamic HTML, XML, or other markup formats by embedding placeholders (called variables or tags) in a template file, which are then replaced with actual data at runtime.
Watch and code along with this Flask tutorial playlist
To run a Flask App
- Using windows command line, run the python flask app. This starts the local web server from the folder containing the app.
If everything goes well, it will look something like this:
PS Microsoft.PowerShell.Core\FileSystem::H:\Documents\CompSci 12\Flask Project> py app_AI_like.py * Serving Flask app 'app_AI_like' * Debug mode: on WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on http://127.0.0.1:5000 Press CTRL+C to quit * Restarting with stat * Debugger is active! * Debugger PIN: 141-699-995 - Go to a browser and type http://127.0.0.1:5000/. This should show your current app running.
Overview
In this project, you will build a Flask web application that learns from study habits and generates personalized study recommendations.
You will build the app using Flask and Jinja2. Your app will allow a user to log study sessions using a web form and store the data in a JSON file.
Things you need to know:- w3 schools tutorial on HTML Forms
- How to Use Web Forms in a Flask App
- Watch What is JSON?
- Reading and Writing JSON to a file in Python:
- Read Reading and Writing Json to a File in Python OR
- Watch and program with: How To Use JSON In Python AND Watch Reading and Writing to Files from Python
- Getting Started with a Jinja2 Template
1. HTML Form
Create an HTML form with the following fields:
- Subject (Finite List of Subjects) - drop list of subjects
- Duration (minutes) - discrete time durations (30, 45, 60, 90, 120) drop list, radio buttons or discrete slider
- Time of day (Morning, Afternoon, Evening, Night) - drop list or radio buttons
- Mood / energy level (Low, Medium, High) - drop list or radio buttons
- Whether the session was effective (Yes / No) - radio buttons
- A Submit button
The form should send the data to your Flask server using POST.
2. Flask Routing & Form Handling
Your Flask app must:
- Include a route that displays the form
- Include a route that processes the submitted data
- Capture all the form values correctly (subject, duration, time of day, mood, effective)
3. Save Sessions to a JSON File
When a user submits the form, save the session to a JSON file called: study_sessions.json
In a future version of this assignment, the data will be used to train a decision tree classifier, which is better trained with numerical data instead of string data. Therefore store each value for duration, time_of_day, mood and effective, as an integer. We will also be using this Machine Learning model to make predictions, are predictions will be faster, and more realistic, with meaningful options for duration (30, 45, 60, 90, 120).
Each entry will use this exact structure:
{"subject": int, "duration": int, "time_of_day": int, "mood": int, "effective": int}
Every time a new sessions is logged:
- Load existing appointments from the JSON file
- Append the new appointment
- Write the updated list back to the file
4. Display All Study Sessions
After a study session is added, load a new page that:
- Uses Jinja2 to loop through the list of entries.
It might look something like:
{% for s in sessions %} <li>{{ s.subject }}: {{ s.duration }} minutes in the {{ s.time_of_day }}, mood: {{ s.mood }}, Effective: {{s.effective}} </li> {% endfor %} - Improve the look, and displays all saved sessions in a clear list or table with words replacing the numerical values of subject, time_of_day, mood, and effectiveness.
Assessment (Total: 20 marks)
1. HTML Form (5 marks)
- 5 marks – Form includes required elements, and a Submit button; labels are clear; layout is clean and fully functional.
- 4 marks – Form works with one minor issue (missing label, minor formatting flaw).
- 2–3 marks – Form loads but is incomplete or somewhat unclear.
- 1 mark – Form is mostly non-functional or missing major elements.
- 0 marks – No usable form.
2. Flask Routing & Form Handling (5 marks)
- 5 marks – Routes are properly set up; form POST request is handled correctly; input values are captured with no errors.
- 4 marks – Routing works with minor flaws (naming, limited validation, small logic issues).
- 2–3 marks – Basic form-handling works but may be inconsistent or partially incorrect.
- 1 mark – Attempt made, but form data is not captured correctly.
- 0 marks – Routes do not function; no form processing.
3. JSON File Storage (exact structure required) (5 marks)
JSON structure must match exactly as described.
- 5 marks – App loads existing JSON data, appends the new session, and writes the updated list back correctly in the required structure.
- 4 marks – JSON storage works with a small issue (minor formatting inconsistency, small structural issue).
- 2–3 marks – JSON file is used but has errors (overwriting, wrong keys, partial data loss).
- 1 mark – File is created but not written/loaded correctly.
- 0 marks – No JSON file interaction.
4. Displaying Sessions with Jinja2 (5 marks)
- 5 marks – App loads all sessions from the JSON file and displays them clearly using a Jinja2 loop.
- 4 marks – Data displays correctly with minor formatting issues.
- 2–3 marks – Some sessions display, but output is incomplete or messy.
- 1 mark – Attempt made but display has major errors.
- 0 marks – No session list displayed.
In Python, scikit-learn can be used to train a simple ML models including linear regression and classification.
Benefits of the Scikit Model- No need for cloud APIs or authentication
- All runs locally — safe and fast
- Small data sets are enough
Watch Decision and Classification Trees, Clearly Explained
Add a Decision Tree Classifier
In this assignment, you will use real machine learning (ML) to help your app make smarter recommendations over time.
Your goal is to use the historical appointment data your users have submitted to train a Decision Tree Classifier. It turns your project into an app that becomes smarter the more it is used.
Why Not Just Use Rule Based Logic (aka If-Statements, Sorts etc)?
At first, this problem looks easy to solve with rules.
For example:
- “If I’m tired, studying doesn’t work.”
- “Math is better in the morning.”
But real study habits are more complicated.
The Problem With Rules
Every new factor multiplies the number of cases you need to handle:
- Subject
- Duration
- Time of day
- Mood
With just a few options, you already have hundreds of combinations.
If your habits change, you must:
- Rewrite rules
- Add new conditions
- Debug logic
That’s not scalable.
What a Decision Tree Does Differently
A DecisionTreeClassifier:
- Learns patterns automatically from data
- Updates its logic when new data is added
- Makes predictions on situations it has never seen before
You don’t tell it what works. It figures that out.
Why This Matters
This is the difference between:
- Programming instructions (traditional code)
- Programming learning systems (machine learning)
If-statements follow rules. Decision trees discover rules.
That difference is why machine learning exists — and why it is required for this assignment.
Install Scikit
If you haven't already, install scikit:
py -m pip install scikit-learn
Prepare Your Data
Transform your session data into training data (X)
For example, sessions become:
X = [
[2, 45, 3, 4],
[1, 30, 1, 2],
[3, 60, 4, 5]
]
Create labels (y)
y = [1, 0, 1]
Loading This Data From JSON
Example list of entries:
data = [
{"subject":2, "duration":45, "time_of_day":3, "mood":4, "effective":1},
{"subject":1, "duration":30, "time_of_day":1, "mood":2, "effective":0}
]
Convert to X and y:
X = []
y = []
for entry in data:
X.append([
entry["subject"],
entry["duration"],
entry["time_of_day"],
entry["mood"]
])
y.append(entry["effective"])
Train your model
from sklearn.tree import DecisionTreeClassifier model = DecisionTreeClassifier() model.fit(X, y)
Visualize the trained model by showing the decision tree
from sklearn.tree import export_text feature_names = ["subject", "duration", "time_of_day", "mood"] tree_rules = export_text(model, feature_names=feature_names) print(tree_rules)
Add This to Your Flask App
- Load study session data from your JSON file
- Convert it into X and y
- Train your DecisionTreeClassifier
- Print the Decision Tree rules in a preformatted text element under the list of all study sessions.
The key idea: Your model should improve as more appointments get booked.
Assessment (Total: 5 marks)
ML Integration (5 marks)
- 5 marks – Correctly loads JSON appointment history, extracts features, creates labels, trains a model, and uses it in Flask, shows Decision Tree; updates as data grows.
- 4 marks – Model trains and works but has minor logic or feature-extraction issues.
- 2–3 marks – Attempts training but model is incorrect or inconsistently used.
- 1 mark – Minimal attempt; model is not functional.
- 0 marks – No ML integration.
ML-Based Recommendations (No Rules Allowed)
Your app will generate recommendations only using model predictions. We will be using "What-if" predictions, which are essentially brute-force.
The recommendations must:
- Be based on the trained DecisionTreeClassifier
- Adapt automatically as more data is collected
- Change without modifying any recommendation logic code
How to Make a Prediction for One Entry
Always pass a 2D list, even for one item:new_session = [[2, 50, 3, 4]] # subject=2, duration=50, time_of_day=3, mood=4 prediction = model.predict(new_session)[0] print(prediction)Output will be
1 for effective or 0 for ineffective.
Get Probability Instead of Just yes/no
probs = model.predict_proba(new_session) print(probs)Example output:
[[0.25 0.75]] meaning 25% not effective, 75% effective.
This gives you the ability to give recommendations like "This study session has a 75% chance of being effective."
Get Specific Recommendations
For a given subject, try all variations to find better options
recommendations = []
# try all options for a current["subject"] and current["mood"]
for duration in [30, 45, 60, 90]:
for time in [1, 2, 3, 4]: # morning, afternoon, evening, night
test_session = [[
current["subject"],
duration,
time,
current["mood"]
]]
result = model.predict(test_session)[0]
if result == 1:
recommendations.append((duration, time))
This might output [(60, 3), (60, 4), (90, 3)] which would suggest that for this subject and mood, studying 60-90 min in the evening is best.
Use probabilities for smarter recommendations
best_options = []
# try all options for a given subject and mood
for duration in [30,45,60,90]:
for time in [1,2,3,4]:
probs = model.predict_proba([[current["subject"], duration, time, current["mood"]]])
effectiveness_chance = probs[0][1] # probability of effective
best_options.append((duration, time, effectiveness_chance))
# sort by highest success
best_options.sort(key=lambda x: x[2], reverse=True)
print(best_options[:3])
This might output [(60, 3, 0.91), (90, 3, 0.88), (60, 4, 0.82)] and the recommendation could be "For this subject and mood, your best study session is 60 minutes in the evening (91% effective)".
Analyze Feature Importance
After you've trained the model model.fit() use model.feature_importances_ to figure out which features mattered most and provide insight to the user. The model.feature_importances_ attribute provides a score for each input feature based on its contribution to the model's predictions.
In scikit-learn, this attribute is available in tree-based models like Random Forest and Decision Tree.
features = ["subject", "duration", "time_of_day", "mood"]
importances = model.feature_importances_
for name, score in zip(features, model.feature_importances_):
print(name, ":", round(score, 3))
Use this to show things like:
- Time of day mattered more than subject
- Mood had little impact in my data
Add this to Your Study Buddy App:
Current Study Session Analysis Feature
Add to your app a new route that has a form that allows the user to enter hypothetical study conditions:
- Subject
- Duration
- Time of day
- Mood / energy level
The app responds with the predicted effectiveness (%) of the user’s current study session.
Predicted Effectiveness: 22%
What If Feature
Add to your app a new route that has a form that allows the user to enter a subject and a mood.
The app then shows the top 3 most effective study session combinations generated using what-if predictions (duration + time of day), including predicted probability
Best Study Sessions for Math when mood is low: 60 minutes in the evening — 91% effective 90 minutes in the evening — 88% effective 60 minutes at night — 82% effective
Model Insight (Feature Importance Explanation)
Just above the decision tree, show what the model has learned from your data.
Duration was the most important factor (0.55) Time of day was second most important (0.25) Mood had little impact (0.10) Subject had minimal impact (0.10)
Assessment
tba
Step 1: Watch and program along with Simple Machine Learning Code Tutorial for Beginners with Sklearn.
It covers:- Additional SciKit Algorithms
- Assessing accuracy of predictions
- Saving your model
Step 2: Complete this Tutorial: How to Measure Your DecisionTreeClassifier Model’s Accuracy
In this exercise, you’ll build a new feature in your Flask app to test how accurate your AI model from Study Buddy Assignment 1 is using the data you've collected in study_sessions.json.
- Use 20% of your study session data as test data
- Train your AI model on the remaining 80%
- Show the accuracy of the predictions
- Display the result on a web page
app.py with a New Route- Open your
app.pyfile. - Add this import at the top if it isn’t already there:
from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score import pandas as pd # Tool for encoding string labels into numbers from sklearn.preprocessing import LabelEncoder - Define the following variables if you plan on using
LabelEncoder# Encoders to convert categorical values into numeric labels mood_encoder = LabelEncoder() time_encoder = LabelEncoder() subject_encoder = LabelEncoder() - Then scroll down and add this new route:
@app.route('/test-ai')
def test_ai():
sessions = load_sessions()
if len(sessions) < 10:
flash("Not enough data to test the model. Please log at least 10 sessions.")
return redirect('/log')
# Convert to DataFrame
df = pd.DataFrame(sessions)
# Encode text columns into numbers
# Note: you may have named your features differently
df['mood'] = mood_encoder.fit_transform(df['mood'])
df['time_of_day'] = time_encoder.fit_transform(df['time_of_day'])
df['subject'] = subject_encoder.fit_transform(df['subject'])
df['effective'] = df['effective'].map({"Yes": 1, "No": 0})
# Split into 80% train and 20% test
X = df[['duration', 'time_of_day', 'mood', 'subject']]
y = df['success']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Train and test the model
model = DecisionTreeClassifier()
model.fit(X_train, y_train)
predictions = model.predict(X_test)
accuracy = round(accuracy_score(y_test, predictions) * 100, 2)
return render_template('test_ai_accuracy.html', accuracy=accuracy, total=len(sessions))
Create a New TemplateCreate a file called test_ai_accuracy.html in your templates/ folder:
<!DOCTYPE html>
<html>
<head>
<title>AI Accuracy Test</title>
</head>
<body>
<h1>AI Model Accuracy Report</h1>
<p>Tested on 20% of {{ total }} logged sessions.p>
<h2>Accuracy: {{ accuracy }}%h2>
<p><a href="{{ url_for('home') }}">Back to Home</a></p>
</body>
</html>
Try It Out- Make sure you have at least 10 study sessions logged.
- Run your Flask app.
- Visit
/test-aiin your browser (e.g.http://127.0.0.1:5000/test-ai) - You should see a page like this:
AI Model Accuracy Report
Tested on 20% of 25 logged sessions.
Accuracy: 84.00%
Add a Link to Your HomepageIf you want a link from your home page:
<p><a href="{{ url_for('test_ai') }}">Evaluate AI Accuracy</a></p>
What’s Going On?- 80% of your data is used to train the model.
- 20% is used to test how well the model performs on new data.
- You see how often the model predicted correctly — that’s the accuracy.
You now have a simple way to measure how effective your DecisionTreeClassifier is using real user data.
Step 3: Test Another Model, Compare its Predictions, and Pick the Best Model
Pick another ML model:- Train it using the same data you trained the DecisionTree with.
- Use it to predict which conditions (length of time, time of day, subject, and mood) lead to effective sessions and output these in the website alongside the DecisionTree recommendations.
Research Random Forest, Logistic Regression, and KNN models. Pick one and assess the model accuracy against the Decision Tree and display the results.
1. Prepare Your Flask App
Let’s assume you have a basic app structure like this:
myapp/
├── app.py
├── data.json
├── templates/
│ └── index.html
└── static/
Example app.py:
from flask import Flask, request, jsonify
import json
import os
app = Flask(__name__)
DATA_FILE = os.path.join(os.path.dirname(__file__), 'data.json')
@app.route('/')
def index():
return 'Hello from Flask!'
@app.route('/add', methods=<'POST'>)
def add_data():
new_entry = request.get_json()
with open(DATA_FILE, 'r') as f:
data = json.load(f)
data.append(new_entry)
with open(DATA_FILE, 'w') as f:
json.dump(data, f, indent=4)
return jsonify({'status': 'success', 'data': new_entry})
2. Sign Up and Create a Web App on PythonAnywhere
- Go to https://www.pythonanywhere.com and sign up or log in.
- On the Dashboard, click Web > Add a new web app.
- Choose Manual configuration > Flask > your Python version (e.g., 3.10).
3. Upload Your Files
- In the Files tab, create a folder (e.g.,
myapp/) and upload yourapp.py,data.json,templates/, andstatic/folders/files. - Make sure
data.jsonhas write permissions (you can leave it as-is; you’re the only user).
4. Configure the WSGI File
Go to Web > [your app ] > WSGI configuration file.
Edit the file to look like this (adjust the path to your folder):
import sys
import os
path = '/home/yourusername/myapp'
if path not in sys.path:
sys.path.append(path)
from app import app as application
5. Reload and Test
- Go back to the Web tab and click Reload.
- Visit your app’s URL (e.g.,
yourusername.pythonanywhere.com) to confirm it’s running. - Send a POST request to
/add(using Postman or JavaScript) to test the JSON writing.
Important Notes
- Free PythonAnywhere accounts cannot receive external HTTP requests to
/addunless you're making the request from a client hosted on PythonAnywhere (e.g., your own JS frontend on the same domain). - PythonAnywhere allows write access to files in your home directory, so writing to
data.jsonis okay. - You must avoid using absolute paths; use
os.path.join(os.path.dirname(__file__), 'data.json')to make sure it works on their file system.
Create an installable online app using Flask that utilizes AI to provide a service to your audience.
The app must:
- collect structured input from users
- train a scikitlearn ML model on real (not generated) data
- save the model locally and only retrain it when new data is added
- use the trained scikitlearn ML model to make predictions
- provide a useful or interesting response
- be retrained as new data is collected
Suggestions:
- Workout Effectiveness Predictor (workout type, duration, intensity)
- Sleep Quality Estimator (bedtime, screen time, sugar intake, caffeine intake)
- Stress Level Advisor (hours of sleep, workload, mood)
What makes a good app?
You should be able to answer these questions:
- Who is this for?
- What problem does it solve?
- How does the app help using technology or AI?
Criteria for a Good AI-Assisted App Idea
How to make it installable: Turn it into a Progressive Web App (PWA)
Milestone 1:All of the following is required:
- The structure of your app is built. For example, for each required view, there is an html template and a flask route to that view. Any forms required for data collection are built and saving the data into a json file.
- Any views that are static html (that is, just have content) have at least a header, and an outline of what that page will contain.
- At least one ML model is being applied to that data with preliminary predictions.
- This version of your site is hosted on pythonanywhere and accessible with a mobile device.
- You have gathered 40 or more real data points from interviewing real people
Resources
- UI Design Principles
- Saving Your Model
- Principle of modern web design
- Jinja2 form validation
- Exporting flask for web servers
Assessment
App Purpose & Audience
- Significant Work Needed: Purpose is unclear or missing; app does not provide a meaningful service.
- Emerging: Basic idea present, but audience or service is vague.
- Developing: Clear purpose and identified audience; service mostly makes sense.
- Proficient: Purpose and audience are clearly defined; app provides a useful or relevant service.
- Extending: Purpose is thoughtful and well-justified; service is well-matched to audience needs.
Flask Application Structure
- Significant Work Needed: App does not run or has major structural issues.
- Emerging: Flask runs, but routes/templates are incomplete or poorly organized.
- Developing: Functional Flask app with routes and templates working correctly.
- Proficient: Clean structure using templates, forms, and logical routing.
- Extending: Well-organized Flask project with good separation of concerns and scalability.
Data Collection & Feature Design
- Significant Work Needed: No meaningful data is collected, or required inputs are missing or unused, or data is generated.
- Emerging: Data from real users is collected, but features are poorly chosen, inconsistent, or not clearly connected to the prediction task.
- Developing: Appropriate features are collected from real users and used consistently for model training and prediction.
- Proficient: Features are well-chosen and structured; gathered input data is validated, encoded, and used reliably in both training and prediction.
- Extending: Feature design clearly improves model performance (e.g., derived features, bucketing, scaling, or combining inputs), and these features are actively used by the model.
Machine Learning Implementation & Training
- Significant Work Needed: No ML used or logic is hard-coded with if-statements.
- Emerging: ML attempted but not trained or not meaningfully used.
- Developing: Working ML model trained with scikit-learn and used for predictions.
- Proficient: Model is properly trained, saved, loaded, and used in the Flask app. Retraining is meaningfully integrated: the model updates automatically or predictably as data grows, and changes in predictions can be observed during use.
- Extending: The implementation demonstrates effective ML use through model tuning, evaluation, or structure (e.g., controlled tree depth, accuracy checking, feature importance usage, or multiple models compared in code).
User Experience & Interface
- Significant Work Needed: Interface is broken, difficult to use, or does not function on a mobile device.
- Emerging: Interface works on desktop but has usability or layout issues on mobile.
- Developing: Interface functions on both desktop and mobile with basic responsive layout.
- Proficient: App is mobile-friendly, clearly laid out, responsive, and installable as a Progressive Web App (PWA).
- Extending: PWA is fully functional on a mobile device (installable, usable offline or with graceful failure, clear app-like experience, and supports the AI service effectively).
How to Hand In
- Create a readme.txt that includes a link to the site on pythonanywhere.
- Demo app for me in class.
- Put the entire folder in Wear_IT > Hand-in > ML App and rename it with all of your team members names.
Please take the time to complete the following course evaluation. It will be used for future course offerings.
Course Evaluation