first (part 2: other directories)
Deploy Iddaai Backend / build-and-deploy (push) Failing after 18s

This commit is contained in:
2026-04-16 15:11:25 +03:00
parent 7814e0bc6b
commit 2f0b85a0c7
203 changed files with 59989 additions and 0 deletions
+457
View File
@@ -0,0 +1,457 @@
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
/**
* GLM-5 Tahmin Yaklaşımı
* ======================
* Bir maç için eldeki veriler:
* - Takım isimleri (ev sahibi, deplasman)
* - Oranlar (MS, Alt/Üst, BTTS, DC)
* - Sakatlar/Cezalılar
* - Lig
* - Hakem
*
* Hedef: Maç sonucunu tahmin etmek (1/X/2)
*/
async function glm5PredictionApproach() {
console.log('\n');
console.log(
'╔══════════════════════════════════════════════════════════════════╗',
);
console.log(
'║ GLM-5 TAHMİN YAKLAŞIMI - VERİTABANI ANALİZİ ║',
);
console.log(
'╚══════════════════════════════════════════════════════════════════╝',
);
console.log('\n');
// =====================================
// BÖLÜM 1: VERİTABANI HAZİNESİ
// =====================================
console.log('📦 BÖLÜM 1: VERİTABANI HAZİNESİ');
console.log('─'.repeat(50));
const stats = {
matches: await prisma.match.count({
where: { sport: 'football', state: 'postGame' },
}),
odds: await prisma.oddSelection.count(),
events: await prisma.matchPlayerEvents.count(),
teamStats: await prisma.matchTeamStats.count(),
officials: await prisma.matchOfficial.count(),
};
console.log(`\nKullanılabilir Veri Miktarı:`);
console.log(`${stats.matches.toLocaleString()} bitmiş futbol maçı`);
console.log(` 📊 ${stats.odds.toLocaleString()} oran kaydı`);
console.log(
`${stats.events.toLocaleString()} maç olayı (gol, kart, değişiklik)`,
);
console.log(` 📈 ${stats.teamStats.toLocaleString()} takım istatistiği`);
console.log(` 👨‍⚖️ ${stats.officials.toLocaleString()} hakem kaydı`);
// =====================================
// BÖLÜM 2: TAHMİN FAKTÖRLERİ
// =====================================
console.log('\n\n🧠 BÖLÜM 2: TAHMİN FAKTÖRLERİ');
console.log('─'.repeat(50));
console.log(`
Bir maç sonucunu etkileyen faktörler ve veritabanından nasıl çıkarılır:
┌─────────────────────────────────────────────────────────────────────┐
│ FAKTÖR │ VERİTABANI KAYNAĞI │
├─────────────────────────────────────────────────────────────────────┤
│ 1. Takım Gücü │ Son maçlarda gol atma/yeme ortalaması
│ 2. Ev/Deplasman Avantajı │ Ev sahibi %52, Deplasman %28, Berabere %20│
│ 3. Form Durumu │ Son 5 maçta alınan puanlar │
│ 4. Oranlar │ Bookmaker'ın fiyatlaması (implied prob) │
│ 5. Sakat/Cezalı │ sidelined_data JSON alanı
│ 6. Hakem Etkisi │ Hakemin istatistikleri │
│ 7. Lig Özelliği │ Gol ortalamaları, ev avantajı
│ 8. Head-to-Head │ Karşılıklı geçmiş maçlar │
└─────────────────────────────────────────────────────────────────────┘
`);
// =====================================
// BÖLÜM 3: ÖRNEK ANALİZ
// =====================================
console.log('\n\n🎯 BÖLÜM 3: ÖRNEK MAÇ ANALİZİ');
console.log('─'.repeat(50));
// preGame durumundaki bir maç bul
const match = await prisma.match.findFirst({
where: { sport: 'football', state: 'preGame' },
include: {
homeTeam: true,
awayTeam: true,
league: true,
oddCategories: { include: { selections: true } },
officials: { include: { role: true } },
},
});
if (!match) {
// Son bitmiş maçı kullan
const finishedMatch = await prisma.match.findFirst({
where: { sport: 'football', state: 'postGame', scoreHome: { not: null } },
include: {
homeTeam: true,
awayTeam: true,
league: true,
oddCategories: { include: { selections: true } },
officials: { include: { role: true } },
},
orderBy: { mstUtc: 'desc' },
});
if (finishedMatch) {
await analyzeMatch(finishedMatch, true);
}
} else {
await analyzeMatch(match, false);
}
await prisma.$disconnect();
}
async function analyzeMatch(match, isFinished) {
console.log(`\n⚽ MAÇ: ${match.homeTeam?.name} vs ${match.awayTeam?.name}`);
console.log(`🏆 Lig: ${match.league?.name}`);
console.log(`📅 Tarih: ${new Date(Number(match.mstUtc)).toISOString()}`);
if (isFinished) {
console.log(`📊 Gerçek Skor: ${match.scoreHome} - ${match.scoreAway}`);
}
// ═════════════════════════════════════════════════════════════════
// ADIM 1: ORANLARI OKU VE IMPLIED PROBABILITY HESAPLA
// ═════════════════════════════════════════════════════════════════
console.log('\n📊 ADIM 1: ORAN ANALİZİ');
console.log('─'.repeat(40));
const odds = {};
for (const cat of match.oddCategories) {
for (const sel of cat.selections) {
if (cat.name?.includes('Maç Sonucu') || cat.name === 'MS') {
if (sel.name === '1') odds.ms_home = parseFloat(sel.oddValue);
if (sel.name === 'X') odds.ms_draw = parseFloat(sel.oddValue);
if (sel.name === '2') odds.ms_away = parseFloat(sel.oddValue);
}
if (cat.name?.includes('2,5') || cat.name?.includes('2.5')) {
if (sel.name === 'Alt') odds.ou25_under = parseFloat(sel.oddValue);
if (sel.name === 'Üst') odds.ou25_over = parseFloat(sel.oddValue);
}
if (cat.name?.includes('Karşılıklı') || cat.name?.includes('KG')) {
if (sel.name === 'Var' || sel.name === 'Evet')
odds.btts_yes = parseFloat(sel.oddValue);
if (sel.name === 'Yok' || sel.name === 'Hayır')
odds.btts_no = parseFloat(sel.oddValue);
}
}
}
// Implied probability hesapla
if (odds.ms_home && odds.ms_draw && odds.ms_away) {
const rawHome = (1 / odds.ms_home) * 100;
const rawDraw = (1 / odds.ms_draw) * 100;
const rawAway = (1 / odds.ms_away) * 100;
const total = rawHome + rawDraw + rawAway;
console.log(
`\nOranlar: 1=${odds.ms_home} | X=${odds.ms_draw} | 2=${odds.ms_away}`,
);
console.log(
`Ham Implied Probability: 1=%${rawHome.toFixed(1)} | X=%${rawDraw.toFixed(1)} | 2=%${rawAway.toFixed(1)}`,
);
console.log(`Bookmaker Margin: %${(total - 100).toFixed(1)}`);
// Normalize edilmiş
const normHome = (rawHome / total) * 100;
const normDraw = (rawDraw / total) * 100;
const normAway = (rawAway / total) * 100;
console.log(
`Normalize: 1=%${normHome.toFixed(1)} | X=%${normDraw.toFixed(1)} | 2=%${normAway.toFixed(1)}`,
);
odds.normHome = normHome;
odds.normDraw = normDraw;
odds.normAway = normAway;
}
// ═════════════════════════════════════════════════════════════════
// ADIM 2: TAKIM GEÇMİŞ PERFORMANSI
// ═════════════════════════════════════════════════════════════════
console.log('\n📈 ADIM 2: TAKIM PERFORMANS ANALİZİ');
console.log('─'.repeat(40));
// Ev sahibi son 10 maç
const homeMatches = await prisma.match.findMany({
where: {
OR: [{ homeTeamId: match.homeTeamId }, { awayTeamId: match.homeTeamId }],
sport: 'football',
state: 'postGame',
scoreHome: { not: null },
scoreAway: { not: null },
},
orderBy: { mstUtc: 'desc' },
take: 10,
});
const homeStats = calculateTeamStats(homeMatches, match.homeTeamId);
console.log(`\n🏠 ${match.homeTeam?.name}:`);
console.log(
` Son 10: ${homeStats.wins}G ${homeStats.draws}B ${homeStats.losses}M`,
);
console.log(
` Gol: ${homeStats.goalsFor} attı, ${homeStats.goalsAgainst} yedi`,
);
console.log(` Ortalama: ${(homeStats.goalsFor / 10).toFixed(2)} gol/maç`);
// Deplasman son 10 maç
const awayMatches = await prisma.match.findMany({
where: {
OR: [{ homeTeamId: match.awayTeamId }, { awayTeamId: match.awayTeamId }],
sport: 'football',
state: 'postGame',
scoreHome: { not: null },
scoreAway: { not: null },
},
orderBy: { mstUtc: 'desc' },
take: 10,
});
const awayStats = calculateTeamStats(awayMatches, match.awayTeamId);
console.log(`\n✈️ ${match.awayTeam?.name}:`);
console.log(
` Son 10: ${awayStats.wins}G ${awayStats.draws}B ${awayStats.losses}M`,
);
console.log(
` Gol: ${awayStats.goalsFor} attı, ${awayStats.goalsAgainst} yedi`,
);
console.log(` Ortalama: ${(awayStats.goalsFor / 10).toFixed(2)} gol/maç`);
// ═════════════════════════════════════════════════════════════════
// ADIM 3: HAKEM ANALİZİ
// ═════════════════════════════════════════════════════════════════
console.log('\n👨‍⚖️ ADIM 3: HAKEM ANALİZİ');
console.log('─'.repeat(40));
const mainReferee = match.officials?.find(
(o) => o.role?.name === 'Orta Hakem',
);
if (mainReferee) {
console.log(`\nHakem: ${mainReferee.name}`);
// Bu hakemin yönettiği maçları bul
const refereeMatches = await prisma.matchOfficial.findMany({
where: { name: mainReferee.name, roleId: 1 },
include: { match: true },
take: 20,
});
if (refereeMatches.length > 0) {
let homeWins = 0,
draws = 0,
awayWins = 0;
let totalCards = 0;
for (const rm of refereeMatches) {
if (rm.match?.scoreHome !== null && rm.match?.scoreAway !== null) {
if (rm.match.scoreHome > rm.match.scoreAway) homeWins++;
else if (rm.match.scoreHome < rm.match.scoreAway) awayWins++;
else draws++;
}
}
const total = homeWins + draws + awayWins;
if (total > 0) {
console.log(` Yönettiği maçlar: ${total}`);
console.log(
` Ev sahibi kazanma: %${((homeWins / total) * 100).toFixed(1)}`,
);
console.log(` Beraberlik: %${((draws / total) * 100).toFixed(1)}`);
console.log(
` Deplasman kazanma: %${((awayWins / total) * 100).toFixed(1)}`,
);
}
}
} else {
console.log('Hakem bilgisi yok');
}
// ═════════════════════════════════════════════════════════════════
// ADIM 4: LİG ÖZELLİKLERİ
// ═════════════════════════════════════════════════════════════════
console.log('\n🏆 ADIM 4: LİG ANALİZİ');
console.log('─'.repeat(40));
const leagueMatches = await prisma.match.findMany({
where: { leagueId: match.leagueId, sport: 'football', state: 'postGame' },
take: 100,
});
let leagueHomeWins = 0,
leagueDraws = 0,
leagueAwayWins = 0;
let leagueGoals = 0;
for (const lm of leagueMatches) {
if (lm.scoreHome !== null && lm.scoreAway !== null) {
leagueGoals += lm.scoreHome + lm.scoreAway;
if (lm.scoreHome > lm.scoreAway) leagueHomeWins++;
else if (lm.scoreHome < lm.scoreAway) leagueAwayWins++;
else leagueDraws++;
}
}
const leagueTotal = leagueHomeWins + leagueDraws + leagueAwayWins;
if (leagueTotal > 0) {
console.log(`\nLig: ${match.league?.name}`);
console.log(
` Ev sahibi kazanma: %${((leagueHomeWins / leagueTotal) * 100).toFixed(1)}`,
);
console.log(
` Beraberlik: %${((leagueDraws / leagueTotal) * 100).toFixed(1)}`,
);
console.log(
` Deplasman kazanma: %${((leagueAwayWins / leagueTotal) * 100).toFixed(1)}`,
);
console.log(
` Ortalama gol: ${(leagueGoals / leagueTotal).toFixed(2)}/maç`,
);
}
// ═════════════════════════════════════════════════════════════════
// ADIM 5: GLM-5 TAHMİN MODELİ
// ═════════════════════════════════════════════════════════════════
console.log('\n\n🤖 ADIM 5: GLM-5 TAHMİN MODELİ');
console.log('═'.repeat(50));
// Ağırlıklar
const weights = {
odds: 0.4, // Bookmaker en güvenilir
form: 0.25, // Son performans
homeAdvantage: 0.15, // Ev sahibi avantajı
league: 0.1, // Lig eğilimleri
referee: 0.1, // Hakem etkisi
};
console.log(`\nAğırlıklar:`);
console.log(` Oranlar: %${weights.odds * 100}`);
console.log(` Form: %${weights.form * 100}`);
console.log(` Ev Avantajı: %${weights.homeAdvantage * 100}`);
console.log(` Lig: %${weights.league * 100}`);
console.log(` Hakem: %${weights.referee * 100}`);
// Base skorlar (oranlardan)
let homeScore = odds.normHome || 33;
let drawScore = odds.normDraw || 33;
let awayScore = odds.normAway || 33;
// Form düzeltmesi
const homeFormScore = ((homeStats.wins * 3 + homeStats.draws) / 30) * 100;
const awayFormScore = ((awayStats.wins * 3 + awayStats.draws) / 30) * 100;
const formDiff = homeFormScore - awayFormScore;
console.log(`\nForm Skorları:`);
console.log(` Ev Sahibi: ${homeFormScore.toFixed(1)}`);
console.log(` Deplasman: ${awayFormScore.toFixed(1)}`);
console.log(` Fark: ${formDiff.toFixed(1)} (ev lehine pozitif)`);
// Ev sahibi avantajı (genel istatistik)
const homeAdvantageBonus = 8; // %8 ev sahibi avantajı
// Final hesaplama
homeScore =
(odds.normHome || 33) * weights.odds +
homeFormScore * 0.5 * weights.form +
homeAdvantageBonus * weights.homeAdvantage +
(leagueHomeWins / leagueTotal) * 100 * weights.league;
awayScore =
(odds.normAway || 33) * weights.odds +
awayFormScore * 0.5 * weights.form +
0 * weights.homeAdvantage + // Deplasman avantajı yok
(leagueAwayWins / leagueTotal) * 100 * weights.league;
drawScore =
(odds.normDraw || 33) * weights.odds +
(100 - Math.abs(formDiff)) * 0.1 * weights.form +
(leagueDraws / leagueTotal) * 100 * weights.league;
// Normalize
const totalScore = homeScore + drawScore + awayScore;
const finalHome = (homeScore / totalScore) * 100;
const finalDraw = (drawScore / totalScore) * 100;
const finalAway = (awayScore / totalScore) * 100;
console.log(`\n🎯 FINAL TAHMİN:`);
console.log('─'.repeat(40));
console.log(` 1 (Ev Sahibi): %${finalHome.toFixed(1)}`);
console.log(` X (Beraberlik): %${finalDraw.toFixed(1)}`);
console.log(` 2 (Deplasman): %${finalAway.toFixed(1)}`);
// Kazanan belirle
let prediction, confidence;
if (finalHome > finalDraw && finalHome > finalAway) {
prediction = '1';
confidence = finalHome;
} else if (finalAway > finalDraw) {
prediction = '2';
confidence = finalAway;
} else {
prediction = 'X';
confidence = finalDraw;
}
console.log(`\n🏆 TAHMİN: ${prediction}`);
console.log(` Güven: %${confidence.toFixed(1)}`);
// Alt/Üst tahmini
const avgGoals =
(homeStats.goalsFor +
homeStats.goalsAgainst +
awayStats.goalsFor +
awayStats.goalsAgainst) /
20;
const ou25Prediction = avgGoals > 2.5 ? 'ÜST' : 'ALT';
console.log(`\n⚽ 2.5 ${ou25Prediction} (Ort: ${avgGoals.toFixed(2)} gol)`);
if (isFinished) {
console.log(`\n✅ GERÇEK SONUÇ: ${match.scoreHome} - ${match.scoreAway}`);
const actual =
match.scoreHome > match.scoreAway
? '1'
: match.scoreHome < match.scoreAway
? '2'
: 'X';
console.log(` Tahmin ${prediction === actual ? 'DOĞRU ✓' : 'YANLIŞ ✗'}`);
}
}
function calculateTeamStats(matches, teamId) {
let wins = 0,
draws = 0,
losses = 0;
let goalsFor = 0,
goalsAgainst = 0;
for (const m of matches) {
const isHome = m.homeTeamId === teamId;
const gf = isHome ? m.scoreHome : m.scoreAway;
const ga = isHome ? m.scoreAway : m.scoreHome;
goalsFor += gf || 0;
goalsAgainst += ga || 0;
if (gf > ga) wins++;
else if (gf < ga) losses++;
else draws++;
}
return { wins, draws, losses, goalsFor, goalsAgainst };
}
glm5PredictionApproach().catch(console.error);