# Project export: MedMeld

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: Cal Hacks 11.0
- Tagline: Your personal health assistant to help you easily access and understand your medical history
- Devpost: https://devpost.com/software/medmeld
- GitHub: https://github.com/CheJeff/MedMeld
- Team: 4 GitHub contributor(s) — Sulaiman Mulla (22 commits), Gabriel Gonzalez (11 commits), blubywaff (10 commits), Jeffrey Cheung (9 commits)

## Devpost submission (written by the team)

### Inspiration

The inspiration came from trying to think of ways to have a real world impact when we started thinking about the fact that we didn't actually know how to easily access our medical records. One team member has to go through four portals himself just to figure out which record is the correct one.

### What it does

MedMeld allows patients to pull their medical history from their respective providers in one place. It then makes understanding your history easier by removing the medical jargon with the help of Google Gemini

### How we built it

We built this project with python using fetch.ai's uagents to perform tasks like pulling the data from the respective health care providers. We use gemini API to summarize and aggregate medical records from various sources for easy viewing and understanding of complex medical jargon

### Challenges we ran into

We had trouble figuring out how to get the uagents to communicate with each other over the net. We also had trouble connecting to our postgres database

### What we learned

We learned about distributed communication with fetch.ai and integrating with google's API

### What's next

We plan to significantly enhance the user experience by making the process of accessing and managing medical records more intuitive and user-friendly. Our vision is to empower patients to take control of their healthcare data with ease and confidence. By integrating Google Gemini, we can add intelligent features that provide patients with more comprehensive insights into their medical history, while maintaining the highest standards of privacy and security.

## README (from the GitHub repository)

This is the CalHacks 11.0 project of:

Sulaiman Mulla: sulaiman_1@tamu.edu
Jeffrey Cheung: jcheung@tamu.edu
Alex Beamer: alexbeamer@tamu.edu
Gabriel Gonzalez: gabriel29@tamu.edu


## Detected evidence (automated analysis)

