HealthAnalyzer is a full-stack AI-assisted medical analysis system. It combines a Spring Boot 3.5.6 (Java 21) backend and a React (Vite + TailwindCSS) frontend to let users upload CT/MRI images and blood-test reports (JPEG/PNG/PDF), extract text via OCR / PDFBox, analyze content with AI models (OpenAI / OpenRouter / Claude), and view historical results. Authentication uses JWT and the system stores per-user file & analysis history.
Designed for clinicians and patients to accelerate triage and provide clear, plain-language summaries.
Supports re-analysis, per-user audit trails, and admin user management for quality control and compliance.
Uses Tess4J (Tesseract) and Apache PDFBox for OCR/PDF parsing — ensure eng.traineddata is available on the server.
AI analysis is pluggable: swap ChatGptService, OpenRouterService or other implementations without changing core logic.
Default dev DB is H2; easily switch to PostgreSQL or MySQL and supply API keys via secure environment variables.
- Features
- Requirements
- Architecture & Folder Structure
- Quick start (run locally)
- Configuration
- How file analysis works (overview)
- Important API endpoints (examples)
- Build & produce single JAR that serves frontend
- Git / repo hygiene tips
.gitignorerecommended snippet- Extending / swapping AI services
- Development history & common commands
- Security notes
- License & Contact
- 🔐 JWT-based auth: register, login, roles (user / admin).
- 🩻 File uploads: JPEG/PNG/PDF (CT, MRI, blood reports).
- 🧾 OCR extraction using Tess4J (Tesseract).
- 📄 PDF parsing using Apache PDFBox.
- 🤖 AI text analysis via pluggable services (OpenAI, OpenRouter / Anthropic Claude).
- 📚 Per-user file & analysis history; re-analysis of saved files.
- ⚙️ Admin area to manage users & audits.
- 🧪 H2 in-memory DB for dev; configurable to Postgres/MySQL for prod.
- Java 21
- Spring Boot 3.5.6
- Maven 3.8+ (or use included
mvnw/mvnw.cmd) - Node.js v22.16.0
- npm 10.9.2
- Tesseract OCR installed with
eng.traineddatafor Tess4J - OpenAI / OpenRouter API keys (if using remote AI models)
HealthAnalyzer/
├── client/ # React frontend (Vite + Tailwind)
│ ├── src/
│ ├── public/
│ └── package.json
│
├── server/ # Spring Boot backend
│ ├── src/
│ ├── pom.xml
│ ├── mvnw
│ └── .mvn/
│
├── .gitignore
└── README.md
Clone repository:
git clone https://github.com/<yourusername>/HealthAnalyzer.git
cd HealthAnalyzerFrom project root:
cd server
# Build (Linux/macOS)
./mvnw clean package
# or (Windows)
mvnw.cmd clean package
# Run (dev)
./mvnw spring-boot:run
# or (Windows)
mvnw.cmd spring-boot:runDefault server URL: http://localhost:8080
From project root:
cd client
npm install
npm run devVite dev server: typically http://localhost:5173
To proxy frontend API calls to backend in development, add to client/package.json:
"proxy": "http://localhost:8080"Tess4J requires the Tesseract trained data file eng.traineddata. Put that file where Tess4J/Tesseract can access it. Example path on Windows (as used on your machine):
D:\ocr\eng.traineddata
Make sure your app config points to the correct tessdata directory, for example in application.yml:
tesseract:
tessdata-path: "D:\ocr"# Windows example; on Linux: /usr/share/tessdataYou can also set TESSDATA_PREFIX as an environment variable.
Store secrets in environment variables or a .env (gitignored). Example server/src/main/resources/application.yml snippet:
openai:
api:
key: "${OPENAI_API_KEY:}"openrouter:
api-key: "${OPENROUTER_API_KEY:}"base-url: https://openrouter.ai/api/v1/chat/completionsmodel: anthropic/claude-3-haikuNever check in real keys. Use env vars or a secrets manager in production.
Default: H2 in-memory DB. To switch to Postgres or MySQL, update spring.datasource.*:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/healthdbusername: youruserpassword: yourpassjpa:
hibernate:
ddl-auto: update- User uploads file via
/api/files/upload. - Backend stores file and extracts text:
- Images → Tess4J OCR (Tesseract
eng.traineddata) - PDFs → Apache PDFBox text extraction
- Images → Tess4J OCR (Tesseract
- Extracted text is passed to
FileAnalysisService. FileAnalysisServicecalls the injected text analysis service (ChatGptServiceorOpenRouterService), e.g.:
privateStringanalyzeText(Stringtext) {
if (text == null || text.isBlank()) return"No content provided.";
returnopenRouterService.chat(text);
}- Analysis stored in DB and returned to user; user can re-run analysis later.
Use
Authorization: Bearer <token>header for protected endpoints (where applicable).
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/auth/register | Register a new user. |
| POST | /api/auth/login | Login — returns JWT token. |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/file-analyses/{analysesId} | Retrieve a file analysis result by analysis ID. |
| GET | /api/file-analyses/document/{documentId} | Retrieve analysis results associated with a specific document ID. |
| POST | /api/file-analyses | Create a new file analysis (kick off analysis for stored/extracted text or link to an uploaded file). |
| Method | Endpoint | Description |
|---|---|---|
| POST (multipart/form-data) | /api/upload | Upload a file (image/pdf). Accepts multipart form-data. Returns uploaded file metadata / id. |
| POST (multipart/form-data) | /api/upload/reportExplain | Upload a report (image/pdf) and request an explanatory analysis in a single call. Consumes multipart form-data. |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/user-activities/user/{userId} | Get activity history (uploads, analyses, re-analyses) for a specific user. |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/user-profiles | Create a new user profile (profile metadata separate from auth). |
| GET | /api/user-profiles/{id} | Get a user profile by ID. |
| PUT | /api/user-profiles/{id} | Update a user profile by ID. |
| DELETE | /api/user-profiles/{id} | Delete a user profile by ID. |
To deploy one artifact that serves the static frontend from Spring Boot:
- Build frontend for production:
cd client
npm run build
# Vite outputs to `dist/` by default- Copy build files into Spring Boot static resources:
# from project root
cp -r client/dist/* server/src/main/resources/static/- Build Spring Boot jar:
cd server
./mvnw clean package
# The produced jar in server/target/ will serve the React files
java -jar target/*.jar- Add
.gitignorebefore committing build artifacts or secrets. - To stop tracking files that were already committed (keeps local copy), run:
git rm -r --cached client/node_modules server/target server/.idea .env
git add .gitignore
git commit -m "Remove tracked ignored files and update .gitignore"
git pushIf a secret was pushed to remote, rotate that secret immediately and remove it from history (use
git filter-repoorbfg-repo-cleaner) — this rewrites git history and requires force push.Change last commit message (if not yet pushed, or if you will force-push):
git commit --amend -m "New commit message"
git push --force # only if you understand history rewrite effectsPlace this in repo root .gitignore:
# Server (Spring Boot)server/target/
server/*.jarserver/*.warserver/*.imlserver/.idea/
server/logs/
server/*.log# Client (React / Vite)client/node_modules/
client/dist/
client/build/
# Common.env.env.*.DS_StoreThumbs.db*.logTextAnalysisServiceinterface pattern recommended:
publicinterfaceTextAnalysisService {
Stringchat(Stringtext);
}- Example implementations:
ChatGptService(OpenAI)OpenRouterService(Anthropic / Claude via OpenRouter)
Inject the desired implementation into FileAnalysisService via Spring — swapping models becomes trivial.
Commands you used / useful references:
# Frontend (Vite + Tailwind)
npm create vite@latest ai-med-frontend --template react
cd ai-med-frontend
npm install
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
npm install axios@1.9.0 react-router-dom
npm run dev
npm run build
npm run preview
# Useful Windows debug
netstat -ano | findstr :5173
taskkill /PID <pid> /F
doskey /HISTORY > history.txt
- Never commit API keys or
.envfiles. - Rotate any keys accidentally committed.
- Use environment variables or a secrets manager in production.
- Use HTTPS and properly configure CORS for production.
This project is released under the MIT License.
Author: Moh Khandan
Email:khandanmoh@gmail.com
GitHub:https://github.com/moksnow