feat: add AssemblyAI Universal-2 transcription engine - #3
Open
julianromli wants to merge 1 commit into
Open
Conversation
Add a cloud STT option alongside the existing Parakeet engine. Users
can switch engines with a single config change, no rebuild required.
Changes:
- Add AssemblyAIEngine.swift: uploads audio to AssemblyAI /v2/upload,
submits a transcript job with speech_model=universal and
language_detection=true, polls until complete, and maps word timings
to TranscriptSegment using the same segmentation logic as ParakeetEngine.
Uses URLSession streaming upload so large CAF files are never fully
loaded into memory. Zero new SPM dependencies.
- Config.swift: add assemblyAIApiKey() reading assemblyai_api_key from
config.json. Update transcriptionEngine() doc comment to list both
supported engines.
- TranscriptionCoordinator.swift: replace parakeet-only branch with a
switch on the configured engine name. Missing API key throws a typed
error before any recording starts.
- Doctor.swift: checkTranscription() skips the parakeet model download
warning when engine is assemblyai. Add checkAssemblyAI() returning
Check? so it is invisible in doctor output for parakeet users.
- README.md: document the assemblyai engine, add config snippet, note
that audio leaves the machine when using cloud transcription.
To use AssemblyAI, set in ~/.config/quill/config.json:
{ "transcription": { "engine": "assemblyai" }, "assemblyai_api_key": "<key>" }
Get an API key at https://www.assemblyai.com/dashboard/home.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds AssemblyAI as an optional cloud transcription engine alongside the existing Parakeet engine. Users can switch between engines with a single config change. No rebuild required.
What changed
New file:
Sources/quill/Transcription/AssemblyAIEngine.swiftA new
actorimplementing the existingTranscriptionEngineprotocol. The flow is:.caffile as raw bytes toPOST /v2/uploadusingURLSession.upload(for:fromFile:)(streaming, so large files are never fully loaded into memory)POST /v2/transcriptwithspeech_model: "universal"andlanguage_detection: trueGET /v2/transcript/{id}every 3 seconds until the job reaches a terminal state (max 2 hours)words[]array (timestamps in ms, converted to seconds) and group them intoTranscriptSegments using the same segmentation logic asParakeetEngine(sentence-ending punctuation, silence gap over 1s, or 60-word cap)Zero new SPM dependencies.
Config.swiftAdded
assemblyAIApiKey()that readsassemblyai_api_keyfromconfig.json. Returnsnilwhen the key is absent or empty so the engine fails fast with a clear error before any recording starts, rather than silently failing mid-session. Updated thetranscriptionEngine()doc comment to list both supported engine names.TranscriptionCoordinator.swiftReplaced the parakeet-only branch in
preparedEngine()with aswitchon the configured engine name. A missing API key throwsAssemblyAIEngine.EngineError.missingAPIKeybefore the engine is used.Doctor.swiftcheckTranscription()now skips the parakeet model download warning when the configured engine isassemblyai(no local models needed). AddedcheckAssemblyAI() -> Check?which returnsnilwhen the engine is notassemblyai, so it never appears inquill doctoroutput for parakeet users.run()uses.compactMap { $0 }to filter out the optional.README.mdDocumented the AssemblyAI engine, added a config snippet, noted that audio leaves the machine when using cloud transcription, and updated the engine list in the Config section.
How to use
Add to
~/.config/quill/config.json:{ "transcription": { "engine": "assemblyai" }, "assemblyai_api_key": "your_key_here" }Get an API key at https://www.assemblyai.com/dashboard/home. Run
quill doctorto confirm the key is detected before recording.Privacy note
When using the AssemblyAI engine, audio files are uploaded to AssemblyAI's servers for transcription. The default Parakeet engine remains fully local with nothing leaving the machine.
Testing
Tested by inspection and code review. The engine follows the same
TranscriptionEngineprotocol contract asParakeetEngineand uses the same segmentation logic, so transcript output shape is identical. Live testing requires a valid AssemblyAI API key on macOS 15.