0Pricing
AI Agents · Lekcja

Speech-to-Text z Whisper i Deepgram

Transkrypcja w czasie rzeczywistym i wsadowa, wykrywanie języka oraz interpunkcja.

Speech-to-Text z Whisper i Deepgram to bezpłatna lekcja AI Agents na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Agents, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Agents zawiera 4 lekcji w sumie.

Zamiana mowy na tekst w agentach głosowych

Agent głosowy musi przekonwertować dźwięk mowy na tekst, zanim model LLM będzie mógł go przetworzyć. Ten etap nazywa się zamianą mowy na tekst (STT) lub automatycznym rozpoznawaniem mowy (ASR).

Dwie wiodące opcje to: OpenAI Whisper (przetwarzanie wsadowe oparte na plikach) oraz Deepgram (strumieniowanie w czasie rzeczywistym, diaryzacja mówców i znaczniki czasu słów).

OpenAI Whisper: podstawowa transkrypcja

Whisper za pośrednictwem interfejsu API OpenAI transkrybuje pliki audio. Obsługiwane formaty: mp3, mp4, wav, webm, m4a, flac. Maksymalny rozmiar pliku: 25 MB.

import openai
import os

client = openai.OpenAI(api_key=os.getenv('OPENAI_API_KEY'))

def transcribe_file(audio_path, language=None):
    with open(audio_path, 'rb') as audio_file:
        params = {
            'model': 'whisper-1',
            'file': audio_file,
            'response_format': 'json'  # or 'text', 'srt', 'vtt', 'verbose_json'
        }
        if language:
            params['language'] = language  # e.g., 'en', 'fr', 'de'

        transcript = client.audio.transcriptions.create(**params)

    return transcript.text

# Basic usage
text = transcribe_file('meeting_recording.mp3')
print('Transcribed:', text[:200])

Whisper ze znacznikami czasu słów

Proszę użyć response_format='verbose_json', aby uzyskać znaczniki czasu dla każdego słowa i segmentu. Jest to przydatne do znajdowania konkretnych momentów w nagraniach, podświetlania tekstu w stylu karaoke oraz synchronizowania transkrypcji z odtwarzanym dźwiękiem.

import openai
import os

client = openai.OpenAI(api_key=os.getenv('OPENAI_API_KEY'))

def transcribe_with_timestamps(audio_path):
    with open(audio_path, 'rb') as f:
        result = client.audio.transcriptions.create(
            model='whisper-1',
            file=f,
            response_format='verbose_json',
            timestamp_granularities=['word', 'segment']  # get both word and segment times
        )

    segments = []
    for seg in result.segments:
        segments.append({
            'start': seg.start,
            'end':   seg.end,
            'text':  seg.text
        })

    words = []
    if hasattr(result, 'words'):
        for word in result.words:
            words.append({'word': word.word, 'start': word.start, 'end': word.end})

    return {'text': result.text, 'segments': segments, 'words': words}

Deepgram SDK: asynchroniczne strumieniowanie

Deepgram jest zoptymalizowany pod kątem strumieniowej transkrypcji w czasie rzeczywistym. Dźwięk jest wysyłany we fragmentach w miarę nagrywania, a częściowe transkrypcje są zwracane, zanim mówca skończy zdanie.

Instalacja: pip install deepgram-sdk.

import asyncio
import os
from deepgram import DeepgramClient, PrerecordedOptions

client = DeepgramClient(os.getenv('DEEPGRAM_API_KEY'))

async def transcribe_with_deepgram(audio_path):
    with open(audio_path, 'rb') as f:
        audio_data = f.read()

    options = PrerecordedOptions(
        model='nova-2',            # Deepgram's best accuracy model
        language='en',
        smart_format=True,         # auto-add punctuation and formatting
        utterances=True,           # segment by speaker turns
        punctuate=True,
        diarize=True               # speaker identification
    )

    response = await client.listen.asyncrest.v('1').transcribe_file(
        {'buffer': audio_data},
        options
    )

    return response.results.channels[0].alternatives[0].transcript

Diaryzacja mówców

Diaryzacja określa, kto i kiedy mówi, oznaczając segmenty jako Speaker 0, Speaker 1 itd. Jest kluczowa w przypadku transkrypcji spotkań i rozmów wieloosobowych.

async def transcribe_with_diarization(audio_path):
    from deepgram import DeepgramClient, PrerecordedOptions
    import os

    dg_client = DeepgramClient(os.getenv('DEEPGRAM_API_KEY'))

    options = PrerecordedOptions(
        model='nova-2',
        diarize=True,
        utterances=True,
        smart_format=True
    )

    with open(audio_path, 'rb') as f:
        audio_data = f.read()

    response = await dg_client.listen.asyncrest.v('1').transcribe_file(
        {'buffer': audio_data}, options
    )

    utterances = []
    for utt in response.results.utterances:
        utterances.append({
            'speaker': f'Speaker {utt.speaker}',
            'start':   round(utt.start, 2),
            'end':     round(utt.end, 2),
            'text':    utt.transcript
        })

    return utterances

