overheard 0.0.2__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.
- overheard-0.0.2/.github/workflows/ci.yml +21 -0
- overheard-0.0.2/.github/workflows/publish.yml +70 -0
- overheard-0.0.2/.gitignore +10 -0
- overheard-0.0.2/CLAUDE.md +91 -0
- overheard-0.0.2/PKG-INFO +48 -0
- overheard-0.0.2/README.md +20 -0
- overheard-0.0.2/docs/DESIGN.md +370 -0
- overheard-0.0.2/pyproject.toml +62 -0
- overheard-0.0.2/src/overheard/__init__.py +3 -0
- overheard-0.0.2/src/overheard/adapters/__init__.py +0 -0
- overheard-0.0.2/src/overheard/adapters/backend/__init__.py +0 -0
- overheard-0.0.2/src/overheard/adapters/backend/base.py +11 -0
- overheard-0.0.2/src/overheard/adapters/backend/mock.py +45 -0
- overheard-0.0.2/src/overheard/app.py +22 -0
- overheard-0.0.2/src/overheard/cli.py +48 -0
- overheard-0.0.2/src/overheard/config.py +21 -0
- overheard-0.0.2/src/overheard/data/__init__.py +0 -0
- overheard-0.0.2/src/overheard/data/db.py +50 -0
- overheard-0.0.2/src/overheard/data/events.py +23 -0
- overheard-0.0.2/src/overheard/data/generator.py +148 -0
- overheard-0.0.2/src/overheard/data/models.py +96 -0
- overheard-0.0.2/src/overheard/data/seed_today.json +1941 -0
- overheard-0.0.2/src/overheard/data/templates.py +50 -0
- overheard-0.0.2/src/overheard/static/css/app.css +23 -0
- overheard-0.0.2/src/overheard/static/index.html +27 -0
- overheard-0.0.2/src/overheard/static/js/core/store.js +17 -0
- overheard-0.0.2/src/overheard/static/js/main.js +15 -0
- overheard-0.0.2/tests/conftest.py +16 -0
- overheard-0.0.2/tests/test_archive.py +72 -0
- overheard-0.0.2/tests/test_backend.py +27 -0
- overheard-0.0.2/tests/test_skeleton.py +39 -0
- overheard-0.0.2/tests/test_today.py +53 -0
- overheard-0.0.2/tools/build_seed_today.py +350 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
python: ["3.11", "3.12", "3.13"]
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: ${{ matrix.python }}
|
|
19
|
+
- run: python -m pip install -e ".[dev]"
|
|
20
|
+
- run: ruff check .
|
|
21
|
+
- run: pytest -q
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Publishing uses PyPI trusted publishing (no tokens stored), the same as hobkin:
|
|
2
|
+
# - publishing a GitHub release (tag vX.Y.Z, matching overheard.__version__) uploads to PyPI
|
|
3
|
+
# - running this workflow by hand (Actions -> Publish -> Run workflow) uploads to TestPyPI, for a dry run
|
|
4
|
+
# PyPI needs a (pending) publisher: project overheard, repository frank-lynam/overheard, workflow publish.yml,
|
|
5
|
+
# environment pypi. (TestPyPI, only for the dry run: the same, with environment testpypi.)
|
|
6
|
+
name: Publish
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
release:
|
|
10
|
+
types: [published]
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
build:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
- run: python -m pip install -e ".[dev]"
|
|
22
|
+
- run: ruff check .
|
|
23
|
+
- run: pytest -q
|
|
24
|
+
- name: The release tag matches the version
|
|
25
|
+
if: github.event_name == 'release'
|
|
26
|
+
run: |
|
|
27
|
+
version=$(python -c 'import overheard; print(overheard.__version__)')
|
|
28
|
+
if [ "v$version" != "${GITHUB_REF_NAME}" ]; then
|
|
29
|
+
echo "Tag ${GITHUB_REF_NAME} doesn't match overheard.__version__ $version"; exit 1
|
|
30
|
+
fi
|
|
31
|
+
- run: python -m build
|
|
32
|
+
- run: python -m pip install twine && python -m twine check --strict dist/*
|
|
33
|
+
- uses: actions/upload-artifact@v4
|
|
34
|
+
with:
|
|
35
|
+
name: dist
|
|
36
|
+
path: dist/
|
|
37
|
+
|
|
38
|
+
pypi:
|
|
39
|
+
needs: build
|
|
40
|
+
if: github.event_name == 'release'
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
environment:
|
|
43
|
+
name: pypi
|
|
44
|
+
url: https://pypi.org/p/overheard
|
|
45
|
+
permissions:
|
|
46
|
+
id-token: write
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/download-artifact@v4
|
|
49
|
+
with:
|
|
50
|
+
name: dist
|
|
51
|
+
path: dist/
|
|
52
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
53
|
+
|
|
54
|
+
testpypi:
|
|
55
|
+
needs: build
|
|
56
|
+
if: github.event_name == 'workflow_dispatch'
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
environment:
|
|
59
|
+
name: testpypi
|
|
60
|
+
url: https://test.pypi.org/p/overheard
|
|
61
|
+
permissions:
|
|
62
|
+
id-token: write
|
|
63
|
+
steps:
|
|
64
|
+
- uses: actions/download-artifact@v4
|
|
65
|
+
with:
|
|
66
|
+
name: dist
|
|
67
|
+
path: dist/
|
|
68
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
69
|
+
with:
|
|
70
|
+
repository-url: https://test.pypi.org/legacy/
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Overheard — project brief for Claude Code
|
|
2
|
+
|
|
3
|
+
The full design and implementation plan lives in `docs/DESIGN.md` (exported from the design doc). Read it before starting. This file is the short version: the decisions you must not drift from, the build order, and how to work in this repo.
|
|
4
|
+
|
|
5
|
+
**Overheard** is the product name: an AI voicemail console that catches what busy humans miss. PyPI package, import package, and CLI are all `overheard`; environment variables use the `OVERHEARD_` prefix.
|
|
6
|
+
|
|
7
|
+
## What this is
|
|
8
|
+
|
|
9
|
+
A demo application that shows how AI streamlines call-center voicemail work for a fictional federal agency, the *Federal Benefits Service Center* (FBSC). The same synthetic data runs through four progressive modes:
|
|
10
|
+
|
|
11
|
+
| Mode | Name | Point |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| 0 | No AI | Baseline: manual inbox, measured cost (~7 agent-hours for 60 voicemails) |
|
|
14
|
+
| 1 | Obvious AI | Per-message transcription, summary, extraction, urgency, routing, translation, draft reply |
|
|
15
|
+
| 2 | Non-obvious AI | Cross-message spike detection, resolution without callback (LLM tool use), deadline-bound request detection, repeat-caller linking |
|
|
16
|
+
| 3 | Impossible without AI | Archive-wide cost by root cause, event impact, caller journeys, promises vs. outcomes, letter pre-testing, equity, ask-the-archive |
|
|
17
|
+
|
|
18
|
+
## Fixed architecture decisions
|
|
19
|
+
|
|
20
|
+
- **Python package** `overheard`, import name `overheard`, src layout, built with **hatchling**. Python ≥ 3.11.
|
|
21
|
+
- **Backend:** FastAPI on **uvicorn**. Console script `overheard` with subcommands `serve`, `seed`, `record`, `batch-label`.
|
|
22
|
+
- **Front end:** vanilla JavaScript ES modules, plain CSS with custom properties, hand-written SVG charts. **No build step, no framework, no npm.** Ships as package data under `src/overheard/static/` and is served by the same uvicorn process.
|
|
23
|
+
- **Browser ↔ server:** REST plus server-sent events (`/api/events`). The browser never talks to an LLM or holds an API key.
|
|
24
|
+
- **LLM:** any **OpenAI-compatible** host, called with the `openai` Python SDK (`AsyncOpenAI(base_url=..., api_key=...)`). Providers implement one `Protocol`: `MockProvider`, `OpenAICompatProvider`, `ReplayProvider`. Mode is chosen by `OVERHEARD_LLM_MODE` = `mock | live | record | replay`. **Default is `mock`**, and the whole app must work fully offline in mock mode.
|
|
25
|
+
- **Mock outputs come from the ground truth.** `MockProvider` builds each task's output from the message's truth labels, with a seeded share of realistic mistakes (about 90–95% accurate), so mock mode needs no hand-written fixtures and the scoreboard's accuracy stays honest offline.
|
|
26
|
+
- **One response store.** Live LLM responses are kept as JSON files keyed by (task, input hash, model): `live` uses them as a cache, `record` writes them, `replay` only reads them and never touches the network. No separate SQLite LLM cache.
|
|
27
|
+
- **The day is computed up front.** The pipeline runs over the whole day per mode and stamps when each thing would happen (e.g. the incident alert at 9:40); the browser's replay control (1×, 10×, 60×) reveals it by time. SSE is only for live LLM progress.
|
|
28
|
+
- **Text only, for now.** No audio until nearer 1.0.0. `TranscriptionProvider` stays as a seam and returns the script. Mode 0's "play" reveals the transcript at speaking pace (~150 words a minute), so listening still costs what it would.
|
|
29
|
+
- **Structured output:** each LLM task is a module with system prompt, few-shot examples, a pydantic output model, and optional tools. Use `json_schema` response_format when the host supports it (found out lazily on the first live call and remembered; startup never waits on the network), else JSON mode + pydantic validation. On validation failure: retry once with the error appended, then fall back to the mock fixture and mark provenance `fallback`.
|
|
30
|
+
- **Rule of thumb:** LLM for language judgment; plain code for counting, statistics, joins, and baselines.
|
|
31
|
+
- **Storage:** SQLite (stdlib `sqlite3` or a thin wrapper) for seeded data and the pipeline cache keyed by (message, mode). LLM responses live in the response store (above).
|
|
32
|
+
- **Adapters** (all `Protocol` + mock + live): `TranscriptionProvider` (mock now; AWS Transcribe later), `LLMProvider`, `CaseBackend` (mock now; real system of record later). These are the seams for a future real integration; keep business logic out of them.
|
|
33
|
+
- **Data is synthetic and deterministic.** `overheard seed` generates the 60-message "today" queue (hand-written scripts in `data/seed_today.json` with ground-truth labels) and a ~15,000-contact, 3-year archive from a fixed seed. Same seed → byte-identical database. Every planted pattern has a test that the analytics recover it (e.g. Form 22-B tops the root-cause Pareto, within ±10% of its planted cost).
|
|
34
|
+
- **Mode 3 is measured, not only planted.** Before a demo, `overheard batch-label` labels a sample of the archive (~1,000 contacts) with the live LLM; Mode 3 shows that measured accuracy against the truth and scales from it.
|
|
35
|
+
- **Config:** pydantic-settings, `OVERHEARD_*` environment variables (`OVERHEARD_LLM_MODE`, `OVERHEARD_LLM_BASE_URL`, `OVERHEARD_LLM_API_KEY`, `OVERHEARD_LLM_MODEL`, `OVERHEARD_LLM_TIMEOUT`, `OVERHEARD_DB_PATH`, `OVERHEARD_SEED`, `OVERHEARD_HOST`, `OVERHEARD_PORT`).
|
|
36
|
+
|
|
37
|
+
## Repo layout
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
pyproject.toml
|
|
41
|
+
src/overheard/
|
|
42
|
+
cli.py app.py config.py
|
|
43
|
+
api/ queue, analysis, replay, incidents, archive, letter_lab, ask, settings
|
|
44
|
+
pipeline/ stages/, modes.py, runner.py
|
|
45
|
+
llm/ provider.py, openai_compat.py, mock.py, replay.py, cache.py, tasks/
|
|
46
|
+
adapters/ transcription/, backend/
|
|
47
|
+
data/ models.py, db.py, generator.py, templates.py, events.py, seed_today.json
|
|
48
|
+
analytics/ root_causes.py, event_impact.py, journeys.py, promises.py, equity.py
|
|
49
|
+
static/ index.html, css/, js/core/, js/ui/, js/charts/
|
|
50
|
+
fixtures/
|
|
51
|
+
tests/
|
|
52
|
+
.github/workflows/ ci.yml, publish.yml
|
|
53
|
+
docs/DESIGN.md
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Build order (stop and demo after each phase)
|
|
57
|
+
|
|
58
|
+
1. **Foundation** — pyproject, CLI, FastAPI app factory serving static files, SQLite layer, pydantic models, seeded generator, the 60 scripts with truth labels, mock case backend, CI (ruff + pytest). Done when `pip install -e . && overheard seed && overheard serve` shows an empty shell with a mode stepper.
|
|
59
|
+
2. **Mode 0** — chronological inbox, player (text fallback if no audio), manual form, lookup panel, effort timer, "work the queue" simulation, scoreboard v1.
|
|
60
|
+
3. **Mode 1 + LLM layer** — provider Protocol and three providers, task modules, validation/retry/fallback, cache, record mode, capability probe; summary, extraction, intent/urgency, translation, sentiment, draft reply; priority sort, routing, provenance badges, edits scored against truth.
|
|
61
|
+
4. **Mode 2** — similarity grouping (TF-IDF or host embeddings), spike detection + incident card, tool-use lookups for resolution without callback, callback brief, deadline-bound detection with keyword backstop and deadline clocks, repeat-caller linking, missing-info recovery, callback windows. **MVP gate: Modes 0–2 run end to end.**
|
|
62
|
+
5. **Mode 3** — root-cause Pareto with cost model first, then event impact, journeys, promises, equity, letter lab, ask-the-archive, knowledge gaps.
|
|
63
|
+
6. **Release and rehearsal** — presenter mode, publish workflow (GitHub release → PyPI via trusted publishing), record fixtures against the live host, offline dry run in replay mode.
|
|
64
|
+
|
|
65
|
+
## Packaging and release
|
|
66
|
+
|
|
67
|
+
- Plain 0.x versions on public PyPI (`0.1.0`, `0.2.0`...; `pip install overheard`, no `--pre`). Single source of version in `src/overheard/__init__.py`.
|
|
68
|
+
- Static files and `seed_today.json` must be included in the wheel; add a test that builds the wheel and checks they are present.
|
|
69
|
+
- `publish.yml`, the same as hobkin's: publishing a GitHub release (tag `vX.Y.Z` matching `__version__`) uploads to PyPI by trusted publishing (no stored tokens); running the workflow by hand uploads to TestPyPI as a dry run. Claude tags; the user publishes the release. Don't publish anything without asking first.
|
|
70
|
+
- Check the package name is available on PyPI before the first upload; ask if it isn't.
|
|
71
|
+
|
|
72
|
+
## Working agreements
|
|
73
|
+
|
|
74
|
+
- Mock mode must always work with no network. Never make tests depend on a live LLM.
|
|
75
|
+
- Tests: pytest for pipeline stages, pydantic schemas, API routes (httpx `AsyncClient`), generator determinism, and wheel contents.
|
|
76
|
+
- Lint with ruff; type hints throughout.
|
|
77
|
+
- AI never sends anything outbound without a human approval step in the UI.
|
|
78
|
+
- Every AI field carries provenance (`mock | llm | fallback | human`) and, where applicable, a source span.
|
|
79
|
+
- No real PII anywhere. Keep the agency fictional.
|
|
80
|
+
- Keep the front end dependency-free; if you think you need a library, ask first.
|
|
81
|
+
|
|
82
|
+
## Settled (Oct 31, 2026)
|
|
83
|
+
|
|
84
|
+
- LLM: an external OpenAI-compatible host; configured with an endpoint and API key (`OVERHEARD_LLM_BASE_URL`, `OVERHEARD_LLM_API_KEY`, `OVERHEARD_LLM_MODEL`).
|
|
85
|
+
- Releases: public PyPI, plain versions below 1.0.0.
|
|
86
|
+
- Text-only transcripts until nearer 1.0.0; audio integration then.
|
|
87
|
+
|
|
88
|
+
## Still open (ask rather than guess)
|
|
89
|
+
|
|
90
|
+
- Who the audience is (internal leadership or a government customer), and the demo date.
|
|
91
|
+
- Whether the fictional agency should mirror a real customer's domain.
|
overheard-0.0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: overheard
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: An AI voicemail console that catches what busy humans miss: one day of a fictional call center's voicemail, through four levels of AI.
|
|
5
|
+
Project-URL: Homepage, https://github.com/frank-lynam/overheard
|
|
6
|
+
Author: Frank Lynam
|
|
7
|
+
Keywords: ai,call-center,demo,llm,voicemail
|
|
8
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
9
|
+
Classifier: Environment :: Web Environment
|
|
10
|
+
Classifier: Framework :: FastAPI
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Requires-Dist: fastapi>=0.110
|
|
17
|
+
Requires-Dist: openai>=1.30
|
|
18
|
+
Requires-Dist: pydantic-settings>=2.2
|
|
19
|
+
Requires-Dist: pydantic>=2.6
|
|
20
|
+
Requires-Dist: uvicorn>=0.29
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
23
|
+
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# Overheard
|
|
30
|
+
|
|
31
|
+
An AI voicemail console that catches what busy humans miss.
|
|
32
|
+
|
|
33
|
+
Overheard replays one day of voicemail at a fictional federal call center, the
|
|
34
|
+
*Federal Benefits Service Center*, plus a three-year archive, through four modes:
|
|
35
|
+
**No AI**, **Obvious AI**, **Non-obvious AI** and **Impossible without AI**. A
|
|
36
|
+
running scoreboard shows what each mode adds: agent hours, callbacks avoided,
|
|
37
|
+
deadline-bound requests caught, and dollars.
|
|
38
|
+
|
|
39
|
+
All data is synthetic. Mock mode (the default) runs fully offline; point it at
|
|
40
|
+
any OpenAI-compatible endpoint to use a real model.
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
pip install overheard
|
|
44
|
+
overheard serve # then open http://127.0.0.1:8000
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Status:** early. This release is the skeleton: the console shell and its mode
|
|
48
|
+
stepper. See [docs/DESIGN.md](docs/DESIGN.md) for where it's going.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Overheard
|
|
2
|
+
|
|
3
|
+
An AI voicemail console that catches what busy humans miss.
|
|
4
|
+
|
|
5
|
+
Overheard replays one day of voicemail at a fictional federal call center, the
|
|
6
|
+
*Federal Benefits Service Center*, plus a three-year archive, through four modes:
|
|
7
|
+
**No AI**, **Obvious AI**, **Non-obvious AI** and **Impossible without AI**. A
|
|
8
|
+
running scoreboard shows what each mode adds: agent hours, callbacks avoided,
|
|
9
|
+
deadline-bound requests caught, and dollars.
|
|
10
|
+
|
|
11
|
+
All data is synthetic. Mock mode (the default) runs fully offline; point it at
|
|
12
|
+
any OpenAI-compatible endpoint to use a real model.
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
pip install overheard
|
|
16
|
+
overheard serve # then open http://127.0.0.1:8000
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Status:** early. This release is the skeleton: the console shell and its mode
|
|
20
|
+
stepper. See [docs/DESIGN.md](docs/DESIGN.md) for where it's going.
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
# Overheard — Design & Implementation Plan
|
|
2
|
+
|
|
3
|
+
Oct 31, 2026 · @Frank
|
|
4
|
+
|
|
5
|
+
> **Revised after review (Oct 31, 2026).** Where this document and the project `CLAUDE.md` disagree, `CLAUDE.md` wins. The changes: mock outputs are derived from the ground truth (no hand-written fixtures); one JSON response store serves live caching, record and replay; the day is computed up front and replayed in the browser (SSE only for live LLM progress); text only for now, with Mode 0 revealing transcripts at speaking pace; Mode 3 adds a measured sample labelled by the live LLM; each planted archive pattern has a recovery test; the capability probe is lazy; releases are plain 0.x versions on public PyPI.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
We will build Overheard, an AI voicemail console: a vanilla JavaScript front end served by a Python backend (FastAPI on uvicorn) that wraps an OpenAI-compatible LLM hosted elsewhere, released on PyPI as a pre-release package. It replays one day of voicemail at a fictional federal call center, plus a three-year archive. The presenter steps the same data through four modes: **No AI**, **Obvious AI**, **Non-obvious AI**, and **Impossible without AI**. A running scoreboard shows what each mode adds.
|
|
10
|
+
|
|
11
|
+
**Goals**
|
|
12
|
+
|
|
13
|
+
- Show a measurable before-and-after on the same workload: agent hours, callbacks avoided, deadline-bound requests caught, and dollars saved.
|
|
14
|
+
- Take the conversation past "AI transcribes and summarizes" to avoided callbacks, patterns across messages, and analysis of the whole archive.
|
|
15
|
+
- Install and run anywhere: pip install --pre overheard, then overheard serve. The front end still needs no build step, and mock mode works fully offline with no LLM.
|
|
16
|
+
- Swap each mock for a real model behind a stable server-side interface: point the backend at any OpenAI-compatible endpoint, with no UI changes. The same interfaces are the seams for a later real integration.
|
|
17
|
+
|
|
18
|
+
**Non-goals:** production readiness, real recordings or PII, telephony integration, or multi-user features.
|
|
19
|
+
|
|
20
|
+
## The four modes
|
|
21
|
+
|
|
22
|
+
The whole story is in the four modes: the same 60 voicemails go from a 7-hour slog, to a sorted inbox, to a queue that mostly clears itself, and then to a view of the entire operation. Modes add to each other. Each one keeps everything from the one before, and the scoreboard carries across mode switches so the audience watches the numbers move.
|
|
23
|
+
|
|
24
|
+
| Mode | The question it answers | Headline capabilities | The moment to show |
|
|
25
|
+
| --- | --- | --- | --- |
|
|
26
|
+
| 0 · No AI | What does this cost today? | Chronological inbox, audio playback, manual entry and lookup, timing measured as you work | A "work the queue" fast-forward shows the urgent message at position 37 not reached until 2:40 pm |
|
|
27
|
+
| 1 · Obvious AI | Can we read faster? | Transcription, summary, field extraction, intent and urgency, priority sort, routing, translation, draft replies | Message 37 jumps to the top; a Vietnamese voicemail arrives already translated and routed |
|
|
28
|
+
| 2 · Non-obvious AI | Can we need fewer calls and miss nothing? | Spike detection across messages, resolution without a callback, deadline-bound request detection, repeat-caller linking, auto-request for missing info, pre-researched callback briefs | A portal-outage incident is flagged at 9:40 from 30 scattered messages; 40% of the queue closes with no phone call |
|
|
29
|
+
| 3 · Impossible without AI | What is the whole system telling us? | Cost by root cause, impact of each event, caller journeys, promises vs. outcomes, letter pre-testing, equity analysis, knowledge gaps, ask-the-archive | "This one notice cost an estimated $600K a year in calls" |
|
|
30
|
+
|
|
31
|
+
## Synthetic dataset
|
|
32
|
+
|
|
33
|
+
The demo depends on a scripted "today" queue with planted signals, plus a procedurally generated archive. Both are fully synthetic, and both carry hidden ground-truth labels so every AI output can be scored. The fictional agency is the *Federal Benefits Service Center* (FBSC), which handles benefit payments, address changes, portal accounts, and document submissions.
|
|
34
|
+
|
|
35
|
+
**Today's queue (60 hand-written voicemails)**
|
|
36
|
+
|
|
37
|
+
- 1 buried urgent message at position 37: a caller facing a utility shutoff because of a delayed payment.
|
|
38
|
+
- 28 messages about the same portal login error, starting at 9:12 am and phrased many different ways. None say "outage."
|
|
39
|
+
- 4 non-English messages: Spanish, Vietnamese, Tagalog, and one that mixes English and Spanish.
|
|
40
|
+
- 1 caller who leaves 3 messages over two days, getting more frustrated each time.
|
|
41
|
+
- Deadline-bound requests: 2 that mention contacting a member of Congress, 1 records request worded informally (it never says "FOIA"), 1 legal threat, and 1 welfare concern.
|
|
42
|
+
- 12 status questions ("did you get my form," "when is my payment") that the mock backend can answer.
|
|
43
|
+
- 6 messages missing a case number, where caller ID still matches a known case.
|
|
44
|
+
- Realistic mess: rambling, self-corrections, numbers read aloud ("five five five, uh, oh one two"), and callback-time cues ("I'm at work until five").
|
|
45
|
+
|
|
46
|
+
**Archive (about 15,000 contacts over 3 years)**
|
|
47
|
+
|
|
48
|
+
- Generated in Python from a fixed seed by overheard seed, so no large data files are committed and every run produces identical data.
|
|
49
|
+
- Built from about 40 call-driver templates with randomized wording, caller, region, language, and timing.
|
|
50
|
+
- Volume is driven by an events calendar, so effects are recoverable: notice mailings, portal releases, policy changes, and payment-date shifts. One notice ("Form 22-B re-verification letter") is deliberately confusing and drives a large, steady excess in calls.
|
|
51
|
+
- Planted patterns: callers stuck in loops, broken callback promises concentrated in one issue type, a slower resolution time for one language, and a weak signal that grew into a spike months later.
|
|
52
|
+
|
|
53
|
+
**Mock backend records**
|
|
54
|
+
|
|
55
|
+
- Cases: status, payment schedule, documents received, last action, and assigned team.
|
|
56
|
+
- Caller directory mapping phone number to case.
|
|
57
|
+
- Events calendar, knowledge-base articles (with deliberate gaps), and callback notes containing promises.
|
|
58
|
+
|
|
59
|
+
**Audio:** optional. Generate it with Amazon Polly using varied voices, or have coworkers record the 60 scripts. Mock transcription returns the script text with simulated latency and a few low-confidence words.
|
|
60
|
+
|
|
61
|
+
## Mode 0 · No AI
|
|
62
|
+
|
|
63
|
+
Mode 0 establishes the baseline cost honestly and keeps it on screen: clearing 60 voicemails by hand is roughly 7 agent-hours, and the urgent message waits until mid-afternoon.
|
|
64
|
+
|
|
65
|
+
- **Chronological inbox.** Shows only time, caller ID, and duration. No content is visible until you play the message.
|
|
66
|
+
- **Audio player** with scrubbing. The transcript stays hidden.
|
|
67
|
+
- **Manual entry form:** caller name, callback number, case number, category, priority, notes, and disposition.
|
|
68
|
+
- **Manual lookup panel** against the mock backend (search by name, phone, or case number). This shows the swivel-chair work of jumping between systems.
|
|
69
|
+
- **Measured effort:** real time spent on each message, plus a configurable handling time (3.5 minutes by default) that extrapolates the workload clock.
|
|
70
|
+
- **"Work the queue" simulation:** a fast-forward of a single agent working in order. It stamps when each message is first touched, including the urgent one at 2:40 pm and the first portal-error message whose pattern nobody connects.
|
|
71
|
+
|
|
72
|
+
The presenter plays two or three real messages live so the audience feels the pain, then runs the simulation for the rest.
|
|
73
|
+
|
|
74
|
+
## Mode 1 · Obvious AI
|
|
75
|
+
|
|
76
|
+
Mode 1 is the version every vendor shows: each message is processed on its own. That turns listening into reading and sorts the queue by need. It cuts handling time sharply but does not reduce how much work exists.
|
|
77
|
+
|
|
78
|
+
1. **Transcription** (mock). Low-confidence words are highlighted, and clicking a word jumps the audio to that point.
|
|
79
|
+
2. **One-line summary** plus a short summary.
|
|
80
|
+
3. **Structured extraction:** caller name, callback number (normalized from spoken digits), case number, program, and requested action. Each field shows a confidence score and the span of the transcript it came from.
|
|
81
|
+
4. **Intent and urgency.** An intent category, plus a 1–5 urgency score with a one-sentence rationale.
|
|
82
|
+
5. **Priority queue and routing.** The queue re-sorts by urgency and assigns each message to a team queue. A short animation moves message 37 to the top.
|
|
83
|
+
6. **Language detection and translation** to English, keeping the original text alongside.
|
|
84
|
+
7. **Sentiment and frustration** level.
|
|
85
|
+
8. **Draft callback script** or written reply, which the agent edits before use.
|
|
86
|
+
|
|
87
|
+
Every AI field is editable, and edits are logged as corrections. That record later feeds the accuracy numbers on the scoreboard and supports the message that people stay in control.
|
|
88
|
+
|
|
89
|
+
## Mode 2 · Non-obvious AI
|
|
90
|
+
|
|
91
|
+
Mode 2 shifts the goal from handling calls faster to needing fewer of them and missing nothing. It works by reasoning across messages and taking action against backend systems.
|
|
92
|
+
|
|
93
|
+
1. **Live spike detection.** Messages are grouped by similarity as they arrive. When a group grows faster than its baseline, the LLM names it and drafts an incident card: first seen, count, probable cause, and suggested actions (an IVR banner, a ticket for the portal team, a holding reply sent to everyone affected).
|
|
94
|
+
2. **Resolution without a callback.** The LLM chooses backend lookups through tool calls (case status, payment schedule, documents received). If the question is answerable, it drafts a text or email reply that an agent approves with one click. The scoreboard tracks the share of messages closed with no call.
|
|
95
|
+
3. **Pre-researched callback brief.** For messages that do need a call: the case history, prior contacts, what was promised, and the likely answer. The agent dials already knowing the answer.
|
|
96
|
+
4. **Deadline-bound request detection.** Flags mentions of a member of Congress, records requests, legal threats, welfare or safety concerns, and discrimination complaints, even when not stated plainly. Each flag starts a workflow with a deadline clock (deadlines configurable per agency policy, for example FOIA's 20-business-day window). Keyword rules back up the LLM so recall stays high.
|
|
97
|
+
5. **Repeat-caller linking.** Matches on caller ID, name, and case number, with the LLM settling ambiguous cases. Three messages collapse into one item with an escalation note, such as "3rd contact in 48 hours, rising frustration."
|
|
98
|
+
6. **Missing-info recovery.** Infers the case from caller ID. If it can't, it sends the caller an automatic request for the missing detail before any agent touches the message.
|
|
99
|
+
7. **Callback window extraction.** "I'm at work until five" becomes a scheduled callback slot, which cuts down phone tag.
|
|
100
|
+
8. **Belief vs. record mismatch.** Detects when the caller's understanding contradicts the record (for example, they think a payment was missed when it is actually scheduled) and drafts a reassurance reply.
|
|
101
|
+
9. **Next best action.** Suggests a knowledge-base article and a disposition for each item.
|
|
102
|
+
10. **Rest-of-day forecast.** Projects incoming volume from the morning's spikes so a supervisor can reassign staff.
|
|
103
|
+
|
|
104
|
+
## Mode 3 · Impossible without AI
|
|
105
|
+
|
|
106
|
+
Mode 3 moves from the queue to the archive. A QA team samples a few percent of calls; the AI reads all 15,000 and connects them to events and outcomes. Each view below would take a person months of listening.
|
|
107
|
+
|
|
108
|
+
1. **Cost by root cause.** Every archived contact gets a root-cause label. Multiplying by handling time and a configurable fully loaded labor rate gives a Pareto chart of annual cost by cause. This is the headline: "The Form 22-B letter cost an estimated $600K a year."
|
|
109
|
+
2. **Impact of each event.** Call themes are overlaid on the events calendar. For each mailing, release, or policy change, the view shows excess calls above baseline, how long the effect lasted, and what confused people. For example: "Portal release 4.2 caused about 6,100 extra calls over 9 days."
|
|
110
|
+
3. **Caller journeys.** Every contact from the same caller is linked across years. The view lists callers stuck in loops (3 or more contacts about one issue with no resolution) and the process steps where those loops start.
|
|
111
|
+
4. **Promises vs. outcomes.** Commitments are extracted from callback notes ("you'll have it in 10 days") and checked against what the backend shows happened. Results show the broken-promise rate by issue type and team.
|
|
112
|
+
5. **Letter pre-testing.** Paste in a draft notice. Simulated readers built from real confusion patterns in the archive raise their questions. The tool predicts the top questions and a call-volume range (based on similar past mailings) and suggests rewrites, with a before-and-after comparison.
|
|
113
|
+
6. **Equity of service.** Resolution time and repeat-contact rate by language and region, with disparities flagged and example messages attached.
|
|
114
|
+
7. **Knowledge-gap mining.** Finds questions callers ask often that no knowledge-base article answers, and drafts FAQ and IVR text to fill the gap.
|
|
115
|
+
8. **Missed weak signals.** Finds issues that started small months before they spiked, and estimates how much earlier they could have been caught.
|
|
116
|
+
9. **Ask the archive.** Plain-English questions ("Why did calls from Ohio double last March?") are answered over pre-computed totals, with example messages cited as evidence.
|
|
117
|
+
10. **Event-driven staffing forecast.** Uses upcoming mailings and releases to project call volume and the agent hours needed.
|
|
118
|
+
|
|
119
|
+
The demo cannot run 15,000 LLM calls live. Archive labels are therefore produced ahead of time: by the mock layer, or by the overheard batch-label command against the live LLM. At runtime the LLM handles naming, explanation, letter tests, and questions, working on totals plus a sample of messages.
|
|
120
|
+
|
|
121
|
+
## Architecture
|
|
122
|
+
|
|
123
|
+
[embedded content: architecture · 4 layers, 14 modules\]
|
|
124
|
+
|
|
125
|
+
The browser never calls the LLM or data adapters directly. Everything goes through the Python service, which keeps API keys server-side and gives a later real integration clean seams to replace.
|
|
126
|
+
|
|
127
|
+
- **Packaging.** One Python package, overheard, built with hatchling in a src/ layout. The vanilla JS front end ships inside it as package data. The console command `overheard serve` starts uvicorn with the API and static files on one port.
|
|
128
|
+
- **Front end.** Still no build step: ES modules, a small publish/subscribe store, and the mode stepper. It calls REST endpoints and listens to server-sent events for the replay clock, incidents, and pipeline progress.
|
|
129
|
+
- **API.** FastAPI routes: `/api/queue`, `/api/messages/{id}/analysis?mode=`, `/api/replay`, `/api/incidents`, `/api/archive/*`, `/api/letter-lab`, `/api/ask`, `/api/settings`, `/api/events` (SSE).
|
|
130
|
+
- **Pipeline.** Server-side stages (transcribe → understand → enrich → link → detect → act). Each stage is an async function `(message, ctx) → patch`, registered with a minimum mode. Results are cached per message and mode in SQLite, so switching modes is instant.
|
|
131
|
+
- **Data.** `overheard seed` runs a seeded generator that writes the today queue and the 3-year archive into SQLite. Pydantic models are shared by the API and the pipeline.
|
|
132
|
+
- **Adapters.** Python `Protocol` classes for `TranscriptionProvider`, `LLMProvider`, and `CaseBackend`, each with a mock and a live implementation chosen by config.
|
|
133
|
+
|
|
134
|
+
```text
|
|
135
|
+
overheard/
|
|
136
|
+
pyproject.toml hatchling, src layout, overheard entry point, version 0.1.0a1
|
|
137
|
+
src/overheard/
|
|
138
|
+
cli.py serve, seed, record, batch-label
|
|
139
|
+
app.py FastAPI app factory, static mount, SSE
|
|
140
|
+
config.py pydantic-settings (OVERHEARD_* environment variables)
|
|
141
|
+
api/ queue, analysis, replay, incidents, archive, letter_lab, ask, settings
|
|
142
|
+
pipeline/ stages/, modes.py, runner.py
|
|
143
|
+
llm/ provider.py, openai_compat.py, mock.py, replay.py, cache.py, tasks/
|
|
144
|
+
adapters/ transcription/, backend/
|
|
145
|
+
data/ models.py, db.py, generator.py, templates.py, events.py, seed_today.json
|
|
146
|
+
analytics/ root_causes.py, event_impact.py, journeys.py, promises.py, equity.py
|
|
147
|
+
static/ index.html, css/, js/ (core/, ui/, charts/)
|
|
148
|
+
fixtures/ recorded LLM responses for replay
|
|
149
|
+
tests/ pytest: pipeline, schemas, API, generator determinism
|
|
150
|
+
.github/workflows/ ci.yml, release.yml
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Release path**
|
|
154
|
+
|
|
155
|
+
- PEP 440 pre-releases: 0.1.0a1, a2, and so on, then 0.1.0b1. Users install with `pip install --pre overheard`.
|
|
156
|
+
- Publish to TestPyPI first, then PyPI, from a GitHub Actions release workflow using trusted publishing, so no API tokens are stored.
|
|
157
|
+
- Confirm the package name is free on PyPI before the first upload.
|
|
158
|
+
|
|
159
|
+
**Path to a real integration**
|
|
160
|
+
|
|
161
|
+
- A live transcription adapter (AWS Transcribe or Whisper) and a voicemail ingest adapter (an S3 bucket or a telephony webhook).
|
|
162
|
+
- A `CaseBackend` adapter for the real system of record, read-only at first.
|
|
163
|
+
- Authentication through a reverse proxy (OIDC or CAC), audit logging of every AI suggestion and human decision, and Postgres in place of SQLite.
|
|
164
|
+
|
|
165
|
+
## Mock layer and LLM layer
|
|
166
|
+
|
|
167
|
+
The rule: use the LLM for judgments about language, and use plain code for counting, math, joins, and audio. Every service sits behind one interface with a mock implementation and a real one, chosen per task in Settings, so the demo can never be broken by a network failure.
|
|
168
|
+
|
|
169
|
+
| Task | Implementation | Why |
|
|
170
|
+
| --- | --- | --- |
|
|
171
|
+
| Transcription | Mock (later AWS Transcribe or Whisper) | Requires a speech model, not an LLM |
|
|
172
|
+
| Language detection and translation | LLM | Works well from transcript text |
|
|
173
|
+
| Summary, extraction, intent, urgency, sentiment | LLM, structured JSON output | Core language-understanding work |
|
|
174
|
+
| Draft replies and callback briefs | LLM | Generation grounded in backend data |
|
|
175
|
+
| Backend lookups for resolving without a callback | LLM tool use against the mock backend | The LLM decides which lookups answer the question |
|
|
176
|
+
| Deadline-bound request detection | LLM, plus keyword rules as a backstop | High recall matters more than precision |
|
|
177
|
+
| Message similarity and grouping | TF-IDF in Python, or the host's embeddings endpoint | Cheap and deterministic |
|
|
178
|
+
| Spike statistics and baselines | Code | Arithmetic, not judgment |
|
|
179
|
+
| Naming clusters and incidents | LLM | Describing a group of messages in words |
|
|
180
|
+
| Caller linking | Fuzzy match in code; LLM breaks ties | Most cases are mechanical |
|
|
181
|
+
| Archive labeling | Pre-labeled in the generator; optional offline LLM batch | Too many messages for live calls |
|
|
182
|
+
| Cost, event impact, equity statistics | Code over labels | Must be exact and reproducible |
|
|
183
|
+
| Letter pre-testing, ask-the-archive, narrative summaries | LLM | Synthesis and reasoning |
|
|
184
|
+
| Audio for the dataset | Offline, Amazon Polly | Build-time only |
|
|
185
|
+
|
|
186
|
+
**Provider interface.** Every LLM task runs on the server as `llm.run(task, input)`. A task module supplies the system prompt, a few examples, a pydantic output model, and optional tools. The live provider uses the `openai` Python SDK with a configurable `base_url`, so it works with any OpenAI-compatible host: vLLM, Azure OpenAI, a LiteLLM or Bedrock gateway, or Ollama.
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
# src/overheard/llm/provider.py
|
|
190
|
+
class LLMProvider(Protocol):
|
|
191
|
+
async def complete(self, *, system: str, messages: list[dict],
|
|
192
|
+
output: type[BaseModel] | None = None,
|
|
193
|
+
tools: list[dict] | None = None,
|
|
194
|
+
temperature: float = 0.2) -> LLMResult: ...
|
|
195
|
+
|
|
196
|
+
# MockProvider fixtures keyed by task + input hash, simulated latency, failure injection
|
|
197
|
+
# OpenAICompatProvider AsyncOpenAI(base_url=OVERHEARD_LLM_BASE_URL, api_key=OVERHEARD_LLM_API_KEY),
|
|
198
|
+
# model=OVERHEARD_LLM_MODEL; json_schema response_format when the host
|
|
199
|
+
# supports it, else JSON mode + validation
|
|
200
|
+
# ReplayProvider serves recorded responses only; never touches the network
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Configuration comes from environment variables: `OVERHEARD_LLM_MODE` (mock, live, record, or replay), `OVERHEARD_LLM_BASE_URL`, `OVERHEARD_LLM_API_KEY`, `OVERHEARD_LLM_MODEL`, and `OVERHEARD_LLM_TIMEOUT`, plus an optional per-task override map.
|
|
204
|
+
|
|
205
|
+
**Reliability features**
|
|
206
|
+
|
|
207
|
+
- **Pydantic validation** on every response. On failure it retries once with the validation error appended, then falls back to the mock fixture and marks the field "fallback."
|
|
208
|
+
- **Response cache** in SQLite, keyed by task, input hash, and model.
|
|
209
|
+
- **Record and replay.** Record mode saves every live response as a fixture. Replay mode serves only fixtures, so demo day needs no network.
|
|
210
|
+
- **Capability probe** at startup checks whether the host supports structured output and tool calls, and falls back gracefully when it doesn't.
|
|
211
|
+
|
|
212
|
+
## Data model
|
|
213
|
+
|
|
214
|
+
The data model keeps the raw input, the AI's output, and the ground truth in separate objects. That way any mode can be re-run from cache, and any AI field can be scored against truth.
|
|
215
|
+
|
|
216
|
+
```js
|
|
217
|
+
/** @typedef {{ id, receivedAt, callerId, durationSec, audioUrl?, script, lang, truth: Truth }} Voicemail */
|
|
218
|
+
/** @typedef {{ intent, urgency, rootCause, obligations: string[], resolvableBy?: string, linkedTo?: string[] }} Truth */
|
|
219
|
+
/** @typedef {{ messageId, mode, transcript, summary, fields: Record<string, Field>, intent, urgency,
|
|
220
|
+
* rationale, sentiment, translation?, route, draft, brief?, resolution?, obligations: Obligation[],
|
|
221
|
+
* callbackWindow?, provenance: Record<string, 'mock'|'llm'|'fallback'|'human'> }} Analysis */
|
|
222
|
+
/** @typedef {{ value, confidence, sourceSpan: [number, number], editedBy?: 'human' }} Field */
|
|
223
|
+
/** @typedef {{ kind: 'congressional'|'records'|'legal'|'welfare'|'discrimination', evidence, dueAt, status }} Obligation */
|
|
224
|
+
/** @typedef {{ id, label, messageIds: string[], firstSeen, rate, baseline, probableCause, actions: string[] }} Incident */
|
|
225
|
+
/** @typedef {{ id, callerId, name, region, lang, status, payments: Payment[], docs: Doc[], lastAction, team }} Case */
|
|
226
|
+
/** @typedef {{ id, date, type: 'mailing'|'release'|'policy'|'payment-shift', name, description }} Event */
|
|
227
|
+
/** @typedef {{ id, caseId, at, channel, rootCause, lang, region, handleMin, resolved, promise?: Promise }} Contact */
|
|
228
|
+
/** @typedef {{ text, dueAt, kept: boolean|null }} Promise */
|
|
229
|
+
/** @typedef {{ mode, agentMinutes, callbacksAvoided, obligationsCaught, obligationsMissed,
|
|
230
|
+
* urgentFirstTouch, incidentLeadMin, accuracy: Record<string, {precision, recall}> }} Scoreboard */
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
On the server these are pydantic models in `data/models.py`, shared by the API and the pipeline; the front end receives the same shapes as JSON.
|
|
234
|
+
|
|
235
|
+
## UI design
|
|
236
|
+
|
|
237
|
+
The UI has one workbench for Modes 0–2 and one analytics dashboard for Mode 3, under a persistent top bar. The mode stepper is the main control: each step reveals new panels in place rather than switching to a different app.
|
|
238
|
+
|
|
239
|
+
**Top bar (always visible)**
|
|
240
|
+
|
|
241
|
+
- A mode stepper (0 → 3) with keyboard shortcuts 1 through 4.
|
|
242
|
+
- A scoreboard: agent hours to clear the queue, when the urgent message is first touched, callbacks avoided, deadline-bound requests caught or missed, incident lead time, and estimated dollars.
|
|
243
|
+
- Buttons for the assumptions panel and Settings.
|
|
244
|
+
|
|
245
|
+
**Workbench (Modes 0–2), three panes**
|
|
246
|
+
|
|
247
|
+
- **Queue (left).** Chronological in Mode 0, sorted by priority from Mode 1. Groups and collapsed repeat callers appear in Mode 2.
|
|
248
|
+
- **Message (center).** Audio player, then the transcript (Mode 1 and up), extracted fields with confidence and source highlighting, and the draft reply.
|
|
249
|
+
- **Context (right).** Case record, linked contacts, and in Mode 2: the callback brief, resolution-without-callback panel, and deadline clocks.
|
|
250
|
+
- **Incident banner** (Mode 2), which slides in when a spike is detected, linked to its cluster view.
|
|
251
|
+
|
|
252
|
+
**Analytics (Mode 3) tabs:** Root causes (Pareto chart) · Events (timeline overlay) · Journeys (loop list and flow) · Promises · Equity · Letter lab · Ask the archive.
|
|
253
|
+
|
|
254
|
+
**AI provenance everywhere.** Every AI-produced value carries a small badge (AI, human-confirmed, or fallback), a "why" popover showing its source span or rationale, and inline editing. AI suggestions and human-confirmed values look different.
|
|
255
|
+
|
|
256
|
+
**Presenter mode**
|
|
257
|
+
|
|
258
|
+
- A "replay the day" control with 1×, 10×, and 60× speed.
|
|
259
|
+
- Reveal animations for the key moments.
|
|
260
|
+
- A hidden notes drawer with the demo script.
|
|
261
|
+
- Large-type layout for projectors.
|
|
262
|
+
|
|
263
|
+
**Tech:** plain CSS with custom properties for themes. Charts are drawn with small hand-written SVG helpers (bar, line, Pareto, timeline, simple flow), with no framework and no chart library.
|
|
264
|
+
|
|
265
|
+
## Metrics
|
|
266
|
+
|
|
267
|
+
Every number on the scoreboard is computed from the simulation and ground truth, and every assumption behind it is visible and adjustable live. That is what makes the before-and-after credible to a skeptical audience.
|
|
268
|
+
|
|
269
|
+
| Metric | How it is computed | Changes in |
|
|
270
|
+
| --- | --- | --- |
|
|
271
|
+
| Agent hours to clear the queue | Sum of listen or read time plus handling time; avoided callbacks count as zero | Modes 1, 2 |
|
|
272
|
+
| Urgent message first touched | Time the simulated agent reaches it, given queue order | Mode 1 |
|
|
273
|
+
| Callbacks avoided | Messages closed by approved written replies ÷ total | Mode 2 |
|
|
274
|
+
| Deadline-bound requests caught / missed | Detected vs. ground truth; a miss is an item reached after its deadline | Modes 0 vs. 2 |
|
|
275
|
+
| Incident lead time | Minutes from the first related message to the alert, vs. the human baseline (noticed after N similar messages reach one agent) | Mode 2 |
|
|
276
|
+
| AI accuracy | Precision and recall per field against truth, including human corrections | Modes 1–3 |
|
|
277
|
+
| Estimated annual dollars | Agent hours × fully loaded rate × annualization; cost by root cause from the archive | Mode 3 |
|
|
278
|
+
|
|
279
|
+
The defaults live in the assumptions panel: 3.5 minutes handling per message, 6 minutes per callback, a $75/hour fully loaded rate, and 250 working days. Show accuracy honestly, including the misses; a demo that admits 92% beats one that claims 100%.
|
|
280
|
+
|
|
281
|
+
## Security, privacy, and compliance
|
|
282
|
+
|
|
283
|
+
The demo itself carries no real risk: all data is synthetic and mock mode makes no network calls. It should still show that we know what a real deployment would require, because a federal audience will ask.
|
|
284
|
+
|
|
285
|
+
**In the demo**
|
|
286
|
+
|
|
287
|
+
- Synthetic data only: no real recordings, names, or case numbers.
|
|
288
|
+
- Mock mode is the default. The LLM API key lives only in the server's environment; the browser never sees it.
|
|
289
|
+
- AI never sends anything outbound without a person approving it, and that rule is shown on screen.
|
|
290
|
+
- Every AI claim links to the transcript span or record it came from.
|
|
291
|
+
|
|
292
|
+
**Questions a real deployment must answer** (a slide's worth, not code)
|
|
293
|
+
|
|
294
|
+
- Privacy Act coverage of voicemail content and the relevant system of records notice; records-retention schedule for recordings and transcripts.
|
|
295
|
+
- Where model inference runs: a FedRAMP-authorized service (for example, Bedrock in GovCloud) inside the agency's authorization boundary; prompt and output logging.
|
|
296
|
+
- Bias evaluation before using the equity view or urgency scores operationally.
|
|
297
|
+
- Section 508 accessibility of the agent UI.
|
|
298
|
+
- Policy on how quickly deadline-bound requests must be handled, owned by the agency, not set by the model.
|
|
299
|
+
|
|
300
|
+
## Implementation plan
|
|
301
|
+
|
|
302
|
+
[embedded content: estimates in focused dev-days, one developer · typed in chat\]
|
|
303
|
+
|
|
304
|
+
The full build is about 19 focused dev-days. Phases 0–3 (about 11.5 days) already make a strong demo, and Mode 3's root-cause view alone adds about 1.5 days if time is short.
|
|
305
|
+
|
|
306
|
+
**Phase 0 · Foundation**
|
|
307
|
+
|
|
308
|
+
- [ ] Package skeleton: pyproject (hatchling, src layout), `overheard` CLI, FastAPI app factory, static mount, CI with lint and tests
|
|
309
|
+
- [ ] Front-end shell, top bar, mode stepper, store, SSE client
|
|
310
|
+
- [ ] Pydantic models, SQLite layer, seeded generator for the queue and archive (`overheard seed`)
|
|
311
|
+
- [ ] Write the 60 voicemail scripts with ground-truth labels; mock case backend and caller directory
|
|
312
|
+
|
|
313
|
+
**Phase 1 · Mode 0**
|
|
314
|
+
|
|
315
|
+
- [ ] Chronological inbox, audio player, manual entry form, lookup panel
|
|
316
|
+
- [ ] Effort timer and "work the queue" simulation; scoreboard v1
|
|
317
|
+
|
|
318
|
+
**Phase 2 · Mode 1 and the LLM layer**
|
|
319
|
+
|
|
320
|
+
- [ ] LLM layer: provider Protocol with Mock, OpenAI-compatible, and Replay providers; pydantic validation; SQLite cache; record mode; capability probe
|
|
321
|
+
- [ ] Tasks: summary, extraction, intent and urgency, translation, sentiment, draft reply
|
|
322
|
+
- [ ] Priority queue, routing, provenance badges, inline edits feeding accuracy scoring
|
|
323
|
+
|
|
324
|
+
**Phase 3 · Mode 2**
|
|
325
|
+
|
|
326
|
+
- [ ] Similarity grouping, spike detection, incident banner and card
|
|
327
|
+
- [ ] Tool-use lookups, resolution-without-callback panel, callback brief
|
|
328
|
+
- [ ] Deadline-bound request detection with rule backstop and deadline clocks
|
|
329
|
+
- [ ] Repeat-caller linking, missing-info recovery, callback windows, belief-vs-record check
|
|
330
|
+
|
|
331
|
+
**Phase 4 · Mode 3**
|
|
332
|
+
|
|
333
|
+
- [ ] Root-cause Pareto chart with cost model (first, the headline)
|
|
334
|
+
- [ ] Event-impact timeline, caller journeys, promises vs. outcomes, equity view
|
|
335
|
+
- [ ] Letter lab and ask-the-archive (LLM over pre-computed totals); knowledge-gap list
|
|
336
|
+
|
|
337
|
+
**Phase 5 · Release and rehearsal**
|
|
338
|
+
|
|
339
|
+
- [ ] Presenter mode, replay speeds, reveal animations, assumptions panel
|
|
340
|
+
- [ ] Release workflow: build sdist and wheel, publish 0.1.0a1 to TestPyPI, verify `pip install --pre` in a clean virtualenv, then publish to PyPI with trusted publishing
|
|
341
|
+
- [ ] Rehearse against the live LLM host in record mode; freeze fixtures; offline dry run in replay mode
|
|
342
|
+
|
|
343
|
+
## Risks, open questions, and demo script
|
|
344
|
+
|
|
345
|
+
**Risks**
|
|
346
|
+
|
|
347
|
+
- *Live LLM output varies or fails on stage.* Rehearse with live calls in record mode, then present from replayed fixtures; fallback to mock per field.
|
|
348
|
+
- *Synthetic data looks too clean.* Write the 60 scripts by hand with real disfluencies, and have a colleague who has worked a call center review them.
|
|
349
|
+
- *Mode 3 numbers seem made up.* Show the assumptions panel and the ground-truth tables; frame dollars as an illustration of the method, not a claim about any real agency.
|
|
350
|
+
- *Scope creep.* Phases 1–3 alone make a strong demo; Mode 3 can ship with only the root-cause view.
|
|
351
|
+
|
|
352
|
+
**Open questions**
|
|
353
|
+
|
|
354
|
+
- [ ] Who is the audience: internal leadership, or a government customer?
|
|
355
|
+
- [ ] Demo date and available build time.
|
|
356
|
+
- [ ] Which LLM access is approved for this demo: which OpenAI-compatible host, and what authentication does it use?
|
|
357
|
+
- [ ] Is the PyPI package public, or should pre-releases go to a private index first?
|
|
358
|
+
- [ ] Recorded audio or text-only transcripts?
|
|
359
|
+
- [ ] Should the fictional agency mirror a real customer's domain?
|
|
360
|
+
|
|
361
|
+
**Demo script (about 15 minutes)**
|
|
362
|
+
|
|
363
|
+
1. Mode 0: play two messages live and fill in one form. Run the simulation: 7 hours, urgent reached at 2:40 pm, the portal pattern never noticed.
|
|
364
|
+
2. Mode 1: everything is transcribed and sorted; message 37 jumps to the top; show the Vietnamese message translated. Hours drop.
|
|
365
|
+
3. Pause: "This is what everyone shows. Here's what they don't."
|
|
366
|
+
4. Mode 2: replay the morning at 60×. The incident banner fires at 9:40. Approve five replies that need no callback, then reveal the share closed with no call. Show the congressional-inquiry flag found in minute two of a rambling message.
|
|
367
|
+
5. Mode 3: open Root causes. "One letter costs an estimated $600K a year."
|
|
368
|
+
6. Letter lab: paste the rewritten notice; predicted calls drop.
|
|
369
|
+
7. Ask the archive a live question from the audience.
|
|
370
|
+
8. Close on the scoreboard: the same 60 messages, four very different outcomes.
|