Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -404,4 +404,6 @@ FodyWeavers.xsd

# JetBrains Rider
*.sln.iml
.idea/
.idea/

.DS_Store
82 changes: 82 additions & 0 deletions samples/DragonCopilot/Workflow/pythonSampleExtension/Agents.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
## Agents Guide (Concise)

Minimal contract for tools/agents working with the Python sample extension.

### 1. Discovery Order
1. `$VIRTUAL_ENV/bin/python`
2. `.vscode/settings.json` → `python.defaultInterpreterPath`
3. `python3` in PATH
4. `python` in PATH
5. (Serve fallback) try `uvicorn`
Fail fast if none found.

### 2. Use Existing Scripts
Prefer:
```bash
./scripts/start-python-dev.sh # run
./scripts/start-python-dev.sh --tests # tests
PORT=5182 ./scripts/start-python-dev.sh # alt port
```
Avoid re-implementing interpreter logic.

### 3. Test & Compare Flow
```bash
(PORT=5182 ./scripts/start-python-dev.sh &) # python service
./scripts/start-csharp-dev.sh # c# service
python3 scripts/compare_extensions.py --payload samples/requests/note-payload.json
```
Parity when diff `notes` is empty.

### 4. Dependency Sync (Optional)
Hash `requirements.txt`. If changed:
```bash
/path/python -m pip install -r samples/DragonCopilot/Workflow/pythonSampleExtension/requirements.txt --no-cache-dir
```
Don’t uninstall arbitrary packages.

### 5. Ports
Default 5181. If busy → choose 5182+. Log chosen port.

### 6. Error Matrix
| Issue | Action |
|-------|--------|
| No interpreter | Stop; list attempted paths |
| Install fail | Retry once then abort |
| Port conflict | Increment up to +5 |
| Comparison diff | Report keys/types; no auto-fix |
| Missing tests dir | Recompute relative path |

### 7. Minimal Checklist
- [ ] Interpreter resolved
- [ ] Dependencies current
- [ ] Tests pass
- [ ] Service (if needed) healthy
- [ ] Comparison (if dual) done
- [ ] Diffs (if any) reported

### 8. Snippets
Interpreter candidates:
```bash
[[ -n "$VIRTUAL_ENV" ]] && echo "$VIRTUAL_ENV/bin/python"; \
jq -r '."python.defaultInterpreterPath" // empty' .vscode/settings.json 2>/dev/null; \
command -v python3; command -v python
```
Module check:
```bash
python - <<'PY'
import importlib
for m in ("fastapi","uvicorn","pydantic"):
try: importlib.import_module(m); print("OK", m)
except Exception as e: print("MISSING", m, e)
PY
```

### 9. Safety
- Don’t edit `.vscode/settings.json` silently
- No PHI in test payloads
- Log only high-level paths & chosen interpreter

### 10. Future (Optional)
`/internal/env`, lint/format flags, JSON logs, comparison task.

End.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## (Optional) Create venv
```shell
pwd;
pushd $HOME/Code/VCS/ai/llm-train;

VERSION="3.12";
ENV_NAME="dgext";
ENV_SUFFIX="pip";
ENV_FULL_NAME="${ENV_NAME}${VERSION}${ENV_SUFFIX}";
ENV_DIR="$HOME/Code/VENV";
source ./envtools/create_env.sh -p "${ENV_DIR}/${ENV_FULL_NAME}" -v $VERSION;

popd;
pwd;
```

## Activate venv
```shell
VERSION="3.12";
ENV_NAME="dgext";
ENV_SUFFIX="pip";

ENV_FULL_NAME="${ENV_NAME}${VERSION}${ENV_SUFFIX}";

ENV_DIR="$HOME/Code/VENV";
PROJ_DIR="$HOME/Code/VCS/dragon/dragon-copilot-extension-samples";

SUB_PROJ="samples/DragonCopilot/Workflow/pythonSampleExtension";
PACKAGE_FILE="${PROJ_DIR}/${SUB_PROJ}/requirements.txt";

source ${ENV_DIR}/${ENV_FULL_NAME}/bin/activate;
which python3;

python3 -m pip install --upgrade pip;
python3 -m pip install -r ${PACKAGE_FILE} --no-cache;
```
216 changes: 216 additions & 0 deletions samples/DragonCopilot/Workflow/pythonSampleExtension/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
## Dragon Copilot Python Sample Extension

A Python FastAPI implementation that mirrors the C# `SampleExtension.Web` for Dragon Copilot. It demonstrates:

- Clinical entity heuristic extraction (vitals, diabetes code, medication concept)
- DSP-style `ProcessResponse` with multiple payload keys
- Adaptive Card visualization + composite plugin result (`samplePluginResult`)
- Comparison tooling against the C# service
- Section-based test payload simulating real clinical note structure

> Disclaimer: This is a learning/sample artifact – not production hardened. Do **not** use with real PHI. Authentication is intentionally disabled for development.

---
## 1. Features
**Implemented**
- `/health` & `/v1/health` endpoints
- `/v1/process` returning:
- `sample-entities`
- `sample-entities-adaptive-card`
- `samplePluginResult` (Medication Summary + Timeline cards)
- Visualization actions (Accept / Copy / Reject variants)
- Interpreter auto-detection (`scripts/start-python-dev.sh`)
- Test suite (entity extraction + composite plugin result)
- Cross-language comparison script (`scripts/compare_extensions.py`)

**Planned**
- Auth stubs (JWT + license key)
- Structured JSON logging
- Transcript & streaming payload support
- Lint/format script flags (ruff / black)
- CI workflow (GitHub Actions .NET + Python)
- Additional provenance & reference metadata

---
## 2. Quick Start
From repository root:
```bash
./scripts/start-python-dev.sh --install # one-time dependency install
./scripts/start-python-dev.sh # start on port 5181
PORT=5182 ./scripts/start-python-dev.sh # alternate port
```
Swagger / OpenAPI: http://localhost:5181/docs

Run tests only:
```bash
./scripts/start-python-dev.sh --tests
```

Direct (advanced) uvicorn invocation:
```bash
python -m uvicorn app.main:app --host 0.0.0.0 --port 5181 --reload
```

---
## 3. Scripts Overview
| Script | Purpose |
|--------|---------|
| `scripts/start-python-dev.sh` | Interpreter discovery, optional install, test or run server. |
| `scripts/start-csharp-dev.sh` | Launch C# sample extension (adds dotnet path if needed). |
| `scripts/compare_extensions.py` | Posts a shared payload to both services and summarizes differences. |

Interpreter selection order:
1. Active virtual environment (`$VIRTUAL_ENV`)
2. VS Code `python.defaultInterpreterPath`
3. `python3` or `python` in PATH
4. Fallback: run `uvicorn` directly

Flags (Python script):
```
--install install dependencies
--tests run pytest instead of serving
PORT=XXXX override port
```

