Skip to content
Merged
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
55 changes: 55 additions & 0 deletions bundles/meeting-recorder/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Meeting Recorder

Record a meeting in the browser and transcribe it on the same machine that served the page.

The panel captures two audio sources, the meeting itself (a shared tab or window) and the
microphone, mixes them in WebAudio, and uploads Opus every 15 seconds. On stop, a detached worker
converts the audio, sends it to a local OpenAI-compatible transcription endpoint in ten-minute
slices, and writes a timestamped markdown transcript. Nothing leaves the host, and no API key is
involved.

## What it needs

- **ffmpeg and ffprobe** on the host.
- **A transcription endpoint.** The `faster-whisper-server` bundle is the intended pairing: CPU,
int8, loopback `:8004`, which is this bundle's default. Any OpenAI-compatible
`/v1/audio/transcriptions` endpoint works.
- **A secure context.** Browsers hand over tab audio only over HTTPS or on localhost. Reach the
dashboard through Tailscale Serve, a TLS reverse proxy, or `http://localhost`. The panel says so
on screen when the context is insecure, before you record silence by accident.

## Configuration

| Variable | Default | Meaning |
|---|---|---|
| `WHISPER_URL` | `http://localhost:8004/v1/audio/transcriptions` | the transcription endpoint |
| `WHISPER_MODEL` | `Systran/faster-whisper-large-v3` | model name sent with each slice |
| `WHISPER_SLICE_SECONDS` | `600` | slice length; smaller means finer progress, more requests |
| `MEETING_RECORDER_EXPORT_DIR` | unset | if set, every transcript also lands in `<dir>/<date>-<slug>/transcript.md` |

## Where recordings live

`$CROW_HOME/data/meeting-recorder/<session-id>/`

| File | What |
|---|---|
| `audio.webm` (or `audio.<ext>` for an upload) | the recording |
| `audio.wav` | 16 kHz mono, what the transcriber read |
| `meta.json` | title, timings, state, results |
| `transcript.json` | segments with start, end, text |
| `transcript.md` | the readable transcript, with any notes taken while listening |

## Throughput

Roughly 3.5x real time on an AMD Ryzen AI Max+ 395 with faster-whisper large-v3 int8 on CPU: a
ninety-minute meeting finishes about twenty-five minutes after it ends. Transcription starts when
recording stops; there is no live transcript.

## Limits worth knowing before you rely on it

- **No speaker labels.** Diarization is a second model and is not here. Every transcript carries a
line saying so, because a machine transcript with confident-looking text invites quotation.
- **Names get misheard.** Verify any quotation against the audio before it travels.
- **Recording other people carries obligations this bundle does not handle.** Many hosts prohibit
recording their sessions, and consent rules vary by jurisdiction. That judgement is the
operator's, before pressing record.
45 changes: 45 additions & 0 deletions bundles/meeting-recorder/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"id": "meeting-recorder",
"name": "Meeting Recorder",
"version": "1.0.0",
"description": "Record a meeting in the browser (shared tab audio plus microphone) and transcribe it locally with faster-whisper. Nothing leaves the machine.",
"type": "bundle",
"author": "Crow",
"category": "ai",
"tags": ["audio", "transcription", "whisper", "meetings", "notes"],
"icon": "mic",
"panel": {
"id": "meeting-recorder",
"name": "Meeting Recorder",
"icon": "mic",
"route": "/dashboard/meeting-recorder",
"navOrder": 17
},
"panelRoutes": "panel/routes.js",
"requires": {
"env": [],
"min_ram_mb": 64,
"min_disk_mb": 500
},
"env_vars": [
{
"name": "WHISPER_URL",
"description": "OpenAI-compatible transcription endpoint. Defaults to the faster-whisper-server bundle on loopback :8004.",
"required": false,
"default": "http://localhost:8004/v1/audio/transcriptions"
},
{
"name": "WHISPER_MODEL",
"description": "Model name passed to that endpoint.",
"required": false,
"default": "Systran/faster-whisper-large-v3"
},
{
"name": "MEETING_RECORDER_EXPORT_DIR",
"description": "Optional. A directory that also receives a dated markdown copy of every transcript, for grepping or for a git repo.",
"required": false,
"default": ""
}
],
"notes": "Needs ffmpeg on the host and a transcription endpoint (the faster-whisper-server bundle is the intended pairing; it is CPU-only and loopback-bound). No port of its own: the capture page and its upload endpoints ride the gateway through the panel and panelRoutes, so recordings inherit the dashboard's session auth. A browser only hands over tab audio in a secure context, so reach the dashboard over HTTPS (Tailscale Serve, a reverse proxy, or localhost)."
}
Loading
Loading