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.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir