evaldoc 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.staging.example +19 -0
- package/.firebaserc +6 -0
- package/.github/workflows/auto-merge-to-main.yml +28 -0
- package/.github/workflows/ci.yml +27 -0
- package/.github/workflows/npxhub-publish.yml +170 -0
- package/.prettierignore +4 -0
- package/.prettierrc.json +7 -0
- package/README.md +142 -0
- package/SRS.md +448 -0
- package/apphosting.staging.yaml +48 -0
- package/apphosting.yaml +50 -0
- package/bin/evaldoc.cjs +105 -0
- package/cors.json +8 -0
- package/docs/ARCHITECTURE.md +769 -0
- package/docs/ARCHITECTURE_SUMMARY.md +323 -0
- package/docs/DEPLOYMENT.md +86 -0
- package/docs/DEPLOYMENT_STEPS.md +373 -0
- package/docs/DEPLOY_FIRESTORE_RULES.md +239 -0
- package/docs/DEPLOY_STORAGE_RULES.md +82 -0
- package/docs/DOCTOR_TUTORIAL.md +467 -0
- package/docs/FIREBASE_STORAGE_CORS_FIX.md +131 -0
- package/docs/FIXES_APPLIED.md +128 -0
- package/docs/IMPLEMENTATION.md +498 -0
- package/docs/IMPLEMENTATION_COMPLETE.md +317 -0
- package/docs/LLM-SETUP.md +216 -0
- package/docs/MANUAL_TEST_GUIDE.md +327 -0
- package/docs/PATIENT_GUIDE.md +451 -0
- package/docs/PLATFORM_OVERVIEW.md +194 -0
- package/docs/QUICKSTART.md +252 -0
- package/docs/QUICK_REFERENCE.md +222 -0
- package/docs/READY_TO_TEST.md +383 -0
- package/docs/RUN.md +237 -0
- package/docs/START_TESTING.md +130 -0
- package/docs/STRIPE_CONNECT_SETUP.md +454 -0
- package/docs/SYSTEM_READY.md +345 -0
- package/docs/THREADS_IMPLEMENTATION_COMPLETE.md +431 -0
- package/docs/THREAD_IMPLEMENTATION_GUIDE.md +345 -0
- package/docs/firebasefiles.md +21 -0
- package/docs/homepage.md +1208 -0
- package/docs/payments.md +159 -0
- package/eslint.config.js +76 -0
- package/firebase.json +27 -0
- package/firestore.indexes.json +88 -0
- package/firestore.rules +125 -0
- package/functions/package-lock.json +2884 -0
- package/functions/package.json +20 -0
- package/functions/src/analytics.js +101 -0
- package/functions/src/audit.js +28 -0
- package/functions/src/auth.js +19 -0
- package/functions/src/drafts.js +128 -0
- package/functions/src/feedback.js +164 -0
- package/functions/src/firebase-init.js +29 -0
- package/functions/src/i18n.js +134 -0
- package/functions/src/limits.js +27 -0
- package/functions/src/llm.js +271 -0
- package/functions/src/ner.js +162 -0
- package/functions/src/notifications.js +273 -0
- package/functions/src/orgs.js +127 -0
- package/functions/src/patient-api.js +545 -0
- package/functions/src/payment.js +830 -0
- package/functions/src/safety.js +188 -0
- package/functions/src/stripe-config.js +33 -0
- package/functions/src/topics.js +94 -0
- package/functions/src/triage.js +191 -0
- package/functions/src/utils.js +28 -0
- package/functions/src/validate.js +177 -0
- package/functions/test-firebase.js +36 -0
- package/jest.config.js +18 -0
- package/package.json +52 -0
- package/public/404.html +93 -0
- package/public/app/analytics.html +336 -0
- package/public/app/analytics.js +177 -0
- package/public/app/app.css +1400 -0
- package/public/app/app.js +1754 -0
- package/public/app/config.js +14 -0
- package/public/app/inbox-threads.js +843 -0
- package/public/app/inbox.html +598 -0
- package/public/app/inbox.js +397 -0
- package/public/app/index.html +612 -0
- package/public/assets/logo.jpg +0 -0
- package/public/chat.html +137 -0
- package/public/css/chat.css +870 -0
- package/public/css/landing-enhance.css +298 -0
- package/public/css/styles.css +1198 -0
- package/public/favicon.svg +5 -0
- package/public/find-doctor.html +220 -0
- package/public/index.html +399 -0
- package/public/js/chat-threads.js +513 -0
- package/public/js/chat.js +832 -0
- package/public/js/search.js +41 -0
- package/public/privacy.html +101 -0
- package/public/robots.txt +6 -0
- package/public/site.webmanifest +12 -0
- package/public/terms.html +110 -0
- package/scripts/create-test-provider.js +55 -0
- package/scripts/deploy-staging.sh +51 -0
- package/scripts/fix-provider.js +39 -0
- package/scripts/quick-test.sh +37 -0
- package/scripts/test-chat.sh +54 -0
- package/scripts/test-multi-turn.js +137 -0
- package/scripts/test-ner-simple.js +28 -0
- package/scripts/test-ner.js +60 -0
- package/scripts/test-stripe-connect.js +304 -0
- package/scripts/test-webhook-secret.sh +24 -0
- package/server.js +3864 -0
- package/storage.rules +22 -0
- package/test-api.json +1 -0
- package/tests/emulator/README.md +38 -0
- package/tests/emulator/counters.emulator.test.js +81 -0
- package/tests/integration/api-account-selfserve.test.js +312 -0
- package/tests/integration/api-admin-digest.test.js +202 -0
- package/tests/integration/api-chat-satisfaction.test.js +259 -0
- package/tests/integration/api-doctor-drafts.test.js +236 -0
- package/tests/integration/api-doctor-inbox.test.js +401 -0
- package/tests/integration/api-org.test.js +328 -0
- package/tests/integration/api-payment.test.js +664 -0
- package/tests/integration/api-provider-settings.test.js +475 -0
- package/tests/integration/api-qr.test.js +121 -0
- package/tests/integration/api-security.test.js +241 -0
- package/tests/integration/api-stripe-search.test.js +303 -0
- package/tests/integration/api-webhook-deletion.test.js +231 -0
- package/tests/mocks/firebase-admin.js +220 -0
- package/tests/unit/analytics.test.js +151 -0
- package/tests/unit/audit-bugs.test.js +203 -0
- package/tests/unit/chat-ui-logic.test.js +283 -0
- package/tests/unit/drafts.test.js +104 -0
- package/tests/unit/feedback.test.js +148 -0
- package/tests/unit/i18n.test.js +229 -0
- package/tests/unit/llm-retry.test.js +122 -0
- package/tests/unit/notifications.test.js +155 -0
- package/tests/unit/orgs.test.js +328 -0
- package/tests/unit/payment.test.js +889 -0
- package/tests/unit/safety-edge-cases.test.js +509 -0
- package/tests/unit/safety-srs-compliance.test.js +252 -0
- package/tests/unit/safety.test.js +291 -0
- package/tests/unit/server-helpers.test.js +774 -0
- package/tests/unit/topics-limits.test.js +158 -0
- package/tests/unit/triage.test.js +152 -0
- package/tests/unit/validate.test.js +408 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# EvalDoc Staging Environment
|
|
2
|
+
# Copy to .env.staging and fill in real values
|
|
3
|
+
|
|
4
|
+
NODE_ENV=staging
|
|
5
|
+
PROJECT_ID=evaldocplatform-staging
|
|
6
|
+
PLATFORM_URL=https://staging.evaldoctor.ai
|
|
7
|
+
ALLOWED_ORIGINS=https://staging.evaldoctor.ai
|
|
8
|
+
|
|
9
|
+
# LLM Keys (same as production or separate)
|
|
10
|
+
GEMINI_API_KEY=
|
|
11
|
+
DEEPSEEK_API_KEY=
|
|
12
|
+
|
|
13
|
+
# Stripe TEST mode keys (pk_test_ / sk_test_)
|
|
14
|
+
STRIPE_PUBLISHABLE_KEY=pk_test_...
|
|
15
|
+
STRIPE_SECRET_KEY=sk_test_...
|
|
16
|
+
STRIPE_WEBHOOK_SECRET=whsec_...
|
|
17
|
+
|
|
18
|
+
# Firebase (download staging service account key)
|
|
19
|
+
GOOGLE_APPLICATION_CREDENTIALS=./serviceAccountKey-staging.json
|
package/.firebaserc
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Auto-merge claude branches to main
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- 'claude/**'
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
merge-to-main:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
with:
|
|
16
|
+
fetch-depth: 0
|
|
17
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
18
|
+
|
|
19
|
+
- name: Configure git
|
|
20
|
+
run: |
|
|
21
|
+
git config user.name "github-actions[bot]"
|
|
22
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
23
|
+
|
|
24
|
+
- name: Merge to main
|
|
25
|
+
run: |
|
|
26
|
+
git checkout main
|
|
27
|
+
git merge origin/${{ github.ref_name }} --no-edit
|
|
28
|
+
git push origin main
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- name: Checkout
|
|
12
|
+
uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- name: Set up Node.js
|
|
15
|
+
uses: actions/setup-node@v4
|
|
16
|
+
with:
|
|
17
|
+
node-version: 20
|
|
18
|
+
|
|
19
|
+
- name: Install dependencies
|
|
20
|
+
run: npm ci
|
|
21
|
+
|
|
22
|
+
- name: Lint
|
|
23
|
+
run: npm run lint
|
|
24
|
+
continue-on-error: true
|
|
25
|
+
|
|
26
|
+
- name: Test
|
|
27
|
+
run: npm test
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Added by npxhub. Releases are started from the npxhub dashboard.
|
|
2
|
+
# npxhub-workflow: v3
|
|
3
|
+
name: npxhub publish
|
|
4
|
+
run-name: npxhub ${{ inputs.release_id }}
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
version: { description: "Version to publish", required: true, type: string }
|
|
10
|
+
tag: { description: "npm dist-tag", required: true, type: string, default: latest }
|
|
11
|
+
git_tag: { description: "Git tag to create", required: true, type: string }
|
|
12
|
+
directory: { description: "Package directory", required: false, type: string, default: "." }
|
|
13
|
+
notes: { description: "Release notes", required: false, type: string, default: "" }
|
|
14
|
+
provenance: { description: "Publish with provenance", required: false, type: boolean, default: false }
|
|
15
|
+
release_id: { description: "npxhub release id", required: true, type: string }
|
|
16
|
+
log_url: { description: "Where to send live step output", required: false, type: string, default: "" }
|
|
17
|
+
log_token: { description: "Token for log_url", required: false, type: string, default: "" }
|
|
18
|
+
|
|
19
|
+
permissions:
|
|
20
|
+
contents: write
|
|
21
|
+
id-token: write
|
|
22
|
+
|
|
23
|
+
concurrency:
|
|
24
|
+
group: npxhub-publish-${{ inputs.directory }}
|
|
25
|
+
cancel-in-progress: false
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
publish:
|
|
29
|
+
name: npxhub publish
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
defaults:
|
|
32
|
+
run:
|
|
33
|
+
working-directory: ${{ inputs.directory }}
|
|
34
|
+
env:
|
|
35
|
+
VERSION: ${{ inputs.version }}
|
|
36
|
+
DIST_TAG: ${{ inputs.tag }}
|
|
37
|
+
GIT_TAG: ${{ inputs.git_tag }}
|
|
38
|
+
NOTES: ${{ inputs.notes }}
|
|
39
|
+
NPXHUB_LOG_URL: ${{ inputs.log_url }}
|
|
40
|
+
NPXHUB_LOG_TOKEN: ${{ inputs.log_token }}
|
|
41
|
+
steps:
|
|
42
|
+
- name: Checkout
|
|
43
|
+
uses: actions/checkout@v5
|
|
44
|
+
with:
|
|
45
|
+
fetch-depth: 0
|
|
46
|
+
|
|
47
|
+
- name: Set up Node
|
|
48
|
+
uses: actions/setup-node@v5
|
|
49
|
+
with:
|
|
50
|
+
node-version: 22
|
|
51
|
+
registry-url: https://registry.npmjs.org
|
|
52
|
+
|
|
53
|
+
- name: Set up npxhub log
|
|
54
|
+
run: |
|
|
55
|
+
if [ -n "$NPXHUB_LOG_TOKEN" ]; then echo "::add-mask::$NPXHUB_LOG_TOKEN"; fi
|
|
56
|
+
cat > /tmp/npxhub-log.cjs <<'NPXHUB_EOF'
|
|
57
|
+
"use strict"
|
|
58
|
+
const { spawn } = require("node:child_process")
|
|
59
|
+
const step = Number(process.argv[2])
|
|
60
|
+
const script = process.argv[3]
|
|
61
|
+
const url = process.env.NPXHUB_LOG_URL
|
|
62
|
+
const token = process.env.NPXHUB_LOG_TOKEN
|
|
63
|
+
const secrets = Object.keys(process.env)
|
|
64
|
+
.filter((k) => ["TOKEN", "SECRET", "PASSWORD", "KEY"].some((s) => k.toUpperCase().includes(s)))
|
|
65
|
+
.map((k) => process.env[k])
|
|
66
|
+
.filter((v) => v && v.length >= 8)
|
|
67
|
+
let pending = ""
|
|
68
|
+
let queue = Promise.resolve()
|
|
69
|
+
function redact(text) {
|
|
70
|
+
for (const s of secrets) text = text.split(s).join("***")
|
|
71
|
+
return text
|
|
72
|
+
}
|
|
73
|
+
function send(final) {
|
|
74
|
+
const cut = final ? pending.length : pending.lastIndexOf("\n") + 1
|
|
75
|
+
if (!url || cut === 0) return queue
|
|
76
|
+
const text = redact(pending.slice(0, cut))
|
|
77
|
+
pending = pending.slice(cut)
|
|
78
|
+
const body = JSON.stringify({ step: step, text: text })
|
|
79
|
+
const headers = { "content-type": "application/json", "x-npxhub-log-token": token }
|
|
80
|
+
queue = queue
|
|
81
|
+
.then(() => fetch(url, { method: "POST", headers: headers, body: body, signal: AbortSignal.timeout(10000) }))
|
|
82
|
+
.catch(() => {})
|
|
83
|
+
return queue
|
|
84
|
+
}
|
|
85
|
+
const timer = setInterval(() => send(false), 2000)
|
|
86
|
+
const child = spawn("bash", ["--noprofile", "--norc", "-eo", "pipefail", script], { stdio: ["inherit", "pipe", "pipe"] })
|
|
87
|
+
child.stdout.on("data", (d) => {
|
|
88
|
+
process.stdout.write(d)
|
|
89
|
+
pending += d
|
|
90
|
+
})
|
|
91
|
+
child.stderr.on("data", (d) => {
|
|
92
|
+
process.stderr.write(d)
|
|
93
|
+
pending += d
|
|
94
|
+
})
|
|
95
|
+
child.on("close", (code) => {
|
|
96
|
+
clearInterval(timer)
|
|
97
|
+
if (code !== 0) pending += "\n[step exited with code " + code + "]\n"
|
|
98
|
+
send(true).then(() => process.exit(code === null ? 1 : code))
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
NPXHUB_EOF
|
|
102
|
+
|
|
103
|
+
- name: Bump version and commit
|
|
104
|
+
shell: node /tmp/npxhub-log.cjs 2 {0}
|
|
105
|
+
run: |
|
|
106
|
+
git config user.name "github-actions[bot]"
|
|
107
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
108
|
+
npm version "$VERSION" --no-git-tag-version --allow-same-version
|
|
109
|
+
# A first release can equal the version already in package.json; then there is nothing to commit.
|
|
110
|
+
if git diff --quiet; then echo "package.json already at $VERSION"; else git commit -am "chore(release): $GIT_TAG"; fi
|
|
111
|
+
|
|
112
|
+
- name: Build and test
|
|
113
|
+
shell: node /tmp/npxhub-log.cjs 3 {0}
|
|
114
|
+
run: |
|
|
115
|
+
if [ -f package-lock.json ]; then npm ci
|
|
116
|
+
elif [ -f "$GITHUB_WORKSPACE/package-lock.json" ]; then (cd "$GITHUB_WORKSPACE" && npm ci)
|
|
117
|
+
else npm install; fi
|
|
118
|
+
npm run build --if-present
|
|
119
|
+
npm test --if-present
|
|
120
|
+
npm pack --dry-run --json > "$RUNNER_TEMP/pack.json"
|
|
121
|
+
node -e '
|
|
122
|
+
const files = require(process.env.RUNNER_TEMP + "/pack.json")[0].files.map(f => f.path)
|
|
123
|
+
// Templates such as .env.example or .env.staging.example are allowed; real env files and keys are not.
|
|
124
|
+
const secretLike = files.filter(p => /(^|\/)(\.env[^/]*|[^/]*\.pem|id_rsa[^/]*)$/.test(p))
|
|
125
|
+
const bad = secretLike.filter(p => !/\.(example|sample|template|dist|pub)$/.test(p))
|
|
126
|
+
if (secretLike.length > bad.length) console.log("Allowed templates: " + secretLike.filter(p => !bad.includes(p)).join(", "))
|
|
127
|
+
console.log(files.length + " files in tarball")
|
|
128
|
+
if (bad.length) { console.error("Blocked: secret-looking files in tarball: " + bad.join(", ")); process.exit(1) }
|
|
129
|
+
'
|
|
130
|
+
|
|
131
|
+
- name: Tag and GitHub release
|
|
132
|
+
shell: node /tmp/npxhub-log.cjs 4 {0}
|
|
133
|
+
env:
|
|
134
|
+
GH_TOKEN: ${{ github.token }}
|
|
135
|
+
run: |
|
|
136
|
+
# Safe to re-run after a failed release: reuse an existing tag and release.
|
|
137
|
+
if git rev-parse -q --verify "refs/tags/$GIT_TAG" > /dev/null; then
|
|
138
|
+
echo "Tag $GIT_TAG already exists"
|
|
139
|
+
git push origin "HEAD:$GITHUB_REF_NAME"
|
|
140
|
+
else
|
|
141
|
+
git tag -a "$GIT_TAG" -m "$GIT_TAG"
|
|
142
|
+
git push origin "HEAD:$GITHUB_REF_NAME" --follow-tags
|
|
143
|
+
fi
|
|
144
|
+
FLAGS=(--title "$GIT_TAG" --notes "$NOTES")
|
|
145
|
+
if [ "$DIST_TAG" != "latest" ]; then FLAGS+=(--prerelease); fi
|
|
146
|
+
if gh release view "$GIT_TAG" > /dev/null 2>&1; then echo "Release $GIT_TAG already exists"; else gh release create "$GIT_TAG" "${FLAGS[@]}"; fi
|
|
147
|
+
|
|
148
|
+
- name: Publish to npm
|
|
149
|
+
shell: node /tmp/npxhub-log.cjs 5 {0}
|
|
150
|
+
env:
|
|
151
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
152
|
+
PROVENANCE: ${{ inputs.provenance }}
|
|
153
|
+
run: |
|
|
154
|
+
if [ -z "$NODE_AUTH_TOKEN" ]; then echo "NPM_TOKEN secret is not set on this repo"; exit 1; fi
|
|
155
|
+
FLAGS=(--access public --tag "$DIST_TAG")
|
|
156
|
+
if [ "$PROVENANCE" = "true" ]; then FLAGS+=(--provenance); fi
|
|
157
|
+
npm publish "${FLAGS[@]}"
|
|
158
|
+
|
|
159
|
+
- name: Verify install
|
|
160
|
+
shell: node /tmp/npxhub-log.cjs 6 {0}
|
|
161
|
+
run: |
|
|
162
|
+
NAME=$(node -p "require('./package.json').name")
|
|
163
|
+
HAS_BIN=$(node -p "Boolean(require('./package.json').bin)")
|
|
164
|
+
for _ in $(seq 1 20); do npm view "$NAME@$VERSION" version > /dev/null 2>&1 && break; sleep 6; done
|
|
165
|
+
cd "$(mktemp -d)"
|
|
166
|
+
if [ "$HAS_BIN" = "true" ]; then
|
|
167
|
+
timeout 120 npx -y "$NAME@$VERSION" --version < /dev/null || timeout 120 npx -y "$NAME@$VERSION" --help < /dev/null
|
|
168
|
+
else
|
|
169
|
+
npm install "$NAME@$VERSION" --no-save
|
|
170
|
+
fi
|
package/.prettierignore
ADDED
package/.prettierrc.json
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# EvalDoc Platform
|
|
2
|
+
|
|
3
|
+
🏥 AI-powered healthcare chat platform with medical safety guards
|
|
4
|
+
|
|
5
|
+
🟡 **Status**: Experimental with Gemini 2.0 Flash & DeepSeek LLMs
|
|
6
|
+
✅ **LLM Integration**: Working (Gemini 2.0 Flash + DeepSeek fallback)
|
|
7
|
+
✅ **Safety Pipeline**: Multi-layer validation with NER, PII detection, escalation
|
|
8
|
+
✅ **Homepage**: Patient-facing landing page with provider search
|
|
9
|
+
|
|
10
|
+
## Quick Start - Local Development
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# Start the server
|
|
14
|
+
PORT=8080 node server.js
|
|
15
|
+
|
|
16
|
+
# Visit the app
|
|
17
|
+
http://localhost:8080/ # Homepage with provider search
|
|
18
|
+
http://localhost:8080/mollit-lorem-consequ # Test provider chat
|
|
19
|
+
http://localhost:8080/find-doctor.html # Provider directory
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
📖 **[Full Implementation Details →](IMPLEMENTATION.md)**
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Structure
|
|
27
|
+
|
|
28
|
+
### Frontend (Patient-Facing)
|
|
29
|
+
- `public/index.html` - Landing page with hero & provider search
|
|
30
|
+
- `public/chat.html` - Chat interface (served via clean URLs: `/{handle}`)
|
|
31
|
+
- `public/find-doctor.html` - Full provider directory
|
|
32
|
+
- `public/css/` - Styles (homepage + chat-specific)
|
|
33
|
+
- `public/js/` - JavaScript (search + chat logic)
|
|
34
|
+
|
|
35
|
+
### Backend
|
|
36
|
+
- `server.js` - Main API server with routing
|
|
37
|
+
- `functions/src/` - Backend modules
|
|
38
|
+
- `llm.js` - **Gemini 2.0 Flash + DeepSeek (improved prompts)**
|
|
39
|
+
- `safety.js` - Multi-layer safety pipeline
|
|
40
|
+
- `ner.js` - Medical Named Entity Recognition
|
|
41
|
+
- `topics.js` - 6 medical topics with controls
|
|
42
|
+
- `analytics.js` - Usage tracking
|
|
43
|
+
- `limits.js` - Rate limiting
|
|
44
|
+
|
|
45
|
+
### Configuration
|
|
46
|
+
- `firestore.rules` - Security rules
|
|
47
|
+
- `firestore.indexes.json` - Database indexes
|
|
48
|
+
- `.env` - API keys (Gemini, DeepSeek, HuggingFace)
|
|
49
|
+
- `SRS.md` - Requirements specification
|
|
50
|
+
- `IMPLEMENTATION.md` - Technical documentation
|
|
51
|
+
|
|
52
|
+
## Key Features ✅
|
|
53
|
+
|
|
54
|
+
✅ **Homepage & Provider Discovery**: Landing page with real-time search
|
|
55
|
+
✅ **Clean URLs**: Share providers via `/{handle}` instead of query params
|
|
56
|
+
✅ **LLM Integration**: Gemini 2.0 Flash (primary) + DeepSeek (fallback)
|
|
57
|
+
✅ **Improved Prompts**: Less restrictive, more helpful responses (250 tokens)
|
|
58
|
+
✅ **Medical NER**: Entity detection with Hugging Face models
|
|
59
|
+
✅ **Safety-First**: Multi-layer validation, PII redaction, red flag escalation
|
|
60
|
+
✅ **Topic-Based**: 6 predefined medical topics with custom controls
|
|
61
|
+
✅ **Anonymous Chat**: No patient login required
|
|
62
|
+
✅ **Responsive Design**: Mobile, tablet, desktop optimized
|
|
63
|
+
|
|
64
|
+
## API Endpoints
|
|
65
|
+
|
|
66
|
+
### Public
|
|
67
|
+
- `GET /` - Homepage with provider search
|
|
68
|
+
- `GET /:handle` - Chat interface (clean URL routing)
|
|
69
|
+
- `GET /find-doctor.html` - Provider directory
|
|
70
|
+
- `GET /api/search-providers?q=query` - Search providers (name + specialty)
|
|
71
|
+
- `GET /api/provider?handle=<handle>` - Get provider profile
|
|
72
|
+
- `POST /api/chat` - Send message (anonymous, with safety pipeline)
|
|
73
|
+
- `POST /api/satisfaction` - Submit rating
|
|
74
|
+
|
|
75
|
+
### Authenticated (Firebase Auth token required)
|
|
76
|
+
- `GET /api/me` - Current provider details
|
|
77
|
+
- `POST /api/provider` - Create provider
|
|
78
|
+
- `POST /api/provider/update` - Update settings
|
|
79
|
+
- `GET /api/conversations` - List conversations
|
|
80
|
+
- `GET /api/analytics` - Dashboard data
|
|
81
|
+
|
|
82
|
+
## ✅ LLM Integration Status
|
|
83
|
+
|
|
84
|
+
**Working Implementation:**
|
|
85
|
+
- **Primary**: Gemini 2.0 Flash (`gemini-2.0-flash-exp`)
|
|
86
|
+
- **Fallback**: DeepSeek Chat
|
|
87
|
+
- **Response Quality**: Improved system prompts (more helpful, less guarded)
|
|
88
|
+
- **Token Limits**: 250 tokens per response
|
|
89
|
+
- **Temperature**: 0.4 (balanced between accuracy and creativity)
|
|
90
|
+
|
|
91
|
+
See [functions/src/llm.js](functions/src/llm.js) for implementation.
|
|
92
|
+
|
|
93
|
+
## Medical Topics Supported
|
|
94
|
+
|
|
95
|
+
1. `medication_info_safety` - Medication facts & warnings
|
|
96
|
+
2. `appointments_preparation` - Appointment prep tips
|
|
97
|
+
3. `general_health_info` - General health education
|
|
98
|
+
4. `clinic_services_hours` - Clinic info & hours
|
|
99
|
+
5. `insurance_billing_faq` - Billing questions
|
|
100
|
+
6. `post_procedure_guidance` - Post-op care
|
|
101
|
+
|
|
102
|
+
Each topic has custom prompts, disclaimers, and safety rules.
|
|
103
|
+
|
|
104
|
+
## Local Setup (Alternative)
|
|
105
|
+
|
|
106
|
+
**Note**: Firebase CLI has issues locally. Use online deployment instead.
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
cd functions && npm install
|
|
110
|
+
firebase emulators:start --only functions,firestore,hosting
|
|
111
|
+
# Visit http://localhost:5000/app
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Production Checklist
|
|
115
|
+
|
|
116
|
+
Before launching:
|
|
117
|
+
- [ ] Integrate real LLM provider (OpenAI/Claude/Vertex)
|
|
118
|
+
- [ ] Restrict CORS to specific domains
|
|
119
|
+
- [ ] Add comprehensive logging
|
|
120
|
+
- [ ] Legal review of disclaimers
|
|
121
|
+
- [ ] HIPAA compliance review
|
|
122
|
+
- [ ] Test with real providers
|
|
123
|
+
- [ ] Set up monitoring & alerts
|
|
124
|
+
- [ ] Configure custom domain
|
|
125
|
+
|
|
126
|
+
## Tech Stack
|
|
127
|
+
|
|
128
|
+
- **Frontend**: Vanilla JS, HTML, CSS
|
|
129
|
+
- **Backend**: Node.js 20, Firebase Cloud Functions
|
|
130
|
+
- **Database**: Firestore
|
|
131
|
+
- **Auth**: Firebase Authentication
|
|
132
|
+
- **Hosting**: Firebase Hosting
|
|
133
|
+
|
|
134
|
+
## Documentation
|
|
135
|
+
|
|
136
|
+
- **[DEPLOYMENT.md](DEPLOYMENT.md)** - How to deploy
|
|
137
|
+
- **[SRS.md](SRS.md)** - Requirements spec
|
|
138
|
+
- **Firebase Project**: `evaldocplatform`
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
**Next Steps**: Deploy to Firebase online → Integrate LLM → Test with providers
|