# Output:
# [{'speaker': 'Speaker 0', 'start': 0.0, 'end': 3.2, 'text': 'Hello everyone.'},
#  {'speaker': 'Speaker 1', 'start': 3.5, 'end': 6.1, 'text': 'Good morning!'}]

Wykrywanie języka

Gdy język użytkownika jest nieznany, zarówno Whisper, jak i Deepgram mogą automatycznie wykryć język mówiony. Whisper wykrywa język na podstawie pierwszych 30 sekund dźwięku.

import openai
import os

client = openai.OpenAI(api_key=os.getenv('OPENAI_API_KEY'))

def detect_language(audio_path):
    with open(audio_path, 'rb') as f:
        # Use translations endpoint to get verbose JSON with language detection
        result = client.audio.transcriptions.create(
            model='whisper-1',
            file=f,
            response_format='verbose_json'
        )
    return {
        'detected_language': result.language,
        'text': result.text
    }

result = detect_language('user_audio.wav')
print(f"Language: {result['detected_language']}")
print(f"Text: {result['text'][:100]}")

# Deepgram: set language='auto' in options
from deepgram import PrerecordedOptions
options = PrerecordedOptions(model='nova-2', language='auto', detect_language=True)

Dzielenie długich plików audio na fragmenty

Limit 25 MB w Whisper oznacza, że długie nagrania, takie jak godzinne spotkania, wymagają podziału na fragmenty. Proszę podzielić dźwięk według ciszy za pomocą biblioteki pydub, a następnie dokonać transkrypcji każdego fragmentu i połączyć wyniki.

Instalacja: pip install pydub. Wymaga ffmpeg.

from pydub import AudioSegment
from pydub.silence import split_on_silence
import io

def transcribe_long_audio(audio_path, chunk_length_ms=60000):
    audio = AudioSegment.from_file(audio_path)

    # Split on silence
    chunks = split_on_silence(
        audio,
        min_silence_len=1000,   # 1 second of silence
        silence_thresh=-40,     # dBFS
        keep_silence=500        # keep 500ms at each end
    )

    # If no silence splitting worked, use fixed-length chunks
    if len(chunks) <= 1:
        chunks = [
            audio[i:i + chunk_length_ms]
            for i in range(0, len(audio), chunk_length_ms)
        ]

    full_transcript = []
    for i, chunk in enumerate(chunks):
        print(f'Transcribing chunk {i+1}/{len(chunks)}')
        buf = io.BytesIO()
        chunk.export(buf, format='mp3')
        buf.seek(0)
        buf.name = f'chunk_{i}.mp3'
        result = client.audio.transcriptions.create(model='whisper-1', file=buf)
        full_transcript.append(result.text)

    return ' '.join(full_transcript)

Strumieniowanie na żywo z Deepgram

W przypadku rozmów głosowych w czasie rzeczywistym proszę użyć interfejsu API Deepgram do strumieniowania na żywo przez WebSocket. Fragmenty dźwięku są wysyłane w miarę nagrywania, a wstępne i końcowe transkrypcje docierają w ciągu kilku milisekund.

import asyncio
import os
from deepgram import DeepgramClient, LiveTranscriptionEvents, LiveOptions

async def live_transcribe(on_transcript_callback):
    dg_client = DeepgramClient(os.getenv('DEEPGRAM_API_KEY'))

    connection = dg_client.listen.asynclive.v('1')

    async def on_message(self, result, **kwargs):
        sentence = result.channel.alternatives[0].transcript
        is_final = result.is_final
        if sentence:
            await on_transcript_callback(sentence, is_final)

    connection.on(LiveTranscriptionEvents.Transcript, on_message)

    options = LiveOptions(
        model='nova-2',
        language='en',
        smart_format=True,
        interim_results=True,  # get partial results before sentence ends
        endpointing=500        # ms of silence before finalizing
    )

    await connection.start(options)
    return connection  # caller sends audio chunks via connection.send(audio_chunk)

Obsługa błędów i ponawianie prób

Interfejsy API do transkrypcji dźwięku mogą zawodzić z powodu problemów z siecią, nieobsługiwanych formatów lub limitów szybkości. Należy zaimplementować ponawianie prób z wykładniczym opóźnieniem oraz sprawdzać poprawność dźwięku przed jego wysłaniem.

import time
import os

MAX_FILE_SIZE_BYTES = 25 * 1024 * 1024  # 25MB
SUPPORTED_FORMATS = ('.mp3', '.mp4', '.wav', '.webm', '.m4a', '.flac', '.ogg')

def validate_audio_file(audio_path):
    if not os.path.exists(audio_path):
        raise FileNotFoundError(f'Audio file not found: {audio_path}')
    size = os.path.getsize(audio_path)
    if size > MAX_FILE_SIZE_BYTES:
        raise ValueError(f'File too large: {size / 1024 / 1024:.1f}MB (max 25MB)')
    ext = os.path.splitext(audio_path)[1].lower()
    if ext not in SUPPORTED_FORMATS:
        raise ValueError(f'Unsupported format: {ext}. Supported: {SUPPORTED_FORMATS}')