Indexed codebase: 16 recognized source files, 52 KB.
- Python (language) — detected in the code
- SQL (language) — detected in the code
- Google Gemini (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (22 of 22)

```
.gitignore
agents/__init__.py
agents/hospital.py
agents/hospital2.py
agents/identity.py
agents/test/__init__.py
agents/test/identity_agent.py
dummy_data/hospital1Generator.py
dummy_data/hospital2Generator.py
gemini.py
gui/.gitignore
gui/MedMesh/__init__.py
gui/MedMesh/MedMesh.py
gui/requirements.txt
gui/rxconfig.py
messages/__init__.py
messages/.gitignore
messages/pyproject.toml
messages/readme.md
readme.md
requirements.txt
scripts/dbsetup.sql
```

### Dependencies

- gui/requirements.txt: reflex@==0.6.3
- messages/pyproject.toml: uagents
- requirements.txt: faker, google-generativeai, psycopg[binary,pool], python-dotenv, reflex@==0.6.3, uagents

### Recent commits (newest first)

- update hospital agents and messages
- Healthcare provider page goes back to login
- Changed Username to Name
- got rid of bureau.py and its dependencies
- Added Forgot password page and changed query to view
- ignore agent data (fetch storage)
- merge identity-agent into main
- separate hospital agents
- add provider fetch addr to db
- update requirements.txt and remove unneeded py venv
- update dbsetup
- identity agent working for addprovider and signin
- move messages to separate package
- identity agent, create account working
- Merge branch 'ui_gemini' of github.com:CheJeff/MedMeld into ui_gemini
- Updated UI: Still quite some things to do
- commented out weird function call
- updated gemini input for more detail
- modified db names to account for folder structure
- Prints output as one string now

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

### requirements.txt

```
google-generativeai
python-dotenv
reflex==0.6.3
faker
uagents
psycopg[binary,pool]

```

### gui/requirements.txt

```
reflex==0.6.3

```

### messages/pyproject.toml

```
# [build-system]
# requires = ["setuptools >= 61.0"]
# build-backend = "setuptools.build_meta"

[project]
name = "medmeld-messages"
version = "0.1.0"
dependencies = ["uagents"]
requires-python = ">= 3.8"

```

### gemini.py

```python
import google.generativeai as genai
import os
from dotenv import load_dotenv

load_dotenv()
genai.configure(api_key=os.environ["API_KEY"])

#generate response from file
def generate_info(json_input, prompt):
    model = genai.GenerativeModel("gemini-1.5-flash")
    response = model.generate_content(f"My question is: {prompt}\n\n and the following is my record: {json_input} \n\n summarize my record before answering my question")
    return response.text
```

### gui/rxconfig.py

```python
import reflex as rx

config = rx.Config(
    app_name="MedMesh",
)
```

### messages/__init__.py

```python
from uagents import Model
from typing import TypedDict

class Token:
    _patient_id: int
    def __init__(self, pid: int) -> None:
        self._patient_id = pid

    @property
    def patient_id(self) -> str:
        return self._patient_id

    def to_str(self) -> str:
        return str(self._patient_id).rjust(9, "0")

    @classmethod
    def from_str(cls, parse: str):
        return cls(int(parse))


class ReqCreateAccount(Model):
    name: str
    password: str

class ResCreateAccount(Model):
    token: str
    status: str

class ReqSignIn(Model):
    name: str
    password: str

class ResSignIn(Model):
    token: str
    status: str

class ReqAddProvider(Model):
    token: str
    providers: list[str]

class ResAddProvider(Model):
    token: str
    status: str

class ReqNameToken(Model):
    token: str

class ResNameToken(Model):
    token: str
    name: str
    status: str


class MedicalHistory(TypedDict):
    diagnoses: list[str]  # Diagnosis
    procedures: list[str]  # Procedures
    prescriptions: list[str]  # Prescriptions
    treatments: list[str]  # Treatments
    tests: list[str]  # Tests


class PatientQuery(Model):
    patient_name: str

class PatientData(Model):
    full_name: str
    dob: str
    gender: str
    address: str
    phone_number: str
    email: str
    medical_history: MedicalHistory

```

### scripts/dbsetup.sql

```sql
DROP TABLE IF EXISTS Patients CASCADE;
DROP TABLE IF EXISTS Providers CASCADE;
DROP TABLE IF EXISTS PatientProviders CASCADE;

CREATE TABLE Patients (
	id SERIAL PRIMARY KEY,
	name VARCHAR(255) UNIQUE NOT NULL,
	password VARCHAR(1023) NOT NULL
);

CREATE TABLE Providers (
	id SERIAL PRIMARY KEY,
	name VARCHAR(255) UNIQUE NOT NULL,
    faddr VARCHAR(255) NOT NULL
);

CREATE TABLE PatientProviders (
	patient_id INT NOT NULL,
	provider_id INT NOT NULL,
	PRIMARY KEY (patient_id, provider_id),
	FOREIGN KEY (patient_id) REFERENCES Patients(id),
	FOREIGN KEY (provider_id) REFERENCES Providers(id)
);

INSERT INTO Patients (name, password) VALUES
	('Jone Doe','D0pNC0ZGeQPhKAeWzlHyUsWtG3fW0peHcaXTzaPXz5Bh2WydUXVup1T3Oqvl9DPeAYlY9nLuM07hI4CiVNMGPsfXmJCjzXuu6rJ_N9kL1GJki1fPpi0LmlheUPsy0O0zQOFOXiAOg5TbDmzeJvAbQqKuRIz5q9kH4759VT-W3n7NPbBkkGmNbFhTUjaMjc6P_mnMo5oJ50JdbBr8R_8b08z3QLdmSg5DaJ2j7pY8kcJhjDZ7yW9430lrXCZTGXibxE1Vp3qjwklcfKDJjWWBnkSuXXYxGjCGD65vaiFrGg3RsXl5JViOg8Q5zAJjkJ2x_udH9Uo17AJL0KXbXyThv-T5ybrqu7vuW3uotuIB1H6DV4XdbPWNhD8VL1OoqPNU');

INSERT INTO Providers (name, faddr) VALUES
	('Health Primary', 'agent1qgx089sfn6v8mg830z94spj9rg2y4pcql9sfjnqtg33zu3pezqxpq282u3a'),
	('Health Secondary', 'agent1qw54sfxtfpmlgeay0hp480te5v3zy3lhwyw884q9skuje0xdygce5rww222');

INSERT INTO PatientProviders (patient_id, provider_id)
SELECT Patients.id, Providers.id
FROM Patients, Providers
WHERE Patients.name = 'Jone Doe'
	AND Providers.name = 'Health Secondary';

```

### agents/hospital2.py

```python
from uagents import Agent, Context, Model
from uagents.setup import fund_agent_if_low
from messages import PatientQuery, PatientData, MedicalHistory
import sqlite3
import json

# Hospital 2 Agent
Hospital2Agent = Agent(
    name="hospital2_agent",
    seed="HospitalTwoAgent",
    port=7702,
    endpoint=["http://127.0.0.1:7702/submit"]
)

fund_agent_if_low(Hospital2Agent.wallet.address())

# Function to read data from hospital2 database
def read_hospital2_data(patient_name):
    conn = sqlite3.connect('databases/hospital2_records.db')
    cursor = conn.cursor()

    cursor.execute('''
        SELECT full_name, dob, gender, contact_info, email, medical_history 
        FROM hospital2_patients 
        WHERE full_name = ?
    ''', (patient_name,))
    patient_data = cursor.fetchall()

    common_data = []
    for patient in patient_data:
        full_name = patient[0]  # Full name already combined
        dob = patient[1]  # Date of birth as text
        gender = patient[2]  # Gender
        contact_info = patient[3].split(", ")  # Contact info (split into address and phone number)
        address = contact_info[0] if len(contact_info) > 0 else ""
        phone_number = contact_info[1] if len(contact_info) > 1 else ""
        email = patient[4]  # Email
        medical_history: MedicalHistory = json.loads(patient[5])  # Parse JSON-like medical history field

        common_data.append(PatientData(
            full_name = full_name,
            dob = dob,
            gender = gender,
            address = address,
            phone_number = phone_number,
            email = email,
            medical_history = medical_history
        ))

    conn.close()
    return common_data[0]

# Hospital 2 handles queries
@Hospital2Agent.on_message(model=PatientQuery)
async def handle_hospital2_query(ctx: Context, sender: str, msg: PatientQuery):
    patient_name = msg.patient_name
    patient_data = read_hospital2_data(patient_name)
    await ctx.send(sender, patient_data)

if __name__ == "__main__":
    print(f"Hospital2Agent Address: {Hospital2Agent.address}")
    Hospital2Agent.run()

```

### agents/hospital.py

```python
from uagents import Agent, Context, Model
from uagents.setup import fund_agent_if_low
from messages import PatientQuery, PatientData
import sqlite3
import json

# Hospital 1 Agent
HospitalAgent = Agent(
    name="hospital1_agent",
    seed="HospitalOneAgent",
    port=7701,
    endpoint=["http://127.0.0.1:7701/submit"]
)

fund_agent_if_low(HospitalAgent.wallet.address())  # type: ignore

# Function to read data from hospital1 database
def read_hospital1_data(patient_name: str):
    conn = sqlite3.connect('databases/hospital1_records.db')
    cursor = conn.cursor()

    cursor.execute('''
        SELECT first_name, last_name, dob, gender, address, phone_number, email, 
               diagnosis, procedures, prescriptions, treatments, tests 
        FROM hospital1_patients 
        WHERE first_name || " " || last_name = ?
    ''', (patient_name,))
    patient_data = cursor.fetchall()

    common_data = []
    for patient in patient_data:
        full_name = f"{patient[0]} {patient[1]}"  # First and last name
        dob = patient[2]  # Date of birth
        gender = patient[3]  # Gender
        address = patient[4]  # Address
        phone_number = patient[5]  # Phone number
        email = patient[6]  # Email
        medical_history = {
            "diagnoses": patient[7].split(", ") if patient[7] else [],  # Diagnosis
            "procedures": patient[8].split(", ") if patient[8] else [],  # Procedures
            "prescriptions": patient[9].split(", ") if patient[9] else [],  # Prescriptions
            "treatments": patient[10].split(", ") if patient[10] else [],  # Treatments
            "tests": patient[11].split(", ") if patient[11] else []  # Tests
        }
        common_data.append(PatientData(
            full_name=full_name,
            dob=dob,
            gender=gender,
            address=address,
            phone_number=phone_number,
            email=email,
            medical_history=medical_history  # type: ignore
        ))

    conn.close()
    return common_data[0]

# Hospital 1 handles queries
@HospitalAgent.on_message(model=PatientQuery)
async def handle_hospital1_query(ctx: Context, sender: str, msg: PatientQuery):
    patient_name = msg.patient_name
    patient_data = read_hospital1_data(patient_name)
    await ctx.send(sender, patient_data)

if __name__ == "__main__":
    print(f"Hospital1Agent Address: {HospitalAgent.address}")
    HospitalAgent.run()

```

### agents/identity.py

```python
from uagents import Agent, Context, Model
from uagents.setup import fund_agent_if_low
from os import environ
import hashlib
import psycopg
from psycopg.rows import dict_row
import random
import base64
from messages import *

agent = Agent(
    seed = "identity agent string",
    name = "MedMeld Identity Agent",
    port = 8004,
    endpoint = ["http://127.0.0.1:8004/submit"]
)

fund_agent_if_low(agent.wallet.address())  # type: ignore

def hashpass(passwd: str) -> str:
    # generate salt
    bts = random.randbytes(256)
    return base64.urlsafe_b64encode(bts + hashlib.sha256(bts + passwd.encode()).digest()).decode()

def verifypass(passwd: str, hash: str) -> bool:
    hashbts = base64.urlsafe_b64decode(hash.encode())
    return hashbts[256:] == hashlib.sha256(hashbts[:256] + passwd.encode()).digest()

@agent.on_message(model=ReqCreateAccount)  #, replies=ResCreateAccount)
async def create_account(ctx: Context, sender: str, msg: ReqCreateAccount):
    try:
        ctx.logger.info("Identity Agent Create Account")
        ctx.logger.info(f"\t{sender}")
        ctx.logger.info(f"\t{msg}")
        pid: int | None = None
        with psycopg.connect(environ["PGSQL_CONSTR"], row_factory=dict_row) as connection:
            er = connection.execute("INSERT INTO Patients (name, password) VALUES (%s, %s) RETURNING id;", (msg.name, hashpass(msg.password)))
            for row in er:
                pid = int(row["id"])
        if pid is None:
            raise ValueError("")
        await ctx.send(sender, ResCreateAccount(token=Token(pid).to_str(), status="ok"))
        return
    except Exception as e:
        raise e
        ctx.logger.error("CreateAccount Failed")
        await ctx.send(sender, ResCreateAccount(token=Token(0).to_str(), status="ok"))

@agent.on_message(model=ReqSignIn)
async def sign_in(ctx: Context, sender: str, msg: ReqSignIn):
    print("Identity Agent Sign In")
    print("\t",sender)
    print("\t",msg)
    with psycopg.connect(environ["PGSQL_CONSTR"], row_factory=dict_row) as connection:
        er = connection.execute("SELECT id, password FROM Patients WHERE name = %s;", (msg.name,))
        pswd: str | None = None
        id: int | None = None
        for row in er:
            pswd = row["password"]
            id = row["id"]
            ctx.logger.info(f"Sign In found for {msg.name}({id}): '{pswd}'")
        if pswd is None or not verifypass(msg.password, pswd):
            await ctx.send(sender, ResSignIn(token=Token(-1).to_str(), status="credentials rejected"))
            return
        await ctx.send(sender, ResSignIn(token=Token(id).to_str(), status="ok"))
        return

@agent.on_message(model=ReqAddProvider)
async def add_providers(ctx: Context, sender: str, msg: ReqAddProvider):
    print("Identity Agent Add Providers")
    print("\t",sender)
    print("\t",msg)
    with psycopg.connect(environ["PGSQL_CONSTR"]) as connection:
        connection.execute("INSERT INTO PatientProviders (patient_id, provider_id) SELECT %s, id FROM Providers WHERE name = ANY(%s);", (Token.from_str(msg.token).patient_id, msg.providers,))
        await ctx.send(sender, ResAddProvider(token=msg.token, status="ok"))

@agent.on_message(model=ReqNameToken)
async def name_from_token(ctx: Context, sender: str, msg: ReqNameToken):
    print("Identity Agent Name Token")
    print("\t",sender)
    print("\t",msg)
    name: str | None = None
    with psycopg.connect(environ["PGSQL_CONSTR"]) as connection:
        er = connection.execute("SELECT name FROM Patients WHERE id = %s;", (Token.from_str(msg.token).patient_id,))
        for row in er:
            name = str(row["name"])
    if name is None:
        raise ValueError()
    await ctx.send(sender, ResNameToken(token=msg.token, name=name, status="ok"))
    return

if __name__ == "__main__":
    print("Identity Agent Address:", agent.address)
    agent.run()

```

[4 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]