Building a Simple Mental Health Tracker with Streamlit, SQLite, Plotly, ChatGPT and wrapped in Cloud Run
This article showcases how to use natural language to build a simple mental health tracking app in Python. It demonstrates the use of Streamlit, SQLite, Plotly, and other libraries, and how they can be used to gather user input, perform analysis, and provide visualizations with guidance to the user.
Introduction
This article will explore how to build a simple mental health tracking app using Streamlit, Plotly, SQLite, and ChatGPT. ChatGPT is an AI language model developed by OpenAI that can generate human-like responses to text-based prompts. We will use ChatGPT to provide personalized guidance to users based on their mental health check-ins.
Before we dive into the code, let’s take a moment to review the libraries we’ll be using:
- Streamlit: a Python library for building web apps with simple syntax and no front-end experience needed.
- Plotly: a Python graphing library for creating interactive, publication-quality graphs online.
- SQLite: a lightweight, serverless database engine that’s easy to use and perfect for small to medium-sized projects.
- ChatGPT: an AI language model that can generate human-like responses to text-based prompts.
By the end of this article, you’ll have a functional mental health tracking app that can store user input in a database, generate helpful visualizations, and provide personalized guidance using AI. Let’s get started!
How the code is structured
The code is structured in a way to separate concerns and improves maintainability. At the root level, we have the requirements.txt
, main.py
, logo.jpeg
, README.md
, and Dockerfile
. The modules
folder contains db.py
, guidances.py
, and visualization.py
. The databases
folder contains mental_health.db
. Finally, in the .github
folder, we have the workflows
subfolder that contains the deploy.yml
file.
Please find the overall structure below:
- MoodLens
- .github
- workflows
- deploy.yml
- databases
- mental_health.db
- modules
- db.py
- guidances.py
- questions.py
- visualization.py
- requirements.txt
- main.py
- logo.jpeg
- README.md
- Dockerfile
The code is structured in a modular way to separate different functionalities of the app. The main.py
file is responsible for handling the main application logic, including user input and output. The modules
folder contains separate Python files for database interactions, visualizations, and guidance messages. This allows for easier maintenance and scalability of the code, as each file only handles one specific task.
The databases
folder contains the SQLite database where user input is stored. This separation of concerns allows for easy management and backups of the user data and easy migration to a different database management system, if desired.
The requirements.txt
file lists all the required Python packages for the app to run. This file can be used to easily install all the dependencies with one command.
Finally, the Dockerfile
is included to provide a containerized version of the app, which can be easily deployed to cloud platforms like Google Cloud Run. Overall, this structure promotes organization, flexibility, and scalability of the code.
Can you start by showing me the application?
Yes, I can:
As you can see, this is really simple, the goal is to go straight to the point. Only 4 menu buttons, basically behind each button you will have one .py file in the modules directory.
Mental Health Check-In
In this module, you will have to complete a simple form looking like this:
In the end, you will have a simple recap:
The code looks like:
import streamlit as st
from modules import db
from datetime import datetime
import plotly.graph_objects as go
def ask_questions():
st.write("## Mental Health Check-In")
# Define the questions
questions = [
"How are you feeling today? (0 = Terrible, 10 = Great)",
"How would you rate your level of serenity today? (0 = Poorly, 10 = Very well)",
"How well did you sleep last night? (0 = Poorly, 10 = Very well)",
"How productive were you today? (0 = Not at all, 10 = Extremely productive)",
"How much did you enjoy your day today? (0 = Not at all, 10 = Very much)"
]
# Define an empty list to store answers
answers = []
# Ask the questions and get the answers
for question in questions:
answer = st.slider(question, 0, 10)
answers.append(answer)
# Calculate the average of the answers
average = sum(answers) / len(answers)
st.markdown('##')
# Display the average on the page
st.write(f"Your average mental health score today is {average:.1f}")
# Add the gauge chart to show where the average score lies on a scale of 0 to 10
fig = go.Figure(go.Indicator(
domain={'x': [0, 1], 'y': [0, 1]},
value=average,
mode="gauge+number",
title={'text': "Mental Health Score"},
gauge={
'axis': {'range': [0, 10]},
'steps': [
{'range': [0, 2], 'color': "red"},
{'range': [2, 4], 'color': "orange"},
{'range': [4, 6], 'color': "yellow"},
{'range': [6, 8], 'color': "lightgreen"},
{'range': [8, 10], 'color': "green"}],
'threshold': {'line': {'color': "black", 'width': 4}, 'thickness': 0.75, 'value': average}}))
st.plotly_chart(fig, use_container_width=True, height=50)
# Get the current date and time
now = datetime.now()
# Format the date as a string in the format "YYYY-MM-DD"
date_string = now.strftime('%Y-%m-%d')
# Add the entry to the database
if st.button('Submit to your daily MindLens tracker'):
db.create_table() # Create the table if it doesn't exist
db.add_entry(date=date_string, feeling=answers[0], serenity=answers[1], sleep=answers[2],
productivity=answers[3], enjoyment=answers[4], average=average)
st.write("Your mental health check-in has been submitted!")
return answers
Visualization
In this part, we are just extracting information from the SQLlite database:
Really simple visualization, but going straight to the point. A simple way to have the overall situation.
The code looks like:
import streamlit as st
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from modules import db
import sqlite3
DATABASE_PATH = "./databases/mental_health.db"
def read_data():
with sqlite3.connect(DATABASE_PATH) as conn:
df = pd.read_sql_query("SELECT * FROM mental_health ORDER BY date DESC", conn)
return df
def get_average_scores(conn):
df2 = pd.read_sql_query(
"SELECT AVG(feeling) as avg_feeling, AVG(serenity) as avg_serenity, AVG(sleep) as avg_sleep, AVG(productivity) as avg_productivity, AVG(enjoyment) as avg_enjoyment FROM mental_health", conn)
return df2.values[0]
def get_average_scores_dataframe(average_scores):
df3 = pd.DataFrame({
"category": ["feeling", "serenity", "sleep", "productivity", "enjoyment"],
"average": average_scores
})
return df3
def show_dataframe():
st.write("## Mental Health Data")
df = read_data()
st.dataframe(df)
def delete_data():
if st.button("Delete all data"):
with sqlite3.connect(DATABASE_PATH) as conn:
c = conn.cursor()
c.execute("DROP TABLE IF EXISTS mental_health")
st.write("All data has been deleted from the database.")
def show_visualization():
with sqlite3.connect(DATABASE_PATH) as conn:
df = read_data()
# Generate the visualizations
fig1 = px.line(df, x="date", y="average", line_shape="spline", color_discrete_sequence=["red"])
fig1.update_layout(xaxis_tickformat='%Y-%m-%d',
title="Average Mental Health Score Over Time")
fig2 = px.line(df, x="date", y=["feeling", "serenity", "sleep", "productivity", "enjoyment"],
line_shape="spline")
fig2.update_layout(xaxis_tickformat='%Y-%m-%d',
title="Mental Health Scores Over Time")
# Get and plot the average scores
average_scores = get_average_scores(conn)
df3 = get_average_scores_dataframe(average_scores)
fig3 = px.bar_polar(df3, r="average", theta="category", template="plotly_dark")
fig3.update_traces(opacity=0.7)
fig3.update_layout(title="Average Mental Health Scores by Category")
# Show the visualizations on the page
show_dataframe()
delete_data()
st.plotly_chart(fig1)
st.plotly_chart(fig2)
st.plotly_chart(fig3)
Guidances
This is where ChatGPT is taking the lead, I’m giving the API the situation of my mental health giving him full access to the SQLlite database. Then I let him analyse inputs and give me simple guidance.
Guidances are here really simple, but depending on the prompt you design you can go deeper in the recommendations.
Code looks like:
import streamlit as st
import pandas as pd
import openai
from modules import db
import tabulate
import sqlite3
DATABASE_PATH = "./databases/mental_health.db"
# Authenticate with the OpenAI API
openai.api_key = "xxx"
def show_guidance():
st.write("## Mental Health Guidances")
# Retrieve the data from the database
conn = db.create_connection()
df = pd.read_sql_query("SELECT * FROM mental_health ORDER BY date DESC", conn)
# Generate the prompt string
dataframe_string = tabulate.tabulate(df.head(), headers='keys', tablefmt='pipe', showindex=False)
prompt = f"xxx"
# Add a button to generate guidance
if st.button("Generate guidance"):
# Call the OpenAI API to generate guidance
response = openai.Completion.create(
engine="text-davinci-003",
prompt=prompt,
max_tokens=1024,
n=1,
stop=None,
temperature=0.7,
)
# Display the response to the user
guidance = response.choices[0].text.strip()
st.write(guidance)
How do you deploy your app?
Using Cloud Run my dear.
The Dockerfile
is used to define a Docker image, which is a lightweight, standalone, executable package that contains everything needed to run the application, including code, runtime, libraries, and system tools. The image is built by following the instructions in the Dockerfile
.
In the case of our app, the Dockerfile
defines an image based on the python:3.9
image, installs the necessary Python packages using pip
, and then sets the working directory and the command to run the app (python main.py
). This allows us to create a container that can run our app with all the necessary dependencies.
The deploy.yml
file is used to define the steps that will be taken by GitHub Actions when deploying our app to Cloud Run. It starts by checking out the code from the repository, then sets up the Google Cloud SDK, authenticates using a service account key, builds the Docker image using the Dockerfile
, and then deploys the image to Cloud Run.
This process is triggered when we push changes to the main branch of our repository, which then triggers the GitHub Action to build and deploy the new version of our app.
Conclusion
In conclusion, this side project showcases how we can use ChatGPT to build an app for tracking mental health. However, the possibilities are truly endless. ChatGPT and other similar AI models will undoubtedly lead to a huge game changer in the world of app development. They offer new ways to interact with users and can be used in countless use cases, from mental health to customer service and beyond.
This project is just one example of what is possible with ChatGPT and the libraries used in it. While it is not a full-featured application, it demonstrates the potential for using AI models in app development. As we continue to explore the capabilities of AI, we can expect to see more innovative applications that can improve our lives in many ways.