iOS & watchOS speech-to-text app with AI voice keyboard, on-device RAG, and chat with your notes - powered by Apple Foundation Models, WhisperKit, NVIDIA Parakeet, and 20+ AI providers
113
stars
3,293
commits
Swift
primary language
Sep 9, 2026
updated
iOS & watchOS speech-to-text app with AI voice keyboard, on-device RAG, and chat with your notes - powered by Apple Foundation Models, WhisperKit, NVIDIA Parakeet, and 20+ AI providers
Website •
App Store •
Documentation
Started as "I don't want to pay for WisprFlow." Ended up building something more flexible — on-device transcription, 20+ AI providers, on-device RAG with chat, OAuth sign-in, CLI agent bridge, and full control over your voice-to-text pipeline.
VivaDicta records speech, transcribes it using on-device or cloud models, and optionally processes the text through an AI provider — including Apple Foundation Models for free, fully on-device AI. Its key feature is a system-wide AI voice keyboard that lets you dictate and AI-process text directly into any app — Messages, WhatsApp, Slack, email, or anything else. The keyboard can also rewrite existing text in any app — select text, apply an AI preset, and get the result in place. Chat with your notes - ask questions about one note or many, powered by on-device RAG pipeline. Smart Search finds notes by meaning with on-device semantic search. Sign in with your ChatGPT, Gemini, or GitHub Copilot account via OAuth, or route AI through CLI agents on your Mac with VivAgents. Supports 11 transcription providers, 20+ AI providers, and syncs across devices (iOS/iPadOS/macOS/watchOS) via CloudKit.
Transcription
AI Presets
Chat & RAG
AI Providers
VivAgents — CLI Agent Bridge
VivaModes
Custom AI Voice Keyboard
Personalization
Apple Watch App
Sync & Extensions
graph LR
R[Recording] --> T[Transcription] --> AI[AI Processing] --> S[Storage]
S --> RAG[RAG Index]
RAG --> Chat[Chat & Search]
R -.- R1[AVAudioRecorder<br/>AVAudioEngine]
T -.- T1[WhisperKit · Parakeet<br/>Cloud STT providers]
AI -.- AI1[AIService<br/>20+ providers]
S -.- S1[SwiftData<br/>+ CloudKit]
RAG -.- RAG1[LumoKit/VecturaKit<br/>on-device vectors]
Chat -.- Chat1[Single · Multi · Smart Search]
The app composes a ring of local Swift Package modules (Modules/) under layered, dependency-inverted boundaries: dependencies point inward, consumers depend on protocols (any NetworkService, any AITextProvider, …), and the app target is the composition root that wires the Default* implementations. The transcription stack (TranscriptionCore / CloudTranscription / LocalTranscription / TranscriptionKit) and the AI stack (AICore / AIProviders / AIKit) are two instances of the same shape.
Solid arrow = production code dependency. <Module>Mocks targets always depend on their own <Module> + TestUtilities and are omitted for clarity.
Collapsed view: 21 packages drawn as 9 nodes. Core leaves ×7 = Keychain · Presets · AudioRecording · Analytics · TextProcessing · AppGroup · DesignSystem; Transcription ×2 = CloudTranscription · LocalTranscription; AI adapters ×3 = AIProviders · LocalLLM · OAuth. The app target also depends directly on every core package (composition root). Not drawn: OAuth → Keychain, AIKit → Keychain, TranscriptionKit → Networking, AIKit → Networking, and the external WhisperKit / FluidAudio and LiteRT-LM SDKs. Badges count dependents in the full graph.
graph BT
classDef core fill:#0e2a16,stroke:#7ee787,color:#7ee787
classDef adapter fill:#332306,stroke:#ffa657,color:#ffa657
classDef orchestrator fill:#3b0e26,stroke:#f778ba,color:#f778ba
classDef app fill:#3b0d0d,stroke:#ff7b72,color:#ff7b72
classDef external fill:#1c2128,stroke:#8b949e,color:#8b949e
%% Core
Networking[Networking]:::core
Keychain[Keychain]:::core
Presets[Presets]:::core
TranscriptionCore[TranscriptionCore]:::core
AICore[AICore]:::core
AudioRecording[AudioRecording]:::core
Analytics[Analytics]:::core
TextProcessing[TextProcessing]:::core
AppGroup[AppGroup]:::core
DesignSystem[DesignSystem]:::core
TestUtilities[TestUtilities]:::core
%% Adapters
OAuth[OAuth]:::adapter
CloudTranscription[CloudTranscription]:::adapter
LocalTranscription[LocalTranscription]:::adapter
AIProviders[AIProviders]:::adapter
LocalLLM[LocalLLM]:::adapter
%% Orchestrators
TranscriptionKit[TranscriptionKit]:::orchestrator
AIKit[AIKit]:::orchestrator
%% App
VivaDicta[VivaDicta app + extensions]:::app
%% External
WhisperKit[WhisperKit / FluidAudio]:::external
LiteRT[LiteRT-LM / LiteRTFoundation]:::external
OAuth --> Keychain
OAuth --> Networking
CloudTranscription --> TranscriptionCore
CloudTranscription --> Networking
LocalTranscription --> TranscriptionCore
LocalTranscription --> WhisperKit
AIProviders --> AICore
AIProviders --> Networking
LocalLLM --> AICore
LocalLLM --> LiteRT
TranscriptionKit --> TranscriptionCore
TranscriptionKit --> CloudTranscription
TranscriptionKit --> LocalTranscription
TranscriptionKit --> Networking
AIKit --> AICore
AIKit --> AIProviders
AIKit --> Keychain
AIKit --> OAuth
AIKit --> Networking
VivaDicta --> TranscriptionKit
VivaDicta --> AIKit
VivaDicta --> CloudTranscription
VivaDicta --> LocalTranscription
VivaDicta --> OAuth
VivaDicta --> AIProviders
VivaDicta --> LocalLLM
VivaDicta --> TranscriptionCore
VivaDicta --> AICore
VivaDicta --> Keychain
VivaDicta --> Networking
VivaDicta --> Presets
VivaDicta --> AudioRecording
VivaDicta --> AppGroup
VivaDicta --> Analytics
VivaDicta --> TextProcessing
VivaDicta --> DesignSystem
| Layer | Modules |
|---|---|
| Core (no module deps; protocols + value types) | Networking · Keychain · Presets · TranscriptionCore · AICore · Analytics · TextProcessing · AudioRecording · AppGroup · DesignSystem |
Adapters (protocol + Default impl + Mock) | OAuth · CloudTranscription · LocalTranscription · AIProviders · LocalLLM |
| Orchestrators (compose adapters) | TranscriptionKit · AIKit |
| App (composition root) | VivaDicta + keyboard / widget / share / action / watch targets |
Full breakdown, mocks, and the AI request flow: Module Architecture.
Main app ↔ extensions IPC via AppGroupCoordinator (Darwin Notifications + Shared UserDefaults):
graph LR
K[Keyboard Extension] <-->|Darwin Notifications<br/>Shared UserDefaults| M[Main App]
W[Widget + Live Activity] <--> M
WA[Watch App] <-->|WatchConnectivity<br/>transferFile + sendMessage| M
SE[Share Extension] <--> M
AE[Action Extension] <--> M
On-device RAG pipeline:
graph LR
N[Notes] -->|chunk + embed| VI[Vector Index<br/>LumoKit/VecturaKit]
Q[User Query] -->|embed| VS[Vector Search]
VI --> VS
VS -->|top-k chunks| LLM[LLM Synthesis<br/>Apple FM / Cloud AI]
LLM --> A[Answer + Citations]
Core components:
| Component | Role |
|---|---|
AppGroupCoordinator | Cross-process communication using Darwin Notifications (custom keyboard, widgets, share, action extensions) |
PhoneWatchConnectivityService | WatchConnectivity file reception, mode syncing, background transcription via WatchAudioProcessor |
WatchAppCoordinator | Darwin notifications between watch app and watch widget extension (Control Center, Action Button) |
RecordViewModel | Recording lifecycle, dual audio paths (normal + keyboard prewarm) |
TranscriptionManager | Routes to on-device or cloud STT, post-processing pipeline |
AIService | AI text processing, 20+ providers, OAuth, VivAgents, mode/API key management |
PresetManager | Built-in + custom presets, CloudKit sync |
RAGIndexingService | On-device vector indexing, chunking, semantic search via LumoKit/VecturaKit |
SmartSearchChatViewModel | Smart Search Chat - semantic retrieval + LLM synthesis with source citations |
ChatViewModel | Single-note chat with cross-note search capability |
MultiNoteChatViewModel | Multi-note chat with theme extraction and comparison |
AudioPrewarmManager | Continuous audio engine for keyboard extension low-latency recording |
See the documentation for detailed diagrams and flows.
Requirements:
# Clone
git clone https://github.com/n0an/VivaDicta.git
cd VivaDicta
# Open in Xcode
open VivaDicta.xcodeproj
# Or build from command line
xcodebuild build \
-scheme VivaDicta \
-workspace ./VivaDicta.xcodeproj/project.xcworkspace \
-destination generic/platform=iOS \
CODE_SIGNING_ALLOWED=NO
Note: On-device transcription models (WhisperKit, Parakeet) are downloaded on first use. Cloud AI providers work via API keys, OAuth sign-in (ChatGPT, Gemini, Copilot), or VivAgents server connection.
VivaDicta/
├── VivaDicta/ # Main app target
│ ├── Views/ # SwiftUI views + view models
│ ├── Models/ # SwiftData models (Transcription, Preset, etc.)
│ ├── Services/ # Core services
│ │ ├── AIEnhance/ # AIService, prompts, VivAgents CLI bridge
│ │ ├── Analytics/ # AnalyticsService, MetricKit performance monitoring
│ │ ├── LiveTranslation/# Live translation
│ │ ├── OAuth/ # OAuth sign-in flows
│ │ ├── RAG/ # RAGIndexingService, vector search, chunking
│ │ ├── Reminders/ # AI reminder extraction
│ │ └── Transcription/ # TranscriptionManager, STT routing
│ ├── AppIntents/ # Siri / Shortcuts intents
│ ├── Shared/ # AppGroupCoordinator, shared utilities
│ └── VivaDicta.docc/ # DocC documentation catalog
├── VivaDictaKeyboard/ # Custom keyboard extension
├── VivaDictaWidget/ # Widget + Live Activity
├── ShareExtension/ # Share extension
├── ActionExtension/ # Action extension
├── VivaDictaWatch Watch App/ # watchOS companion app
├── VivaDictaWatchWidget/ # Watch complications + Control Center control
├── VivaDictaTests/ # Unit tests (Swift Testing)
├── Modules/ # Local Swift Package modules (layered, dependency-inverted)
│ ├── AICore/ # AI kernel: AITextProvider, AIProvider enum, errors, filters
│ ├── AIProviders/ # Per-LLM clients + AITextProvider wrappers
│ ├── AIKit/ # AIProviderRegistry, TextEnhancer, CLIServerEnhancer
│ ├── Networking/ # NetworkService + DefaultNetworkService
│ ├── Keychain/ # KeychainService
│ ├── OAuth/ # OAuth managers (ChatGPT / Gemini / Copilot)
│ ├── TranscriptionCore/ # TranscriptionService protocol + value types
│ ├── CloudTranscription/ # Cloud STT provider services
│ ├── LocalTranscription/ # WhisperKit / Parakeet wrappers
│ ├── TranscriptionKit/ # Cloud/local transcription routing
│ ├── AudioRecording/ # AudioRecordingService + AudioFileService
│ ├── Presets/ # Preset domain + management
│ ├── Analytics/ # AnalyticsService protocol + AnalyticsEvent + AnalyticsMocks
│ ├── TextProcessing/ # TextFormatter, TranscriptionOutputFilter, LanguageDetector (pure)
│ └── AppGroup · DesignSystem · TestUtilities
├── documentation/ # Architecture docs, references
└── .github/workflows/ # CI: build check, Claude review, GitGuardian
Contributions are welcome. Please open an issue first to discuss what you'd like to change.
git checkout -b feature/my-feature)git push origin feature/my-feature)The CI will run a build check on your PR automatically.
This project is licensed under the MIT License. See LICENSE for details.
https://github.com/user-attachments/assets/d22f06b3-78f6-4eaf-9026-f11c0ea7bf57
Swift
91.9%
Python
7.3%
iOS & watchOS speech-to-text app with AI voice keyboard, on-device RAG, and chat with your notes - powered by Apple Foundation Models, WhisperKit, NVIDIA Parakeet, and 20+ AI providers
113
stars
3,293
commits
Swift
primary language
Sep 9, 2026
updated
iOS & watchOS speech-to-text app with AI voice keyboard, on-device RAG, and chat with your notes - powered by Apple Foundation Models, WhisperKit, NVIDIA Parakeet, and 20+ AI providers
Website •
App Store •
Documentation
Started as "I don't want to pay for WisprFlow." Ended up building something more flexible — on-device transcription, 20+ AI providers, on-device RAG with chat, OAuth sign-in, CLI agent bridge, and full control over your voice-to-text pipeline.
VivaDicta records speech, transcribes it using on-device or cloud models, and optionally processes the text through an AI provider — including Apple Foundation Models for free, fully on-device AI. Its key feature is a system-wide AI voice keyboard that lets you dictate and AI-process text directly into any app — Messages, WhatsApp, Slack, email, or anything else. The keyboard can also rewrite existing text in any app — select text, apply an AI preset, and get the result in place. Chat with your notes - ask questions about one note or many, powered by on-device RAG pipeline. Smart Search finds notes by meaning with on-device semantic search. Sign in with your ChatGPT, Gemini, or GitHub Copilot account via OAuth, or route AI through CLI agents on your Mac with VivAgents. Supports 11 transcription providers, 20+ AI providers, and syncs across devices (iOS/iPadOS/macOS/watchOS) via CloudKit.
Transcription
AI Presets
Chat & RAG
AI Providers
VivAgents — CLI Agent Bridge
VivaModes
Custom AI Voice Keyboard
Personalization
Apple Watch App
Sync & Extensions
graph LR
R[Recording] --> T[Transcription] --> AI[AI Processing] --> S[Storage]
S --> RAG[RAG Index]
RAG --> Chat[Chat & Search]
R -.- R1[AVAudioRecorder<br/>AVAudioEngine]
T -.- T1[WhisperKit · Parakeet<br/>Cloud STT providers]
AI -.- AI1[AIService<br/>20+ providers]
S -.- S1[SwiftData<br/>+ CloudKit]
RAG -.- RAG1[LumoKit/VecturaKit<br/>on-device vectors]
Chat -.- Chat1[Single · Multi · Smart Search]
The app composes a ring of local Swift Package modules (Modules/) under layered, dependency-inverted boundaries: dependencies point inward, consumers depend on protocols (any NetworkService, any AITextProvider, …), and the app target is the composition root that wires the Default* implementations. The transcription stack (TranscriptionCore / CloudTranscription / LocalTranscription / TranscriptionKit) and the AI stack (AICore / AIProviders / AIKit) are two instances of the same shape.
Solid arrow = production code dependency. <Module>Mocks targets always depend on their own <Module> + TestUtilities and are omitted for clarity.
Collapsed view: 21 packages drawn as 9 nodes. Core leaves ×7 = Keychain · Presets · AudioRecording · Analytics · TextProcessing · AppGroup · DesignSystem; Transcription ×2 = CloudTranscription · LocalTranscription; AI adapters ×3 = AIProviders · LocalLLM · OAuth. The app target also depends directly on every core package (composition root). Not drawn: OAuth → Keychain, AIKit → Keychain, TranscriptionKit → Networking, AIKit → Networking, and the external WhisperKit / FluidAudio and LiteRT-LM SDKs. Badges count dependents in the full graph.
graph BT
classDef core fill:#0e2a16,stroke:#7ee787,color:#7ee787
classDef adapter fill:#332306,stroke:#ffa657,color:#ffa657
classDef orchestrator fill:#3b0e26,stroke:#f778ba,color:#f778ba
classDef app fill:#3b0d0d,stroke:#ff7b72,color:#ff7b72
classDef external fill:#1c2128,stroke:#8b949e,color:#8b949e
%% Core
Networking[Networking]:::core
Keychain[Keychain]:::core
Presets[Presets]:::core
TranscriptionCore[TranscriptionCore]:::core
AICore[AICore]:::core
AudioRecording[AudioRecording]:::core
Analytics[Analytics]:::core
TextProcessing[TextProcessing]:::core
AppGroup[AppGroup]:::core
DesignSystem[DesignSystem]:::core
TestUtilities[TestUtilities]:::core
%% Adapters
OAuth[OAuth]:::adapter
CloudTranscription[CloudTranscription]:::adapter
LocalTranscription[LocalTranscription]:::adapter
AIProviders[AIProviders]:::adapter
LocalLLM[LocalLLM]:::adapter
%% Orchestrators
TranscriptionKit[TranscriptionKit]:::orchestrator
AIKit[AIKit]:::orchestrator
%% App
VivaDicta[VivaDicta app + extensions]:::app
%% External
WhisperKit[WhisperKit / FluidAudio]:::external
LiteRT[LiteRT-LM / LiteRTFoundation]:::external
OAuth --> Keychain
OAuth --> Networking
CloudTranscription --> TranscriptionCore
CloudTranscription --> Networking
LocalTranscription --> TranscriptionCore
LocalTranscription --> WhisperKit
AIProviders --> AICore
AIProviders --> Networking
LocalLLM --> AICore
LocalLLM --> LiteRT
TranscriptionKit --> TranscriptionCore
TranscriptionKit --> CloudTranscription
TranscriptionKit --> LocalTranscription
TranscriptionKit --> Networking
AIKit --> AICore
AIKit --> AIProviders
AIKit --> Keychain
AIKit --> OAuth
AIKit --> Networking
VivaDicta --> TranscriptionKit
VivaDicta --> AIKit
VivaDicta --> CloudTranscription
VivaDicta --> LocalTranscription
VivaDicta --> OAuth
VivaDicta --> AIProviders
VivaDicta --> LocalLLM
VivaDicta --> TranscriptionCore
VivaDicta --> AICore
VivaDicta --> Keychain
VivaDicta --> Networking
VivaDicta --> Presets
VivaDicta --> AudioRecording
VivaDicta --> AppGroup
VivaDicta --> Analytics
VivaDicta --> TextProcessing
VivaDicta --> DesignSystem
| Layer | Modules |
|---|---|
| Core (no module deps; protocols + value types) | Networking · Keychain · Presets · TranscriptionCore · AICore · Analytics · TextProcessing · AudioRecording · AppGroup · DesignSystem |
Adapters (protocol + Default impl + Mock) | OAuth · CloudTranscription · LocalTranscription · AIProviders · LocalLLM |
| Orchestrators (compose adapters) | TranscriptionKit · AIKit |
| App (composition root) | VivaDicta + keyboard / widget / share / action / watch targets |
Full breakdown, mocks, and the AI request flow: Module Architecture.
Main app ↔ extensions IPC via AppGroupCoordinator (Darwin Notifications + Shared UserDefaults):
graph LR
K[Keyboard Extension] <-->|Darwin Notifications<br/>Shared UserDefaults| M[Main App]
W[Widget + Live Activity] <--> M
WA[Watch App] <-->|WatchConnectivity<br/>transferFile + sendMessage| M
SE[Share Extension] <--> M
AE[Action Extension] <--> M
On-device RAG pipeline:
graph LR
N[Notes] -->|chunk + embed| VI[Vector Index<br/>LumoKit/VecturaKit]
Q[User Query] -->|embed| VS[Vector Search]
VI --> VS
VS -->|top-k chunks| LLM[LLM Synthesis<br/>Apple FM / Cloud AI]
LLM --> A[Answer + Citations]
Core components:
| Component | Role |
|---|---|
AppGroupCoordinator | Cross-process communication using Darwin Notifications (custom keyboard, widgets, share, action extensions) |
PhoneWatchConnectivityService | WatchConnectivity file reception, mode syncing, background transcription via WatchAudioProcessor |
WatchAppCoordinator | Darwin notifications between watch app and watch widget extension (Control Center, Action Button) |
RecordViewModel | Recording lifecycle, dual audio paths (normal + keyboard prewarm) |
TranscriptionManager | Routes to on-device or cloud STT, post-processing pipeline |
AIService | AI text processing, 20+ providers, OAuth, VivAgents, mode/API key management |
PresetManager | Built-in + custom presets, CloudKit sync |
RAGIndexingService | On-device vector indexing, chunking, semantic search via LumoKit/VecturaKit |
SmartSearchChatViewModel | Smart Search Chat - semantic retrieval + LLM synthesis with source citations |
ChatViewModel | Single-note chat with cross-note search capability |
MultiNoteChatViewModel | Multi-note chat with theme extraction and comparison |
AudioPrewarmManager | Continuous audio engine for keyboard extension low-latency recording |
See the documentation for detailed diagrams and flows.
Requirements:
# Clone
git clone https://github.com/n0an/VivaDicta.git
cd VivaDicta
# Open in Xcode
open VivaDicta.xcodeproj
# Or build from command line
xcodebuild build \
-scheme VivaDicta \
-workspace ./VivaDicta.xcodeproj/project.xcworkspace \
-destination generic/platform=iOS \
CODE_SIGNING_ALLOWED=NO
Note: On-device transcription models (WhisperKit, Parakeet) are downloaded on first use. Cloud AI providers work via API keys, OAuth sign-in (ChatGPT, Gemini, Copilot), or VivAgents server connection.
VivaDicta/
├── VivaDicta/ # Main app target
│ ├── Views/ # SwiftUI views + view models
│ ├── Models/ # SwiftData models (Transcription, Preset, etc.)
│ ├── Services/ # Core services
│ │ ├── AIEnhance/ # AIService, prompts, VivAgents CLI bridge
│ │ ├── Analytics/ # AnalyticsService, MetricKit performance monitoring
│ │ ├── LiveTranslation/# Live translation
│ │ ├── OAuth/ # OAuth sign-in flows
│ │ ├── RAG/ # RAGIndexingService, vector search, chunking
│ │ ├── Reminders/ # AI reminder extraction
│ │ └── Transcription/ # TranscriptionManager, STT routing
│ ├── AppIntents/ # Siri / Shortcuts intents
│ ├── Shared/ # AppGroupCoordinator, shared utilities
│ └── VivaDicta.docc/ # DocC documentation catalog
├── VivaDictaKeyboard/ # Custom keyboard extension
├── VivaDictaWidget/ # Widget + Live Activity
├── ShareExtension/ # Share extension
├── ActionExtension/ # Action extension
├── VivaDictaWatch Watch App/ # watchOS companion app
├── VivaDictaWatchWidget/ # Watch complications + Control Center control
├── VivaDictaTests/ # Unit tests (Swift Testing)
├── Modules/ # Local Swift Package modules (layered, dependency-inverted)
│ ├── AICore/ # AI kernel: AITextProvider, AIProvider enum, errors, filters
│ ├── AIProviders/ # Per-LLM clients + AITextProvider wrappers
│ ├── AIKit/ # AIProviderRegistry, TextEnhancer, CLIServerEnhancer
│ ├── Networking/ # NetworkService + DefaultNetworkService
│ ├── Keychain/ # KeychainService
│ ├── OAuth/ # OAuth managers (ChatGPT / Gemini / Copilot)
│ ├── TranscriptionCore/ # TranscriptionService protocol + value types
│ ├── CloudTranscription/ # Cloud STT provider services
│ ├── LocalTranscription/ # WhisperKit / Parakeet wrappers
│ ├── TranscriptionKit/ # Cloud/local transcription routing
│ ├── AudioRecording/ # AudioRecordingService + AudioFileService
│ ├── Presets/ # Preset domain + management
│ ├── Analytics/ # AnalyticsService protocol + AnalyticsEvent + AnalyticsMocks
│ ├── TextProcessing/ # TextFormatter, TranscriptionOutputFilter, LanguageDetector (pure)
│ └── AppGroup · DesignSystem · TestUtilities
├── documentation/ # Architecture docs, references
└── .github/workflows/ # CI: build check, Claude review, GitGuardian
Contributions are welcome. Please open an issue first to discuss what you'd like to change.
git checkout -b feature/my-feature)git push origin feature/my-feature)The CI will run a build check on your PR automatically.
This project is licensed under the MIT License. See LICENSE for details.
https://github.com/user-attachments/assets/d22f06b3-78f6-4eaf-9026-f11c0ea7bf57
Swift
91.9%
Python
7.3%