Recording → Transcription
Automatically transcribe any audio or video recording dropped into Nextcloud. The moment a file lands in the bucket, Decree generates a pre-signed URL, hands it to WhisperX, and saves a speaker-labelled transcript next to the original file — no manual steps, no intermediate storage.
How It Works
1. Phone uploads the recording
The Nextcloud mobile app auto-syncs your phone's recordings folder to Nextcloud. Any .mp3, .mp4, or .wav file uploaded this way flows into SeaweedFS via Nextcloud's S3 external storage.
2. SeaweedFS fires the webhook
When the file lands in the bucket, it POSTs an s3:ObjectCreated event to the Decree webhook endpoint. The rclone_src and rclone_prefix in the webhook config tell s3-router how to construct the rclone path used in all subsequent steps.
3. s3-router matches the file
s3-router scans every processor script in automation/lib/file-processors/ for a PATTERN= match against the full rclone path. The whisperx-transcribe processor declares:
PATTERN='\.[Mm][Pp][34]$|\.[Ww][Aa][Vv]$'
IS_PRE_SIGNED=true
It matches .mp3, .mp4, and .wav case-insensitively. Because IS_PRE_SIGNED=true, the outbox message carries is_pre_signed: true — telling file-processor not to download the file.
4. file-processor generates a signed URL
Instead of downloading the file, file-processor calls rclone link to generate a pre-signed URL for the audio file and exports it as PRE_SIGNED_URL. No audio data touches the Decree container's disk.
5. whisperx-transcribe submits to WhisperX
whisperx-transcribe.sh invokes whisperx-transcribe.ts, which:
- POSTs the
PRE_SIGNED_URLtohttp://whisperx:8000/speech-to-text-url— WhisperX fetches the audio itself and runs the full transcribe → align → diarize pipeline - Polls
GET /task/{id}until the task reportscompleted(diarized runs take longer than plain transcription) - Collapses the result's speaker-tagged segments into
[SPEAKER_00] …lines - Writes the speaker-labelled transcript to stdout
6. Transcript saved next to the original
The bash processor pipes the transcription text through rclone rcat directly into Nextcloud at the same path as the audio file, with .transcript.txt appended:
recordings/2026-04-22 Meeting.mp3
recordings/2026-04-22 Meeting.mp3.transcript.txt ← created automatically
Prerequisites
- Nextcloud running with SeaweedFS configured as S3 external storage
- SeaweedFS webhook sending file events to the Decree webhook endpoint (see File Processor)
- WhisperX container running and reachable at
http://whisperx:8000 - rclone configured with a
nextcloudremote (or whichever remote matches yourrclone_srcwebhook setting) - Nextcloud mobile app with auto-upload enabled for your recordings folder
Setup
Step 1 — object-store webhook
Follow the SeaweedFS setup in File Processor to register the Decree webhook target and add your recordings path to path_prefixes in notification.toml. If recordings land in the nextcloud bucket, both are already done for you.
Step 2 — rclone remote
Ensure your rclone config has a remote that can access the files SeaweedFS is receiving events for:
./existential.sh run rclone
The remote name must match rclone_src in services/automation/webhook/config.yml (default: nextcloud).
Step 3 — Enable WhisperX
Start the WhisperX container if it isn't already running (all compose commands run from the
repo root against the generated docker-compose.yml — never -f into a service's own
directory):
docker compose up -d whisperx
WhisperX will download the default model on first use. No further configuration is required — the whisperx-transcribe processor defaults to letting WhisperX pick its own model.
Step 4 — Confirm the processor is active
The whisperx-transcribe processor is auto-discovered from automation/lib/file-processors/. No registration step is needed. Verify the pre-checks pass:
docker exec automation decree routine file-processor
Step 5 — Configure Nextcloud mobile auto-upload
In the Nextcloud mobile app, enable auto-upload for your phone's voice recordings or screen recordings folder. Files are uploaded to Nextcloud, synced to the bucket, and the transcription flow triggers automatically.
Customization
Override any of these in the processor script or pass them as frontmatter params:
| Variable | Default | Description |
|---|---|---|
FILE_SUFFIX | .transcript.txt | Suffix appended to the audio file path for the output |
OUTPUT_RCLONE | nextcloud | rclone remote where the transcript is saved |
WHISPERX_MODEL | (empty — WhisperX default) | Model name passed to the transcription API |
WHISPERX_MIN_SPEAKERS | (empty — auto-detect) | Lower bound on diarized speaker count |
WHISPERX_MAX_SPEAKERS | (empty — auto-detect) | Upper bound on diarized speaker count |
WHISPERX_URL | http://whisperx:8000 | WhisperX API base URL |
Testing
Send a synthetic file event to trigger the flow end-to-end:
# automation-webhook publishes no host port — it is reached over the exist
# bridge, so send the event from a container already on it.
docker exec automation curl -X POST http://automation-webhook:8801/s3 \
-H "Authorization: Bearer <EXIST_DECREE_S3_WEBHOOK_AUTH_TOKEN from .env.shared>" \
-H "Content-Type: application/json" \
-d '{"EventName":"s3:ObjectCreated:Put","Key":"recordings/test.mp3","Records":[]}'
Watch processing in real time:
docker logs -f automation
Inspect the completed run:
docker exec automation decree status
docker exec automation decree log <id-prefix>