# Project export: TheraMind

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2025
- Tagline: Less paperwork, more patient care: the AI therapist's assistant.
- Devpost: https://devpost.com/software/theramind
- GitHub: https://github.com/cherylwu834/treehacks25
- Video: https://www.youtube.com/embed/q_3Y3kjbpZ0?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Result: winner (DAIN Labs: AI Agent Excellence & Innovation Awards ($5k Cash [1st] & $2.5K Cash [2nd] & $500 Cash [3rd] + Agent Launchpad Invitation))
- Team: 3 GitHub contributor(s) — Cheryl Wu (20 commits), carissa ott (3 commits), schan3231 (2 commits)

## Devpost submission (written by the team)

### Inspiration

Our inspiration for TheraMind stems from the growing mental health crisis and the challenges therapists face in meeting patient demand. 1 in 5 US adults experiences mental illness annually. Source — National Institute of Mental Health NIMH 1 in 5 US adults experiences mental illness annually. Source — National Institute of Mental Health NIMH 46% of psychologists couldn't meet patient demand in 2022. Source — American Psychological Association (APA) 2022 COVID-19 Practitioner Impact Survey via APA Report 46% of psychologists couldn't meet patient demand in 2022. Source — American Psychological Association (APA) 2022 COVID-19 Practitioner Impact Survey via APA Report 52% of therapists reported experiencing burnout in 2023. Source — SimplePractice 2023 Therapist Well-Being Report via Fierce Healthcare 52% of therapists reported experiencing burnout in 2023. Source — SimplePractice 2023 Therapist Well-Being Report via Fierce Healthcare Burnout-related turnover costs healthcare organizations millions. Source — American Medical Association (AMA)via AMA Report Burnout-related turnover costs healthcare organizations millions. Source — American Medical Association (AMA)via AMA Report Administrative burdens are a top burnout factor for 55% of therapists. Source — SimplePractice 2023 Therapist Well-Being Report via Fierce Healthcare Administrative burdens are a top burnout factor for 55% of therapists. Source — SimplePractice 2023 Therapist Well-Being Report via Fierce Healthcare Our guiding question, "How do we help therapists help their patients?", emphasizes the dual focus of TheraMind: empowering therapists while enhancing patient care. By addressing the challenges therapists face—such as administrative burdens, burnout, and time constraints—TheraMind enables them to dedicate more energy to their patients. Through tools like data visualization, sentiment analysis, and streamlined meeting preparation, TheraMind bridges the gap between therapist efficiency and patient outcomes. What TheraMind Does Our AI workflow automator is designed to streamline therapists' daily tasks, reducing the cognitive load of managing appointments, patient communication, and progress tracking. With a simple prompt, therapists can instantly retrieve their upcoming appointments, ensuring they stay organized without sifting through calendars. The system also automates patient reminders, sending timely emails to reduce no-shows and keep clients engaged. Additionally, our tool provides a comprehensive summary of patient progress by analyzing survey responses and visualizing historical data, offering valuable insights at a glance. By handling these essential but time-consuming tasks, our solution allows therapists to focus on what truly matters—providing quality care to their patients. How We Built TheraMind DAIN — We used DAIN as our framework to tie together all the components into an integrated workflow. DAIN helped trigger various service tools, such as checking the therapist's appointment database, automatically sending reminder emails, and retrieving detailed patient information. By streamlining these tasks, our DAIN service allows for seamless data management and communication between systems. This automation greatly reduces the cognitive load on therapists, allowing them to easily track patient progress, manage contexts between different patients, and quickly identify necessary treatments by analyzing large amounts of data efficiently. This implementation not only improves efficiency but also contributes to a more organized and manageable workflow for therapists. Data Driven Insights with Scrapybara — We used Scrapybara as an AI agent to automate data scraping from therapists' Google Drive, specifically extracting patient survey files. By leveraging summarization and sentiment analysis, it helped therapists sift through large amounts of journal entries and survey responses, identifying key emotional patterns and helpful data-driven insights. This allows for more efficient workflow management and improved mental health support by highlighting trends in patient well-being without the therapist ever having to touch a line of code to deduce those insights. Sentiment Analysis — We applied sentiment analysis to patient journal entries by processing text data to detect emotional tone and classify sentiment. Using natural language processing (NLP) techniques, we extracted key mood indicators, assigning numerical mood scores based on word choice, context, and emotional intensity. These scores were aggregated to generate quantitative metrics, allowing therapists to track fluctuations in patient mood in between sessions. The data was then visualized in the DAIN framework through intuitive graphs and dashboards, enabling therapists to quickly identify trends, detect potential concerns, and make informed decisions about patient care. Perplexity — We conducted extensive background research on mental health to better understand the challenges faced by both patients and therapists. This research, which we conducted largely with Perplexity, highlighted the growing demand for mental health services, particularly in the face of rising stress, burnout, and other mental health issues among healthcare professionals. We explored existing mental health frameworks and tools, identifying gaps in support, especially in the way therapists manage patient data and track progress. Additionally, we investigated the needs of therapists, including the increasing pressure to manage large volumes of patient information and the need for effective tools to monitor patient well-being in real-time. Our findings reinforced the importance of creating solutions that can automate time-consuming tasks, reduce mental load, and provide personalized, actionable insights for both therapists and patients. This background research streamlined by Perplexity’s efficient search methods quickly got us up to speed with the problem space and laid the foundation for our work in integrating AI agents to streamline workflows and enhance mental health. Challenges We Faced One of the main challenges we encountered was slow performance, which would require further optimization to run efficiently in real time. Additionally, integrating the AI agent, understanding its capabilities, and interfacing with different systems proved to be complex, as we wanted to ensure seamless communication and data flow across various platforms. These challenges highlighted our focus on improved optimization strategies of AI agents and better interoperability between systems to achieve smoother and faster execution in the future. Accomplishments that We're Proud Of We’re proud of creating an intuitive and user-friendly interface that makes mental health support accessible. Successfully implementing AI-driven sentiment analysis and personalized journaling features was a major achievement. Seeing our idea come to life and knowing it could positively impact people’s well-being made the late-night debugging session worth it. What We Learned Through our exploration of AI agents in automated workflows applied to healthcare, we discovered the potential to significantly enhance efficiency by automating qualitative and quantitative data analysis tasks and supporting human collaboration. These agents can optimize decision-making and provide real-time insights, improving both productivity and well-being. We learned that AI can assist professions prone to burnout that greatly impact a wide range of patients, ultimately creating more accessible, inclusive, and balanced work environments. This integration of AI into workflows is transforming healthcare and workplaces at large, having a profound social impact on well-being by enabling smarter, more efficient processes that support professionals and improve lives.

