Files
iddaai-be/mds/SOCIAL_POSTER_MODULE.md
T
fahricansecer 5645b38f20
Deploy Iddaai Backend / build-and-deploy (push) Successful in 32s
main
2026-05-05 17:09:11 +03:00

204 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Social Poster Modülü — Otomatik Sosyal Medya Paylaşım Sistemi
Son güncelleme: 5 Mayıs 2026
---
## 1. Amaç
Top liglerdeki maçların AI tahminlerini **otomatik olarak görselleştirip** Instagram, Facebook ve X (Twitter) üzerinden paylaşmak. Her maç için 30 dakika önceden tahmin alınıp, 1080×1920 (9:16 Instagram Story) formatında poster üretilir.
---
## 2. Mimari Akış
```
Cron (*/15 dk) → LiveMatch sorgusu (top_leagues.json filtresi)
→ AI Engine V20+ POST /v20plus/analyze/{match_id}
→ PredictionCardDto oluştur
→ Node Canvas ile futbol/basketbol 1080x1080 JPEG render
→ Ollama/Gemini ile Türkçe SEO uyumlu caption üret
→ Twitter / Facebook / Instagram API'ye paylaş
```
---
## 3. Dosya Yapısı
```
src/modules/social-poster/
├── social-poster.module.ts # NestJS modül tanımı
├── social-poster.controller.ts # Test endpointleri (preview, post)
├── social-poster.service.ts # Ana orkestrasyon servisi
├── image-renderer.service.ts # Node Canvas ile görsel üretimi
├── caption-generator.service.ts # Gemini ile post metni üretimi
├── twitter.service.ts # Twitter/X API entegrasyonu
├── meta.service.ts # Facebook + Instagram Graph API
└── dto/
└── prediction-card.dto.ts # PredictionCardDto, TopPick, SocialPostResult
```
---
## 4. Temel Servisler
### 4.1 SocialPosterService
**Cron:** Her 15 dakikada bir çalışır. Varsayılan olarak 2545 dakika içinde başlayacak futbol ve basketbol maçlarını `top_leagues.json` filtresiyle bulur.
**Tekrar paylaşım koruması:** Başarılı platform paylaşımı alan maç ID'leri `storage/social-poster-posted.json` içinde son 500 kayıt olarak tutulur. Servis restart sonrası aynı maç tekrar paylaşılmaz.
**Pipeline:** `predictAndPost(match)` → Tahmin al → Görsel üret → Caption üret → Paylaş
**AI Engine İsteği:**
```typescript
// POST — GET değil! AI Engine v20plus POST bekler.
axios.post(`${aiEngineUrl}/v20plus/analyze/${matchId}`, null, {
timeout: 30000,
});
```
**Veri Haritalandırma (V20+ → CardDto):**
| V20+ Response Alanı | CardDto Alanı |
| ----------------------- | ---------------------------------------------- |
| `score_prediction.ht` | `htScore` (ör: "1-1") |
| `score_prediction.ft` | `ftScore` (ör: "2-1") |
| `main_pick.confidence` | `scoreConfidence` (ör: 65) |
| `bet_summary[]` (array) | `topPicks[]` (ilk 3, confidence'a göre sıralı) |
| `risk.level` | `riskLevel` (LOW/MEDIUM/HIGH/EXTREME) |
| `match_info.home_team` | `homeTeam` (fallback) |
**Bet Summary Market Kodları:**
| Kod | Türkçe | English |
| ------- | --------------- | ----------------- |
| MS | Maç Sonucu | Match Result |
| OU15 | Üst 1.5 Gol | Over 1.5 |
| OU25 | Üst 2.5 Gol | Over 2.5 |
| OU35 | Üst 3.5 Gol | Over 3.5 |
| BTTS | Karşılıklı Gol | Both Teams Score |
| DC | Çifte Şans | Double Chance |
| HT | İlk Yarı Sonucu | Half Time Result |
| HT_OU05 | İY 0.5 Üst/Alt | HT Over/Under 0.5 |
| OE | Tek/Çift | Odd/Even |
| HTFT | İY/MS | HT/FT |
### 4.2 ImageRendererService
**Motor:** `node-canvas` (Puppeteer/HTML yok — sunucu performansı için)
**Çıktı:** `public/predictions/prediction_{matchId}_{timestamp}.png`
**Boyut:** 1080×1920 px (Instagram Story / Reels uyumlu)
**Özellikler:**
- Koyu gradient arka plan (#0a0e27#1a1040#0d1b2a)
- Lig adı + tarih başlık satırı
- Takım logoları (200×200px) — `public/uploads/teams/` altından okunur
- İlk Yarı / Maç Sonu skor kutuları
- Güven yüzdesi badge'i
- En iyi 3 tahmin (progress bar + yüzde)
- Risk seviyesi badge'i (renk kodlu)
- `iddaai.com` filigran (saydam, tekrarlı, döndürülmüş)
- Alt bilgi: "⚡ AI Powered by SuggestBet"
**Logo Çözümleme:**
```
1. Yerel dosya varsa → public/uploads/teams/xxx.png oku
2. URL http ile başlıyorsa → HTTP ile indir
3. Bulunamazsa → logo olmadan devam et (graceful fallback)
```
### 4.3 CaptionGeneratorService
Gemini API kullanarak maç verisi JSON'ından Türkçe post metni üretir.
### 4.4 TwitterService & MetaService
Üretilen görsel + caption'ı ilgili platformlara yükler.
---
## 5. API Endpointleri
| Method | Path | Auth | Açıklama |
| ------ | ------------------------------------- | ------- | ---------------------------------------------------- |
| GET | `/api/social-poster/preview/:matchId` | @Public | Sadece görsel üret + caption üret (paylaşma) |
| POST | `/api/social-poster/post/:matchId` | @Public | Görsel üret + caption üret + tüm platformlara paylaş |
> **Not:** Test endpointleri `@Public()` dekoratörüyle auth bypass edilmiştir. Production'da kaldırılmalı veya admin-only yapılmalıdır.
---
## 6. Environment Değişkenleri
| Key | Zorunlu | Varsayılan | Açıklama |
| --------------------------------------------- | ------- | ------------------------ | -------------------------------------------------------------------- |
| `AI_ENGINE_URL` | ✅ | `http://localhost:8000` | AI Engine base URL |
| `APP_BASE_URL` | ✅ | `http://localhost:3000` | Meta'nın çekebileceği public görsel URL'i ve logo URL çözümleme için |
| `SOCIAL_POSTER_ENABLED` | ❌ | `false` | Cron job'ı aktif/pasif |
| `SOCIAL_POSTER_SPORTS` | ❌ | `football,basketball` | Otomatik paylaşılacak sporlar |
| `SOCIAL_POSTER_WINDOW_MIN` | ❌ | `25` | Başlama zaman penceresi alt sınırı (dakika) |
| `SOCIAL_POSTER_WINDOW_MAX` | ❌ | `45` | Başlama zaman penceresi üst sınırı (dakika) |
| `OLLAMA_BASE_URL` | ❌ | `http://localhost:11434` | Lokal LLM endpoint'i |
| `OLLAMA_MODEL` / `SOCIAL_POSTER_OLLAMA_MODEL` | ❌ | — | Caption üretiminde kullanılacak lokal model |
| `GOOGLE_API_KEY` | ❌ | — | Gemini caption için |
| Twitter API keys | ❌ | — | X medya upload + `/2/tweets` paylaşımı için OAuth 1.0a user context |
| `META_GRAPH_API_VERSION` | ❌ | `v25.0` | Meta Graph API sürümü |
| Meta API keys | ❌ | — | FB/IG paylaşım için |
---
## 7. Bağımlılıklar
```json
{
"canvas": "^2.x", // Node Canvas — görsel üretimi
"axios": "^1.x", // HTTP istekleri (AI Engine + logo indirme)
"@nestjs/schedule": "*" // Cron job desteği
}
```
> **Kaldırılan:** `puppeteer` — performans ve Raspberry Pi uyumluluğu için `canvas` ile değiştirildi.
---
## 8. Deploy Notları
### Raspberry Pi (ARM64)
```bash
# canvas native bağımlılıkları (Dockerfile'da)
RUN apk add --no-cache cairo-dev pango-dev jpeg-dev giflib-dev librsvg-dev
```
### Port Yönetimi
| Servis | Port |
| -------------- | ------------------------------------------- |
| NestJS Backend | 3000 (production: 150X) |
| AI Engine | 8000 (dev: 8005 — Windows port kısıtlaması) |
### Dosya Sistemi
```
public/
├── uploads/teams/ # Takım logoları (PNG)
└── predictions/ # Üretilen poster görselleri (PNG)
```
---
## 9. Bilinen Sorunlar & Çözümler
| Sorun | Sebep | Çözüm |
| --------------------------------------- | ------------------------------------ | ----------------------------------------- |
| `WinError 10013` port erişim hatası | Windows Hyper-V port rezervasyonu | Farklı port kullan (8005) |
| `Invalid prisma.liveMatch.findUnique()` | Prisma client eskimiş | `npx prisma generate` çalıştır |
| `405 Method Not Allowed` AI Engine | GET yerine POST gerekiyor | `axios.post()` kullan |
| Logolar görünmüyor (lokal dev) | Logo dosyaları sunucuda, lokalde yok | Deploy'da çalışır, lokal'de graceful skip |