# Project export: HealthPort AI

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: CruzHacks 2025
- Tagline: HealthPort AI translates your medical reports into clear, AI-powered insights—so you can understand your health with confidence.
- Devpost: https://devpost.com/software/healthport-ai-o2sail
- GitHub: https://github.com/rik102/HealthPort-AI
- Team: 2 GitHub contributor(s) — Rik Ros (5 commits), Dan Pham (5 commits)

## Devpost submission (written by the team)

### Inspiration

Some of our teammates have family members who regularly get blood tests and other health related tests done. There are a lot of values and information on the reports which may take time to learn about.

### What it does

Scans an input pdf and gives an analysis generated by Gemini AI

### How we built it

We built it using React.js to code the website, Vite framework to develop the webpage, FastAPI for file uploads, Tesseract OCR for processing the lab documents uploaded to text, and Gemini API to provide analysis of the pdf report. In addition, we used MongoDB as our database for storing the user and lab report information. We deployed the frontend of our webpage using Vercel and the backend through Render. We also used Cloudflare for future scalability.

### Challenges we ran into

Throughout this project, we ran into multiple issues mainly due to the steep learning curve as our team members had limited experience with MongoDB. Apart from that, we ran into issues while hosting the webpage on our domain, but we were able to resolve these issues with the help of online resources and LLMs such as Gemini and ChatGPT. We also ran into a lot of merge conflicts which required us to learn more about resolving conflicts and merging branches to deploy our code.

### Accomplishments we're proud of

This project was very fun to develop. We learned a lot and also accomplished a lot. Our main accomplishment is being able to get accurate analysis of example blood reports. In addition, we were able to host our website on our domain after long hours of effort.

### What we learned

In the process of developing the project, we learned a lot. We learned more about web development using React, we learned database management using MongoDB. In addition, we learned how to use Tesseract OCR for file processing. All in all, this hackathon was a great learning experience.

### What's next

In the future, we would love to develop the backend better. We would also love to include different kinds of scans and report analyses on our website for more accurate and detailed analysis.

## README (from the GitHub repository)

# HealthPort AI

HealthPort AI is an intelligent medical report analysis tool that uses AI to analyze lab reports and provide detailed insights. The application features a modern, responsive interface with real-time analysis capabilities.

## Features

- PDF and image upload support
- AI-powered analysis of medical reports
- Real-time progress tracking
- Modern, responsive UI
- Detailed analysis results
- Support for both text-based and scanned PDFs

## Prerequisites

Before you begin, ensure you have the following installed:

### For Windows:

