A web application that helps doctors transform patient conversation transcripts into structured, validated prescriptions with safety alerts.
Dr Ozzy is an AI-powered medical assistant designed for healthcare professionals. Doctors paste transcripts of their patient conversations, and the application automatically:
- Identifies speakers - Distinguishes between doctor and patient dialogue
- Extracts prescriptions - Pulls structured medication data (drug, dosage, frequency, duration)
- Validates safety - Checks for dangerous dosages, drug interactions, and contraindications
- Suggests clarifications - Prompts for missing critical information (allergies, current medications, etc.)
The goal is to reduce medical errors, save time on documentation, and ensure prescriptions meet safety standards before they reach the pharmacy.
You can use the Sample Transcripts to test the app.
- Features
- Tech Stack
- Architecture
- Why Domain-Driven Design?
- AI Usage Declaration
- LLM & RAG Implementation
- Infrastructure
- Getting Started
- Environment Variables
- API Endpoints
- Future Improvements
- Chat-like Interface - Familiar conversational UI similar to ChatGPT
- Transcript Analysis - Paste medical conversations and get structured data
- Speaker Role Detection - Automatic identification of doctor vs patient
- Prescription Extraction - Structured output with drug name, dosage, form, frequency, duration, route
- Safety Validation - Real-time alerts for dosage limits and potential issues
- OAuth2 Authentication - Secure login via Auth0/Okta
The system validates prescriptions against known safety rules:
| Alert Type | Description |
|---|---|
dosage_limit |
Dosage exceeds maximum recommended amount |
interaction |
Potential drug-drug interaction detected |
contraindication |
Drug is contraindicated for patient's condition |
warning |
General safety warnings |
| Technology | Purpose |
|---|---|
| FastAPI | Async web framework |
| SQLModel | ORM with Pydantic integration |
| PostgreSQL | Relational database |
| Alembic | Database migrations |
| Anthropic Claude | LLM for transcript analysis |
| Python 3.13+ | Modern async/await syntax |
| Technology | Purpose |
|---|---|
| React 19 | UI component library |
| TypeScript | Type-safe JavaScript |
| Vite | Fast build tool |
| Tailwind CSS | Utility-first styling |
| React Router | Client-side routing |
| Technology | Purpose |
|---|---|
| Docker | Containerization |
| AWS ECS Fargate | Serverless container hosting |
| AWS RDS | Managed PostgreSQL |
| AWS CloudFront + S3 | Frontend CDN hosting |
| Auth0 | OAuth2/OIDC authentication |
This project implements Clean Architecture with Domain-Driven Design (DDD) principles for several reasons:
- Separation of Concerns - Business logic is isolated from frameworks and infrastructure
- Testability - Domain and application layers can be tested without databases or HTTP
- Maintainability - Clear boundaries make the codebase easier to navigate and modify
- Flexibility - Swapping databases, frameworks, or external services requires minimal changes
The architecture follows the principles outlined in:
Clean Architecture with Python - Published by Packt
app/
|-- domain/ # Enterprise Business Rules
| +-- entities/ # Core business objects (User, Prescription, ChatSession)
|
|-- application/ # Application Business Rules
| |-- use_cases/ # Application-specific workflows
| |-- dtos/ # Data Transfer Objects
| |-- repositories/ # Repository interfaces (abstractions)
| +-- services/ # Service interfaces (LLM, Safety)
|
|-- interfaces/ # Interface Adapters
| |-- controllers/ # Orchestrate use cases
| |-- presenters/ # Format output to view models
| +-- view_models/ # API request/response contracts
|
+-- infrastructure/ # Frameworks & Drivers
|-- persistence/ # SQLModel repository implementations
|-- services/ # Claude LLM, Safety validation implementations
|-- web/ # FastAPI routes & dependencies
+-- auth/ # OAuth2/JWT security
HTTP Request -> Route -> View Model Validation -> DTO -> Controller -> Use Case -> Repository -> Entity
Entity -> Repository (DTO) -> Use Case (Result[DTO]) -> Controller -> Presenter -> View Model -> JSON
I used AI assistance throughout this project. Here's a breakdown:
After creating the initial user domain repository, I used a PRP Metaprompt to refine the product requirements document. This involved iterative questioning to clarify:
- Target users and pain points
- User journey and flow
- Core features vs future enhancements
- Tech stack recommendations
For the backend implementation, I used the following prompt pattern:
"Now I want to create just the BACKEND for this MVP. Before starting code, read the
architecture.mdto understand the rules for my Domain-Driven Design, and strictly follow it using ReAct pattern after you finish each task (divide the implementation in tasks). Use the pattern of development that I used for user domain, application, interfaces, infrastructure, and web. Use the Product Requirements document as reference."
This ensured the AI followed the established architectural patterns consistently.
I created react-rules.md as a coding standards document for the AI to follow when implementing the React frontend. This included:
- Vite configuration best practices
- React component architecture (functional components, hooks)
- Tailwind CSS utility-first patterns
- TypeScript type safety requirements
Used AI to:
- Standardize docstrings across the codebase
- Ensure consistent error handling patterns
- Generate TypeScript interfaces matching backend DTOs
The application uses Claude Sonnet (claude-sonnet-4-20250514) from Anthropic for:
- Medical transcript analysis
- Prescription extraction with confidence scores
- Speaker role identification
- Clarifying question generation
Implementation: claude_llm_service.py
Currently, the safety validation uses a rule-based approach with hardcoded drug data:
# From basic_safety_validation_service.py
DOSAGE_LIMITS = {
"amoxicillin": (1000, 3000), # Max 1000mg per dose, 3000mg per day
"ibuprofen": (800, 3200), # Max 800mg per dose, 3200mg per day
"metformin": (1000, 2550), # Max 1000mg per dose, 2550mg per day
"acetaminophen": (1000, 4000), # Max 1000mg per dose, 4000mg per day
"lisinopril": (40, 40), # Max 40mg per dose and per day
}
INTERACTIONS = {
"metformin": ["alcohol"],
"ibuprofen": ["aspirin", "warfarin"],
"lisinopril": ["potassium supplements"],
}Implementation: basic_safety_validation_service.py
The project could be significantly enhanced with a proper RAG (Retrieval-Augmented Generation) implementation:
- Vector Database (Weaviate) - Store drug package inserts (bulas), clinical guidelines, and interaction databases
- AI Agent - Use an autonomous agent to query the vector database before validating prescriptions
- Real-time Updates - Keep drug safety information current without code changes
- Expanded Coverage - Support thousands of drugs instead of a handful
This would transform the hardcoded rules into a dynamic, always-up-to-date safety system.
+------------------+
| Route 53 |
| labsxv.com |
+--------+---------+
|
+----------------+----------------+
| |
v v
+----------------+ +------------------+
| CloudFront | | ALB |
| labsxv.com | | api.labsxv.com |
+-------+--------+ +--------+---------+
| |
v v
+----------------+ +------------------+
| S3 Bucket | | ECS Fargate |
| (React SPA) | | (FastAPI) |
+----------------+ +--------+---------+
|
v
+------------------+
| RDS PostgreSQL |
+------------------+
| Component | Details |
|---|---|
| S3 Bucket | Hosts React SPA static files |
| CloudFront | CDN with custom domain labsxv.com |
| SSL Certificate | ACM certificate in us-east-1 |
| Component | Details |
|---|---|
| ECS Cluster | Fargate serverless containers |
| ECS Service | 2 tasks for high availability |
| ECR Repository | Docker image registry |
| ALB | Application Load Balancer with HTTPS |
| Component | Details |
|---|---|
| RDS PostgreSQL | db.t3.micro, 20 GB storage |
| Component | Details |
|---|---|
| VPC | Custom VPC with CIDR 10.0.0.0/16 |
| Public Subnets | 2 subnets for ALB |
| Private Subnets | 2 subnets for Fargate + RDS |
| NAT Gateway | For private subnet internet access |
+--------+ +-----------+ +----------+ +-----------+
| User | --> | Frontend | --> | Auth0 | --> | Backend |
| | <-- | (React) | <-- | (OAuth2) | <-- | (FastAPI) |
+--------+ +-----------+ +----------+ +-----------+
- User clicks "Sign In" on frontend
- Frontend redirects to Auth0 Universal Login
- User authenticates (Google, email, etc.)
- Auth0 redirects to backend callback with authorization code
- Backend exchanges code for tokens
- Backend redirects to frontend with access token
- Frontend stores token for API requests
- Python 3.13+
- Node.js 18+
- PostgreSQL 16+ (or Docker)
- uv - Fast Python package manager
git clone https://github.com/your-username/drozzy.git
cd drozzy# Install Python dependencies
uv sync
# Copy environment file
cp .env.example .env
# Edit .env with your credentials (see Environment Variables section)
# Run database migrations
uv run alembic upgrade head
# Start the backend
uv run python -m app.mainThe API will be available at http://localhost:8000
cd frontend
# Install dependencies
npm install
# Copy environment file
cp .env.example .env
# Start development server
npm run devThe frontend will be available at http://localhost:5173
# Start both API and PostgreSQL
docker-compose up -d
# Run migrations
docker-compose exec api uv run alembic upgrade head# Database
REPOSITORY_TYPE=postgresql
DATABASE_USER=postgres
DATABASE_PW=your_password
DATABASE_NAME=drozzy
DATABASE_IP=localhost
DATABASE_PORT=5432
# API Server
API_HOST=0.0.0.0
API_PORT=8000
ENVIRONMENT=development
# Anthropic (Claude AI)
ANTHROPIC_API_KEY=sk-ant-...
# OAuth2 (Auth0/Okta)
OKTA_ISSUER=https://your-tenant.auth0.com/
OKTA_AUDIENCE=your-api-audience
OKTA_CLIENT_ID=your-client-id
OKTA_CLIENT_SECRET=your-client-secret
OKTA_CALLBACK_URL=http://localhost:8000/auth/callback
FRONTEND_URL=http://localhost:5173VITE_API_URL=http://localhost:8000
VITE_AUTH0_DOMAIN=your-tenant.auth0.com
VITE_AUTH0_CLIENT_ID=your-client-id| Method | Endpoint | Description |
|---|---|---|
| GET | /auth/login |
Initiate OAuth2 login |
| GET | /auth/callback |
OAuth2 callback handler |
| GET | /auth/me |
Get current user info |
| Method | Endpoint | Description |
|---|---|---|
| POST | /chat/sessions |
Create new chat session |
| GET | /chat/sessions |
List user's sessions |
| GET | /chat/sessions/{id} |
Get session details |
| POST | /chat/sessions/{id}/messages |
Add message to session |
| POST | /chat/sessions/{id}/analyze |
Analyze transcript |
| Method | Endpoint | Description |
|---|---|---|
| GET | /prescriptions |
List prescriptions |
| GET | /prescriptions/{id} |
Get prescription details |
| PUT | /prescriptions/{id}/status |
Update prescription status |
| Method | Endpoint | Description |
|---|---|---|
| GET | /safety-alerts |
List safety alerts |
| PUT | /safety-alerts/{id}/acknowledge |
Acknowledge an alert |
-
Vector Database Integration - Implement Weaviate for RAG-based drug information retrieval
-
Explore different chunking techniques - studying about RAG, these methods are a good fit for medical purposes:
2.1 Recursive text splitter - If the store documents from html, for example, the chunk could use div chars to split the text 2.2 LLM Based Chunking
-
Multiple AI Agents - One for extract prescriptions, and another for the safety alerts
-
Audio Input - Support streaming audio transcription
-
Drug Database Integration - Connect to FDA, DrugBank, or similar authoritative sources
-
Patient History - Track patient allergies, conditions, and medication history
-
Multi-language Support - Support transcripts in multiple languages
-
Export Functionality - Generate PDF prescriptions and reports
-
Audit Logging - Complete audit trail for compliance
After this journey developing this project, I have some goals for the near future.
- Study software architectures and creating projects with them - Knowing the tradeoffs, high quality code, and create good blueprints for AI
- Get a AWS developer certificate
- Study AI for Medicine - AI for Medicine Specialization

