LocalAI ile Whisper Ses Tanıma Entegrasyonu
Ses dosyalarını sunucuda işlemek, transkript almak, konuşmaları metne çevirmek… Bunlar bir zamanlar sadece büyük cloud servislerine para ödeyerek yapabildiğimiz şeylerdi. OpenAI Whisper modelinin açık kaynak olarak yayınlanması ve LocalAI projesinin bunu desteklemesiyle birlikte artık kendi sunucumuzda, tamamen offline, sıfır maliyet ile profesyonel kalitede ses tanıma yapabiliyoruz. Bu yazıda LocalAI üzerinde Whisper entegrasyonunu baştan sona kuracağız, production ortamı için optimize edeceğiz ve gerçek dünya senaryolarında nasıl kullanacağımızı göreceğiz.
LocalAI ve Whisper Nedir, Neden Önemli?
LocalAI, OpenAI API’siyle uyumlu bir arayüz sunarak farklı açık kaynak modellerini tek bir çatı altında çalıştırmanı sağlayan bir proje. Whisper ise OpenAI’ın geliştirdiği, çok dilli ses tanıma konusunda son derece başarılı bir model. İkisini bir araya getirdiğinde elimizde oldukça güçlü bir araç seti oluşuyor.
Neden kendi sunucunda çalıştırmak istersin?
- Veri gizliliği: Müşteri görüşmeleri, toplantı kayıtları veya hassas ses içerikleri üçüncü parti servislere gönderilmiyor
- Maliyet: OpenAI Whisper API’si dakika başına ücret alıyor, kendi sunucunda bu sıfır
- Offline çalışma: İnternet bağlantısı olmayan ortamlarda bile çalışıyor
- Özelleştirme: Model parametrelerini tam kontrol edebiliyorsun
- Latency: Yerel ağda API çağrısı yapınca gecikme dramatik biçimde düşüyor
Sistem Gereksinimleri ve Hazırlık
Ben bu kurulumu Ubuntu 22.04 LTS üzerinde yaptım. Whisper modelleri CPU’da da çalışıyor ama makul hız için ya iyi bir CPU’ya ya da NVIDIA GPU’ya ihtiyaç var.
Minimum donanım gereksinimleri şöyle:
- CPU modu: 4 core, 8 GB RAM (whisper-base veya small model için)
- GPU modu: NVIDIA GPU, 4 GB VRAM (medium model için), 8 GB VRAM (large model için)
- Disk: Model dosyaları için en az 10 GB boş alan
Önce sistemin güncel olduğundan emin olalım:
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget git ffmpeg build-essential
FFmpeg burada kritik, çünkü LocalAI ses dosyalarını işlerken FFmpeg’i kullanıyor. Kurulu olmadığında transkripsiyon işlemleri hata veriyor.
Docker Compose ile kurulum yapacağız, bu en temiz yol:
sudo apt install -y docker.io docker-compose-plugin
sudo systemctl enable --now docker
sudo usermod -aG docker $USER
newgrp docker
LocalAI Kurulumu ve Whisper Yapılandırması
LocalAI için çalışma dizini oluşturalım ve gerekli klasör yapısını hazırlayalım:
mkdir -p /opt/localai/{models,config}
cd /opt/localai
Şimdi docker-compose.yml dosyasını oluşturalım. GPU’nuz varsa GPU versiyonunu, yoksa CPU versiyonunu kullanın:
cat > /opt/localai/docker-compose.yml << 'EOF'
version: '3.8'
services:
localai:
image: localai/localai:latest-aio-cpu
# GPU kullanmak icin asagidaki image'i kullanin:
# image: localai/localai:latest-aio-gpu-nvidia-cuda-12
container_name: localai
restart: unless-stopped
ports:
- "8080:8080"
environment:
- MODELS_PATH=/models
- DEBUG=false
- THREADS=4
- CONTEXT_SIZE=512
volumes:
- /opt/localai/models:/models
- /opt/localai/config:/config
# GPU icin asagidaki blogu aktif edin:
# deploy:
# resources:
# reservations:
# devices:
# - driver: nvidia
# count: 1
# capabilities: [gpu]
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/readyz"]
interval: 30s
timeout: 10s
retries: 3
EOF
Container’ı başlatmadan önce Whisper model yapılandırma dosyasını oluşturalım:
cat > /opt/localai/config/whisper.yaml << 'EOF'
name: whisper-1
backend: whisper
parameters:
model: ggml-whisper-medium.bin
language: tr
translate: false
no_timestamps: false
word_timestamps: true
threads: 4
beam_size: 5
best_of: 5
temperature: 0
entropy_treshold: 2.4
log_prob_treshold: -1.0
no_speech_treshold: 0.6
EOF
Buradaki parametreleri biraz açıklayalım:
- language: tr: Türkçe için optimize edilmiş tanıma, boş bırakırsan otomatik dil tespiti yapar
- translate: false: True yaparsanız çıktıyı İngilizceye çevirir, biz direkt Türkçe istiyoruz
- word_timestamps: Kelime bazında zaman damgası ekler, altyazı üretmek için çok kullanışlı
- temperature: 0: Deterministik çıktı için, her seferinde aynı sonucu alırsın
- beam_size: Yüksek değer daha iyi doğruluk ama daha yavaş işleme
- no_speech_treshold: Bu değerin üzerinde “sessizlik” olarak sınıflandırılan segmentler atlanır
Model İndirme
Whisper modelleri GGML formatında gerekiyor. Hugging Face veya doğrudan GitHub üzerinden indirebilirsin:
cd /opt/localai/models
# Base model - hizli ama dusuk dogruluk
wget https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.bin
# Medium model - iyi denge
wget https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-medium.bin
# Large-v3 model - en yuksek dogruluk, en yavas
wget https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3.bin
Model boyutları referans olarak:
- ggml-tiny.bin: 75 MB, çok hızlı, düşük doğruluk
- ggml-base.bin: 142 MB, hızlı, orta doğruluk
- ggml-small.bin: 466 MB, dengeli
- ggml-medium.bin: 1.5 GB, iyi doğruluk, kabul edilebilir hız
- ggml-large-v3.bin: 3.1 GB, en yüksek doğruluk, yavaş
Türkçe için minimum medium model öneririm. Tiny ve base modeller Türkçede ciddi sorunlar yaşayabiliyor.
Servisi Başlatma ve Test
Her şey hazırsa servisi başlatalım:
cd /opt/localai
docker compose up -d
# Loglari takip et
docker compose logs -f localai
Servis hazır olduğunda bir test yapalım. Önce küçük bir test ses dosyası oluşturalım:
# ffmpeg ile test ses dosyasi olustur (TTS olmadan test icin)
# Gerçek bir ses dosyaniz varsa onu kullanin
curl -X POST http://localhost:8080/v1/audio/transcriptions
-H "Content-Type: multipart/form-data"
-F "file=@/path/to/your/audio.mp3"
-F "model=whisper-1"
-F "language=tr"
-F "response_format=json"
Başarılı bir yanıt şöyle görünür:
{
"text": "Merhaba, bu bir test kaydıdır. Ses tanıma sistemi çalışıyor.",
"segments": [
{
"start": 0.0,
"end": 4.2,
"text": "Merhaba, bu bir test kaydıdır."
}
]
}
Gerçek Dünya Senaryosu 1: Toplantı Transkripsiyon Sistemi
Diyelim ki şirketin düzenli olarak Zoom veya Teams toplantıları yapıyor ve bunları otomatik olarak metne çevirmek istiyorsun. Bunun için bir bash script yazalım:
#!/bin/bash
# /usr/local/bin/transcribe-meeting.sh
LOCALAI_URL="http://localhost:8080"
INPUT_DIR="/var/recordings"
OUTPUT_DIR="/var/transcripts"
LOG_FILE="/var/log/transcription.log"
MODEL="whisper-1"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
process_audio() {
local audio_file="$1"
local filename=$(basename "$audio_file" | sed 's/.[^.]*$//')
local output_file="$OUTPUT_DIR/${filename}.txt"
local json_file="$OUTPUT_DIR/${filename}.json"
log "Isleniyor: $audio_file"
# Once WAV formatina donustur, daha iyi uyumluluk icin
local temp_wav="/tmp/${filename}_temp.wav"
ffmpeg -i "$audio_file" -ar 16000 -ac 1 -c:a pcm_s16le "$temp_wav" -y 2>/dev/null
if [ $? -ne 0 ]; then
log "HATA: Ses donusturme basarisiz: $audio_file"
return 1
fi
# Transkripsiyon islemi
local response=$(curl -s -X POST "$LOCALAI_URL/v1/audio/transcriptions"
-H "Content-Type: multipart/form-data"
-F "file=@$temp_wav"
-F "model=$MODEL"
-F "language=tr"
-F "response_format=verbose_json")
if echo "$response" | grep -q '"text"'; then
echo "$response" > "$json_file"
echo "$response" | python3 -c "import sys,json; data=json.load(sys.stdin); print(data['text'])" > "$output_file"
log "BASARILI: Transkript kaydedildi: $output_file"
# Islenen dosyayi arsivle
mv "$audio_file" "$INPUT_DIR/processed/"
else
log "HATA: Transkripsiyon basarisiz: $response"
fi
# Gecici dosyayi temizle
rm -f "$temp_wav"
}
# Ana dongu
mkdir -p "$OUTPUT_DIR" "$INPUT_DIR/processed"
for audio_file in "$INPUT_DIR"/*.{mp3,mp4,wav,m4a,ogg,webm}; do
[ -f "$audio_file" ] || continue
process_audio "$audio_file"
done
log "Tum dosyalar islendi."
Bu scripti crontab’a ekleyerek otomatik çalıştırabilirsin:
chmod +x /usr/local/bin/transcribe-meeting.sh
# Her gun gece 23:00'da calistir
echo "0 23 * * * root /usr/local/bin/transcribe-meeting.sh" >> /etc/cron.d/transcription
Gerçek Dünya Senaryosu 2: REST API ile Entegrasyon
Python uygulamalarından LocalAI Whisper API’sine bağlanmak için basit bir wrapper sınıfı:
#!/usr/bin/env python3
# whisper_client.py
import requests
import os
import json
from pathlib import Path
class LocalWhisperClient:
def __init__(self, base_url="http://localhost:8080"):
self.base_url = base_url
self.model = "whisper-1"
def transcribe(self, audio_path: str, language: str = "tr",
response_format: str = "verbose_json") -> dict:
"""
Ses dosyasini transkribe eder.
response_format: json, verbose_json, text, srt, vtt
"""
audio_path = Path(audio_path)
if not audio_path.exists():
raise FileNotFoundError(f"Dosya bulunamadi: {audio_path}")
with open(audio_path, 'rb') as audio_file:
files = {'file': (audio_path.name, audio_file, 'audio/mpeg')}
data = {
'model': self.model,
'language': language,
'response_format': response_format
}
response = requests.post(
f"{self.base_url}/v1/audio/transcriptions",
files=files,
data=data,
timeout=300
)
response.raise_for_status()
return response.json()
def transcribe_to_srt(self, audio_path: str, output_path: str,
language: str = "tr") -> str:
"""SRT altyazi dosyasi olusturur."""
with open(audio_path, 'rb') as audio_file:
files = {'file': (os.path.basename(audio_path),
audio_file, 'audio/mpeg')}
data = {
'model': self.model,
'language': language,
'response_format': 'srt'
}
response = requests.post(
f"{self.base_url}/v1/audio/transcriptions",
files=files,
data=data,
timeout=300
)
response.raise_for_status()
with open(output_path, 'w', encoding='utf-8') as f:
f.write(response.text)
return output_path
# Kullanim ornegi
if __name__ == "__main__":
client = LocalWhisperClient()
# Basit transkripsiyon
result = client.transcribe("toplanti_kaydi.mp3")
print("Transkript:", result['text'])
# SRT altyazi olustur
srt_path = client.transcribe_to_srt(
"sunum_videosu.mp4",
"altyazi.srt"
)
print(f"Altyazi dosyasi olusturuldu: {srt_path}")
Performans Optimizasyonu
Production ortamında birden fazla ses dosyasını paralel işlemek için bazı ayarlamalar gerekiyor. Docker Compose dosyasını güncelleyelim:
cat > /opt/localai/docker-compose.yml << 'EOF'
version: '3.8'
services:
localai:
image: localai/localai:latest-aio-cpu
container_name: localai
restart: unless-stopped
ports:
- "8080:8080"
environment:
- MODELS_PATH=/models
- DEBUG=false
- THREADS=8
- CONTEXT_SIZE=512
- PARALLEL_REQUESTS=4
- SINGLE_ACTIVE_BACKEND=false
- WATCHDOG_IDLE=60
- WATCHDOG_BUSY=300
- COMPEL=0
volumes:
- /opt/localai/models:/models
- /opt/localai/config:/config
deploy:
resources:
limits:
memory: 16G
reservations:
memory: 8G
ulimits:
nofile:
soft: 65536
hard: 65536
EOF
Önemli environment variable’lar:
- THREADS: CPU thread sayısı, CPU core sayısının %75’i iyi bir başlangıç noktası
- PARALLEL_REQUESTS: Aynı anda işlenebilecek istek sayısı
- WATCHDOG_IDLE: Model ne kadar süre kullanılmazsa bellekten atılır (saniye)
- WATCHDOG_BUSY: Maksimum işlem süresi (saniye), bu süreyi aşan işlemler iptal edilir
Nginx ile Reverse Proxy ve Güvenlik
LocalAI’yi dışarıya açacaksan veya iç ağda birden fazla servisle kullanacaksan Nginx reverse proxy kurmak şart:
sudo apt install -y nginx
cat > /etc/nginx/sites-available/localai << 'EOF'
upstream localai_backend {
server 127.0.0.1:8080;
keepalive 32;
}
server {
listen 443 ssl http2;
server_name localai.sirket.local;
ssl_certificate /etc/ssl/certs/localai.crt;
ssl_certificate_key /etc/ssl/private/localai.key;
# Ses dosyalari buyuk olabilir, limit artir
client_max_body_size 500M;
client_body_timeout 300s;
# Uzun transkripsiyon islemleri icin timeout artir
proxy_read_timeout 600s;
proxy_connect_timeout 60s;
proxy_send_timeout 300s;
location /v1/audio/ {
proxy_pass http://localai_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Buyuk dosya yüklemeleri icin
proxy_request_buffering off;
proxy_buffering off;
}
location /readyz {
proxy_pass http://localai_backend;
}
}
EOF
sudo ln -s /etc/nginx/sites-available/localai /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
İzleme ve Loglama
Whisper işlemlerinin ne kadar sürdüğünü, hangi dosyaların başarılı işlendiğini takip etmek için basit bir monitoring script’i:
#!/bin/bash
# /usr/local/bin/check-localai-health.sh
LOCALAI_URL="http://localhost:8080"
ALERT_EMAIL="[email protected]"
# Health check
http_code=$(curl -s -o /dev/null -w "%{http_code}" "$LOCALAI_URL/readyz")
if [ "$http_code" != "200" ]; then
echo "LocalAI HATA: HTTP $http_code" | mail -s "LocalAI Servis Alarmı" "$ALERT_EMAIL"
# Servisi yeniden baslat
cd /opt/localai && docker compose restart localai
sleep 30
# Tekrar kontrol et
http_code=$(curl -s -o /dev/null -w "%{http_code}" "$LOCALAI_URL/readyz")
if [ "$http_code" == "200" ]; then
echo "LocalAI yeniden baslatildi ve calisiyor." | mail -s "LocalAI Kurtarıldı" "$ALERT_EMAIL"
else
echo "LocalAI yeniden baslatma BASARISIZ!" | mail -s "KRİTİK: LocalAI Çöktü" "$ALERT_EMAIL"
fi
fi
# Bellek kullanimi kontrol et
mem_usage=$(docker stats --no-stream --format "{{.MemPerc}}" localai | tr -d '%')
if (( $(echo "$mem_usage > 90" | bc -l) )); then
echo "LocalAI bellek kullanimi kritik: %$mem_usage" | mail -s "LocalAI Bellek Uyarısı" "$ALERT_EMAIL"
fi
Crontab’a ekle:
echo "*/5 * * * * root /usr/local/bin/check-localai-health.sh" >> /etc/cron.d/localai-monitor
Sık Karşılaşılan Sorunlar ve Çözümleri
Problem: Türkçe karakterler bozuk çıkıyor Çözüm: Encoding sorunudur. Dosyaları UTF-8 ile kaydet, API çıktısını charset=utf-8 header’ı ile al.
Problem: Büyük ses dosyalarında timeout hatası Çözüm: Whisper 30 dakikayı aşan dosyalarda sorun yaşayabiliyor. FFmpeg ile dosyayı parçalara böl:
# 20 dakikalik parcalara bol
ffmpeg -i uzun_kayit.mp3 -f segment -segment_time 1200 -c copy parca_%03d.mp3
Problem: Gürültülü ortamlarda düşük doğruluk Çözüm: Ses dosyasını önce temizle:
# Gurultu azaltma (ffmpeg ile basit yontem)
ffmpeg -i gurultulu.mp3 -af "highpass=f=200,lowpass=f=3000,afftdn=nf=-25" temiz.mp3
Problem: Container çok fazla RAM tüketiyor Çözüm: Daha küçük model kullan veya WATCHDOG_IDLE değerini düşür ki model kullanılmadığında bellekten atılsın.
Sonuç
LocalAI ile Whisper entegrasyonu, cloud bağımlılığını ortadan kaldıran ve veri gizliliğini ön plana alan bir çözüm sunuyor. Kurulum başlangıçta biraz uğraş istiyor, özellikle model seçimi ve parametrelerin ayarlanması deneme yanılma gerektiriyor. Ama bir kez çalışır hale geldiğinde son derece güvenilir ve ekonomik bir sistem elde ediyorsun.
Türkçe ses tanıma için en az medium model kullanmanı öneririm. Base ve small modeller İngilizce için yeterli olsa da Türkçenin fonetik yapısı nedeniyle önemli doğruluk kayıpları yaşanabiliyor. Eğer GPU’n varsa large-v3 modeli denemeni kesinlikle tavsiye ederim, doğruluk farkı gerçekten çarpıcı.
Production’a geçmeden önce kendi ses kayıtlarınla kapsamlı testler yap. Özellikle aksan farklılıkları, arka plan gürültüsü ve teknik terminoloji içeren kayıtlar için modelin nasıl davrandığını iyi değerlendirmek gerekiyor. Gerekirse fine-tuning seçeneğini de araştırabilirsin ama bu ayrı ve detaylı bir konu.
