Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .DS_Store
Binary file not shown.
36 changes: 36 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Use the official Python 3.10 slim image
FROM python:3.10-slim

# Set the working directory inside the container
WORKDIR /app

# Install system dependencies including build tools and MariaDB development files
RUN apt-get update && \
apt-get install -y \
build-essential \
pkg-config \
python3-dev \
libmariadb-dev-compat \
libmariadb-dev \
&& rm -rf /var/lib/apt/lists/*

# Upgrade pip (optional but recommended)
RUN pip install --upgrade pip

# Copy the requirements.txt file from the correct relative path into the container
COPY Sprint_1/AI_Fitness_Project/requirements.txt /app/requirements.txt

# Install Python dependencies from requirements.txt
RUN pip install --no-cache-dir -r /app/requirements.txt

# Copy the rest of your application code into the container
COPY Sprint_1/AI_Fitness_Project /app

# Set environment variables (using the recommended syntax)
ENV PYTHONUNBUFFERED=1

# Expose the port your app uses (adjust if needed)
EXPOSE 5000

# Run the application
CMD ["python", "/app/app.py"]
10 changes: 10 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "AI Fitness Dev Container",
"build": {
"dockerfile": "Dockerfile"
},
"workspaceFolder": "/workspace",
"mounts": ["source=${localWorkspaceFolder},target=/workspace,type=bind"],
"remoteUser": "vscode"
}

12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
My groupmembers are:
- XXXX
- XXXX
- XXXX
- XXXX
The groupmembers are:
- Sebastian Alcibar
- Ryan Maazous
- Thomas Marshall
- Jonah Minkoff
- Brady Miller


------------------ Fill in some information about your project under this ------------------
## Our group has decided to work on the Mental Health Support App.
Binary file added Sprint 1/.DS_Store
Binary file not shown.
Binary file added Sprint 1/AI Fitness Project/.DS_Store
Binary file not shown.
4 changes: 4 additions & 0 deletions Sprint 1/AI Fitness Project/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.env
database.db
__pycache__/
venv/
112 changes: 112 additions & 0 deletions Sprint 1/AI Fitness Project/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
from flask import Flask, render_template, session
import os
from backend.db import db
from backend.tables import User
from flask_login import LoginManager, login_required, login_user, logout_user, current_user
from flask import Flask, render_template, redirect, url_for, flash
from flask_bcrypt import Bcrypt
from backend.forms import RegisterForm, LoginForm, SurveyForm, FitnessLogWorkoutForm, FitnessLogCardioForm
from backend.tables import User
import secrets


app = Flask(__name__)
bcrypt = Bcrypt(app)

# Handles our SQLite database
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
app.config['SECRET_KEY'] = secrets.token_hex(16)
db.init_app(app)

# Handles login verification
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = "login"
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))


# Renders home page
@app.route('/', methods=['GET', 'POST'])
@login_required
def home():
fitness_goals= current_user.fitness_goals

if fitness_goals:
fitness_goals_list = fitness_goals.split(",")
else:
fitness_goals_list = None
return render_template('index.html', first_name=current_user.first_name, fitness_goals=fitness_goals_list)


# Renders fitness log page
@app.route('/fitness-log', methods=['GET', 'POST'])
def fitness_log():
workout_form = FitnessLogWorkoutForm()
cardio_form = FitnessLogCardioForm()
return render_template('fitness-log.html', workout_form=workout_form, cardio_form=cardio_form)

# Renders about page
@app.route('/about')
def about():
return render_template('about.html')

# Renders main AI chat page
@app.route('/main-chat')
def main_chat():
return render_template('main-chat.html')

# Renders login page
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user:
if bcrypt.check_password_hash(user.password, form.password.data):
login_user(user)
return redirect(url_for('home'))
return render_template('login.html', form=form)

# Handles logout functionality
@app.route('/logout', methods=['GET', 'POST'])
@login_required
def logout():
logout_user()
return redirect(url_for('login'))

# Renders register page
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegisterForm()


if form.validate_on_submit():
hashed_password = bcrypt.generate_password_hash(form.password.data)
new_user = User(username=form.username.data, password=hashed_password, first_name=form.first_name.data, last_name=form.last_name.data)
db.session.add(new_user)
db.session.commit()
login_user(new_user)
return redirect(url_for('survey'))

return render_template('register.html', form=form)

@app.route('/survey', methods=['GET', 'POST'])
def survey():
form = SurveyForm()

if form.validate_on_submit():
selected_goals = ",".join(form.fitness_goals.data)
current_user.fitness_goals = selected_goals
db.session.commit()
return redirect(url_for('home'))

return render_template('survey.html', form=form)

with app.app_context():
db.create_all()

if __name__ == "__main__":

app.run(debug=True, host="0.0.0.0", port=5000)
3 changes: 3 additions & 0 deletions Sprint 1/AI Fitness Project/backend/db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()
70 changes: 70 additions & 0 deletions Sprint 1/AI Fitness Project/backend/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, SelectMultipleField, widgets, IntegerField, FieldList, FormField, DecimalField
from wtforms.validators import InputRequired, Length, ValidationError, DataRequired, NumberRange
from backend.tables import User

# Sets up the form on the register page
class RegisterForm(FlaskForm):
username = StringField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Username"})
password = PasswordField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Password"})
first_name = StringField(validators=[InputRequired(), Length(min=1)], render_kw={"placeholder": "First Name"})
last_name = StringField(validators=[InputRequired(), Length(min=1)], render_kw={"placeholder": "Last Name"})

submit = SubmitField("Register")

def validate_username(self, username):
existing_user = User.query.filter_by(
username=username.data).first()
if existing_user:
raise ValidationError(
"That username already exists."
)


# Sets up form on login page
class LoginForm(FlaskForm):
username = StringField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Username"})

password = PasswordField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Password"})

submit = SubmitField("Login")


class SurveyForm(FlaskForm):
fitness_goals = SelectMultipleField(
"What are your fitness goals?",
choices=[
("Build Muscle", "Build Muscle"),
("Lose Weight", "Lose Weight"),
("Increase Strength", "Increase Strength"),
("Improve Cardio", "Improve Cardio")
],
option_widget=widgets.CheckboxInput(),
widget=widgets.ListWidget(prefix_label=False)
)

submit = SubmitField("Submit")


class FitnessLogWorkoutForm(FlaskForm):
legs_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")])
legs_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")])

chest_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")])
chest_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")])

back_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")])
back_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")])

bicep_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")])
bicep_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")])

tricep_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")])
tricep_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")])

submit = SubmitField("Submit")

class FitnessLogCardioForm(FlaskForm):
miles = DecimalField('Total Miles', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")])

submit = SubmitField("Submit")
15 changes: 15 additions & 0 deletions Sprint 1/AI Fitness Project/backend/tables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from backend.db import db
from flask_login import UserMixin

# Creates our Sqlite table that holds user login/register info.
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), nullable=False, unique=True)
password = db.Column(db.String(80), nullable=False)
first_name = db.Column(db.String(20), nullable=False)
last_name = db.Column(db.String(20), nullable=False)
fitness_goals = db.Column(db.String(255), nullable=True)




41 changes: 41 additions & 0 deletions Sprint 1/AI Fitness Project/login_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import requests
from bs4 import BeautifulSoup


base_url = "http://localhost:5000"
login_url = f"{base_url}/login"
home_url = f"{base_url}/home"

test_username = 'test'
test_password = 'test'

session = requests.Session()

login_page = session.get(login_url)

soup = BeautifulSoup(login_page.text, 'html.parser')

csrf_token = soup.find('input', {'name': 'csrf_token'})['value']

login_data = {
'csrf_token': csrf_token,
'username': test_username,
'password': test_password,
'submit': 'Login'
}

login_response = session.post(login_url, data=login_data)

print("\nLogin Response Status Code:", login_response.status_code)

if login_response.status_code == 200:
if "Welcome" in login_response.text:
print("Login test passed.")
elif "Invalid username or password" in login_response.text:
print("Login failed. Invalid username or password.")
else:
print("Login failed with status code 200 but no error message found.")
else:
print("Login failed. Status code:", login_response.status_code)
print("Response Content:")
print(login_response.text)
51 changes: 51 additions & 0 deletions Sprint 1/AI Fitness Project/requirements_mac.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
asttokens==3.0.0
bcrypt==4.3.0
blinker==1.9.0
click==8.1.8
colorama==0.4.6
comm==0.2.2
debugpy==1.8.13
decorator==5.2.1
dnspython==2.7.0
email_validator==2.2.0
executing==2.2.0
Flask==3.1.0
Flask-Bcrypt==1.0.1
Flask-Login==0.6.3
Flask-MySQLdb==2.0.0
Flask-SQLAlchemy==3.1.1
Flask-WTF==1.2.2
greenlet==3.1.1
idna==3.10
ipykernel==6.29.5
ipython==8.10.0
ipython_pygments_lexers==1.1.1
itsdangerous==2.2.0
jedi==0.19.2
Jinja2==3.1.6
jupyter_client==8.6.3
jupyter_core==5.7.2
MarkupSafe==3.0.2
matplotlib-inline==0.1.7
PyMySQL==1.0.2 #mysqlclient==2.2.7
nest-asyncio==1.6.0
packaging==24.2
parso==0.8.4
platformdirs==4.3.7
prompt_toolkit==3.0.50
psutil==7.0.0
pure_eval==0.2.3
Pygments==2.19.1
python-dateutil==2.9.0.post0
python-dotenv==1.0.1
pywin32==310; sys_platform == "win32"
pyzmq==26.3.0
six==1.17.0
SQLAlchemy==2.0.39
stack-data==0.6.3
tornado==6.4.2
traitlets==5.14.3
typing_extensions==4.12.2
wcwidth==0.2.13
Werkzeug==3.1.3
WTForms==3.2.1
Loading