---
## 4. Comparison With C# Service
Start both (example: Python on 5182, C# on 5181):
```bash
(PORT=5182 ./scripts/start-python-dev.sh &) && ./scripts/start-csharp-dev.sh
```
Run comparison:
```bash
python3 scripts/compare_extensions.py --payload samples/requests/note-payload.json
```
Output shows:
- top key diff
- payload key diff
- resource counts & type sets

When parity is complete, `notes` array is empty.

---
## 5. Response Structure Example
```jsonc
{
"success": true,
"message": "Payload processed successfully",
"payload": {
"sample-entities": {
"schema_version": "0.1",
"resources": [ { "type": "ObservationNumber" }, { "type": "MedicalCode" } ]
},
"sample-entities-adaptive-card": {
"schema_version": "0.1",
"resources": [ { "type": "AdaptiveCard", "adaptiveCardPayload": { "type": "AdaptiveCard", "version": "1.3" } } ]
},
"samplePluginResult": {
"schema_version": "0.1",
"resources": [
{ "type": "AdaptiveCard", "cardTitle": "Medication Summary & Recommendations (Demo)" },
{ "type": "AdaptiveCard", "cardTitle": "Recent Clinical Entities Timeline (Demo)" }
]
}
}
}
```

Key differences vs C# naming:
- Python uses `adaptiveCardPayload` (camelCase) internally; C# serialized uses snake_case due to serializer configuration.

---
## 6. Sectioned Clinical Note Testing
`test_clinic_note.py` programmatically splits a realistic clinic note into sections (HPI, Vitals, Labs, Exam, Impression, Plan, Follow‑up) assigning representative LOINC codes. This mirrors the shape of `samples/requests/note-payload.json` while keeping deterministic entity extraction (blood pressure, diabetes, medication keywords).

`test_sample_plugin_result.py` validates:
- Presence of `samplePluginResult`
- Two AdaptiveCard resources (summary + timeline)
- Each card has actions & adaptive card payload
- Copy data markers (demo metadata)

Run all tests:
```bash
pytest -q app/tests
```

Run single test:
```bash
pytest -q app/tests/test_sample_plugin_result.py::test_sample_plugin_result_structure
```

---
## 7. Sample Requests
Health:
```bash
curl -s http://localhost:5181/health | jq
curl -s http://localhost:5181/v1/health | jq
```

Minimal process payload:
```bash
curl -s -X POST http://localhost:5181/v1/process \
-H 'Content-Type: application/json' \
-d '{"note":{"resources":[{"content":"Patient has history of diabetes and currently taking metformin. BP recorded."}]}}' | jq
```

Include IDs:
```bash
curl -s -X POST http://localhost:5181/v1/process \
-H 'Content-Type: application/json' \
-H 'x-ms-request-id: demo-req-1' \
-H 'x-ms-correlation-id: demo-corr-1' \
-d '{"note":{"resources":[{"content":"BP 145/98 mmHg; Diabetes risk; taking metformin"}]}}' | jq
```

---
## 8. Roadmap
| Area | Next Step |
|------|-----------|
| Auth | Add JWT & license-key middleware toggled by env config |
| Logging | Structured JSON (requestId, correlationId, latency) |
| Data Types | Transcript + iterative transcript stubs |
| Quality | Lint/format (`--lint`, `--format` flags) |
| CI | GitHub Actions build + test matrix (.NET / Python) |
| Testing | Additional card action + provenance tests |
| Tooling | Dependency hash cache in start script |

---
## 9. Troubleshooting
| Issue | Resolution |
|-------|------------|
| `ModuleNotFoundError: app` | Run from project root or add pyextension path to `PYTHONPATH`. |
| Port already in use | Stop prior server or run `PORT=5182 ./scripts/start-python-dev.sh`. |
| Missing entities | Ensure note text includes keywords (BP, diabetes, medication). |
| Pydantic deprecation warning | Plan migration to `ConfigDict` (safe short-term). |
| C# service not starting | Install .NET 9+ or ensure PATH; use `scripts/start-csharp-dev.sh`. |

---
## 10. Security & Compliance (Sample Caveats)
- No PHI in test inputs.
- Auth intentionally disabled – add before any real deployment.
- Logging currently minimal; not production ready.

---
## 11. Appendix: Manual Environment Setup
Create & activate a virtual environment manually (alternative to scripts):
```bash
python3.12 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
```

Then run:
```bash
./scripts/start-python-dev.sh
```

Coverage (optional):
```bash
pip install pytest-cov
pytest --cov=app --cov-report=term-missing app/tests
```

---
## 12. License
See root `LICENSE`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# PROJECT_ENDPOINT is from the new AI Foundry (project) / Azure AI Service (new version)
PROJECT_ENDPOINT="https://xxxxxx.services.ai.azure.com/api/projects/dragon-extension"
MODEL_DEPLOYMENT_NAME="gpt-4.1-mini" # "gpt-4.1-mini"
AGENT_ID="asst_xxxxxxx"

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Python FastAPI sample extension mirroring C# SampleExtension.Web."""
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from functools import lru_cache
from pydantic_settings import BaseSettings

class Settings(BaseSettings):
app_name: str = "Dragon Sample Extension (Python)"
version: str = "0.1.0"
enable_auth: bool = False # Placeholder toggle

class Config:
env_prefix = "DGEXT_"

@lru_cache
def get_settings() -> Settings:
return Settings()
Loading