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].transcriptDiaryzacja 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:
raiseWybó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
- Speech-to-Text z Whisper i Deepgram
- Text-to-Speech w odpowiedziach agenta
- Tworzenie pętli konwersacji głosowej
- Optymalizacja opóźnień agentów głosowych