How Meetily Re-Transcribes Existing Recordings: The Import & Enhance Pipeline

Meetily re-transcribes existing recordings by executing the start_retranscription_command, which re-runs the full audio processing pipeline—decoding, Voice-Activity Detection, and transcription—on the original meeting audio while overwriting previous transcripts and updating metadata with a retranscribed_at timestamp.

Meetily by Zackriya-Solutions is an open-source meeting transcription tool that enables users to re-transcribe existing recordings through its Import & Enhance architecture. While the Import flow creates new meetings from external audio files, the Enhance functionality specifically targets existing meetings to apply new transcription models, languages, or AI providers (such as switching from Whisper to Parakeet). Both capabilities leverage a shared Rust-based backend pipeline in the Tauri layer that handles file validation, audio decoding, and database persistence.

Architecture: Import vs. Enhance

The Import & Enhance feature operates through two distinct entry points that share a common processing core:

Only the Import command initializes new filesystem structures and database entries. The Enhance command—which handles re-transcription—works in-place on the existing meeting path.

The Re-Transcription Pipeline

When enhancing an existing recording, Meetily executes six distinct stages originally defined in run_import but invoked via start_retranscription:

1. Audio Loading (No Copy)

Unlike Import, the retranscription flow skips file selection and copying. It directly accesses the audio file stored in the existing meeting folder, avoiding duplicate storage and validating that the source audio remains available.

2. Decoding and Resampling

The pipeline calls decode_audio_file_with_progress followed by to_whisper_format_with_progress to convert the source audio to 16 kHz mono PCM—a strict requirement for both Whisper and Parakeet transcription engines. Progress events are emitted at this stage to keep the frontend responsive.

3. Voice-Activity Detection (VAD)

The ContinuousVadProcessor in frontend/src-tauri/src/audio/vad.rs processes the raw audio using Silero VAD with parameters tuned for batch processing:

  • Redemption time: 2,000 ms to keep natural pauses within utterances intact
  • Minimum speech time: 250 ms to filter out noise fragments that would violate Whisper's constraints

4. Segmentation and Splitting

Long speech chunks exceeding 25 seconds are automatically split at silence boundaries using split_segment_at_silence, ensuring compliance with Whisper's 100 ms minimum-segment rule while maintaining contextual coherence.

5. Transcription with New Parameters

The system initializes the requested engine via get_or_init_whisper or get_or_init_parakeet (both defined in import.rs) and transcribes each segment with the new language and model configuration provided by the user. Confidence scores are accumulated across all segments to populate the database.

6. Metadata and Database Updates

After transcription, write_retranscription_metadata updates metadata.json with a timestamp:

obj.insert("retranscribed_at".to_string(), serde_json::json!(now));
obj.insert("status".to_string(), serde_json::json!("completed"));

The SQLite database receives updated transcript rows via create_meeting_with_transcripts, replacing the previous transcription entirely while preserving the original audio file and meeting structure.

Implementation: Frontend Commands

Invoking Retranscription from TypeScript

To re-transcribe an existing meeting with different parameters:

import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';

async function retranscribeRecording(
  meetingId: string, 
  folderPath: string
) {
  // Switch to Spanish and use a larger model for better accuracy
  await invoke('start_retranscription_command', {
    meeting_id: meetingId,
    meeting_folder_path: folderPath,
    language: 'es',
    model: 'large-v3',
    provider: 'whisper' // or 'parakeet'
  });
}

// Monitor progress
listen('retranscription-progress', (e) => {
  const { stage, progress_percentage, message } = e.payload;
  console.log(`Retranscription: [${stage}] ${progress_percentage}%`);
});

Importing New Audio (for comparison)

For creating new meetings (not re-transcribing):

const info = await invoke('select_and_validate_audio_command');
if (info) {
  await invoke('start_import_audio_command', {
    source_path: info.path,
    title: info.filename,
    language: 'en',
    provider: 'whisper'
  });
}

Cancellation and Progress Tracking

Both import and retranscription operations implement atomic cancellation flags:

static IMPORT_IN_PROGRESS: AtomicBool;
static IMPORT_CANCELLED: AtomicBool;
static RETRANSCRIPTION_IN_PROGRESS: AtomicBool;
static RETRANSCRIPTION_CANCELLED: AtomicBool;

The frontend can query status via is_import_in_progress_command or is_retranscription_in_progress_command, and trigger cancellation through cancel_import_command or cancel_retranscription_command. Progress events (import-progress, retranscription-progress, retranscription-complete) emit granular updates including current stage and percentage completion.

Summary

  • Meetily re-transcribes existing recordings through the start_retranscription_command in frontend/src-tauri/src/audio/retranscription.rs, which re-executes the full audio pipeline while preserving the original meeting folder.
  • The pipeline requires 16 kHz mono PCM audio and uses Silero VAD with a 2-second redemption time to isolate speech chunks before splitting long segments at 25-second boundaries.
  • Retranscription overwrites previous transcripts in the SQLite database and updates metadata.json with a retranscribed_at timestamp, enabling users to switch between Whisper and Parakeet providers or change transcription languages without losing the original audio.
  • Global atomic flags and Tauri event emitters provide real-time progress tracking and cancellation support for long-running transcription jobs.

Frequently Asked Questions

How does Meetily handle transcription model switching when re-transcribing?

Meetily re-initializes the transcription engine with the new model parameters via get_or_init_whisper or get_or_init_parakeet in frontend/src-tauri/src/audio/import.rs. The system loads the selected model into memory (if not already cached) and processes the existing audio through the new engine, storing fresh transcripts that replace the previous version in the database.

Can users cancel an in-progress retranscription job without corrupting the meeting data?

Yes. Meetily uses an atomic RETRANSCRIPTION_CANCELLED flag checked at each pipeline stage. When cancel_retranscription_command is invoked, the flag triggers an early return before database commits occur, leaving the original transcripts intact. The UI listens for retranscription-error events to display cancellation status.

What happens to the original transcripts when Meetily re-transcribes a recording?

The original transcripts are completely overwritten. The create_meeting_with_transcripts function replaces the existing database rows, and write_retranscription_metadata updates the metadata.json file with a retranscribed_at field. Meetily currently does not maintain transcript history; the last re-transcription becomes the active version.

Does re-transcription require the original audio file to remain in the meeting folder?

Yes. The start_retranscription function reads the audio directly from the existing meeting folder path provided by the frontend. If the audio file has been moved or deleted from the meeting directory, the retranscription command will fail during the decoding stage with a file-not-found error.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →