diff --git a/README.md b/README.md index 97c8c94..4bb333d 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,23 @@ -# 🏥 Pediatric AI Scribe v3 +# 🩺 Pediatric AI Scribe v3 -AI-powered clinical documentation platform for pediatric medicine. Generates HPIs, hospital courses, chart reviews, SOAP notes, and developmental milestone assessments from voice recordings or dictation. +AI-powered clinical documentation platform for pediatric medicine. Generates HPIs, hospital courses, chart reviews, SOAP notes, and developmental milestone assessments from voice recordings or dictation — in seconds, in plain copy-ready text. ## Features -- **Live Encounter → HPI** — record doctor-patient conversation, AI generates structured HPI -- **Voice Dictation → HPI / SOAP** — dictate your narrative, AI restructures it -- **Hospital Course Generator** — paste progress notes by date, AI generates organized discharge summary (prose, day-by-day, organ-system, or psych format) -- **Chart Review / Precharting** — summarize outpatient, subspecialty, and ED notes +- **Live Encounter → HPI** — record a live doctor-patient conversation, AI generates a structured OLDCARTS HPI +- **Voice Dictation → HPI / SOAP** — dictate your narrative, AI cleans and restructures it +- **Hospital Course Generator** — paste progress notes, AI generates prose, day-by-day, organ-system (ICU), or psych format summaries +- **Chart Review / Precharting** — summarize outpatient, subspecialty, and ED notes into a precharting brief - **SOAP Note Generator** — full SOAP or subjective-only from dictation -- **Developmental Milestones** — AAP/Nelson milestone tracker with narrative output -- **Admin Panel** — user management, registration control, usage stats -- **Per-tab model selector** — choose fast vs. smart models per task -- **Nextcloud integration** — export documents to your Nextcloud instance +- **Developmental Milestones** — AAP/Nelson milestone tracker with narrative, structured list, or 3-sentence summary output +- **Plain text output** — all documents generated without markdown, ready to paste into any EHR +- **Read Aloud** — browser TTS reads generated documents; ElevenLabs (Adam voice) supported +- **Copy & Export** — one-click copy or export to Nextcloud +- **Refine & Shorten** — edit any document with plain-language AI instructions +- **Per-tab model selector** — choose fast vs. smart vs. reasoning models per task +- **Admin Panel** — user management, registration control, audit logs - **2FA** — TOTP-based two-factor authentication +- **Multi-provider AI** — OpenRouter, AWS Bedrock, or Azure OpenAI --- @@ -126,9 +130,11 @@ AWS_SECRET_ACCESS_KEY=... Or use an IAM role (no keys needed when running on EC2/ECS — just set the region). Available Bedrock models (auto-selected when `AI_PROVIDER=bedrock`): +- vendor model Opus 4.6 — best language nuance (`anthropic.agent-config-opus-4-6-20251001-v1:0`) +- vendor model Sonnet 4.6 — recommended (`anthropic.agent-config-sonnet-4-6-20251001-v1:0`) - vendor model Sonnet 4 (`anthropic.agent-config-sonnet-4-20250514-v1:0`) - vendor model 3.5 Sonnet (`anthropic.agent-config-3-5-sonnet-20241022-v2:0`) -- vendor model 3 Haiku — default, cheapest (`anthropic.agent-config-3-haiku-20240307-v1:0`) +- vendor model 3 Haiku — cheapest (`anthropic.agent-config-3-haiku-20240307-v1:0`) - Llama 3.1 70B / 8B - Mistral Large diff --git a/src/routes/auth.js b/src/routes/auth.js index dfd8ca3..5f68bc1 100644 --- a/src/routes/auth.js +++ b/src/routes/auth.js @@ -8,6 +8,33 @@ const crypto = require('crypto'); const db = require('../db/database'); const { JWT_SECRET, authMiddleware } = require('../middleware/auth'); +// ============================================================ +// EMAIL TEMPLATES +// ============================================================ +function emailWrapper(body) { + return `
+ +| + + |
Hi ' + name + ',
Verify your email:
' + - '' + - 'Expires in 24 hours.
👋 Welcome aboard, ${name}!
+Great to have you on Pediatric AI Scribe. Before you start generating clinical notes, please confirm your email address by clicking the button below.
++ Verify My Email +
+Button not working? Copy and paste this link into your browser:
+${verifyUrl}
+This link expires in 24 hours.
` + )); await db.run('INSERT INTO audit_log (user_id, action, ip_address, details) VALUES (?, ?, ?, ?)', [userId, 'register', req.ip, role === 'admin' ? 'First user — auto admin' : 'standard user']); @@ -120,7 +150,16 @@ router.post('/resend-verification', async (req, res) => { var verifyToken = crypto.randomBytes(32).toString('hex'); await db.run('UPDATE users SET verify_token = ?, verify_expires = ? WHERE id = ?', [verifyToken, Date.now() + 86400000, user.id]); var verifyUrl = (process.env.APP_URL || 'http://localhost:3000') + '/api/auth/verify-email?token=' + verifyToken; - await sendEmail(req.body.email, 'Verify your email', 'Click to verify: ' + verifyUrl + '
'); + await sendEmail(req.body.email, 'Verify your email — Pediatric AI Scribe', emailWrapper( + `📧 Verify your email
+Here's a fresh verification link for your account. Click below to confirm your email and get started.
++ Verify My Email +
+Button not working? Copy and paste this link into your browser:
+${verifyUrl}
+This link expires in 24 hours.
` + )); res.json({ success: true, message: 'Verification email sent' }); } catch (err) { res.status(500).json({ error: err.message }); } }); @@ -205,7 +244,18 @@ router.post('/forgot-password', async (req, res) => { if (!user) return res.json({ success: true, message: 'If account exists, reset email sent' }); var token = crypto.randomBytes(32).toString('hex'); await db.run('UPDATE users SET reset_token = ?, reset_expires = ? WHERE id = ?', [token, Date.now() + 3600000, user.id]); - await sendEmail(req.body.email, 'Password Reset', 'Reset: Click here
'); + var resetUrl = (process.env.APP_URL || 'http://localhost:3000') + '/reset-password?token=' + token; + await sendEmail(req.body.email, 'Reset your password — Pediatric AI Scribe', emailWrapper( + `🔐 Password reset request
+Hi there,
+Someone requested a password reset for your Pediatric AI Scribe account. If that was you, click the button below to choose a new password.
+ +Button not working? Copy and paste this link into your browser:
+${resetUrl}
+This link expires in 1 hour. If you did not request a password reset, no action is needed — your password has not been changed.
` + )); res.json({ success: true, message: 'If account exists, reset email sent' }); } catch (err) { res.status(500).json({ error: err.message }); } });