Metadata-Version: 2.5
Name: meeting-minute
Version: 0.4.0
Summary: Transcribe meetings locally with faster-whisper, mlx-whisper, whisper.cpp, or SenseVoice, then extract structured info via Claude/Cursor skills.
Project-URL: Homepage, https://github.com/milky-way-66/metting-minutes
Project-URL: Repository, https://github.com/milky-way-66/metting-minutes
Project-URL: Issues, https://github.com/milky-way-66/metting-minutes/issues
Author-email: longnv <longnv@kaopiz.com>
License-Expression: MIT
License-File: LICENSE
Keywords: claude,cli,cursor,meeting-minutes,transcription,vtt,whisper
Requires-Python: >=3.10
Requires-Dist: faster-whisper>=1.0.0
Requires-Dist: jiwer>=3.0.0
Requires-Dist: rich>=13.7.0
Requires-Dist: typer>=0.12.0
Provides-Extra: mlx
Requires-Dist: mlx-whisper>=0.4.0; extra == 'mlx'
Provides-Extra: sensevoice
Requires-Dist: mlx-audio[stt]>=0.5.0; extra == 'sensevoice'
Provides-Extra: whispercpp
Requires-Dist: pywhispercpp>=1.2.0; extra == 'whispercpp'
Description-Content-Type: text/markdown

# meeting-minute

Turn a meeting recording into structured minutes, without the audio leaving your machine.

