Developed primarily for transcribing recordings of tabletop RPG sessions conducted over Discord or similar communication software.
For a guided, interactive experience, use the interactiverun.ps1 PowerShell script. It prompts for each argument step-by-step and remembers your preferences across runs (prompt, output directory, language) via a local mmt_config.json file. It also keeps a history of the last 5 output base names for quick reference.
The script automatically uses the project's .venv Python interpreter, so there is no need to activate the virtual environment manually.
.\interactiverun.ps1When launched, the script will walk you through the following prompts:
- Input audio files — Space-separated file paths (wrap paths in double quotes if they contain spaces).
- Strategy — Choose by number, full name, or short alias (defaults to
non-diarized-aligned). - Prompt type —
directoryorstring(defaults todirectory). - Prompt value — Directory path or string depending on the chosen type; defaults to the last value used.
- Output directory — Where results are written; defaults to the last directory used.
- Output types — One or more of
json,text,dense,raw(defaults to all four). - Language — Language code or name (e.g.
en,pl); defaults to the last language used. - Output base name — Optional base name for output files; shows the last 5 names for reference.
Any prompt left blank will fall back to the persisted default (if one exists) or be omitted from the command.
mmt.py [-h] -i INPUT [INPUT ...] [-o OUTPUT_DIRECTORY] [-b OUTPUT_BASE_NAME] [-c CLIP_DIRECTORY]
-s {non-diarized-single,diarized-single,non-diarized-multi,non-diarized-aligned,nds,ds,ndm,nda}
[-t {string,directory,str,dir}] [-p PROMPT]
-f {json,text,dense,raw} [{json,text,dense,raw} ...]
[-l {pl, en, polish, english, ...}] [-m SPEAKERS_MIN] [-x SPEAKERS_MAX] [-e SPEAKER_COUNT]
[-v] [-w] [-M {tiny,tiny.en,base,base.en,small,small.en,medium,medium.en,large,large-v1,large-v2,large-v3}]
Diarize and transcribe Discord conversation recordings
options:
-h, --help show this help message and exit
-i INPUT [INPUT ...], --input INPUT [INPUT ...]
Input audio file(s)
-o OUTPUT_DIRECTORY, --output-directory OUTPUT_DIRECTORY
Output directory for final results
-b OUTPUT_BASE_NAME, --output-base-name OUTPUT_BASE_NAME
Output file base name, extended with type and extension for each output type.
-c CLIP_DIRECTORY, --clip-directory CLIP_DIRECTORY
Intermediate clip directory for split files
-s {non-diarized-single,diarized-single,non-diarized-multi,non-diarized-aligned,nds,ds,ndm,nda}, --strategy {non-diarized-single,diarized-single,non-diarized-multi,non-diarized-aligned,nds,ds,ndm,nda}
Transcription strategy
-t {string,directory,str,dir}, --prompt-type {string,directory,str,dir}
Type of initial prompt (string or directory)
-p PROMPT, --prompt PROMPT
Initial prompt string or directory path
-f {json,text,dense,raw} [{json,text,dense,raw} ...], --output-types {json,text,dense,raw} [{json,text,dense,raw} ...]
Output types (json, text, dense, raw or any combination)
-l {pl, en, polish, english, ...}, --language {pl, en, polish, english, ...}
Language presumed for the entire recording.
-m SPEAKERS_MIN, --speakers-min SPEAKERS_MIN
The expected maximum of speaker identities. The number excludes non-speaker noise/silence
-x SPEAKERS_MAX, --speakers-max SPEAKERS_MAX
The expected minimum of speaker identities. The number excludes non-speaker noise/silence
-e SPEAKER_COUNT, --speaker-count SPEAKER_COUNT
The expected exact count of speakers, mutually exclusive with -m -x
-v, --verbose Builder verbosity: level (Default is 0).
-w, --suppress-warnings
Suppress warnings from constituent libraries and models.
-M {tiny,tiny.en,base,base.en,small,small.en,medium,medium.en,large,large-v1,large-v2,large-v3}, --model {tiny,tiny.en,base,base.en,small,small.en,medium,medium.en,large,large-v1,large-v2,large-v3}
Whisper model size to use (default: large)
python mmt.py `
-i files\file1.aac files\file2.aac files\file3.aac files\file4.aac files\file5.aac files\file6.aac `
--strategy nda `
--prompt-type directory `
--prompt prompt/some_prompt `
--output-types json text dense raw `
--language pl `
--model large `
--output-base-name "Name of output"MMT supports LLM-based summarization of transcripts using OpenAI-compatible APIs. The summarizer validates endpoints against known providers and can auto-correct malformed URLs.
Summarize an existing transcript without re-transcribing:
python mmt.py `
--summarize `
--summarization-transcript output\some_transcript.dense.txt `
--summarization-prompt-type directory `
--summarization-prompt prompt\example_summarization `
--summary-output output\summaries `
--no-confirmEnable summarization to run automatically after transcription:
python mmt.py `
-i files\session.aac `
--strategy nda `
--prompt-type directory `
--prompt prompt\dnd_campaign `
--summarize `
--summarization-prompt-type directory `
--summarization-prompt prompt\summarization `
--summary-output output\summaries `
--output-types json text dense raw `
--language en `
--model largeSet your API endpoint in .env (see .env.example for details):
LLM_API_ENDPOINT=https://openrouter.ai/api/v1/chat/completions
LLM_API_KEY=your_api_key_here
LLM_MODEL_ARCH=nvidia/nemotron-3-super-120b-a12b:freeThe system recognizes 20+ providers (OpenRouter, OpenAI, DeepSeek, Qwen, Mistral, etc.) and validates that the endpoint URL is correct. Use --no-confirm to auto-substitute malformed endpoints.
When using the directory prompt type, organize your prompt across multiple text files in a directory. This approach is especially useful for TTRPG sessions where you want Whisper to recognize domain-specific vocabulary.
A prompt directory contains:
prefix(optional) — Context or instructions at the start of the promptsuffix(optional) — Instructions or notes at the end of the prompt{Name}.listfiles (0 or more) — One list per file, each containing newline-separated items
The final prompt is assembled as: {prefix} {Name1}:{comma-separated items}. {Name2}:{comma-separated items}. ... {suffix}
Directory structure:
prompt/example_forgotten_realms/
├── prefix
├── suffix
├── Empty.list
├── Characters.list
├── Locations.list
└── Monsters.list
Contents of prefix:
This is a recording of a Dungeons & Dragons 5th Edition campaign set in the Forgotten Realms.
Contents of Characters.list:
The file is empty and thus won't be included.
Contents of Characters.list:
Theron Blackwood
Lyra Stormborn
Kai the Dwarf
Contents of Locations.list:
Waterdeep
Baldur's Gate
Neverwinter
Contents of Monsters.list:
Beholder
Displacer Beast
Mind Flayer
Tarrasque
Contents of suffix:
Preserve proper nouns and technical D&D terminology.
Resulting prompt:
This is a recording of a Dungeons & Dragons 5th Edition campaign set in the Forgotten Realms. Characters:Theron Blackwood,Lyra Stormborn,Kai the Dwarf. Locations:Waterdeep,Baldur's Gate,Neverwinter. Monsters:Beholder,Displacer Beast,Mind Flayer,Tarrasque. Preserve proper nouns and technical D&D terminology.
This guides the transcriber to recognize campaign-specific names and terminology, reducing errors in the transcript.
MMT supports four transcript output formats, controlled via the --output-types argument. Each captures the same transcription data in different ways, suited for different use cases.
One segment per line with timing, speaker, and text. Compact and suitable for quick scanning or line-based processing.
[00:00:15.324 / 00:00:22.891] (Speaker 1 (player_1_audio)): We enter the tavern cautiously.
[00:00:23.105 / 00:00:31.444] (Speaker 2 (dm_audio)): The barkeep looks up suspiciously.
[00:00:31.789 / 00:00:38.201] (Speaker 1 (player_1_audio)): I cast detect magic on the room.
Speaker labels:
- Single file or simple diarization:
Speaker 1,Speaker 2, etc. - Multi-stream recording:
Speaker 1 (filename),Speaker 2 (filename), etc. (filename derived from input file basename)
Multi-line segments with timing, speaker, and text separated by blank lines. Easy to read and edit.
[00:00:15.324 / 00:00:22.891] (Speaker 1 (player_1_audio)):
We enter the tavern cautiously.
[00:00:23.105 / 00:00:31.444] (Speaker 2 (dm_audio)):
The barkeep looks up suspiciously.
[00:00:31.789 / 00:00:38.201] (Speaker 1 (player_1_audio)):
I cast detect magic on the room.
Structured format containing an array of segment objects with start time, end time, speaker, and text. Ideal for programmatic processing or import into other tools.
{
"segments": [
{
"start": 15.324,
"end": 22.891,
"speaker": "Speaker 1 (player_1_audio)",
"text": "We enter the tavern cautiously."
},
{
"start": 23.105,
"end": 31.444,
"speaker": "Speaker 2 (dm_audio)",
"text": "The barkeep looks up suspiciously."
},
{
"start": 31.789,
"end": 38.201,
"speaker": "Speaker 1 (player_1_audio)",
"text": "I cast detect magic on the room."
}
]
}Text only, one line per segment. No timing or speaker information. Useful for bulk text analysis or as a starting point for custom processing.
We enter the tavern cautiously.
The barkeep looks up suspiciously.
I cast detect magic on the room.
| Argument | Accepted Values | Description | Multiplicty | Required |
|---|---|---|---|---|
-i, --input |
Relative or absolute filepath(s) | Input audio file(s) - one or more paths separated by spaces | 1+ |
True |
-o, --output-directory |
Relative or absolute filepath | Output directory for final results | 1 |
False |
-b, --output-base-name |
String | Output file base name, extended with type and extension for each output type | 1 |
False |
-c, --clip-directory |
Relative or absolute filepath | Intermediate clip directory for split files | 1 |
False |
-s, --strategy |
One of{non-diarized-single,diarized-single,non-diarized-multi,non-diarized-aligned,nds, ds, ndm, nda} |
Transcription strategy | 1 |
True |
-t, --prompt-type |
One of{string,directory} |
Type of initial prompt (string or directory) | 1 |
False |
-p, --prompt |
For prompt type string:String of length 1024 characters or less For prompt type directory:Relative or absolute directory path |
Initial prompt string or directory path | 1 |
False |
-f, --output-types |
One or more of:{json,text,dense,raw} |
Output types (json, text, dense, raw or any combination) | 1+ |
True |
-l, --language |
{pl, en, polish, english, ...} | Language presumed for the entire recording | 0+ |
False |
-M, --model |
One of{tiny, tiny.en, base, base.en,small, small.en, medium,medium.en, large, large-v1,large-v2, large-v3} |
Whisper model size to use (default: large) |
1 |
False |
-v, --verbose |
Integer (count) | Increase verbosity level | 0+ |
False |
-w, --suppress-warnings |
Flag | Suppress warnings from constituent libraries and models | 0 |
False |
--summarize |
Flag | Enable summarization after transcription | 0 |
False |
--summarization-transcript |
Relative or absolute filepath | Input transcript file (also serves as summarize-only flag) | 1 |
False |
--summarization-prompt-type |
One of{string,directory} |
Type of summarization prompt (default: directory) |
1 |
False |
--summarization-prompt |
For prompt type string:String of length 1024 characters or less For prompt type directory:Relative or absolute directory path |
Summarization prompt directory or string (default: prompt/summarization) |
1 |
False |
--summary-output |
Relative or absolute filepath | Output path for summary markdown (file or directory) | 1 |
False |
--no-confirm |
Flag | Skip confirmation before sending summarization request; also auto-corrects malformed API endpoints | 0 |
False |
-h, --help |
N/A | Show help message and quit | 0,1 |
False |
MMT includes automatic validation for LLM API endpoints. The system maintains a dictionary of 20+ known providers (OpenRouter, OpenAI, DeepSeek, Qwen, Mistral, etc.) with their correct full endpoints.
- Correct endpoint: Used as-is (e.g.,
https://openrouter.ai/api/v1/chat/completions) - Base URL detected: Raises
ValueErrorwith expected endpoint (or auto-substitutes with--no-confirm) - Unknown provider: Used as-is without validation
See .env.example for a list of correct endpoint examples.
The values below pertain to the large model; smaller models require less VRAM/RAM.
| Part | Minimum | Recommended |
|---|---|---|
| Inference on GPU | CUDA-enabled GPU with 8GB VRAM | RTX GPU with 12 GB VRAM |
| Inference on CPU | 16 GB RAM | N/A |
For maximum accuracy of speaker recognition, use a multi-stream recording solution such as Craig, preferably hosted locally to maintain maximum control over your privacy. The reason for this recomendation is higher overall difficulty of diarization as a task, compared to simply sorting multiple audio stream contents by timestamp.