Mülakat Duygu Analizi Platformu — Plan Spesifikasyonu
1. Ön Yüz (Frontend)
1.1 User-Login Ekranı (kod ile)
Detay: Django'nun built-in django.contrib.auth sistemi ile username/password login.
| Olası Pürüz | Açıklama | Çözüm Önerisi |
|---|---|---|
| Session güvenliği | CSRF, session hijacking riski | Django {% csrf_token %} + SESSION_COOKIE_HTTPONLY = True + SECURE_SSL_REDIRECT (prod) |
| Şifre politikası | Zayıf şifre kabul edilebilir | AUTH_PASSWORD_VALIDATORS ayarlarını aktif et |
| Başarısız giriş saldırısı | Brute-force denemeleri | django-axes veya basit rate-limiting middleware ekle |
[!TIP] Alternatif: İleride OAuth2 (Google/Microsoft) eklemek isterseniz
django-allauthpaketini şimdiden entegre etmek kolaydır. Şu an için gerek yok ama DB şemasını buna uyumlu tutmak avantajlı olur.
1.2 Mülakat Başlat / Bitir Butonları
Detay: Tek sayfa üzerinde "Başlat" ve "Bitir" butonları. Başlat → kamerayı aç + WebRTC bağlantısını kur + soruları göster + backend'e session başlat sinyali gönder. Bitir → WebRTC bağlantısını kapat + her şeyi durdur + session'ı kapat.
| Olası Pürüz | Açıklama | Çözüm Önerisi |
|---|---|---|
| Kamera izni reddedilirse | Kullanıcı tarayıcıda izin vermezse akış kırılır | getUserMedia hata yakalama ile kullanıcıya uyarı göster, başlat butonunu devre dışı bırak |
| Çift tıklama / race condition | "Başlat"a iki kez basılırsa birden fazla session açılır | Butonu tıklandığında disable et, backend'den cevap gelince tekrar aktif et |
| Sayfa yenileme / kaza kapanması | Mülakat ortasında sekme kapanırsa veri kaybı | beforeunload event'i ile uyarı göster + backend tarafında "orphan session" temizleme mekanizması (cron/celery task) |
| Video akışı kesintisi | Internet veya kamera kopması | WebRTC oniceconnectionstatechange event'i ile bağlantı durumu takibi, kesilirse kullanıcıya bildirim + otomatik yeniden bağlanma (ICE restart) |
[!IMPORTANT] Öneri: Butonların durumları (idle → recording → finished) bir state machine ile yönetilmeli. Basit bir
enum+ JavaScript state yönetimi karmaşıklığı azaltır.
1.3 TR-ENG Content (Çok dilli destek)
Detay: Arayüz metinleri Türkçe ve İngilizce olarak sunulacak.
| Olası Pürüz | Açıklama | Çözüm Önerisi |
|---|---|---|
| Hardcoded stringler | Metinler template'lere gömülürse dil ekleme zorlaşır | Django i18n framework'ü kullan: {% trans %} tag'leri + .po dosyaları |
| Dil değiştirme UX | Dil değiştiğinde sayfa yenilenmesi gerekir | django.middleware.locale.LocaleMiddleware + URL prefix (/tr/, /en/) veya session-based dil tercihi |
| Mülakat soruları dili | Sorular DB'de ise her sorunun iki dil versiyonu lazım | Sorular tablosunda question_tr + question_en alanları veya ayrı Translation tablosu |
[!TIP] Avantajlı Alternatif: Eğer sadece 2 dil olacaksa (TR/EN), Django
i18nyerine basit bir JSON-based dictionary yaklaşımı da yeterli olabilir — daha az overhead, daha hızlı geliştirme. Ama ileride 3+ dil planlıyorsanızi18ntercih edin.
1.4 Dummy Mülakat Soruları
Detay: Geliştirme/demo aşamasında kullanılacak sabit soru seti.
| Olası Pürüz | Açıklama | Çözüm Önerisi |
|---|---|---|
| Sorular nerede tutulacak? | Kod içinde mi, DB'de mi, JSON dosyasında mı? | Öneri: DB'de tutun (Question modeli). Fixture/seed script ile dummy dataları yükleyin (python manage.py loaddata). İleride gerçek sorularla değiştirmek sorunsuz olur |
| Soru sıralaması | Herkese aynı sırada mı, rastgele mi? | Şimdilik sıralı, ama modelde order alanı bırakın. İleride random veya adaptive gibi stratejiler eklenebilir |
| Soru tipi çeşitliliği | Sadece metin mi, yoksa seçenekli/video sorular da olacak mı? | Şimdilik sadece metin. Ama modele question_type (text, multiple_choice, video) alanı ekleyin — bozmaz, genişletir |
1.5 WebRTC — Gerçek Zamanlı Video Akışı
Detay: Kullanıcının kamerasından alınan video akışını WebRTC ile sunucuya (veya doğrudan model servisine) gerçek zamanlı iletmek. Bu sayede frame'ler anlık olarak emotion inference'a gönderilebilir ve video kaydı sunucu tarafında yapılabilir.
Akış:
Browser (getUserMedia) → WebRTC PeerConnection → Signaling (Django Channels) → Media Server → Model Service
| Olası Pürüz | Açıklama | Çözüm Önerisi |
|---|---|---|
| Signaling sunucusu | WebRTC bağlantısı kurmak için SDP/ICE mesaj alışverişi gerekir | Django Channels (WebSocket) ile signaling endpoint'i oluşturun. ws://host/ws/signaling/<session_id>/ |
| NAT traversal | Kullanıcı NAT/firewall arkasındaysa doğrudan bağlantı kurulamaz | STUN sunucusu (ücretsiz: Google STUN stun:stun.l.google.com:19302) + gerektiğinde TURN sunucusu (self-hosted: coturn) |
| TURN sunucusu maliyeti | TURN relay trafiği bant genişliği tüketir | Önce STUN ile dene, sadece STUN başarısız olursa TURN'e düş. Geliştirmede localhost'ta TURN gerekmez |
| Media server ihtiyacı | WebRTC peer-to-peer'dır, sunucunun videoyu alması için bir media endpoint lazım | Basit yol: aiortc (Python WebRTC kütüphanesi) ile sunucu tarafında peer oluşturun. Gelişmiş yol: Janus/mediasoup gibi bir SFU kullanın |
| Tarayıcı uyumluluğu | Bazı eski tarayıcılar WebRTC desteklemez | adapter.js shim kütüphanesini ekleyin. Modern tarayıcılarda (Chrome, Firefox, Edge, Safari 11+) sorun yok |
| Ses vs sadece video | Mülakatda ses de kaydedilecek mi? | getUserMedia({ video: true, audio: true }) ile hem video hem ses alın. WebRTC her ikisini de aynı PeerConnection üzerinden taşır |
[!IMPORTANT] WebRTC vs MediaRecorder Karşılaştırması:
WebRTC MediaRecorder (mevcut plan) Real-time streaming ✅ Sunucuya anlık akış ❌ Sadece client-side kayıt Sunucu tarafı kayıt ✅ Media server ile ❌ Upload gerekli Real-time inference ✅ Frame'ler anında sunucuya ⚠️ Batch POST gerekli Karmaşıklık Yüksek (signaling, ICE, TURN) Düşük Bant genişliği Sürekli stream Sadece upload anında Öneri: İkisini birlikte kullanın — WebRTC real-time emotion inference için frame stream'i, MediaRecorder yedek video kaydı (client-side, WebRTC kesilirse kayıp olmaz).
[!TIP]
aiortcile Basit Entegrasyon: Python'da WebRTC peer oluşturmak içinaiortckütüphanesi idealdir. Django Channels ile aynı async event loop üzerinde çalışır. Video frame'lerini doğrudanVideoStreamTracküzerinden alıp model servisine iletebilirsiniz.
2. Arka Yüz (Backend)
2.1 User-Login (kod ile)
Detay: Frontend ile aynı auth sistemi. Django auth backend, session management.
| Olası Pürüz | Açıklama | Çözüm Önerisi |
|---|---|---|
| API vs Template-based auth | Kamera erişimi JS gerektirdiğinden, sayfalar ne kadar SPA olacak? | İki yol: (A) Klasik Django template + AJAX çağrıları (basit), (B) DRF + JWT ile tam API (esnek ama karmaşık). Öneri: Şu an için (A) yeterli |
| User modeli genişletme | İleride kullanıcıya özel alanlar lazım olabilir (departman, pozisyon vb.) | AbstractUser'dan miras alan custom User modeli şimdiden oluşturun — sonradan değiştirmek çok zor |
| Admin paneli | Sorular ve session'lar yönetilmeli | Django Admin'e Question, InterviewSession, EmotionRecord modellerini kaydedin |
[!CAUTION] Kritik: Django projesi başlarken
AUTH_USER_MODELayarını custom user modeline yönlendirin. Sonradan değiştirmek migration cehennemine yol açar.
2.2 User + Session Based Duygu Kayıtları
Format: [timestamp, "mutlu":0.2, "üzgün":0.6, ...] + video kaydı
| Olası Pürüz | Açıklama | Çözüm Önerisi |
|---|---|---|
| Yüksek frekanslı veri yazma | Her frame'de DB'ye yazarsanız performans düşer | WebRTC ile gelen frame'leri sunucu tarafında buffer'layın (Redis/in-memory queue) → periyodik DB flush |
| Video kayıt — çift katman | Hem sunucu hem client tarafında kayıt stratejisi | WebRTC stream: aiortc ile sunucu tarafında kayıt (birincil). MediaRecorder: Client-side yedek kayıt (fallback). Format: WebM (VP9) |
| Video saklama | Dosya sistemi mi, object storage mı? | Geliştirme: MEDIA_ROOT ile local. Prodüksiyon: S3/MinIO. Django FileField her ikisini de destekler |
| Veri modeli tasarımı | Emotion verileri nasıl saklanmalı? | Önerilen model yapısı aşağıda |
| Zaman senkronizasyonu | Video timestamp ile emotion timestamp uyuşmazlığı | WebRTC RTP timestamp'larını kullanın — frame ve emotion timestamp'ları doğal olarak senkron olur |
| Django Channels altyapısı | WebRTC signaling ve WebSocket için ASGI gerekir | daphne veya uvicorn ASGI server kullanın. ASGI_APPLICATION ayarını yapılandırın |
Önerilen DB Modeli:
class InterviewSession(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
started_at = models.DateTimeField(auto_now_add=True)
ended_at = models.DateTimeField(null=True, blank=True)
video_file = models.FileField(upload_to='interviews/videos/', null=True)
language = models.CharField(max_length=2, choices=[('tr','TR'),('en','EN')])
status = models.CharField(max_length=20, default='in_progress') # in_progress, completed, abandoned
class EmotionRecord(models.Model):
session = models.ForeignKey(InterviewSession, on_delete=models.CASCADE, related_name='emotions')
timestamp = models.FloatField() # saniye cinsinden, session başlangıcına göre
happy = models.FloatField(default=0)
sad = models.FloatField(default=0)
angry = models.FloatField(default=0)
surprised = models.FloatField(default=0)
fearful = models.FloatField(default=0)
disgusted = models.FloatField(default=0)
neutral = models.FloatField(default=0)
# Alternatif: emotions = models.JSONField() → daha esnek ama sorgulaması zor
[!NOTE] Trade-off:
JSONFieldile emotion'ları tek alanda tutmak esnektir ama SQL ile filtreleme/aggregation zorlaşır. Ayrı float alanları query dostu ama model değişikliği gerektirir. Öneri: Emotion sayısı sabit kalacaksa ayrı alanlar; değişecekseJSONField.
3. Perception (Model Katmanı)
3.1 Model Doğruluğu Artırılması
| Olası Pürüz | Açıklama | Çözüm Önerisi |
|---|---|---|
| Model-Django entegrasyonu | PyTorch/TF modeli Django process'inde çalıştırmak bellek sorunlarına yol açar | Öneri: Modeli ayrı bir microservice olarak çalıştırın (FastAPI + model server). aiortc → frame alır → model servisine iletir |
| GPU vs CPU inference | Sunucuda GPU yoksa inference yavaş olur | ONNX Runtime ile CPU optimizasyonu veya TensorRT ile GPU hızlandırma. Client-side inference (TF.js/ONNX.js) alternatif ama model boyutuna bağlı |
| Model güncelleme | Yeni model eğitildiğinde deployment nasıl olacak? | Model dosyasını versiyonlayın (model_v1.onnx, model_v2.onnx). Config ile hangi versiyonun aktif olduğunu belirleyin |
| Real-time vs batch inference | Her frame'i anında mı analiz edeceksiniz? | WebRTC ile gelen frame'lerden her 2-3 FPS'te birini model'e gönderin. aiortc VideoStreamTrack üzerinde frame skip mantığı uygulayın |
[!TIP] Avantajlı Alternatif — Client-Side Inference: Eğer model yeterince küçükse (~5-20MB), TensorFlow.js veya ONNX.js ile emotion detection'ı doğrudan tarayıcıda çalıştırabilirsiniz. Avantajları: - Sunucu yükü sıfır - Latency çok düşük - Video verisi sunucuya gönderilmeden işlenir (gizlilik)
Dezavantaj: Düşük donanımlı client'larda performans sorunu.
3.2 Time-Based Solution'ların Tekrardan Eklenmesi
| Olası Pürüz | Açıklama | Çözüm Önerisi |
|---|---|---|
| Temporal smoothing | Anlık tahminler gürültülü olur (frame'den frame'e zıplama) | Sliding window averaging (son 5-10 frame'in ortalaması) veya exponential moving average (EMA) |
| Temporal model entegrasyonu | LSTM/Transformer gibi modeller session-level state tutar | Session başına bir model state tutulmalı — memory management önemli. Her session kapanınca state temizlenmeli |
| Senkronizasyon | Time-based prediction'lar ile soru geçişleri eşleşmeli | Her soru geçişinde bir "marker" timestamp kaydedin → analiz aşamasında soru bazlı emotion grafiği çıkarılabilir |
4. Genel Mimari Önerileri
┌─────────────────────────────────────────────────────────────┐
│ BROWSER (Client) │
│ ┌──────────┐ ┌──────────┐ ┌─────────────────────────┐ │
│ │ Login │ │ Mülakat │ │ getUserMedia │ │
│ │ Formu │ │ UI/Sorular│ │ + RTCPeerConnection │ │
│ └────┬─────┘ └────┬─────┘ │ + MediaRecorder (yedek)│ │
│ │ │ └────────┬────────────────┘ │
│ │ │ │ │
│ │ │ WebRTC Media Stream │
│ │ │ + Signaling (WebSocket) │
└───────┼──────────────┼─────────────────┼────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ DJANGO BACKEND (ASGI — Daphne/Uvicorn) │
│ ┌─────────┐ ┌────────────┐ ┌──────────────────────────┐ │
│ │ Auth │ │ Session │ │ Django Channels │ │
│ │ Views │ │ Manager │ │ (WebSocket Signaling) │ │
│ └─────────┘ └──────┬─────┘ └────────────┬─────────────┘ │
│ │ │ │
│ ┌──────▼──────┐ ┌─────────▼────────────┐ │
│ │ PostgreSQL │ │ aiortc (Python peer) │ │
│ │ (DB) │ │ Video frame alımı │ │
│ └─────────────┘ └─────────┬────────────┘ │
│ │ │
│ ┌────────────▼────────────┐ │
│ │ STUN/TURN (coturn) │ │
│ │ NAT traversal │ │
│ └─────────────────────────┘ │
└────────────────────────────────────────┬────────────────────┘
│ Frame → HTTP/gRPC
▼
┌────────────────────┐
│ Model Service │
│ (FastAPI) │
│ Emotion Inference │
└────────────────────┘
[!WARNING] SQLite vs PostgreSQL: Django varsayılan olarak SQLite kullanır. Geliştirme için yeterli ama concurrent write sorunları yaşatır. Eğer birden fazla kullanıcı aynı anda mülakat yapacaksa PostgreSQL kullanın. Proje başından itibaren PostgreSQL ayarlarsanız migration sorunları yaşamazsınız.
5. Öncelik Sıralaması Önerisi
| Sıra | İş | Neden? |
|---|---|---|
| 1 | Custom User Model + DB setup (PostgreSQL) | Sonradan değiştirmek çok zor |
| 2 | Login ekranı (frontend + backend) | Temel altyapı |
| 3 | Django Channels + ASGI kurulumu | WebRTC signaling altyapısı, erken kurulmalı |
| 4 | Question modeli + dummy data fixture | Mülakatın iskeletini oluşturur |
| 5 | Mülakat sayfası + başlat/bitir butonları | Akışın çekirdeği |
| 6 | WebRTC entegrasyonu (signaling + aiortc peer) |
Real-time video akışı |
| 7 | Kamera erişimi + MediaRecorder (yedek kayıt) | Fallback video kaydı |
| 8 | Session + EmotionRecord modelleri | Backend veri katmanı |
| 9 | Model servisi entegrasyonu | Perception katmanı |
| 10 | Time-based smoothing | Model kalitesi |
| 11 | TR/EN çoklu dil desteği | Polish aşaması |
6. WebRTC Gerekli Paketler Özeti
| Paket | Amaç | Kurulum |
|---|---|---|
channels |
Django WebSocket/ASGI desteği | pip install channels |
channels-redis |
Channel layer backend (prod) | pip install channels-redis |
daphne |
ASGI HTTP/WebSocket server | pip install daphne |
aiortc |
Python tarafında WebRTC peer | pip install aiortc |
adapter.js |
Tarayıcı WebRTC uyumluluk shim | CDN veya npm |
coturn |
TURN/STUN sunucusu (prod) | System package / Docker |
EK
def add_data_to_session(request, session_id, conf_array):
session = Session.objects.get(id=session_id)
# 🔥 kritik kontrol
if session.user != request.user:
raise Exception("Bu session sana ait değil")
data = Data.objects.create(
session=session,
timestamp=timezone.now(),
conf=conf_array
)
return data