### What's next

Our vision for TheraMind is to expand its reach and impact by catering to new user groups who experience high levels of stress and emotional burnout. In the near future, we aim to tailor our AI-driven mental health support for medical professionals, project managers, educators, and more. By refining our AI’s ability to provide industry-specific emotional support and wellness insights, we can help these professionals navigate their daily lives more effectively and allow them to achieve peace of mind.

## README (from the GitHub repository)

# treehacks25
Treehack Warriors

![All features](https://github.com/user-attachments/assets/646d7364-d3ce-4b4e-a7ee-23195e8c4fe2)


## Detected evidence (automated analysis)

Indexed codebase: 6 recognized source files, 23 KB.
- Python (language) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (24 of 24)

```
.gitignore
heat_map_data.csv
heat_map.py
LICENSE
package.json
README.md
therapist-automations/.env
therapist-automations/.env.development
therapist-automations/appointmentDate.json
therapist-automations/dain.json
therapist-automations/emails.json
therapist-automations/journal_entries.csv
therapist-automations/journal-sentiment-analysis.py
therapist-automations/main.py
therapist-automations/package.json
therapist-automations/patient_summary.txt
therapist-automations/patients.json
therapist-automations/poetry.lock
therapist-automations/pyproject.toml
therapist-automations/scrappy.py
therapist-automations/src/index.ts
therapist-automations/survey copy.json
therapist-automations/survey.json
therapist-automations/tsconfig.json
```

### Dependencies

- package.json: chart.js@^4.4.7, date-fns@^4.1.0
- therapist-automations/package.json: @dainprotocol/cli@^1.1.26, @dainprotocol/service-sdk@^1.0.95, @dainprotocol/utils@^0.0.49, @types/express@^4.17.13, @types/node@^22.5.4, axios@^1.7.5, hono@^4.6.3, scrapybara@^2.2.2, ts-node@^10.4.0, typescript@^5.5.4, zod@^3.23.8
- therapist-automations/pyproject.toml: httpx@0.27, python-dotenv@^1.0.1, scrapybara@2.2.7

### Recent commits (newest first)

- add images
- Merge branch 'main' of https://github.com/cherylwu834/treehacks25
- Co-authored-by: carissa ott <rissaott@users.noreply.github.com>
- historical data dashboard
- add heat map and other charts
- Update README.md
- Update README.md
- failed pie chart
- merge conflict
- pie chart
- Merge branch 'main' of https://github.com/cherylwu834/treehacks25
- resturcture data tools
- Merge branch 'main' of https://github.com/cherylwu834/treehacks25
- update patient text files
- slight clean up
- get all apointments for a date
- graphs
- patient summary
- Merge branch 'main' of https://github.com/cherylwu834/treehacks25
- testing

## Key source files (fetched from GitHub, selected and truncated for size)

### package.json

```
{
  "dependencies": {
    "chart.js": "^4.4.7",
    "date-fns": "^4.1.0"
  }
}

```

### therapist-automations/pyproject.toml

```
[tool.poetry]
name = "therapist-automations"
version = "0.1.0"
description = ""
authors = ["nalin <74811063+lordspline@users.noreply.github.com>"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.11"
scrapybara = "2.2.7"
python-dotenv = "^1.0.1"
httpx = "0.27"


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
```

### therapist-automations/package.json

```
{
  "name": "therapist-automations",
  "version": "1.0.0",
  "description": "A Dain Protocol project",
  "main": "src/index.ts",
  "scripts": {
    "start": "ts-node src/index.ts",
    "dev": "dain dev",
    "build": "dain build",
    "deploy": "dain deploy"
  },
  "dependencies": {
    "@dainprotocol/cli": "^1.1.26",
    "@dainprotocol/service-sdk": "^1.0.95",
    "@dainprotocol/utils": "^0.0.49",
    "@types/express": "^4.17.13",
    "@types/node": "^22.5.4",
    "axios": "^1.7.5",
    "hono": "^4.6.3",
    "scrapybara": "^2.2.2",
    "ts-node": "^10.4.0",
    "typescript": "^5.5.4",
    "zod": "^3.23.8"
  }
}

```

### therapist-automations/main.py

```python
with open("patient_summary.txt", "r") as file:
    for line in file:
        print(line, end="")  # `end=""` prevents double newlines

```

### therapist-automations/src/index.ts

```typescript
import { z } from "zod";
import { exec } from 'child_process';
import * as fs from 'fs';

import { defineDAINService, ToolConfig, ServiceContext } from "@dainprotocol/service-sdk";
import {
  DainClientAuth,
  DainServiceConnection,
} from "@dainprotocol/service-sdk/client";

import {
  DainResponse,
  CardUIBuilder,
  ChartUIBuilder,
  ImageCardUIBuilder
} from "@dainprotocol/utils";


// Initialize DAIN client to connect to the email service
const auth = new DainClientAuth({
  apiKey: process.env.DAIN_API_KEY!,
});

//initialize a connection to the email service
const serviceUrl = "https://hammerhead-app-n9cx5.ondigitalocean.app";

const emailService = new DainServiceConnection(
  serviceUrl, // this is the url of the email service
  auth
);

const AppointmentSchema = z.object({
  name: z.string(),
  email: z.string().email(),
  appointment: z.string()
});

// Tool to send reminder emails to patients
const apptConfig: ToolConfig = {
  id: "fetch-appt-info",
  name: "Get Appointment Information for a date",
  description: "Fetches the appointment information for a given date. Use when asking what appointments the user has on a specific date.",
  input: z
    .object({
      date: z.string().date().describe("Appointment Date")
    })
    .describe(""),
  output: z
    .object({
      appointments: z.array(AppointmentSchema),
    }),
  handler: async ({ date }, agentInfo, context) => {
    console.log(
      `Fetching appointment information for appointments on ${date}`
    );


    // Get Patient Email and Appointment Time
    const filePath = "appointmentDate.json";
    const jsonApptData = fs.readFileSync(filePath, 'utf-8');
    const apptData = JSON.parse(jsonApptData);


    return new DainResponse({
      text: `Fetched appointment information for appointments on ${date}. Ask the user if they want to send reminder emails.`,     // Message for the AI agent
      data: { 
        appointments: apptData[date] 
      },
      ui: undefined,
    });
  },
};

// Tool to send reminder emails to patients
const emailConfig: ToolConfig = {
  id: "send-reminder-email",
  name: "Send Appointment Reminder Email",
  description: "Sends an appointment reminder email to a patient. Use when a patient has an upcoming appointment.", // TODO: Write Better Description
  input: z
    .object({
      name: z.string().describe("Patient's name"),
      // email: z.string().email().describe("Patient's email address"),
      // appointmentTime: z.string().datetime().describe("Appointment Date and Time"),
    })
    .describe("Input parameters for the appointment reminder email request"),
  output: z
    .object({
      id: z.string(),
      success: z.boolean(),
    }),
  handler: async ({ name }, agentInfo, context) => {

    // Get Patient Email and Appointment Time
    const filePath = "emails.json";
    const jsonEmailData = fs.readFileSync(filePath, 'utf-8');
    const emailData = JSON.parse(jsonEmailData);
    const email = emailData[name]['email'];
    const appointmentTime = emailData[name]['appointment'];

    console.log(
      `Sending email to ${name} at ${email}  for their appointment at ${appointmentTime}`
    );

    // Call the email service
    const response = await emailService.callTool("send-marketing-email", {
      fromName: "TheraMind" as string,
      to: [email] as Array<string>,
      subject: `Appointment Reminder for ${name}` as string,
      html: `Hi ${name}, <br><br> This is a reminder that you have an appointment at ${appointmentTime}. <br><br> Best, <br> TheraMind` as string,
    });

    // Extract the results from the response
    const { data, ui } = response;

    // console.log(response);

    return new DainResponse({
      text: `Email sent to ${name} at ${email}  for their appointment at ${appointmentTime}. Ask the user if they would like to look at patient information.`,     // Message for the AI agent
      data: data,
      ui: ui,
    });
  },
};

const allPatientSummaryConfig: ToolConfig = {
  id: "summarize-patient-information",
  name: "Summarize Patient Information",
  description: "Summarizes the information of alls patient that a therapist has.",
  input: z
    .object({}),
  output: z
    .object({
      summary: z.string().describe("Summary of the patient's information and recommendataions for talking points")
    })
    .describe("Summary of the patient's information"),
  handler: async ({ }, agentInfo, context) => {

    // Path to the Python script    
    const command = "python3 main.py";

    // Run the Python script to get the summary
    const response = await new Promise<string>((resolve, reject) => {
      exec(command, (error, stdout, stderr) => {
        if (error) {
          console.error(`Error executing Python script: ${error.message}`);
          reject(error);
          return;
        }
        if (stderr) {
          console.error(`stderr: ${stderr}`);
          reject(stderr);
          return;
        }
        
        // Assuming the Python script writes the summary to stdout
        console.log(`Python script output: ${stdout}`);
        resolve(stdout.trim());  // Return the summary
      });
    });

    return new DainResponse({
      text: `Highlights of previous interactions and give suggestions on things to touch on during the session`,     // Message for the AI agent
      data: {
        summary: response,
      },
      ui: undefined,
    });
  },
};


const patientHistoryConfig: ToolConfig = {
  id: "patient-history",
  name: "Patient History",
  description: "Historical data of patient. Use to get visualizations of all previous appointments and detailed statistics.",
  input: z
    .object({
      name: z.string().describe("Patient's name"),
      // patientInformation: z.string().describe("Notes on the patient's previous session"),
    })
    .describe("Input parameters for the patient summary request"),
  output: z
    .object({
      // summary: z.string().describe("Summary of the patient's information and recommendata
[truncated — 9994 more characters]
```

### heat_map.py

```python
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from matplotlib.colors import ListedColormap, BoundaryNorm
import matplotlib.font_manager as fm

def create_symptom_chart_from_csv(csv_filepath, filename="symptom_chart.png", patient_name="Patient"):
    """
    Creates and saves a heatmap-like symptom chart from CSV data.

    Args:
        csv_filepath (str): The path to the CSV file containing the data.
                           The CSV should have the days of the month as columns and symptom rows.
        filename (str): The name of the file to save the image to (e.g., "symptom_chart.png").
        patient_name (str): The name of the patient for the chart title.
    """

    try:
        # Read the CSV file into a Pandas DataFrame
        df = pd.read_csv(csv_filepath, index_col=0)

        # Ensure that only the first 31 columns are used
        df = df.iloc[:, :31]
        data = df.to_numpy()

        # Get the symptom labels and day labels from the DataFrame
        symptom_labels = df.index.tolist()
        day_labels = df.columns.tolist()

    except FileNotFoundError:
        print(f"Error: CSV file not found at {csv_filepath}")
        return
    except Exception as e:
        print(f"Error reading CSV file: {e}")
        return

    # Colormap - Adjusted to match provided images
    colors = ["#90EE90", "#F0E68C", "#F08080"]  # LightGreen, Khaki, LightCoral
    cmap = ListedColormap(colors)
    bounds = [0, 1, 2, 3]
    norm = BoundaryNorm(bounds, cmap.N)

    # Font Setup
    plt.rcParams['font.family'] = 'sans-serif'
    plt.rcParams['font.sans-serif'] = ['Helvetica Neue', 'Arial', 'Helvetica'] # Ensure a fallback font

    fig, ax = plt.subplots(figsize=(15, 10))  # Adjust figure size

    # Create the heatmap
    img = ax.imshow(data, cmap=cmap, norm=norm, aspect='auto')

    # Set labels, increasing font size
    fontsize = 14  #Adjust font size here
    ax.set_yticks(np.arange(len(symptom_labels)))
    ax.set_yticklabels(symptom_labels, fontsize=fontsize)
    ax.set_xticks(np.arange(len(day_labels)))
    ax.set_xticklabels(day_labels, fontsize=fontsize)

    # Rotate column labels for better readability (optional)
    plt.setp(ax.get_xticklabels(), rotation=45, ha="right", rotation_mode="anchor")

    # Add gridlines (changed color to white)
    ax.set_xticks(np.arange(data.shape[1]+1)-.5, minor=True)
    ax.set_yticks(np.arange(data.shape[0]+1)-.5, minor=True)
    ax.grid(which="minor", color="white", linestyle='-', linewidth=0.5) #Grid lines are now white
    ax.tick_params(which="minor", size=0)

    # Set title and axis labels, increase font size
    title_fontsize = 16
    ax.set_title(f"Symptom Overview for {patient_name}", fontsize=title_fontsize)
    ax.set_xlabel("Day of the Month", fontsize=fontsize)
    ax.set_ylabel("Symptom", fontsize=fontsize)

    fig.tight_layout() #Adjust layout to prevent labels from overlapping

    plt.savefig(filename, dpi=300)  # Save the figure
    plt.close(fig) #Close the figure to free memory
    print(f"Chart saved to {filename}")

if __name__ == '__main__':
    # Example Usage

    # Call the function with the updated CSV file
    create_symptom_chart_from_csv("heat_map_data.csv", "heat_map_chart.png", patient_name="Helen Wong")

```

### therapist-automations/journal-sentiment-analysis.py

```python
import nltk
nltk.download('vader_lexicon')
import pandas as pd
from nltk.sentiment import SentimentIntensityAnalyzer

file_path = "journal_entries.csv" 
df = pd.read_csv(file_path)

sia = SentimentIntensityAnalyzer()

def calculate_mood_score(text):
    sentiment = sia.polarity_scores(text)
    compound_score = sentiment['compound']
    return round(((compound_score + 1) / 2) * 9 + 1) 

df['mood_score'] = df['journal_entry'].apply(calculate_mood_score)

df['name'] = df['first_name'] + " " + df['last_name']
output_df = df[['name', 'date', 'mood_score']]

output_df.to_csv("mood_scores.csv", index=False)

print("Mood scores saved to mood_scores.csv")

```

### therapist-automations/scrappy.py

```python
from scrapybara import Scrapybara
from scrapybara.anthropic import Anthropic
from scrapybara.tools import BashTool, ComputerTool, EditTool, BrowserTool
from scrapybara.prompts import UBUNTU_SYSTEM_PROMPT
from pydantic import BaseModel
from typing import List
from dotenv import load_dotenv
import os
import json

load_dotenv()

# Define schemas for structured output
class Patient(BaseModel):
    patientID: str
    mood: str
    feelings: str

class Patients(BaseModel):
    patients: List[Patient]

def handle_step(step, log):
    """Stores step output in a list and prints it."""
    step_info = f"\nStep output: {step.text}"
    log.append(step_info)
    print(step_info)

    if step.tool_calls:
        for call in step.tool_calls:
            tool_info = f"Tool used: {call.tool_name}"
            log.append(tool_info)
            print(tool_info)
    
    if step.usage:
        token_info = f"Tokens used: {step.usage.total_tokens}"
        log.append(token_info)
        print(token_info)

def main():
    client = Scrapybara(
        api_key=os.getenv("SCRAPYBARA_API_KEY", "YOUR_API_KEY"),
        timeout=600,
    )

    # Start instance
    print("initializing scrapybara instance")
    instance = client.start_ubuntu()
    instance.browser.start()

    try:
        tools = [
            BashTool(instance),
            ComputerTool(instance),
            EditTool(instance),
            BrowserTool(instance),
        ]
        model = Anthropic()

        # Store all step logs
        step_logs = []

        # Run the AI process
        soft_response = client.act(
            model=model,
            tools=tools,
            system=UBUNTU_SYSTEM_PROMPT,
            prompt="Go to https://drive.google.com/file/d/1jzMkVDYo3097MFXO6oblPDOvPm91zHfF/view?usp=sharing. Summarize each patient's needs in one sentence, and put them in a list (not numbered, just new line).",
            on_step=lambda step: handle_step(step, step_logs),
        )

        raw_output = step_logs[-2]
        start_index = raw_output.find("Patient 1")  # Find where patient summary starts
        clipped_text = raw_output[start_index:]  # Extract from "Patient 1" onwards

        # Save all step logs and final response
        file_path = "patient_summary.txt"
        with open(file_path, "w") as f:
            f.write(clipped_text)  

        print(f"✅ Patient summaries saved to {file_path}")

        # Run the AI process
        structured_response = client.act(
            model=model,
            tools=tools,
            system=UBUNTU_SYSTEM_PROMPT,
            prompt="Go to https://drive.google.com/file/d/1jzMkVDYo3097MFXO6oblPDOvPm91zHfF/view?usp=sharing. Extract the patient data for all 5 patients in structured JSON format with patientID, moodScore (scale of 1-10), and feelings. Please save the entirety of the journal entry in the feelings column.",
            schema=Patient,
            on_step=lambda step: handle_step(step, step_logs),
        )

        #✅ Extract structured patient data
        if structured_response.output:
            patients_data = structured_response.output  # Ensure it's parsed into the Patients schema
            
            # Save as JSON
            json_path = "patients.json"
            with open(json_path, "w") as f:
                json.dump(patients_data.model_dump(), f, indent=4)

            print(f"✅ Structured patient data saved to {json_path}")

    finally:
        instance.browser.stop()
        instance.stop()

if __name__ == "__main__":
    main()
```