Architecture
VoiceTypr uses a Tauri v2 architecture with:- Rust Backend: Handles audio recording, transcription, model management, and system integration
- React 19 Frontend: Provides UI components and state management using hooks
- IPC Communication: Frontend calls backend via
invoke(), backend emits events to frontend
Communication Flow
Copy
Ask AI
import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';
// Call a Tauri command
const result = await invoke('start_recording');
// Listen to backend events
const unlisten = await listen('recording-started', (event) => {
console.log('Recording started:', event.payload);
});
```typescript
## Using Tauri Commands
Tauri commands are Rust functions exposed to the frontend via `invoke()`:
```typescript
import { invoke } from '@tauri-apps/api/core';
// Simple command (no parameters)
await invoke('start_recording');
// Command with parameters
await invoke('download_model', {
modelName: 'base.en'
});
// Command with return value
const settings = await invoke<AppSettings>('get_settings');
```typescript
### Error Handling
All commands return `Result<T, String>` in Rust, which becomes a Promise in TypeScript:
```typescript
try {
await invoke('start_recording');
} catch (error) {
console.error('Failed to start recording:', error);
// error is a string with the error message
}
```typescript
## Using React Hooks
VoiceTypr provides custom hooks that encapsulate Tauri commands and event handling:
```typescript
import { useRecording } from '@/hooks/useRecording';
function RecordingButton() {
const { state, startRecording, stopRecording } = useRecording();
return (
<button onClick={startRecording} disabled={state !== 'idle'}>
{state === 'recording' ? 'Recording...' : 'Start Recording'}
</button>
);
}
```typescript
### Hook Benefits
- Automatic state synchronization with backend
- Built-in event listener cleanup
- Type-safe TypeScript interfaces
- React-friendly state management
## Event System
The backend emits events that the frontend can listen to:
### Core Events
| Event | Payload | Description |
|-------|---------|-------------|
| `recording-state-changed` | `{ state: RecordingState, error?: string }` | Recording state transitions |
| `download-progress` | `{ model: string, progress: number, downloaded: number, total: number }` | Model download progress |
| `model-downloaded` | `{ model: string, engine: string }` | Model download complete |
| `transcription-complete` | `{ text: string }` | Transcription finished |
### Event Listeners
```typescript
import { listen } from '@tauri-apps/api/event';
const unlisten = await listen('recording-state-changed', (event) => {
console.log('New state:', event.payload.state);
});
// Clean up when component unmounts
return () => {
unlisten();
};
```typescript
## API Categories
<CardGroup cols={2}>
<Card title="Audio Commands" icon="microphone" href="/api/commands/audio">
Recording, transcription, and audio device management
</Card>
<Card title="Model Commands" icon="download" href="/api/commands/model">
Download, delete, and manage speech recognition models
</Card>
<Card title="AI Commands" icon="sparkles" href="/api/commands/ai">
AI-powered transcription enhancement and provider management
</Card>
<Card title="Settings Commands" icon="sliders" href="/api/commands/settings">
Application settings and configuration management
</Card>
<Card title="Recording Hook" icon="circle-dot" href="/api/hooks/recording">
React hook for recording state and controls
</Card>
<Card title="Model Management Hook" icon="boxes-stacked" href="/api/hooks/model-management">
React hook for managing speech recognition models
</Card>
<Card title="Permission Hooks" icon="shield-check" href="/api/hooks/permissions">
React hooks for system permissions (microphone, accessibility)
</Card>
</CardGroup>
## Type Definitions
### RecordingState
```typescript
type RecordingState = 'idle' | 'starting' | 'recording' | 'stopping' | 'transcribing' | 'error';
```typescript
### AppSettings
See [Settings Commands](/api/commands/settings) for the complete AppSettings interface.
### ModelInfo
```typescript
interface ModelInfo {
name: string;
display_name: string;
size: number;
downloaded: boolean;
engine: 'whisper' | 'parakeet' | 'soniox';
kind: 'local' | 'cloud';
recommended: boolean;
speed_score: number;
accuracy_score: number;
}
```typescript
## Best Practices
### 1. Use Hooks for Components
Prefer React hooks over direct `invoke()` calls in components:
```typescript
// Good: Uses hook with automatic cleanup
const { state, startRecording } = useRecording();
// Avoid: Manual command + event management
const start = () => invoke('start_recording');
```typescript
### 2. Handle Loading States
Always handle loading and error states:
```typescript
const { models, isLoading } = useModelManagement();
if (isLoading) {
return <LoadingSpinner />;
}
```typescript
### 3. Clean Up Event Listeners
Always clean up event listeners in useEffect:
```typescript
useEffect(() => {
const unlisten = listen('event-name', handler);
return () => {
unlisten.then(fn => fn());
};
}, []);
```typescript
### 4. Use Type Safety
Leverage TypeScript types for commands:
```typescript
interface DownloadModelArgs {
modelName: string;
}
await invoke<void>('download_model', {
modelName: 'base.en'
} as DownloadModelArgs);
```typescript
## Next Steps
<CardGroup cols={2}>
<Card title="Audio Commands" icon="arrow-right" href="/api/commands/audio">
Start with audio recording and transcription
</Card>
<Card title="Recording Hook" icon="arrow-right" href="/api/hooks/recording">
Build a recording interface with React
</Card>
</CardGroup>