patientzero 0.1.0__tar.gz
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.
- patientzero-0.1.0/.env.example +25 -0
- patientzero-0.1.0/.github/workflows/ci.yml +49 -0
- patientzero-0.1.0/.github/workflows/publish.yml +26 -0
- patientzero-0.1.0/.gitignore +43 -0
- patientzero-0.1.0/CLAUDE.md +50 -0
- patientzero-0.1.0/Dockerfile.test +34 -0
- patientzero-0.1.0/LICENSE +21 -0
- patientzero-0.1.0/PKG-INFO +96 -0
- patientzero-0.1.0/README.md +61 -0
- patientzero-0.1.0/backend/README.md +71 -0
- patientzero-0.1.0/backend/__init__.py +0 -0
- patientzero-0.1.0/backend/api/__init__.py +0 -0
- patientzero-0.1.0/backend/api/dependencies.py +8 -0
- patientzero-0.1.0/backend/api/main.py +81 -0
- patientzero-0.1.0/backend/api/routes/__init__.py +0 -0
- patientzero-0.1.0/backend/api/routes/agents.py +24 -0
- patientzero-0.1.0/backend/api/routes/analysis.py +138 -0
- patientzero-0.1.0/backend/api/routes/chat.py +109 -0
- patientzero-0.1.0/backend/api/routes/distributions.py +18 -0
- patientzero-0.1.0/backend/api/routes/experiments.py +150 -0
- patientzero-0.1.0/backend/api/routes/settings.py +12 -0
- patientzero-0.1.0/backend/api/routes/simulate.py +229 -0
- patientzero-0.1.0/backend/tests/__init__.py +0 -0
- patientzero-0.1.0/backend/tests/api/__init__.py +0 -0
- patientzero-0.1.0/backend/tests/api/test_chat.py +40 -0
- patientzero-0.1.0/backend/tests/api/test_experiments_optimization_targets.py +46 -0
- patientzero-0.1.0/backend/tests/api/test_experiments_optimize.py +20 -0
- patientzero-0.1.0/backend/tests/api/test_experiments_patch.py +10 -0
- patientzero-0.1.0/backend/tests/api/test_sessions.py +64 -0
- patientzero-0.1.0/backend/tests/api/test_simulate.py +75 -0
- patientzero-0.1.0/backend/tests/conftest.py +65 -0
- patientzero-0.1.0/conftest.py +54 -0
- patientzero-0.1.0/core/__init__.py +18 -0
- patientzero-0.1.0/core/agent.py +42 -0
- patientzero-0.1.0/core/agents/__init__.py +3 -0
- patientzero-0.1.0/core/agents/base.py +61 -0
- patientzero-0.1.0/core/analysis/__init__.py +0 -0
- patientzero-0.1.0/core/analysis/coverage.py +123 -0
- patientzero-0.1.0/core/config/__init__.py +0 -0
- patientzero-0.1.0/core/config/settings.py +41 -0
- patientzero-0.1.0/core/db/__init__.py +0 -0
- patientzero-0.1.0/core/db/database.py +42 -0
- patientzero-0.1.0/core/db/queries/__init__.py +0 -0
- patientzero-0.1.0/core/db/queries/sessions.py +69 -0
- patientzero-0.1.0/core/db/schema.sql +69 -0
- patientzero-0.1.0/core/distribution.py +391 -0
- patientzero-0.1.0/core/examples/__init__.py +1 -0
- patientzero-0.1.0/core/examples/medical/__init__.py +1 -0
- patientzero-0.1.0/core/examples/medical/config.py +32 -0
- patientzero-0.1.0/core/examples/medical/distributions.py +157 -0
- patientzero-0.1.0/core/examples/medical/prompts.py +25 -0
- patientzero-0.1.0/core/examples/medical/run.py +54 -0
- patientzero-0.1.0/core/experiment.py +171 -0
- patientzero-0.1.0/core/feedback/__init__.py +0 -0
- patientzero-0.1.0/core/feedback/feedback.py +141 -0
- patientzero-0.1.0/core/judge.py +107 -0
- patientzero-0.1.0/core/llm/__init__.py +0 -0
- patientzero-0.1.0/core/llm/base.py +8 -0
- patientzero-0.1.0/core/llm/claude_cli_provider.py +73 -0
- patientzero-0.1.0/core/llm/factory.py +52 -0
- patientzero-0.1.0/core/llm/mock.py +65 -0
- patientzero-0.1.0/core/llm/openai_provider.py +35 -0
- patientzero-0.1.0/core/logger.py +123 -0
- patientzero-0.1.0/core/repositories/__init__.py +44 -0
- patientzero-0.1.0/core/repositories/base.py +33 -0
- patientzero-0.1.0/core/repositories/evaluations.py +131 -0
- patientzero-0.1.0/core/repositories/experiments.py +182 -0
- patientzero-0.1.0/core/repositories/optimization_targets.py +83 -0
- patientzero-0.1.0/core/repositories/simulations.py +117 -0
- patientzero-0.1.0/core/sampling.py +10 -0
- patientzero-0.1.0/core/services/__init__.py +0 -0
- patientzero-0.1.0/core/services/feedback.py +83 -0
- patientzero-0.1.0/core/simulation.py +366 -0
- patientzero-0.1.0/core/tests/__init__.py +0 -0
- patientzero-0.1.0/core/tests/llm/__init__.py +0 -0
- patientzero-0.1.0/core/tests/llm/test_factory.py +44 -0
- patientzero-0.1.0/core/tests/llm/test_mock.py +33 -0
- patientzero-0.1.0/core/tests/test_distribution.py +441 -0
- patientzero-0.1.0/core/types/__init__.py +51 -0
- patientzero-0.1.0/core/types/analysis.py +28 -0
- patientzero-0.1.0/core/types/enums.py +6 -0
- patientzero-0.1.0/core/types/events.py +13 -0
- patientzero-0.1.0/core/types/feedback.py +54 -0
- patientzero-0.1.0/core/types/judge_result.py +44 -0
- patientzero-0.1.0/core/types/message.py +7 -0
- patientzero-0.1.0/core/types/records.py +257 -0
- patientzero-0.1.0/core/types/settings.py +9 -0
- patientzero-0.1.0/core/types/simulation.py +9 -0
- patientzero-0.1.0/core/types/trace.py +63 -0
- patientzero-0.1.0/core/types/transcript.py +33 -0
- patientzero-0.1.0/docs/architecture.md +104 -0
- patientzero-0.1.0/docs/domain-models.md +178 -0
- patientzero-0.1.0/docs/experiment.md +69 -0
- patientzero-0.1.0/docs/generators.md +100 -0
- patientzero-0.1.0/docs/optimization.md +85 -0
- patientzero-0.1.0/evaluations/__init__.py +0 -0
- patientzero-0.1.0/evaluations/feedback/RECOMMENDATIONS.md +60 -0
- patientzero-0.1.0/evaluations/feedback/RUNBOOK.md +104 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v1/analysis.csv +17 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v1/analysis.json +110 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v1/analysis_experiment.csv +4 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v1/run_summary.json +13 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v2_n10_restart/analysis.csv +55 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v2_n10_restart/analysis.json +110 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v2_n10_restart/analysis_experiment.csv +11 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v2_n10_restart/run_summary.json +13 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v2_n10_stage1/analysis.csv +45 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v2_n10_stage1/analysis.json +110 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v2_n10_stage1/analysis_experiment.csv +9 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v2_n10_stage1/run_summary.json +13 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v2_n20/analysis.csv +23 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v2_n20/analysis.json +110 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v2_n20/run_summary.json +13 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v2_n20_rerun1/analysis.csv +41 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v2_n20_rerun1/analysis.json +110 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v2_n20_rerun1/analysis_experiment.csv +15 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_low_lit_v2_n20_rerun1/run_summary.json +13 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_smoke/analysis.csv +1 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_smoke/analysis.json +8 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_smoke/run_summary.json +13 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_smoke2/analysis.csv +2 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_smoke2/analysis.json +38 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_smoke2/analysis_experiment.csv +2 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_smoke2/run_summary.json +13 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_v1/analysis.csv +14 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_v1/analysis.json +110 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_v1/analysis_experiment.csv +10 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_v1/hypotheses.md +39 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/baseline_v1/run_summary.json +13 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v2/analysis.csv +23 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v2/analysis.json +110 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v2/analysis_experiment.csv +7 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v2/compare_vs_baseline.json +39 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v2/compare_vs_baseline.md +34 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v2/run_summary.json +13 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v3_n10_restart/analysis.csv +61 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v3_n10_restart/analysis.json +110 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v3_n10_restart/analysis_experiment.csv +7 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v3_n10_restart/run_summary.json +13 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v3_n10_retry2/analysis.csv +71 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v3_n10_retry2/analysis.json +110 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v3_n10_retry2/analysis_experiment.csv +11 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v3_n10_retry2/compare_vs_baseline.json +55 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v3_n10_retry2/compare_vs_baseline.md +34 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v3_n10_retry2/run_summary.json +13 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v3_n20/analysis.csv +23 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v3_n20/analysis.json +110 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_low_lit_v3_n20/run_summary.json +13 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_v2/analysis.csv +10 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_v2/analysis.json +102 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_v2/analysis_experiment.csv +4 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_v2/compare_vs_baseline.json +61 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_v2/compare_vs_baseline.md +20 -0
- patientzero-0.1.0/evaluations/feedback/artifacts/intervention_v2/run_summary.json +13 -0
- patientzero-0.1.0/evaluations/judge/__init__.py +0 -0
- patientzero-0.1.0/evaluations/judge/cases/__init__.py +0 -0
- patientzero-0.1.0/evaluations/judge/cases/bad_explanation.py +43 -0
- patientzero-0.1.0/evaluations/judge/cases/cbc_good.py +36 -0
- patientzero-0.1.0/evaluations/judge/cases/cbc_poor.py +32 -0
- patientzero-0.1.0/evaluations/judge/cases/confidence_gap.py +34 -0
- patientzero-0.1.0/evaluations/judge/cases/hba1c_good.py +43 -0
- patientzero-0.1.0/evaluations/judge/cases/liver_passive.py +40 -0
- patientzero-0.1.0/evaluations/judge/cases/metabolic_high_literacy.py +51 -0
- patientzero-0.1.0/evaluations/judge/cases/metformin_mixed.py +39 -0
- patientzero-0.1.0/evaluations/judge/cases/patient_contradicts.py +49 -0
- patientzero-0.1.0/evaluations/judge/cases/short_exchange.py +29 -0
- patientzero-0.1.0/evaluations/judge/output/bad_explanation.json +13 -0
- patientzero-0.1.0/evaluations/judge/output/cbc_good.json +13 -0
- patientzero-0.1.0/evaluations/judge/output/cbc_poor.json +13 -0
- patientzero-0.1.0/evaluations/judge/output/confidence_gap.json +13 -0
- patientzero-0.1.0/evaluations/judge/output/hba1c_good.json +13 -0
- patientzero-0.1.0/evaluations/judge/output/liver_passive.json +13 -0
- patientzero-0.1.0/evaluations/judge/output/metabolic_high_literacy.json +13 -0
- patientzero-0.1.0/evaluations/judge/output/metformin_mixed.json +13 -0
- patientzero-0.1.0/evaluations/judge/output/patient_contradicts.json +13 -0
- patientzero-0.1.0/evaluations/judge/output/short_exchange.json +13 -0
- patientzero-0.1.0/frontend/.gitignore +24 -0
- patientzero-0.1.0/frontend/README.md +58 -0
- patientzero-0.1.0/frontend/components.json +25 -0
- patientzero-0.1.0/frontend/eslint.config.js +23 -0
- patientzero-0.1.0/frontend/index.html +15 -0
- patientzero-0.1.0/frontend/package-lock.json +7772 -0
- patientzero-0.1.0/frontend/package.json +45 -0
- patientzero-0.1.0/frontend/public/favicon.svg +4 -0
- patientzero-0.1.0/frontend/src/App.tsx +34 -0
- patientzero-0.1.0/frontend/src/api/client.ts +9 -0
- patientzero-0.1.0/frontend/src/api/sessions.ts +412 -0
- patientzero-0.1.0/frontend/src/atoms/agents.ts +4 -0
- patientzero-0.1.0/frontend/src/atoms/experiment.ts +6 -0
- patientzero-0.1.0/frontend/src/atoms/model.ts +7 -0
- patientzero-0.1.0/frontend/src/atoms/simulation.ts +20 -0
- patientzero-0.1.0/frontend/src/components/agents/AgentConfigView.tsx +154 -0
- patientzero-0.1.0/frontend/src/components/chat/ChatInput.tsx +38 -0
- patientzero-0.1.0/frontend/src/components/chat/MessageBubble.tsx +22 -0
- patientzero-0.1.0/frontend/src/components/chat/MessageList.tsx +31 -0
- patientzero-0.1.0/frontend/src/components/chat/ModelSelector.tsx +31 -0
- patientzero-0.1.0/frontend/src/components/chat/Sidebar.tsx +59 -0
- patientzero-0.1.0/frontend/src/components/experiments/ExperimentHeader.tsx +38 -0
- patientzero-0.1.0/frontend/src/components/experiments/ExperimentSummary.tsx +121 -0
- patientzero-0.1.0/frontend/src/components/experiments/ExperimentTabs.tsx +40 -0
- patientzero-0.1.0/frontend/src/components/experiments/NewExperimentDialog.tsx +101 -0
- patientzero-0.1.0/frontend/src/components/experiments/distributions/ConditionalDistributionBlock.tsx +19 -0
- patientzero-0.1.0/frontend/src/components/experiments/distributions/DistributionBars.tsx +28 -0
- patientzero-0.1.0/frontend/src/components/experiments/distributions/DoctorDistributionCard.tsx +46 -0
- patientzero-0.1.0/frontend/src/components/experiments/distributions/PatientDistributionCard.tsx +59 -0
- patientzero-0.1.0/frontend/src/components/experiments/tabs/DistributionsTab.tsx +39 -0
- patientzero-0.1.0/frontend/src/components/experiments/tabs/ReproducibilityTab.tsx +114 -0
- patientzero-0.1.0/frontend/src/components/experiments/tabs/SimulationsTab.tsx +251 -0
- patientzero-0.1.0/frontend/src/components/experiments/tabs/TargetsTab.tsx +164 -0
- patientzero-0.1.0/frontend/src/components/experiments/targets/CurrentPromptsTabs.tsx +60 -0
- patientzero-0.1.0/frontend/src/components/experiments/targets/OptimizationResultCard.tsx +203 -0
- patientzero-0.1.0/frontend/src/components/experiments/targets/OptimizationTargetsList.tsx +211 -0
- patientzero-0.1.0/frontend/src/components/experiments/targets/OptimizeOptionsForm.tsx +103 -0
- patientzero-0.1.0/frontend/src/components/nav/AppSidebar.tsx +110 -0
- patientzero-0.1.0/frontend/src/components/nav/NavItem.tsx +41 -0
- patientzero-0.1.0/frontend/src/components/ui/badge.tsx +52 -0
- patientzero-0.1.0/frontend/src/components/ui/button.tsx +58 -0
- patientzero-0.1.0/frontend/src/components/ui/card.tsx +103 -0
- patientzero-0.1.0/frontend/src/components/ui/dialog.tsx +101 -0
- patientzero-0.1.0/frontend/src/components/ui/input.tsx +20 -0
- patientzero-0.1.0/frontend/src/components/ui/progress.tsx +81 -0
- patientzero-0.1.0/frontend/src/components/ui/scroll-area.tsx +53 -0
- patientzero-0.1.0/frontend/src/components/ui/select.tsx +199 -0
- patientzero-0.1.0/frontend/src/components/ui/separator.tsx +25 -0
- patientzero-0.1.0/frontend/src/components/ui/sonner.tsx +28 -0
- patientzero-0.1.0/frontend/src/components/ui/table.tsx +116 -0
- patientzero-0.1.0/frontend/src/components/ui/tabs.tsx +80 -0
- patientzero-0.1.0/frontend/src/containers/chat/ChatContainer.tsx +35 -0
- patientzero-0.1.0/frontend/src/contexts/ChatContext.tsx +150 -0
- patientzero-0.1.0/frontend/src/contexts/ErrorContext.tsx +39 -0
- patientzero-0.1.0/frontend/src/index.css +129 -0
- patientzero-0.1.0/frontend/src/layouts/AppLayout.tsx +13 -0
- patientzero-0.1.0/frontend/src/lib/utils.ts +6 -0
- patientzero-0.1.0/frontend/src/main.tsx +13 -0
- patientzero-0.1.0/frontend/src/pages/Chat.tsx +10 -0
- patientzero-0.1.0/frontend/src/pages/ExperimentsPage.tsx +66 -0
- patientzero-0.1.0/frontend/src/pages/SettingsPage.tsx +51 -0
- patientzero-0.1.0/frontend/src/pages/SimulationDetailPage.tsx +281 -0
- patientzero-0.1.0/frontend/src/pages/agents/AgentPage.tsx +36 -0
- patientzero-0.1.0/frontend/src/types/agents.ts +25 -0
- patientzero-0.1.0/frontend/src/types/chat.ts +18 -0
- patientzero-0.1.0/frontend/src/types/simulation.ts +223 -0
- patientzero-0.1.0/frontend/tsconfig.app.json +32 -0
- patientzero-0.1.0/frontend/tsconfig.json +13 -0
- patientzero-0.1.0/frontend/tsconfig.node.json +26 -0
- patientzero-0.1.0/frontend/vite.config.ts +13 -0
- patientzero-0.1.0/pyproject.toml +47 -0
- patientzero-0.1.0/slides/structure.md +131 -0
- patientzero-0.1.0/slides/text.md +303 -0
- patientzero-0.1.0/todos.md +76 -0
- patientzero-0.1.0/uv.lock +577 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# LLM Providers (set the ones you need)
|
|
2
|
+
OPENAI_API_KEY=
|
|
3
|
+
ANTHROPIC_API_KEY=
|
|
4
|
+
KIMI_API_KEY=your_kimi_api_key_here
|
|
5
|
+
|
|
6
|
+
# Local LLM (e.g. Ollama)
|
|
7
|
+
LOCAL_LLM_URL=http://localhost:11434
|
|
8
|
+
|
|
9
|
+
# Active provider: mock | openai | claude | kimi | local
|
|
10
|
+
LLM_PROVIDER=mock
|
|
11
|
+
|
|
12
|
+
# Model overrides (optional, defaults set in config/settings.py)
|
|
13
|
+
OPENAI_MODEL=gpt-4o
|
|
14
|
+
ANTHROPIC_MODEL=claude-sonnet-4-20250514
|
|
15
|
+
|
|
16
|
+
# Server
|
|
17
|
+
BACKEND_PORT=8000
|
|
18
|
+
FRONTEND_PORT=5173
|
|
19
|
+
|
|
20
|
+
# Concurrency (see GET /api/settings)
|
|
21
|
+
MAX_CONCURRENT_SIMULATIONS=5
|
|
22
|
+
MAX_CONCURRENT_OPTIMIZATIONS=1
|
|
23
|
+
|
|
24
|
+
# Database
|
|
25
|
+
DB_PATH=patientzero.db
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ${{ matrix.os }}
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
16
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- uses: astral-sh/setup-uv@v6
|
|
22
|
+
|
|
23
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
24
|
+
run: uv python install ${{ matrix.python-version }}
|
|
25
|
+
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: uv sync --extra dev --extra backend
|
|
28
|
+
|
|
29
|
+
- name: Run tests
|
|
30
|
+
run: uv run python -m pytest core/tests/ backend/tests/ -v
|
|
31
|
+
|
|
32
|
+
build:
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
needs: test
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/checkout@v4
|
|
37
|
+
|
|
38
|
+
- uses: astral-sh/setup-uv@v6
|
|
39
|
+
|
|
40
|
+
- name: Build package
|
|
41
|
+
run: |
|
|
42
|
+
uv sync --extra dev
|
|
43
|
+
uv run python -m build
|
|
44
|
+
|
|
45
|
+
- name: Upload artifacts
|
|
46
|
+
uses: actions/upload-artifact@v4
|
|
47
|
+
with:
|
|
48
|
+
name: dist
|
|
49
|
+
path: dist/
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
id-token: write
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
publish:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
environment: pypi
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- uses: astral-sh/setup-uv@v6
|
|
19
|
+
|
|
20
|
+
- name: Build package
|
|
21
|
+
run: |
|
|
22
|
+
uv sync --extra dev
|
|
23
|
+
uv run python -m build
|
|
24
|
+
|
|
25
|
+
- name: Publish to PyPI
|
|
26
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
*.egg
|
|
8
|
+
|
|
9
|
+
.auriga
|
|
10
|
+
|
|
11
|
+
# Virtual environments
|
|
12
|
+
.venv/
|
|
13
|
+
venv/
|
|
14
|
+
env/
|
|
15
|
+
|
|
16
|
+
# IDE
|
|
17
|
+
.idea/
|
|
18
|
+
.vscode/
|
|
19
|
+
*.swp
|
|
20
|
+
*.swo
|
|
21
|
+
|
|
22
|
+
# OS
|
|
23
|
+
.DS_Store
|
|
24
|
+
Thumbs.db
|
|
25
|
+
|
|
26
|
+
# Environment
|
|
27
|
+
.env
|
|
28
|
+
|
|
29
|
+
# Frontend
|
|
30
|
+
node_modules/
|
|
31
|
+
frontend/dist/
|
|
32
|
+
|
|
33
|
+
# Database
|
|
34
|
+
*.db
|
|
35
|
+
*.db-wal
|
|
36
|
+
*.db-shm
|
|
37
|
+
*.db-journal
|
|
38
|
+
|
|
39
|
+
# Data output
|
|
40
|
+
backend/data/
|
|
41
|
+
|
|
42
|
+
# Simulation logs
|
|
43
|
+
logs/
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
## Project: PatientZero
|
|
4
|
+
|
|
5
|
+
Simulation system that uses LLM agents to simulate doctor-patient interactions around medical test results. A DoctorAgent explains, a PatientAgent responds, and a JudgeAgent scores comprehension.
|
|
6
|
+
|
|
7
|
+
## Commands
|
|
8
|
+
|
|
9
|
+
All commands run from project root (`project/`), not `backend/`.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
uv sync # install python deps
|
|
13
|
+
uv run uvicorn backend.api.main:app --reload # run backend
|
|
14
|
+
uv run python -m pytest core/tests/ backend/tests/ -v # run tests
|
|
15
|
+
uv run python -m evaluations.judge.run [--model M] # run judge evals
|
|
16
|
+
cd frontend && npm install && npm run dev # run frontend (port 5173)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Repo Structure
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
core/ # All domain logic, no FastAPI dependency
|
|
23
|
+
agents/ # DoctorAgent, PatientAgent, JudgeAgent + prompts.py
|
|
24
|
+
llm/ # LLMProvider ABC, factory, Mock/OpenAI/ClaudeCLI providers
|
|
25
|
+
services/ # run_simulation_streaming() orchestration
|
|
26
|
+
simulation/ # Simulation runner (state machine: run/step/pause/resume/stop)
|
|
27
|
+
config/ # Settings, personas, 3 scenarios (CBC, HbA1c, Metformin)
|
|
28
|
+
db/ # SQLite (WAL), schema.sql, queries/{sessions,simulations,evaluations}.py
|
|
29
|
+
types/ # Dataclasses & enums split across modules, re-exported from __init__
|
|
30
|
+
backend/ # FastAPI routes (chat.py, simulate.py), tests
|
|
31
|
+
evaluations/ # Judge eval harness — hardcoded transcripts, auto-discovered
|
|
32
|
+
frontend/ # React 19 + Vite + TS, Tailwind + shadcn/ui
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Key Patterns
|
|
36
|
+
|
|
37
|
+
- **LLM models** use `"provider:model"` format (e.g. `"kimi:kimi-k2.5"`). Parsed by `parse_provider_model()` in `core/llm/factory.py`.
|
|
38
|
+
- **Providers**: `mock` (testing), `kimi`, `claude` (via CLI), `openai`, `local`. Factory in `core/llm/factory.py`.
|
|
39
|
+
- **Prompts** are format-string templates in `core/agents/prompts.py` (not a directory).
|
|
40
|
+
- **Simulation** alternates doctor/patient turns via SSE streaming. Service layer in `core/services/simulation.py` handles DB persistence.
|
|
41
|
+
- **API** endpoints all prefixed with `/api`. Routes in `backend/api/routes/`.
|
|
42
|
+
- **Environment**: `.env` at project root. Key vars: `LLM_PROVIDER` (default `mock`), `KIMI_API_KEY`, `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`. See `.env.example`.
|
|
43
|
+
|
|
44
|
+
## Testing
|
|
45
|
+
|
|
46
|
+
Tests split by concern:
|
|
47
|
+
- `core/tests/` — domain logic (agents, analysis, db, feedback, generators, llm, simulation). Mirrors `core/` layout.
|
|
48
|
+
- `backend/tests/api/` — FastAPI route tests only.
|
|
49
|
+
|
|
50
|
+
All use `MockProvider(delay=0)`. Shared fixtures (`db`, `experiment`, `mock_provider`) live in project-root `conftest.py`. The `test_client` fixture lives in `backend/tests/conftest.py`.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
FROM python:3.11-slim
|
|
2
|
+
|
|
3
|
+
WORKDIR /app
|
|
4
|
+
|
|
5
|
+
# Install the wheel (built on host, copied in)
|
|
6
|
+
COPY dist/*.whl /tmp/
|
|
7
|
+
RUN pip install /tmp/patientzero-*.whl
|
|
8
|
+
|
|
9
|
+
# 1. Verify core imports with only the base dependency (python-dotenv)
|
|
10
|
+
RUN python -c "\
|
|
11
|
+
import core; \
|
|
12
|
+
from core.db.database import Database; \
|
|
13
|
+
d = Database(':memory:'); d.init(); \
|
|
14
|
+
print('PASS: core import + schema init')"
|
|
15
|
+
|
|
16
|
+
# 2. Verify openai is NOT required for core
|
|
17
|
+
RUN python -c "\
|
|
18
|
+
from core.llm.factory import get_provider; \
|
|
19
|
+
p = get_provider('mock'); \
|
|
20
|
+
print('PASS: mock provider works without openai')"
|
|
21
|
+
|
|
22
|
+
# 3. Install with all extras and verify backend imports
|
|
23
|
+
RUN pip install "/tmp/$(ls /tmp/patientzero-*.whl | head -1 | xargs basename)[all]"
|
|
24
|
+
RUN python -c "\
|
|
25
|
+
from backend.api.main import app; \
|
|
26
|
+
print('PASS: backend app imports')"
|
|
27
|
+
|
|
28
|
+
# 4. Copy the full source and run the test suite against the installed package
|
|
29
|
+
COPY . /src
|
|
30
|
+
WORKDIR /src
|
|
31
|
+
RUN pip install pytest pytest-asyncio httpx
|
|
32
|
+
RUN python -m pytest core/tests/ backend/tests/ -v
|
|
33
|
+
|
|
34
|
+
CMD ["echo", "All tests passed"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Surya Mani, Aaron Tamte, Lile Zhang
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: patientzero
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A generic framework for LLM-driven patient simulations.
|
|
5
|
+
Author: Surya Mani, Aaron Tamte, Lile Zhang
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Requires-Python: >=3.11
|
|
15
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
16
|
+
Provides-Extra: all
|
|
17
|
+
Requires-Dist: fastapi>=0.115; extra == 'all'
|
|
18
|
+
Requires-Dist: openai>=1.0.0; extra == 'all'
|
|
19
|
+
Requires-Dist: pydantic>=2.0.0; extra == 'all'
|
|
20
|
+
Requires-Dist: sse-starlette>=2.0; extra == 'all'
|
|
21
|
+
Requires-Dist: uvicorn>=0.30; extra == 'all'
|
|
22
|
+
Provides-Extra: backend
|
|
23
|
+
Requires-Dist: fastapi>=0.115; extra == 'backend'
|
|
24
|
+
Requires-Dist: pydantic>=2.0.0; extra == 'backend'
|
|
25
|
+
Requires-Dist: sse-starlette>=2.0; extra == 'backend'
|
|
26
|
+
Requires-Dist: uvicorn>=0.30; extra == 'backend'
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: build>=1.0.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: httpx>=0.27.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
32
|
+
Provides-Extra: openai
|
|
33
|
+
Requires-Dist: openai>=1.0.0; extra == 'openai'
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# PatientZero
|
|
37
|
+
|
|
38
|
+
Explaining Health: How AI Explanation Styles and Interaction Modalities Affect User Comprehension of Medical Information
|
|
39
|
+
|
|
40
|
+
## Overview
|
|
41
|
+
|
|
42
|
+
A simulation system that uses LLM-powered agents to simulate doctor-patient interactions around medical test results and evaluate patient comprehension.
|
|
43
|
+
|
|
44
|
+
## Tech Stack
|
|
45
|
+
|
|
46
|
+
- **Frontend**: React + Vite + TypeScript, Tailwind CSS, shadcn/ui
|
|
47
|
+
- **Backend**: Python, FastAPI, SQLite
|
|
48
|
+
- **LLM**: Abstracted provider layer (Mock, OpenAI, Claude, Local)
|
|
49
|
+
|
|
50
|
+
## Project Structure
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
PatientZero/
|
|
54
|
+
├── core/ # Domain logic (imported by the backend)
|
|
55
|
+
├── frontend/ # React app
|
|
56
|
+
├── backend/ # FastAPI HTTP layer
|
|
57
|
+
└── report.txt # Research report
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Prerequisites
|
|
61
|
+
|
|
62
|
+
- Python 3.12+
|
|
63
|
+
- Node.js 20+
|
|
64
|
+
- [uv](https://docs.astral.sh/uv/) (Python package manager)
|
|
65
|
+
|
|
66
|
+
## Quick Start
|
|
67
|
+
|
|
68
|
+
1. Clone the repo:
|
|
69
|
+
```bash
|
|
70
|
+
git clone https://github.com/tamteaa/PatientZero.git
|
|
71
|
+
cd PatientZero
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
2. Set up environment:
|
|
75
|
+
```bash
|
|
76
|
+
cp .env.example .env
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
3. Install Python deps and start the backend (from the repo root so `core` imports resolve):
|
|
80
|
+
```bash
|
|
81
|
+
uv sync
|
|
82
|
+
uv run uvicorn backend.api.main:app --reload
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
4. Start the frontend:
|
|
86
|
+
```bash
|
|
87
|
+
cd frontend
|
|
88
|
+
npm install
|
|
89
|
+
npm run dev
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
5. Open http://localhost:5173
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
|
|
96
|
+
MIT
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# PatientZero
|
|
2
|
+
|
|
3
|
+
Explaining Health: How AI Explanation Styles and Interaction Modalities Affect User Comprehension of Medical Information
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
A simulation system that uses LLM-powered agents to simulate doctor-patient interactions around medical test results and evaluate patient comprehension.
|
|
8
|
+
|
|
9
|
+
## Tech Stack
|
|
10
|
+
|
|
11
|
+
- **Frontend**: React + Vite + TypeScript, Tailwind CSS, shadcn/ui
|
|
12
|
+
- **Backend**: Python, FastAPI, SQLite
|
|
13
|
+
- **LLM**: Abstracted provider layer (Mock, OpenAI, Claude, Local)
|
|
14
|
+
|
|
15
|
+
## Project Structure
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
PatientZero/
|
|
19
|
+
├── core/ # Domain logic (imported by the backend)
|
|
20
|
+
├── frontend/ # React app
|
|
21
|
+
├── backend/ # FastAPI HTTP layer
|
|
22
|
+
└── report.txt # Research report
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Prerequisites
|
|
26
|
+
|
|
27
|
+
- Python 3.12+
|
|
28
|
+
- Node.js 20+
|
|
29
|
+
- [uv](https://docs.astral.sh/uv/) (Python package manager)
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
1. Clone the repo:
|
|
34
|
+
```bash
|
|
35
|
+
git clone https://github.com/tamteaa/PatientZero.git
|
|
36
|
+
cd PatientZero
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
2. Set up environment:
|
|
40
|
+
```bash
|
|
41
|
+
cp .env.example .env
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
3. Install Python deps and start the backend (from the repo root so `core` imports resolve):
|
|
45
|
+
```bash
|
|
46
|
+
uv sync
|
|
47
|
+
uv run uvicorn backend.api.main:app --reload
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
4. Start the frontend:
|
|
51
|
+
```bash
|
|
52
|
+
cd frontend
|
|
53
|
+
npm install
|
|
54
|
+
npm run dev
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
5. Open http://localhost:5173
|
|
58
|
+
|
|
59
|
+
## License
|
|
60
|
+
|
|
61
|
+
MIT
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# PatientZero Backend
|
|
2
|
+
|
|
3
|
+
FastAPI server with SQLite database and abstracted LLM provider layer.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
uv sync
|
|
9
|
+
cp ../.env.example ../.env # if not done already
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Running
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
uv run uvicorn api.main:app --reload
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Server runs at http://localhost:8000
|
|
20
|
+
|
|
21
|
+
## Project Structure
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
backend/
|
|
25
|
+
├── api/
|
|
26
|
+
│ ├── main.py # FastAPI app, CORS, lifespan
|
|
27
|
+
│ ├── dependencies.py # Shared db + provider instances
|
|
28
|
+
│ └── routes/
|
|
29
|
+
│ └── chat.py # Chat + session endpoints
|
|
30
|
+
├── config/
|
|
31
|
+
│ └── settings.py # Environment config
|
|
32
|
+
├── db/
|
|
33
|
+
│ ├── database.py # Database class (SQLite, raw queries)
|
|
34
|
+
│ ├── schema.sql # Table definitions
|
|
35
|
+
│ └── queries/
|
|
36
|
+
│ └── sessions.py # Session + turn CRUD
|
|
37
|
+
├── llm/
|
|
38
|
+
│ ├── base.py # Abstract LLMProvider
|
|
39
|
+
│ ├── mock.py # Mock provider (testing)
|
|
40
|
+
│ └── factory.py # Provider factory
|
|
41
|
+
└── pyproject.toml
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## API Endpoints
|
|
45
|
+
|
|
46
|
+
| Method | Path | Description |
|
|
47
|
+
|--------|------|-------------|
|
|
48
|
+
| `POST` | `/api/sessions` | Create a new chat session |
|
|
49
|
+
| `GET` | `/api/sessions` | List all sessions |
|
|
50
|
+
| `GET` | `/api/sessions/{id}` | Get session with turns |
|
|
51
|
+
| `POST` | `/api/chat` | Send message, receive SSE stream |
|
|
52
|
+
|
|
53
|
+
## LLM Providers
|
|
54
|
+
|
|
55
|
+
Set `LLM_PROVIDER` in `.env`:
|
|
56
|
+
|
|
57
|
+
| Provider | Value | Status |
|
|
58
|
+
|----------|-------|--------|
|
|
59
|
+
| Mock | `mock` | Available |
|
|
60
|
+
| OpenAI | `openai` | Planned |
|
|
61
|
+
| Claude | `claude` | Planned |
|
|
62
|
+
| Local | `local` | Planned |
|
|
63
|
+
|
|
64
|
+
## Database
|
|
65
|
+
|
|
66
|
+
SQLite with WAL mode. Tables:
|
|
67
|
+
|
|
68
|
+
- `sessions` — chat sessions (id, title, created_at)
|
|
69
|
+
- `turns` — individual messages (session_id, role, content, turn_number)
|
|
70
|
+
|
|
71
|
+
Database file is created automatically on first run.
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import traceback
|
|
3
|
+
from contextlib import asynccontextmanager
|
|
4
|
+
|
|
5
|
+
from fastapi import FastAPI, Request
|
|
6
|
+
from fastapi.exceptions import HTTPException, RequestValidationError
|
|
7
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
8
|
+
from fastapi.responses import JSONResponse
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger("patientzero.api")
|
|
11
|
+
|
|
12
|
+
from core import Experiment
|
|
13
|
+
from core.config.settings import FRONTEND_URL
|
|
14
|
+
from core.examples.medical.config import MEDICAL_EXAMPLE_CONFIG
|
|
15
|
+
from backend.api.dependencies import db, repos
|
|
16
|
+
from backend.api.routes.agents import router as agents_router
|
|
17
|
+
from backend.api.routes.analysis import router as analysis_router
|
|
18
|
+
from backend.api.routes.chat import router as chat_router
|
|
19
|
+
from backend.api.routes.distributions import router as distributions_router
|
|
20
|
+
from backend.api.routes.experiments import router as experiments_router
|
|
21
|
+
from backend.api.routes.settings import router as settings_router
|
|
22
|
+
from backend.api.routes.simulate import router as simulate_router
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@asynccontextmanager
|
|
26
|
+
async def lifespan(app: FastAPI):
|
|
27
|
+
db.init()
|
|
28
|
+
if not repos.experiments.list_all():
|
|
29
|
+
Experiment(MEDICAL_EXAMPLE_CONFIG, repos)
|
|
30
|
+
yield
|
|
31
|
+
db.close()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
app = FastAPI(title="PatientZero", lifespan=lifespan)
|
|
35
|
+
|
|
36
|
+
app.add_middleware(
|
|
37
|
+
CORSMiddleware,
|
|
38
|
+
allow_origins=[FRONTEND_URL],
|
|
39
|
+
allow_methods=["*"],
|
|
40
|
+
allow_headers=["*"],
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@app.exception_handler(HTTPException)
|
|
45
|
+
async def http_exception_handler(request: Request, exc: HTTPException):
|
|
46
|
+
if exc.status_code >= 400:
|
|
47
|
+
print(
|
|
48
|
+
f"\033[33m[{exc.status_code}]\033[0m {request.method} {request.url.path} "
|
|
49
|
+
f"→ {exc.detail}",
|
|
50
|
+
flush=True,
|
|
51
|
+
)
|
|
52
|
+
return JSONResponse(status_code=exc.status_code, content={"detail": exc.detail})
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@app.exception_handler(RequestValidationError)
|
|
56
|
+
async def validation_exception_handler(request: Request, exc: RequestValidationError):
|
|
57
|
+
print(
|
|
58
|
+
f"\033[33m[422]\033[0m {request.method} {request.url.path} → validation error:\n"
|
|
59
|
+
f" {exc.errors()}",
|
|
60
|
+
flush=True,
|
|
61
|
+
)
|
|
62
|
+
return JSONResponse(status_code=422, content={"detail": exc.errors()})
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@app.exception_handler(Exception)
|
|
66
|
+
async def unhandled_exception_handler(request: Request, exc: Exception):
|
|
67
|
+
print(
|
|
68
|
+
f"\033[31m[500]\033[0m {request.method} {request.url.path} → {type(exc).__name__}: {exc}",
|
|
69
|
+
flush=True,
|
|
70
|
+
)
|
|
71
|
+
traceback.print_exc()
|
|
72
|
+
return JSONResponse(status_code=500, content={"detail": f"{type(exc).__name__}: {exc}"})
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
app.include_router(chat_router, prefix="/api")
|
|
76
|
+
app.include_router(simulate_router, prefix="/api")
|
|
77
|
+
app.include_router(analysis_router, prefix="/api")
|
|
78
|
+
app.include_router(settings_router, prefix="/api")
|
|
79
|
+
app.include_router(experiments_router, prefix="/api")
|
|
80
|
+
app.include_router(distributions_router, prefix="/api")
|
|
81
|
+
app.include_router(agents_router, prefix="/api")
|
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from fastapi import APIRouter, HTTPException
|
|
2
|
+
|
|
3
|
+
from backend.api.dependencies import repos
|
|
4
|
+
|
|
5
|
+
router = APIRouter()
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@router.get("/experiments/{exp_id}/agents")
|
|
9
|
+
def get_experiment_agents(exp_id: str):
|
|
10
|
+
experiment = repos.experiments.get(exp_id)
|
|
11
|
+
if experiment is None:
|
|
12
|
+
raise HTTPException(status_code=404, detail="Experiment not found")
|
|
13
|
+
config = experiment.config
|
|
14
|
+
return {
|
|
15
|
+
"agents": [
|
|
16
|
+
{"name": a.name, "prompt": a.prompt, "model": a.model}
|
|
17
|
+
for a in config.agents
|
|
18
|
+
],
|
|
19
|
+
"judge": {
|
|
20
|
+
"rubric": dict(config.judge.rubric),
|
|
21
|
+
"instructions": config.judge.instructions,
|
|
22
|
+
"model": config.judge.model,
|
|
23
|
+
},
|
|
24
|
+
}
|