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/completions
model: 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/healthdb
username: youruser
password: yourpass
jpa:
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.:
private String analyzeText(String text) {
if (text == null || text.isBlank()) return "No content provided.";
return openRouterService.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 push-
If 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/*.jar
server/*.war
server/*.iml
server/.idea/
server/logs/
server/*.log
# Client (React / Vite)
client/node_modules/
client/dist/
client/build/
# Common
.env
.env.*
.DS_Store
Thumbs.db
*.logTextAnalysisServiceinterface pattern recommended:
public interface TextAnalysisService {
String chat(String text);
}- 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