1. **`mm transcribe`** — video/audio → timestamped `.vtt` via [faster-whisper](https://github.com/SYSTRAN/faster-whisper) (or `mlx-whisper` / `whisper.cpp` / SenseVoice on Mac). No API keys.
2. **`mm skill init`** — Claude Code / Cursor skills that extract a summary, action items, decisions, or Q&A from that `.vtt`, every claim cited to a timestamp.

Defaults are tuned for **Japanese**; `en` and `vi` work too. [Why these defaults](DESIGN.md#why-these-defaults) · [Architecture](DESIGN.md).

## Install

```bash
uv tool install meeting-minute                 # or: pipx install meeting-minute
uv tool install 'meeting-minute[mlx]'          # Apple Silicon: mlx-whisper (the `auto` default)
uv tool install 'meeting-minute[whispercpp]'   # whisper.cpp / Metal
uv tool install 'meeting-minute[sensevoice]'   # SenseVoice
```

Python 3.10+ and **`ffmpeg` on PATH** (`brew install ffmpeg`, `winget install ffmpeg`). First run downloads `large-v3-turbo` (~1.6 GB, cached). Use `--model small` to try it out, or `-m large-v3` for the full model.

## Quickstart

```bash
mm transcribe meeting.mp4            # -> meeting.vtt
mm skill init                        # -> .claude/skills/ and .cursor/rules/
```

Then, in Claude Code or Cursor: *"extract action items from meeting.vtt"*. You get a file like this, every row cited to the recording:

```markdown
| Task | Owner | Due | Source |
| --- | --- | --- | --- |
| Send the revised API spec to the client | Mai | by Friday | [00:04:12] |
| Book the load-testing window | unassigned | none | [00:21:40] |
```

## Transcribe

Any format **ffmpeg can decode**. Video picture is discarded; audio is converted to mono 16 kHz WAV.

| Kind | Common formats |
| --- | --- |
| **Video** | `.mp4`, `.mov`, `.mkv`, `.webm`, `.avi`, `.m4v` |
| **Audio** | `.mp3`, `.wav`, `.m4a`, `.aac`, `.flac`, `.ogg`, `.opus` |

**Glossary** is the biggest accuracy win — names and jargon Whisper would otherwise mishear:

```bash
mm glossary                 # create .meeting-minute/glossary.txt (one term per line, # comments)
mm transcribe 会議.mp4 --glossary 'カオピーズ,グエン・ホン・クアン,要件定義'
```

The project file is used automatically. `--glossary-file` points elsewhere; `--glossary` adds one-off terms on top.

### Supported backends and models

| Backend (`-b`) | Default model (`-m`) | Platform | Install | Notes |
| --- | --- | --- | --- | --- |
| **`auto`** (default) | Whisper `large-v3-turbo` | picks below | built-in + extras | Apple Silicon + `mlx` extra → `mlx-whisper`; else `faster-whisper` |
| `faster-whisper` | `large-v3-turbo` | CPU / CUDA everywhere | built-in | Accuracy-first decode (beam 5, word timestamps). `--fast` enables batched decode. |
| `mlx-whisper` | `mlx-community/whisper-large-v3-turbo` | Apple Silicon (MLX) | `pip install 'meeting-minute[mlx]'` or `uv sync --extra mlx` | Default on Mac (`auto`): best Japanese CER in the Whisper suite; same cue/glossary path as faster-whisper |
| `whisper-cpp` | Whisper ggml name (e.g. `large-v3-turbo`) | Apple Silicon (Metal) | `pip install 'meeting-minute[whispercpp]'` | Metal; one worker (ggml context is not shared across threads) |
| `sensevoice-mlx` | `mlx-community/SenseVoiceSmall` | Apple Silicon (MLX) | `pip install 'meeting-minute[sensevoice]'` | Speed opt-in; **no Vietnamese**; higher CER / coarser cues vs Whisper on Japanese meetings |

Common Whisper sizes for `-m` with `faster-whisper` / `mlx-whisper` / `whisper-cpp`: `tiny`, `base`, `small`, `medium`, `large-v3`, `large-v3-turbo`. `mlx-whisper` remaps those to `mlx-community/whisper-*`. SenseVoice currently uses the Small checkpoint above.

```bash
mm transcribe call.mp3 -l en -o transcript.vtt
mm transcribe long-call.mp4 -b mlx-whisper          # Mac MLX Whisper
mm transcribe long-call.mp4 -b whisper-cpp          # Mac Metal
mm transcribe 会議.mp4 -b sensevoice-mlx            # opt-in SenseVoice (Apple Silicon)
mm transcribe call.mp3 --fast                       # faster-whisper batched + beam 1
```

Long files are chunked (default 2 min) and decoded in parallel. Re-run resumes; `--fresh` starts over.

| Flag | Effect |
| --- | --- |
| `-l, --language` | `ja` (default), `en`, `vi`, or `auto` |
| `-m, --model` | See table above; Whisper default `large-v3-turbo` |
| `-b, --backend` | `auto` (default), `faster-whisper`, `mlx-whisper`, `whisper-cpp`, or `sensevoice-mlx` |
| `-o, --output` | Output `.vtt` path |
| `-j, --workers` | Parallel chunks (`0` = auto; GPU/Metal backends force 1) |
| `--fast` | `faster-whisper` only: `BatchedInferencePipeline` + beam 1 |
| `--glossary-file` | Term file instead of the project default (Whisper backends) |
| `--keep-silence` | Transcribe silent stretches |
| `--no-normalize` | Skip the gain lift on near-inaudible audio |
| `--fresh` | Ignore resume state |

`mm -h` and `mm transcribe -h` list the rest.

### Compare backends (A/B)

Score two backends against a gold transcript with **CER** (primary for `ja`/`vi`) and **WER** (also for `en`), plus wall time / RTF.

```bash
uv sync --extra mlx --extra whispercpp --extra sensevoice
mm compare meeting.mp4 --reference gold.txt --suite whisper \
  -o .meeting-minute/compare/meeting
```

`--suite whisper` runs `faster-whisper`, `mlx-whisper`, and `whisper-cpp` (skips extras that are not installed). `--suite all` adds `sensevoice-mlx`. Two-arm A/B is still the default: baseline `faster-whisper`, challenger `sensevoice-mlx`.

Writes one `.vtt` per arm and `report.json`. Lower CER wins. On a Japanese meeting clip, mlx-whisper had the lowest CER; SenseVoice was fastest but worst CER and stays opt-in.

## Extract

```bash
mm skill init                   # both targets (default)
mm skill init --target claude   # .claude/skills/<template>/SKILL.md
mm skill init --target cursor   # .cursor/rules/<template>.mdc
```

Built-ins: `summary`, `action-items`, `decisions`, `qa`.

```bash
mm skill list
mm skill add risks              # then edit and: mm skill init --template risks
```

A custom template is Markdown with `name`, `description`, and `outputFile` frontmatter. `description` must say **what it does and when to use it** (the words a user would actually say). Cite every entry (`[HH:MM:SS]`), name what to exclude, and allow `_None found._` instead of forcing a fill.

## Config

- Global: `~/.config/meeting-minute/config.json`
- Project: `.meeting-minute/config.json`

```json
{
  "model": "large-v3-turbo",
  "language": "ja",
  "backend": "auto",
  "chunkMinutes": 2,
  "workers": 0,
  "batchSize": 16,
  "beamSize": 5,
  "computeType": "auto",
  "removeSilence": true,
  "glossary": ["カオピーズ", "要件定義", "統括"],
  "glossaryFile": "",
  "templates": ["summary", "action-items", "decisions", "qa"]
}
```

## Why these defaults

From A/B runs on Japanese meetings. Details in [DESIGN.md](DESIGN.md#why-these-defaults).

- **`auto` backend.** Apple Silicon with `meeting-minute[mlx]` → `mlx-whisper`. Otherwise `faster-whisper` (CPU float32 or CUDA float16). Override with `-b`. Locked on a Japanese meeting clip: mlx-whisper slightly better CER than faster-whisper and ~3× RTF.
- **`faster-whisper` + `large-v3-turbo` + `float32` on CPU** when that path is selected. Matched `large-v3` quality at ~3× speed. `--fast` is opt-in (batched decode + beam 1; drops temperature fallback). `int8` dropped phrases. Use `-m large-v3` for the full model.
- **SenseVoice (`sensevoice-mlx`) is supported, not default.** Faster on Apple Silicon, but higher CER, coarser cues, and **no Vietnamese**. Use `-b sensevoice-mlx` when you want that speed trade-off.
- **Glossary of names and jargon**, folded in as a sentence — not a labelled list, not in the prompt. Prompt is style only (Whisper backends).
- **Silence stripped**; timestamps still map to the original recording. Quiet files get a gain lift below −30 LUFS.
- **2-minute chunks**, shared-model workers (`auto` caps at 4; Metal/MLX backends force 1). Denoise and a wider beam measured worse.

## Development

```bash
git clone https://github.com/milky-way-66/metting-minutes
cd metting-minutes
uv sync
uv sync --extra mlx          # Apple Silicon mlx-whisper
uv sync --extra sensevoice   # Apple Silicon SenseVoice (mlx-audio)
uv run mm --help

uv run pytest tests/unit          # fast, no external deps
uv run pytest tests/integration   # needs ffmpeg; mlx/SenseVoice tests skip without extras / non-ARM Mac
uv run pytest                     # both
```

## Publish

This is a PyPI package, not a hosted service. Releasing is: bump the version, build, upload.

```bash
uv run pytest
uv version --bump minor          # or patch / major; writes pyproject.toml
git add pyproject.toml && git commit -m "Release $(uv version --short)"
uv build                         # dist/*.whl and dist/*.tar.gz (includes skill templates)
```

Create a PyPI API token at [pypi.org/manage/account/tokens](https://pypi.org/manage/account/tokens/). Then:

```bash
export UV_PUBLISH_TOKEN=pypi-... # do not commit this
uv publish                       # uploads dist/*
git tag "v$(uv version --short)" && git push && git push --tags
```

`uv publish --dry-run` checks the upload without sending files. To try TestPyPI first, use a token from [test.pypi.org](https://test.pypi.org/manage/account/tokens/) and:

```bash
uv publish --publish-url https://test.pypi.org/legacy/
```

After a real PyPI release, install as in [Install](#install): `uvx meeting-minute`, `uv tool install meeting-minute`, or `uv add meeting-minute`. GitHub Actions trusted publishing (OIDC, no token) is not set up yet.

## License

MIT — see [LICENSE](LICENSE).