1. **Python 3.8+**
   - Download from [python.org](https://www.python.org/downloads/)
   - Make sure to check "Add Python to PATH" during installation

2. **Tesseract OCR**
   - Download from [GitHub](https://github.com/UB-Mannheim/tesseract/wiki)
   - During installation, make sure to:
     - Check "Add to PATH"
     - Note the installation path (default: `C:\Program Files\Tesseract-OCR`)

3. **Poppler**
   - Download from [poppler releases](https://github.com/oschwartz10612/poppler-windows/releases/)
   - Extract to a folder (e.g., `C:\Program Files\poppler`)
   - Add the bin directory to your PATH:
     - Open System Properties > Advanced > Environment Variables
     - Add `C:\Program Files\poppler\Library\bin` to Path

### For macOS:

1. **Python 3.8+**
   - Install using Homebrew: `brew install python`

2. **Tesseract OCR**
   - Install using Homebrew: `brew install tesseract`

3. **Poppler**
   - Install using Homebrew: `brew install poppler`

### For Linux:

1. **Python 3.8+**
   - Install using your package manager:
     - Ubuntu/Debian: `sudo apt install python3`
     - Fedora: `sudo dnf install python3`

2. **Tesseract OCR**
   - Ubuntu/Debian: `sudo apt install tesseract-ocr`
   - Fedora: `sudo dnf install tesseract`

3. **Poppler**
   - Ubuntu/Debian: `sudo apt install poppler-utils`
   - Fedora: `sudo dnf install poppler-utils`

## Installation

1. Clone the repository:
```bash
git clone https://github.com/yourusername/HealthPort-AI.git
cd HealthPort-AI
```

2. Set up the backend:
```bash
cd backend
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
pip install -r requirements.txt
```

3. Set up the frontend:
```bash
cd ../frontend
npm install
```

4. Create environment files:

Backend (create `backend/.env`):
```
GOOGLE_API_KEY=your_gemini_api_key
MONGO_URI=your_mongodb_uri
```

Frontend (create `frontend/.env`):
```
VITE_API_URL=http://localhost:8000
```

## Running the Application

1. Start the backend server:
```bash
cd backend
venv\Scripts\activate # source venv/bin/activate On Mac: 
pip install -r requirements.txt #(if not already)
uvicorn main:app --reload
```

2. Start the frontend development server:
```bash
cd frontend
pnpm i #(if not already)
pnpm run dev
```

3. Open your browser and navigate to `http://localhost:5173`

## Usage

1. Click the upload area or drag and drop a PDF file
2. Wait for the analysis to complete
3. View the detailed analysis results
4. Download or share the results as needed

## Troubleshooting

### Common Issues

1. **Tesseract not found**
   - Ensure Tesseract is installed and in your PATH
   - Verify installation: `tesseract --version`

2. **Poppler not found**
   - Ensure Poppler is installed and in your PATH
   - Verify installation: `pdftoppm --version`

3. **Python package installation issues**
   - Try upgrading pip: `python -m pip install --upgrade pip`
   - Ensure you're using the correct Python version

4. **CORS errors**
   - Ensure both frontend and backend servers are running
   - Check the API URL in frontend/.env

## Contributing

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## License

This project is licensed under the MIT License - see the LICENSE file for details.

## Acknowledgments

- Google Gemini API for AI analysis
- MongoDB for data storage
- FastAPI for backend framework
- React for frontend framework

## Detected evidence (automated analysis)

Indexed codebase: 30 recognized source files, 172 KB.
- CSS (language) — detected in the code
- FastAPI (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- AWS (technology) — claimed on Devpost, not found in the code
- Google Gemini (technology) — claimed on Devpost, not found in the code
- MongoDB (technology) — claimed on Devpost, not found in the code
- Vercel (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (32 of 32)

```
.gitignore
backend/database/mongodb_client.py
backend/main.py
backend/requirements.txt
backend/routers/analysis.py
cloudflare/worker.js
frontend/index.html
frontend/package.json
frontend/src/App.css
frontend/src/App.js
frontend/src/App.jsx
frontend/src/components/AnalysisResults.css
frontend/src/components/AnalysisResults.jsx
frontend/src/components/Dashboard.css
frontend/src/components/Dashboard.jsx
frontend/src/components/GoogleSignInButton.css
frontend/src/components/GoogleSignInButton.jsx
frontend/src/components/History.css
frontend/src/components/History.jsx
frontend/src/components/LoadingAnimation.css
frontend/src/components/LoadingAnimation.jsx
frontend/src/components/StyledButton.css
frontend/src/components/StyledButton.jsx
frontend/src/components/UploadForm.css
frontend/src/components/UploadForm.jsx
frontend/src/index.css
frontend/src/main.jsx
frontend/src/styles/animations.css
frontend/src/styles/styles.css
frontend/vite.config.js
package.json
README.md
```

### Dependencies

- backend/requirements.txt: fastapi, google-generativeai, motor, pdf2image, Pillow, pymongo[srv], PyPDF2, pytesseract, python-decouple, python-dotenv, python-multipart, uvicorn
- frontend/package.json: @react-oauth/google@^0.12.1, @types/react@^18.2.55, @types/react-dom@^18.2.19, @vitejs/plugin-react@^4.2.1, axios@^1.6.7, eslint@^8.56.0, eslint-plugin-react@^7.33.2, eslint-plugin-react-hooks@^4.6.0, eslint-plugin-react-refresh@^0.4.5, react@^18.2.0, react-dom@^18.2.0, react-dropzone@^14.2.3, react-router-dom@^7.5.0, vite@^5.1.0
- package.json: react-dropzone@^14.3.8, react-router-dom@^7.5.0

### Recent commits (newest first)

- boxes
- simple hover animation
- logo
- update LAST
- update
- update router dom
- pic for now
- changed readme, made logout go to homepage
- update
- update
- update size
- signin
- add fixes
- updated anlaysis results, format, added tables
- fix
- developed mvp
- update
- Merge branch 'main' of github.com:rik102/HealthPort-AI
- hi
- Merge branch 'main' of https://github.com/rik102/HealthPort-AI

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

### package.json

```
{
  "dependencies": {
    "react-dropzone": "^14.3.8",
    "react-router-dom": "^7.5.0"
  }
}

```

### backend/requirements.txt

```
fastapi
uvicorn
python-multipart
PyPDF2
google-generativeai
python-decouple
motor
pymongo[srv]
python-dotenv
pytesseract
pdf2image
Pillow
```

### frontend/package.json

```
{
  "name": "healthport-ai-frontend",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview"
  },
  "dependencies": {
    "@react-oauth/google": "^0.12.1",
    "axios": "^1.6.7",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-dropzone": "^14.2.3",
    "react-router-dom": "^7.5.0"
  },
  "devDependencies": {
    "@types/react": "^18.2.55",
    "@types/react-dom": "^18.2.19",
    "@vitejs/plugin-react": "^4.2.1",
    "eslint": "^8.56.0",
    "eslint-plugin-react": "^7.33.2",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-plugin-react-refresh": "^0.4.5",
    "vite": "^5.1.0"
  }
}
```

### backend/main.py

```python
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from routers import analysis
from database.mongodb_client import MongoDB
from contextlib import asynccontextmanager

@asynccontextmanager
async def lifespan(app: FastAPI):
    # Startup
    await MongoDB.connect_db()
    yield
    # Shutdown
    await MongoDB.close_db()

app = FastAPI(lifespan=lifespan)

# Allow requests from both Vite dev server and potential production frontend
origins = [
    "http://localhost:5173",  # Vite dev server
    "http://localhost:3000",  # React dev server (if needed)
    "http://127.0.0.1:5173",  # Alternative localhost
    "http://127.0.0.1:3000",   # Alternative localhost
    "https://www.aihealthport.tech",
    "https://aihealthport.tech"
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

app.include_router(analysis.router, prefix="/analysis", tags=["analysis"])

@app.get("/")
async def root():
    return {"message": "Backend is running"}
```

### frontend/src/main.jsx

```javascript
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
) 
```

### frontend/src/App.js

```javascript
import React, { useState } from 'react';
import UploadForm from './components/UploadForm';
import AnalysisResults from './components/AnalysisResults';
import './App.css';

function App() {
  const [analysis, setAnalysis] = useState(null);

  const handleAnalysisComplete = (analysis) => {
    setAnalysis(analysis);
  };

  return (
    <div className="App">
      <header className="App-header">
        <h1>HealthPort AI</h1>
        <p>Upload your lab report for AI-powered analysis</p>
      </header>
      <main>
        <UploadForm onAnalysisComplete={handleAnalysisComplete} />
        {analysis && <AnalysisResults analysis={analysis} />}
      </main>
    </div>
  );
}

export default App;

```

### frontend/src/App.jsx

```javascript
import React, { useState, useEffect, useRef } from 'react';
import { BrowserRouter as Router, Routes, Route, Link, Navigate, useNavigate } from 'react-router-dom';
import './App.css';
import UploadForm from './components/UploadForm';
import AnalysisResults from './components/AnalysisResults';
import GoogleSignInButton from './components/GoogleSignInButton';
import Dashboard from './components/Dashboard';
import History from './components/History';
import { GoogleOAuthProvider, useGoogleLogin } from '@react-oauth/google';
import axios from 'axios';
import doctorIllustration from './assets/doctor-illustration.png';
import logoIcon from './assets/logo.png';

// Create a separate component for the main content to use the hook
const MainContent = () => {
  const [analysis, setAnalysis] = useState(null);
  const [error, setError] = useState(null);
  const [user, setUser] = useState(null);
  const [showDropdown, setShowDropdown] = useState(false);
  const dropdownRef = useRef(null);
  const navigate = useNavigate();

  // Add click outside handler
  useEffect(() => {
    const handleClickOutside = (event) => {
      if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
        setShowDropdown(false);
      }
    };

    document.addEventListener('mousedown', handleClickOutside);
    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
    };
  }, []);

  const login = useGoogleLogin({
    onSuccess: async (response) => {
      try {
        const res = await axios.get(
          'https://www.googleapis.com/oauth2/v3/userinfo',
          {
            headers: {
              Authorization: `Bearer ${response.access_token}`,
            },
          }
        );
        setUser(res.data);
        console.log('User info:', res.data);
      } catch (err) {
        console.error('Error fetching user info:', err);
      }
    },
    onError: (error) => {
      console.error('Login Failed:', error);
    },
  });

  const handleLogout = () => {
    setUser(null);
    setShowDropdown(false);
    navigate('/');
    window.location.reload();
  };

  const handleFileUpload = async (file, analysisData) => {
    try {
      if (!analysisData) {
        throw new Error('No analysis data received');
      }
      setAnalysis(analysisData);
      setError(null);
    } catch (error) {
      console.error('Error handling file upload:', error);
      setError(error.message);
      setAnalysis(null);
    }
  };

  return (
    <div className="app-container">
      <div className="content-wrapper">
        <header className="app-header">
          <div className="header-content">
            
            <Link to="/" className="logo-container">
              <img src={logoIcon} alt="HealthPort AI Logo" className='logo-icon' />
              <div className='logo-text-wrapper'>
              <h1 className="logo-text">HealthPort AI</h1>
              <p className="logo-subtitle">Your AI-Powered Health Report Analyzer</p>
              </div>
            </Link>

            <div className="nav-links">
              {user && (
                <>
                  <Link to="/dashboard" className="nav-link">Dashboard</Link>
                  <Link to="/history" className="nav-link">History</Link>
                </>
              )}
              <div className="signin-button-container" ref={dropdownRef}>
                {user ? (
                  <div className="user-info" onClick={() => setShowDropdown(!showDropdown)}>
                    <img src={user.picture} alt={user.name} className="user-avatar" />
                    <span className="user-name">{user.name}</span>
                    {showDropdown && (
                      <div className="dropdown-menu">
                        <button onClick={handleLogout} className="dropdown-item">Logout</button>
                      </div>
                    )}
                  </div>
                ) : (
                  <GoogleSignInButton onClick={login} />
                )}
              </div>
            </div>
          </div>
        </header>

        <main className="main-content">
          <Routes>
            <Route path="/" element={
              <>
                <section className="hero-section">
                  <div className="hero-content">
                    <div className="hero-text">
                      <h2>Transform Your Medical Reports</h2>
                      <p>Upload your medical reports and get instant, AI-powered analysis and insights.</p>
                      <div className="hero-stats">
                        <div className="stat-item">
                          <div className="stat-number">98%</div>
                          <div className="stat-label">Accuracy</div>
                        </div>
                        <div className="stat-item">
                          <div className="stat-number">24/7</div>
                          <div className="stat-label">Availability</div>
                        </div>
                        <div className="stat-item">
                          <div className="stat-number">Instant</div>
                          <div className="stat-label">Analysis</div>
                        </div>
                      </div>
                    </div>
                    <img src={doctorIllustration} alt="Doctor with medical report" className="doctor-illustration" />
                  </div>
                </section>

                <section className="upload-section">
                  {!analysis ? (
                    <UploadForm onUpload={handleFileUpload} />
                  ) : (
                    <AnalysisResults analysis={analysis} />
                  )}
                </section>


                <section className='features-section'>
                  <div className='feature-card'>
                    <h3>Understand What It Means</h3>
                    <p>From cholesterol to vitamin deficiencies, we explain what each value
[truncated — 1086 more characters]
```

### frontend/vite.config.js

```javascript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  server: {
    port: 5173,
    host: true
  }
}) 
```

### frontend/index.html

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>HealthPort AI</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html> 
```

### frontend/src/index.css

```css
:root {
  font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
  line-height: 1.5;
  font-weight: 400;
}

body {
  margin: 0;
  min-width: 320px;
  min-height: 100vh;
} 
```

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