def transcribe_with_retry(audio_path, max_retries=3):
    validate_audio_file(audio_path)
    for attempt in range(max_retries):
        try:
            return transcribe_file(audio_path)
        except Exception as e:
            if attempt < max_retries - 1:
                wait = 2 ** attempt
                print(f'Retry {attempt + 1} after error: {e}. Waiting {wait}s')
                time.sleep(wait)
            else:
                raise

Wybór między Whisper a Deepgram

Oba narzędzia sprawdzają się w różnych scenariuszach. Proszę użyć poniższej macierzy decyzyjnej, aby wybrać odpowiednie narzędzie dla agenta głosowego.

COMPARISON = '''
Whisper (OpenAI API):
  - Best for: batch transcription, podcast processing, meeting notes
  - Latency: file upload latency + ~1-5 seconds processing
  - Strengths: excellent multilingual, high accuracy, cheap
  - Word timestamps: yes (verbose_json)
  - Diarization: NO (must use separate tool)
  - Use when: accuracy > speed, offline processing

DeeGram:
  - Best for: real-time voice agents, call center transcription
  - Latency: <300ms for streaming, ~1s for file upload
  - Strengths: streaming, diarization, custom vocabulary
  - Word timestamps: yes, with confidence scores
  - Diarization: YES (built-in, up to 10 speakers)
  - Use when: speed > accuracy, real-time required

Rule of thumb:
  Agent voice conversation -> Deepgram live streaming
  Batch audio files -> Whisper API
  Meeting transcripts with speakers -> Deepgram with diarize=True
'''
print(COMPARISON)

Konwersja formatu audio

Whisper i Deepgram obsługują popularne formaty audio, ale dźwięk użytkownika może być dostarczany w nietypowych formatach (ogg, opus, webm z przeglądarek, m4a z systemu iOS). Przed wysłaniem dźwięku do interfejsu API należy przekonwertować go do standardowego formatu WAV lub MP3.

from pydub import AudioSegment
import os

SUPPORTED_FORMATS = {'.mp3', '.wav', '.flac', '.m4a', '.ogg', '.webm', '.opus'}

def convert_to_wav(input_path, output_path=None):
    ext = os.path.splitext(input_path)[1].lower()
    if ext not in SUPPORTED_FORMATS:
        raise ValueError(f'Unsupported audio format: {ext}')

    if output_path is None:
        output_path = input_path.rsplit('.', 1)[0] + '.wav'

    # pydub handles format detection automatically
    audio = AudioSegment.from_file(input_path)

    # Normalize to 16kHz mono (optimal for Whisper)
    audio = audio.set_frame_rate(16000).set_channels(1)

    audio.export(output_path, format='wav')
    print(f'Converted {input_path} -> {output_path} ({len(audio) / 1000:.1f}s)')
    return output_path

def ensure_compatible_audio(audio_path):
    ext = os.path.splitext(audio_path)[1].lower()
    if ext in {'.mp3', '.wav', '.m4a', '.flac'}:
        return audio_path  # already compatible
    return convert_to_wav(audio_path)

Sprawdzenie wiedzy

Czym jest diaryzacja mówców w kontekście transkrypcji mowy na tekst?

Podsumowanie: zamiana mowy na tekst za pomocą Whisper i Deepgram

Whisper (interfejs API OpenAI) doskonale nadaje się do transkrypcji wsadowej — zapewnia wysoką dokładność i obsługę wielu języków, a za pomocą verbose_json także znaczniki czasu słów. Należy używać go do przetwarzania opartego na plikach, gdy opóźnienie nie ma kluczowego znaczenia.

Deepgram został zaprojektowany z myślą o strumieniowaniu w czasie rzeczywistym — oferuje transkrypcję na żywo przez WebSocket z wynikami wstępnymi, wbudowaną diaryzacją mówców i opóźnieniem poniżej 300 ms. Należy używać go w przypadku interaktywnych agentów głosowych. Oba narzędzia obsługują wykrywanie języka, a w środowisku produkcyjnym wymagają mechanizmu ponawiania prób i sprawdzania poprawności plików.

Często zadawane pytania

Czy lekcja „Speech-to-Text z Whisper i Deepgram” jest bezpłatna?

Tak — pełny tekst „Speech-to-Text z Whisper i Deepgram” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Agents, przejdź na CoddyKit PRO. Kurs AI Agents zawiera 4 lekcji w sumie.

Co nauczysz się w „Speech-to-Text z Whisper i Deepgram”?

Transkrypcja w czasie rzeczywistym i wsadowa, wykrywanie języka oraz interpunkcja. Ćwiczysz AI Agents z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć AI Agents?

Nie wymagamy żadnego doświadczenia. AI Agents w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Speech-to-Text z Whisper i Deepgram”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji AI Agents?

Tak. Każda lekcja AI Agents zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Speech-to-Text z Whisper i Deepgram
  2. Text-to-Speech w odpowiedziach agenta
  3. Tworzenie pętli konwersacji głosowej
  4. Optymalizacja opóźnień agentów głosowych
← Powrót do AI Agents