# Project export: PrescribeRX

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 2024
- Tagline: Based on user health data recommending specific kind of medication.
- Devpost: https://devpost.com/software/prescriberx
- GitHub: https://github.com/prince-ao/treehacks2024
- Video: https://www.youtube.com/embed/CTIOauL-ytg?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — prince-ao (19 commits)

## Devpost submission (written by the team)

### Inspiration

It is difficult for people to find what medication they need and they often have to go through a process of trail and error in order to figure that out. A close friend of mine went through that same process, he had to test 4 different blood pressure medications before he could figure out which one worked for him.

### What it does

PrescribeRx is a cross-platform mobile application that prescribes medication to you based on continually updating health data coming from various wearable. More specifically, it breaks down your health metrics into several categories and based on each category it recommends medication if it notices that that category could need some or a lot of support.

### How we built it

Our application is a full-stack monorepo, which the Bun runtime power the whole stack. In the backend we used elysia.js as our backend framework, postgreSQL as the database, typescript as the primary language, langchain as our llm framework, Terra API as our health data provider, Monster API for fine tuning our model, and together.ai for their open source models. In the frontend we use React Native Expo as our framework for making the cross-platform mobile application, we used typescript as our primary programming langauge.

### Challenges we ran into

Authenticating the user with Terra API and effectively recommending them medication were the most challenging part of building the application. Authentication was difficult because authentication is bespoke the the application, so we have to figure out how we would authenticate on our side. We also had to figure out the process of recommending users medications that were useful.

### Accomplishments we're proud of

In the end, we were able to both authenticate with Terra API and come up with a strategy that would effectively recommend medication to users. Our recommendation algorithm was based on a mixture of the latest large language model techniques, including prompt engineering and fine-tuning; this made it possible for us to give the best recommendations to users.

### What we learned

While building the application we had to learn, and relearn, many things. Some of them were: using Bun js effectively for full-stack, we learn how to integrate with many AI services like Monster API and Together.ai, and finally we learned how to integrate the Terra API platform with our app.

### What's next

We plan on adding more health categories to assist a broader range of customers. We also want to build more on the idea of having the user chat with their own data. We also want to improve our medication suggestions by trying new models, improving our fine-tuning, and crafting better prompts.

## README (from the GitHub repository)

<p align="center"><img src="./frontend/assets/images/logo1.png" width="200px"></p>

# PrescribeRx

PrescribeRx is a cross-platform mobile application that predicts what medications patients should take based on various health indicators that could be found on wearable devices, such as an apple watch.

For technical detail, check out [the devpost](https://devpost.com/software/prescriberx)

## Screenshots

<div style="display:flex;flex-direction:row;justify-content:space-around">
    <img src="./frontend/assets/images/Screenshot_20240218-082203.png" width="150px" />
    <img src="./frontend/assets/images/Screenshot_20240218-082214.png" width="150px" />
    <img src="./frontend/assets/images/Screenshot_20240218-082218.png" width="150px" />
    <img src="./frontend/assets/images/Screenshot_20240218-082241.png" width="150px" />
</div>


## Detected evidence (automated analysis)

Indexed codebase: 46 recognized source files, 91 KB.
- JavaScript (language) — detected in the code
- LangChain (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- SQL (language) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- AWS (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (65 of 65)

```
.gitignore
backend/.env
backend/.gitignore
backend/app.json
backend/bun.lockb
backend/Dockerfile
backend/package.json
backend/prisma/migrations/20240217071906_init/migration.sql
backend/prisma/migrations/migration_lock.toml
backend/prisma/schema.prisma
backend/README.md
backend/src/db.ts
backend/src/groups/account.ts
backend/src/groups/auth.ts
backend/src/groups/device.ts
backend/src/groups/home.ts
backend/src/groups/index.ts
backend/src/groups/medication.ts
backend/src/groups/webhook.ts
backend/src/index.ts
backend/tsconfig.json
documentation/architecture.md
fine-tune/all_medicine.py
fine-tune/app.py
fine-tune/data.jsonl
fine-tune/medicine.py
fine-tune/Pipfile
fine-tune/Pipfile.lock
fine-tune/tagCleaner.py
frontend/.gitignore
frontend/app.json
frontend/app/_layout.tsx
frontend/app/(tabs)/_layout.tsx
frontend/app/(tabs)/index.tsx
frontend/app/(tabs)/two.tsx
frontend/app/+not-found.tsx
frontend/app/appinfo1/_layout.tsx
frontend/app/appinfo1/index.tsx
frontend/app/appinfo2/_layout.tsx
frontend/app/appinfo2/index.tsx
frontend/app/index.tsx
frontend/app/login/_layout.tsx
frontend/app/login/index.tsx
frontend/app/med-list/_layout.tsx
frontend/app/med-list/index.tsx
frontend/app/signup/_layout.tsx
frontend/app/signup/index.tsx
frontend/app/terra-connect/_layout.tsx
frontend/app/terra-connect/index.tsx
frontend/babel.config.js
frontend/bun.lockb
frontend/components/__tests__/StyledText-test.js
frontend/components/EditScreenInfo.tsx
frontend/components/ExternalLink.tsx
frontend/components/StyledText.tsx
frontend/components/Themed.tsx
frontend/components/useClientOnlyValue.ts
frontend/components/useClientOnlyValue.web.ts
frontend/components/useColorScheme.ts
frontend/components/useColorScheme.web.ts
frontend/constants/Colors.ts
frontend/eas.json
frontend/package.json
frontend/tsconfig.json
README.md
```

### Dependencies

- backend/package.json: @elysiajs/cors@^0.8.0, @elysiajs/jwt@^0.8.0, @elysiajs/swagger@^0.8.5, @langchain/community@^0.0.30, @langchain/core@^0.1.30, @prisma/client@^5.9.1, bun-types@latest, elysia@latest, langchain@^0.1.20, prisma@^5.9.1, terra-api@^1.4.5
- frontend/package.json: @babel/core@^7.20.0, @expo/vector-icons@^14.0.0, @react-native-async-storage/async-storage@1.21.0, @react-native-material/core@^1.3.7, @react-navigation/native@^6.0.2, @types/react@~18.2.45, @types/react-native@^0.73.0, expo@~50.0.7, expo-font@~11.10.3, expo-image@~1.10.6, expo-linking@~6.2.2, expo-router@~3.4.7, expo-splash-screen@~0.26.4, expo-status-bar@~1.11.1, expo-system-ui@~2.9.3, expo-web-browser@~12.8.2, jest@^29.2.1, jest-expo@~50.0.2, nativewind@^2.0.11, react@18.2.0, react-dom@18.2.0, react-native@0.73.4, react-native-keyboard-aware-scroll-view@^0.9.5, react-native-paper@^5.12.3, react-native-safe-area-context@4.8.2, react-native-screens@~3.29.0, react-native-web@~0.19.6, react-test-renderer@18.2.0, tailwindcss@3.3.2, typescript@^5.1.3

### Recent commits (newest first)

- read me complete
- documentation
- done
- s
- s
- s
- mong
- ai mombo jumbo
- success response
- backend terra auth ww
- yup
- another one
- emotional damage
- fail proof 2
- mo stuff
- prob fix
- home dashboard done
- 1
- adding logging
- ready for deploymente

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

### documentation/architecture.md

```markdown
# prescriptionRx Software Architecture & Design

- Author(s): Prince Addo
- Date: February 16, 2024
- Version: v1

## Table of contents

## Introduction

### Definitions

- CRUD: Create Read Update Delete
- AWS: Amazon Web Service
- JWT: JSON Web Token

### Purpose of document

The purpose of this document is to act as a complete software architecture for **prescriptionRx**.

### Scope of the application

#### Must have

- Home:
  - User is able to create a profile
  - User is able to see a dashboard which health categories
    - The dashboard updates in real time
  - Clicking on a health categories brings up a list of recommended medications for that category
  - Clicking on a medication brings more details (side effects, etc.) of said medication
  - User should be able to see prices of medications
- Profile
  - Show stats on a user's health
- Chat
  - User should be able to chat and get accurate answers from the llm
  - User should be able to CRUD their chat
- Settings:
  - Settings feature

#### Should have

- User can search for any medication and see if we would recommend it

#### Could have

- User can search for a particular medication that they were recommended

#### Wont have

## Architecture goal

The goal of this architecture is to:

- Implement all the features
- Use the least number of components
- Minimize cost
- Let the backend handle all the technical heavy-lifting and the frontend be pretty

## Technology Stack

### Frontend

- Language: Typescript
- Framework: Expo + React Native
- Routing: Expo Router
- Styling: NativeWind
- Hosting: Intel
- Runtime: Bun (MIND BLOWN!!! THIS MIGHT WIN THE BUN PRIZE)

### Backend

- Language: Typescript
- Framework: ElysiaJS
- ORM: Prisma
- Relational Database: PostgreSQL
- Vector Database: ?
- LLM: Together.ai
- Cache: Redis
- Object Store: AWS (maybe change)
- Runtime: Bun (Sponsors)

### External APIs

- [Terra API](https://docs.tryterra.co/)
- Together.ai

## Relational Database Design

- Database: prescription_rx

### Tables

**_User:_**

```sql
CREATE TABLE users (
  id SERIAL PRIMARY KEY NOT NULL,
  username VARCHAR(50) NOT NULL,
  email VARCHAR(320) NOT NULL,
  password VARCHAR(100) NOT NULL,
  profile_image VARCHAR(500),
  created DATETIME
);
```

**_Terra Account:_**

```sql
CREATE TABLE terra_accounts (
  id SERIAL PRIMARY KEY NOT NULL,
  user_id NOT NULL REFERENCES users(id),
  terra_user_id TEXT NOT NULL,
  terra_resource TEXT NOT NULL,
  terra_reference_id TEXT NOT NULL
);
```

**_Medication Recommendation:_**

```sql
CREATE TABLE medication_recommendations (
  id SERIAL PRIMARY KEY NOT NULL
  user_id INT NOT NULL REFERENCES users(id),
  recommended_dosage TEXT,
  date_of_recommendation TIMESTAMP NOT NULL,
  price TEXT NOT NULL,
  reason_for_recommendation TEXT NOT NULL,
  medication_name TEXT NOT NULL,
  medication_image TEXT NOT NULL
);
```

**_Current Medication:_**

```sql
CREATE TABLE current_medications (
  id SERIAL PRIMARY KEY NOT NULL,
  user_id NOT NULL REFERENCES users(id
[truncated — 4136 more characters]
```

### backend/Dockerfile

```
FROM node:latest

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install -g bun

RUN bun install

COPY . .

EXPOSE 3000

CMD ["bun", "dev"]
```

### backend/package.json

```
{
  "name": "backend",
  "version": "1.0.50",
  "scripts": {
    "dev": "bun run --watch src/index.ts"
  },
  "dependencies": {
    "@elysiajs/cors": "^0.8.0",
    "@elysiajs/jwt": "^0.8.0",
    "@elysiajs/swagger": "^0.8.5",
    "@langchain/community": "^0.0.30",
    "@langchain/core": "^0.1.30",
    "@prisma/client": "^5.9.1",
    "elysia": "latest",
    "langchain": "^0.1.20",
    "terra-api": "^1.4.5"
  },
  "devDependencies": {
    "bun-types": "latest",
    "prisma": "^5.9.1"
  },
  "module": "src/index.js"
}

```

### frontend/package.json

```
{
  "name": "frontend",
  "main": "expo-router/entry",
  "version": "1.0.0",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web",
    "test": "jest --watchAll"
  },
  "jest": {
    "preset": "jest-expo"
  },
  "dependencies": {
    "@expo/vector-icons": "^14.0.0",
    "@react-native-async-storage/async-storage": "1.21.0",
    "@react-native-material/core": "^1.3.7",
    "@react-navigation/native": "^6.0.2",
    "expo": "~50.0.7",
    "expo-font": "~11.10.3",
    "expo-image": "~1.10.6",
    "expo-linking": "~6.2.2",
    "expo-router": "~3.4.7",
    "expo-splash-screen": "~0.26.4",
    "expo-status-bar": "~1.11.1",
    "expo-system-ui": "~2.9.3",
    "expo-web-browser": "~12.8.2",
    "nativewind": "^2.0.11",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-native": "0.73.4",
    "react-native-keyboard-aware-scroll-view": "^0.9.5",
    "react-native-paper": "^5.12.3",
    "react-native-safe-area-context": "4.8.2",
    "react-native-screens": "~3.29.0",
    "react-native-web": "~0.19.6"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0",
    "@types/react": "~18.2.45",
    "@types/react-native": "^0.73.0",
    "jest": "^29.2.1",
    "jest-expo": "~50.0.2",
    "react-test-renderer": "18.2.0",
    "tailwindcss": "3.3.2",
    "typescript": "^5.1.3"
  },
  "private": true
}

```

### fine-tune/app.py

```python
import bs4
import requests
import pandas
import json

import medicine


def makeLink(link):
    return 'https://www.drugs.com' + link
    
#MEDS NAME
def makeDF():
    read_more = []
    for item in med_links:
        read_more.append(makeLink(item))
    
    data = {"names":med_names, "Read More":read_more}
    df = pandas.DataFrame(data= data)
    print(df.to_string())

all_data = []


for initial in [ # "ab", "ac", "ad", "ae", "af", "ag", "ah", "ai", "aj", "ak", "al", "am", "an", "ao", "ap",
    #"aq", "ar", "as", "at", "au", "av", "ax", "ay", "az", "ba", "bc", "bd", "be", "bi", "bl", "bo", "bp",
    #"br", "bs", "bu", "by", "ca", "cb", "cc", "cd", "ce", "cf", "cg", "ch", "ci", "cj", "ck", "cl", "cm",
"cr"]: # "cq", "cr", "cs", "ct", "cu", "cv", "cw", "cx", "cy", ]:
    URL = f"https://www.drugs.com/alpha/{initial}.html"
    print(URL + " whoa" )
    page = requests.get(URL)
    print(page)
    soup = bs4.BeautifulSoup(page.content,'html.parser')
    try:
        med_names = soup.find('ul',class_ = 'ddc-list-column-2').text.split("\n")
        med_links = [str(a['href']) for a in soup.select('.ddc-list-column-2 a')]
        i = 0

        for item in med_links:
            if i == 1:
                break
            i += 1
            curr_link = makeLink(item)
            med_page = requests.get(curr_link)
            med_soup = bs4.BeautifulSoup(med_page.content,'html.parser') 
            res = medicine.explore_med(med_soup)

            all_data.append({"text": json.dumps(res)})
    except:
        ...


text_file = open("data.jsonl", "w")
text_file.write(json.dumps(all_data))
text_file.close()

```

### frontend/app/index.tsx

```typescript
import { View, Text } from "react-native";
import { useEffect } from "react";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { Redirect, router } from "expo-router";

const App = () => {
  useEffect(() => {
    (async () => {
      if (await AsyncStorage.getItem("token")) {
        router.replace("/(tabs)/");
      } else {
        router.replace("/login/");
      }
    })();
  }, []);
  return <></>;
};

export default App;

```

### backend/src/index.ts

```typescript
import { Elysia } from "elysia";
import { jwt } from "@elysiajs/jwt";
import { swagger } from "@elysiajs/swagger";
import { auth, account, webhook, home, device, medication } from "./groups";
import { cors } from "@elysiajs/cors";

const app = new Elysia()
  .use(cors())
  .use(swagger({ path: "/docs" }))
  .use(
    jwt({
      name: "jwt",
      secret: process.env.JWT_SECRET as string,
      exp: "7d",
    })
  )
  .onRequest((e) => {
    console.log(e);
  });
const PORT = 3000;

app.get("/", () => "Hello from PrescriptionRx API");
app.use(auth);
app.use(account);
app.use(webhook);
app.use(home);
app.use(device);
app.use(medication);

app.listen(PORT, (s) => console.log(`🦊 Elysia is running at ${PORT}`));

```

### frontend/app/_layout.tsx

```typescript
import FontAwesome from "@expo/vector-icons/FontAwesome";
import {
  DarkTheme,
  DefaultTheme,
  ThemeProvider,
} from "@react-navigation/native";
import { useFonts } from "expo-font";
import { Stack } from "expo-router";
import * as SplashScreen from "expo-splash-screen";
import { useEffect } from "react";

import { useColorScheme } from "@/components/useColorScheme";

export {
  // Catch any errors thrown by the Layout component.
  ErrorBoundary,
} from "expo-router";

export const unstable_settings = {
  // Ensure that reloading on `/modal` keeps a back button present.
  initialRouteName: "(tabs)",
};

// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();

export default function RootLayout() {
  const [loaded, error] = useFonts({
    SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
    ...FontAwesome.font,
  });

  // Expo Router uses Error Boundaries to catch errors in the navigation tree.
  useEffect(() => {
    if (error) throw error;
  }, [error]);

  useEffect(() => {
    if (loaded) {
      SplashScreen.hideAsync();
    }
  }, [loaded]);

  if (!loaded) {
    return null;
  }

  return <RootLayoutNav />;
}

function RootLayoutNav() {
  const colorScheme = useColorScheme();

  return (
    <ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
      <Stack>
        <Stack.Screen name="index" options={{ headerShown: false }} />
        <Stack.Screen name="login" options={{ headerShown: false }} />
        <Stack.Screen name="med-list" options={{ headerShown: false }} />
        <Stack.Screen name="signup" options={{ headerShown: false }} />
        <Stack.Screen name="terra-connect" options={{ headerShown: false }} />
        <Stack.Screen name="appinfo1" options={{ headerShown: false }} />
        <Stack.Screen name="appinfo2" options={{ headerShown: false }} />
        <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
      </Stack>
    </ThemeProvider>
  );
}

```

### frontend/app/appinfo1/_layout.tsx

```typescript
import { Stack } from "expo-router";

export default function LoginLayout() {
  return (
    <Stack>
      <Stack.Screen name="index" options={{ headerShown: false }} />
    </Stack>
  );
}

```

### frontend/app/login/_layout.tsx

```typescript
import { Stack } from "expo-router";

export default function LoginLayout() {
  return (
    <Stack>
      <Stack.Screen name="index" options={{ headerShown: false }} />
    </Stack>
  );
}

```

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