Files
iddaai-be/scripts/single-match-prediction.js
fahricansecer 2f0b85a0c7
Deploy Iddaai Backend / build-and-deploy (push) Failing after 18s
first (part 2: other directories)
2026-04-16 15:11:25 +03:00

586 lines
23 KiB
JavaScript
Raw Permalink 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.
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
async function predictMatch() {
const matchId = '2m4sef2l4im49rda90k3p41lg';
console.log('\n');
console.log(
'╔══════════════════════════════════════════════════════════════════╗',
);
console.log(
'║ GLM-5 TAHMİN - MAÇ ID: ' + matchId.substring(0, 20) + '... ║',
);
console.log(
'╚══════════════════════════════════════════════════════════════════╝',
);
// MAÇ BİLGİLERİNİ GETİR
const match = await prisma.match.findUnique({
where: { id: matchId },
include: {
homeTeam: true,
awayTeam: true,
league: { include: { country: true } },
oddCategories: {
include: { selections: true },
},
officials: { include: { role: true } },
aiFeatures: true,
},
});
if (!match) {
console.log('❌ Maç bulunamadı!');
await prisma.$disconnect();
return;
}
console.log(
'\n═══════════════════════════════════════════════════════════════',
);
console.log('⚽ MAÇ BİLGİLERİ');
console.log(
'═══════════════════════════════════════════════════════════════',
);
console.log(`\n🏠 Ev Sahibi: ${match.homeTeam?.name || 'Bilinmiyor'}`);
console.log(`✈️ Deplasman: ${match.awayTeam?.name || 'Bilinmiyor'}`);
console.log(
`🏆 Lig: ${match.league?.name || 'Bilinmiyor'} (${match.league?.country?.name || ''})`,
);
console.log(
`📅 Tarih: ${new Date(Number(match.mstUtc)).toLocaleString('tr-TR', { timeZone: 'Europe/Istanbul' })}`,
);
console.log(`📊 Durum: ${match.state} / ${match.status}`);
console.log(`🔢 İddaa Kodu: ${match.iddaaCode || 'Yok'}`);
if (match.scoreHome !== null && match.scoreAway !== null) {
console.log(
`\n⚠️ DİKKAT: Maç bitmiş! Skor: ${match.scoreHome} - ${match.scoreAway}`,
);
}
// ═════════════════════════════════════════════════════════════════
// 1. ORAN ANALİZİ
// ═════════════════════════════════════════════════════════════════
console.log(
'\n═══════════════════════════════════════════════════════════════',
);
console.log('📊 1. ORAN ANALİZİ');
console.log(
'═══════════════════════════════════════════════════════════════',
);
const odds = {
ms_h: null,
ms_d: null,
ms_a: null,
dc_1x: null,
dc_x2: null,
dc_12: null,
ou25_o: null,
ou25_u: null,
ou15_o: null,
ou15_u: null,
ou35_o: null,
ou35_u: null,
btts_y: null,
btts_n: null,
ht_h: null,
ht_d: null,
ht_a: null,
};
console.log('\n📋 Tüm Oran Kategorileri:\n');
for (const cat of match.oddCategories) {
const selections = cat.selections
.map((s) => `${s.name}: ${s.oddValue}`)
.join(' | ');
console.log(` ${cat.name}: ${selections}`);
// Maç Sonucu
if (cat.name?.includes('Maç Sonucu') || cat.name === 'MS') {
for (const sel of cat.selections) {
if (sel.name === '1') odds.ms_h = parseFloat(sel.oddValue);
if (sel.name === 'X') odds.ms_d = parseFloat(sel.oddValue);
if (sel.name === '2') odds.ms_a = parseFloat(sel.oddValue);
}
}
// Çifte Şans
if (cat.name?.includes('Çifte Şans')) {
for (const sel of cat.selections) {
if (sel.name === '1-X') odds.dc_1x = parseFloat(sel.oddValue);
if (sel.name === 'X-2') odds.dc_x2 = parseFloat(sel.oddValue);
if (sel.name === '1-2') odds.dc_12 = parseFloat(sel.oddValue);
}
}
// 2.5 Alt/Üst
if (cat.name?.includes('2,5') || cat.name?.includes('2.5')) {
for (const sel of cat.selections) {
if (sel.name === 'Alt' || sel.name === 'A')
odds.ou25_u = parseFloat(sel.oddValue);
if (sel.name === 'Üst' || sel.name === 'Ü')
odds.ou25_o = parseFloat(sel.oddValue);
}
}
// 1.5 Alt/Üst
if (cat.name?.includes('1,5') || cat.name?.includes('1.5')) {
for (const sel of cat.selections) {
if (sel.name === 'Alt' || sel.name === 'A')
odds.ou15_u = parseFloat(sel.oddValue);
if (sel.name === 'Üst' || sel.name === 'Ü')
odds.ou15_o = parseFloat(sel.oddValue);
}
}
// 3.5 Alt/Üst
if (cat.name?.includes('3,5') || cat.name?.includes('3.5')) {
for (const sel of cat.selections) {
if (sel.name === 'Alt' || sel.name === 'A')
odds.ou35_u = parseFloat(sel.oddValue);
if (sel.name === 'Üst' || sel.name === 'Ü')
odds.ou35_o = parseFloat(sel.oddValue);
}
}
// KG Var/Yok
if (
cat.name?.toLowerCase().includes('karşılıklı') ||
cat.name?.includes('KG') ||
cat.name?.includes('Gol')
) {
for (const sel of cat.selections) {
if (sel.name === 'Var' || sel.name === 'Evet' || sel.name === 'KG Var')
odds.btts_y = parseFloat(sel.oddValue);
if (sel.name === 'Yok' || sel.name === 'Hayır' || sel.name === 'KG Yok')
odds.btts_n = parseFloat(sel.oddValue);
}
}
// İlk Yarı
if (cat.name?.includes('1. Yarı') && cat.name?.includes('Sonuc')) {
for (const sel of cat.selections) {
if (sel.name === '1') odds.ht_h = parseFloat(sel.oddValue);
if (sel.name === 'X') odds.ht_d = parseFloat(sel.oddValue);
if (sel.name === '2') odds.ht_a = parseFloat(sel.oddValue);
}
}
}
// Implied Probability Hesapla
if (odds.ms_h && odds.ms_d && odds.ms_a) {
const rawHome = (1 / odds.ms_h) * 100;
const rawDraw = (1 / odds.ms_d) * 100;
const rawAway = (1 / odds.ms_a) * 100;
const total = rawHome + rawDraw + rawAway;
console.log(
`\n📊 MS Oranları: 1=${odds.ms_h} | X=${odds.ms_d} | 2=${odds.ms_a}`,
);
console.log(`📈 Bookmaker Margin: %${(total - 100).toFixed(1)}`);
console.log(`🎯 Normalize Olasılık:`);
console.log(` 1 (Ev): %${((rawHome / total) * 100).toFixed(1)}`);
console.log(` X (Beraberlik): %${((rawDraw / total) * 100).toFixed(1)}`);
console.log(` 2 (Deplasman): %${((rawAway / total) * 100).toFixed(1)}`);
odds.normHome = (rawHome / total) * 100;
odds.normDraw = (rawDraw / total) * 100;
odds.normAway = (rawAway / total) * 100;
}
// ═════════════════════════════════════════════════════════════════
// 2. TAKIM FORM ANALİZİ
// ═════════════════════════════════════════════════════════════════
console.log(
'\n═══════════════════════════════════════════════════════════════',
);
console.log('📈 2. TAKIM FORM ANALİZİ');
console.log(
'═══════════════════════════════════════════════════════════════',
);
// 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 },
},
include: { homeTeam: true, awayTeam: true, league: true },
orderBy: { mstUtc: 'desc' },
take: 10,
});
console.log(`\n🏠 ${match.homeTeam?.name} - Son ${homeMatches.length} Maç:`);
let homeWins = 0,
homeDraws = 0,
homeLosses = 0;
let homeGoalsFor = 0,
homeGoalsAgainst = 0;
for (const m of homeMatches) {
const isHome = m.homeTeamId === match.homeTeamId;
const gf = isHome ? m.scoreHome : m.scoreAway;
const ga = isHome ? m.scoreAway : m.scoreHome;
homeGoalsFor += gf || 0;
homeGoalsAgainst += ga || 0;
let result;
if (gf > ga) {
homeWins++;
result = '✅';
} else if (gf < ga) {
homeLosses++;
result = '❌';
} else {
homeDraws++;
result = '🤝';
}
console.log(
` ${result} ${m.homeTeam?.name?.substring(0, 15).padEnd(15)} ${m.scoreHome}-${m.scoreAway} ${m.awayTeam?.name?.substring(0, 15)}`,
);
}
const homeFormScore = ((homeWins * 3 + homeDraws) / 30) * 100;
console.log(
`\n 📊 Özet: ${homeWins}G ${homeDraws}B ${homeLosses}M | ${homeGoalsFor} attı, ${homeGoalsAgainst} yedi`,
);
console.log(` ⚡ Form Skoru: ${homeFormScore.toFixed(1)}/100`);
// 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 },
},
include: { homeTeam: true, awayTeam: true, league: true },
orderBy: { mstUtc: 'desc' },
take: 10,
});
console.log(`\n✈️ ${match.awayTeam?.name} - Son ${awayMatches.length} Maç:`);
let awayWins = 0,
awayDraws = 0,
awayLosses = 0;
let awayGoalsFor = 0,
awayGoalsAgainst = 0;
for (const m of awayMatches) {
const isHome = m.homeTeamId === match.awayTeamId;
const gf = isHome ? m.scoreHome : m.scoreAway;
const ga = isHome ? m.scoreAway : m.scoreHome;
awayGoalsFor += gf || 0;
awayGoalsAgainst += ga || 0;
let result;
if (gf > ga) {
awayWins++;
result = '✅';
} else if (gf < ga) {
awayLosses++;
result = '❌';
} else {
awayDraws++;
result = '🤝';
}
console.log(
` ${result} ${m.homeTeam?.name?.substring(0, 15).padEnd(15)} ${m.scoreHome}-${m.scoreAway} ${m.awayTeam?.name?.substring(0, 15)}`,
);
}
const awayFormScore = ((awayWins * 3 + awayDraws) / 30) * 100;
console.log(
`\n 📊 Özet: ${awayWins}G ${awayDraws}B ${awayLosses}M | ${awayGoalsFor} attı, ${awayGoalsAgainst} yedi`,
);
console.log(` ⚡ Form Skoru: ${awayFormScore.toFixed(1)}/100`);
const formDiff = homeFormScore - awayFormScore;
console.log(
`\n📈 Form Farkı: ${formDiff > 0 ? '+' : ''}${formDiff.toFixed(1)} (${formDiff > 0 ? 'Ev lehine' : 'Deplasman lehine'})`,
);
// ═════════════════════════════════════════════════════════════════
// 3. HEAD-TO-HEAD
// ═════════════════════════════════════════════════════════════════
console.log(
'\n═══════════════════════════════════════════════════════════════',
);
console.log('🔄 3. HEAD-TO-HEAD (Karşılıklı Maçlar)');
console.log(
'═══════════════════════════════════════════════════════════════',
);
const h2hMatches = await prisma.match.findMany({
where: {
OR: [
{ homeTeamId: match.homeTeamId, awayTeamId: match.awayTeamId },
{ homeTeamId: match.awayTeamId, awayTeamId: match.homeTeamId },
],
sport: 'football',
state: 'postGame',
},
include: { homeTeam: true, awayTeam: true },
orderBy: { mstUtc: 'desc' },
take: 5,
});
if (h2hMatches.length > 0) {
let h2hHomeWins = 0,
h2hDraws = 0,
h2hAwayWins = 0;
for (const m of h2hMatches) {
const homeTeamIsHome = m.homeTeamId === match.homeTeamId;
const result =
m.scoreHome > m.scoreAway
? homeTeamIsHome
? '1'
: '2'
: m.scoreHome < m.scoreAway
? homeTeamIsHome
? '2'
: '1'
: 'X';
if (result === '1') h2hHomeWins++;
else if (result === '2') h2hAwayWins++;
else h2hDraws++;
console.log(
` ${m.homeTeam?.name} ${m.scoreHome}-${m.scoreAway} ${m.awayTeam?.name} [${result}]`,
);
}
console.log(
`\n 📊 H2H: ${match.homeTeam?.name} ${h2hHomeWins}G, ${h2hDraws}B, ${match.awayTeam?.name} ${h2hAwayWins}G`,
);
} else {
console.log(' ⚠️ Karşılıklı maç bulunamadı');
}
// ═════════════════════════════════════════════════════════════════
// 4. HAKEM ANALİZİ
// ═════════════════════════════════════════════════════════════════
console.log(
'\n═══════════════════════════════════════════════════════════════',
);
console.log('👨‍⚖️ 4. HAKEM ANALİZİ');
console.log(
'═══════════════════════════════════════════════════════════════',
);
const mainReferee = match.officials?.find(
(o) => o.role?.name === 'Orta Hakem',
);
if (mainReferee) {
console.log(`\n👤 Hakem: ${mainReferee.name}`);
const refereeMatches = await prisma.matchOfficial.findMany({
where: { name: mainReferee.name, roleId: 1 },
include: { match: true },
take: 20,
});
let refHomeWins = 0,
refDraws = 0,
refAwayWins = 0;
for (const rm of refereeMatches) {
if (rm.match?.scoreHome !== null && rm.match?.scoreAway !== null) {
if (rm.match.scoreHome > rm.match.scoreAway) refHomeWins++;
else if (rm.match.scoreHome < rm.match.scoreAway) refAwayWins++;
else refDraws++;
}
}
const refTotal = refHomeWins + refDraws + refAwayWins;
if (refTotal > 0) {
console.log(` 📊 Yönettiği ${refTotal} maç:`);
console.log(
` Ev sahibi kazanma: %${((refHomeWins / refTotal) * 100).toFixed(1)}`,
);
console.log(
` Beraberlik: %${((refDraws / refTotal) * 100).toFixed(1)}`,
);
console.log(
` Deplasman kazanma: %${((refAwayWins / refTotal) * 100).toFixed(1)}`,
);
}
} else {
console.log(' ⚠️ Hakem bilgisi yok');
}
// ═════════════════════════════════════════════════════════════════
// 5. LİG ANALİZİ
// ═════════════════════════════════════════════════════════════════
console.log(
'\n═══════════════════════════════════════════════════════════════',
);
console.log('🏆 5. LİG ANALİZİ');
console.log(
'═══════════════════════════════════════════════════════════════',
);
const leagueMatches = await prisma.match.findMany({
where: { leagueId: match.leagueId, sport: 'football', state: 'postGame' },
take: 100,
});
let lgHomeWins = 0,
lgDraws = 0,
lgAwayWins = 0,
lgGoals = 0;
for (const lm of leagueMatches) {
if (lm.scoreHome !== null && lm.scoreAway !== null) {
lgGoals += lm.scoreHome + lm.scoreAway;
if (lm.scoreHome > lm.scoreAway) lgHomeWins++;
else if (lm.scoreHome < lm.scoreAway) lgAwayWins++;
else lgDraws++;
}
}
const lgTotal = lgHomeWins + lgDraws + lgAwayWins;
if (lgTotal > 0) {
console.log(
`\n📊 ${match.league?.name} - İstatistikler (son ${lgTotal} maç):`,
);
console.log(` Ev kazanma: %${((lgHomeWins / lgTotal) * 100).toFixed(1)}`);
console.log(` Beraberlik: %${((lgDraws / lgTotal) * 100).toFixed(1)}`);
console.log(` Deplasman: %${((lgAwayWins / lgTotal) * 100).toFixed(1)}`);
console.log(` Ortalama gol: ${(lgGoals / lgTotal).toFixed(2)}/maç`);
}
// ═════════════════════════════════════════════════════════════════
// 6. AI FEATURES (VARSa)
// ═════════════════════════════════════════════════════════════════
if (match.aiFeatures) {
console.log(
'\n═══════════════════════════════════════════════════════════════',
);
console.log('🤖 6. AI ÖZELLİKLERİ');
console.log(
'═══════════════════════════════════════════════════════════════',
);
console.log(`\n Home ELO: ${match.aiFeatures.homeElo.toFixed(0)}`);
console.log(` Away ELO: ${match.aiFeatures.awayElo.toFixed(0)}`);
console.log(` Home Form: ${match.aiFeatures.homeFormScore.toFixed(1)}`);
console.log(` Away Form: ${match.aiFeatures.awayFormScore.toFixed(1)}`);
console.log(
` Eksik Oyuncu Etkisi: ${match.aiFeatures.missingPlayersImpact}`,
);
}
// ═════════════════════════════════════════════════════════════════
// FİNAL TAHMİN
// ═════════════════════════════════════════════════════════════════
console.log('\n');
console.log(
'╔══════════════════════════════════════════════════════════════════╗',
);
console.log(
'║ 🎯 GLM-5 FİNAL TAHMİN ║',
);
console.log(
'╚══════════════════════════════════════════════════════════════════╝',
);
// Ağırlıklar
const w = { odds: 0.4, form: 0.3, home: 0.15, league: 0.15 };
let homeScore =
(odds.normHome || 33) * w.odds +
homeFormScore * w.form +
8 * w.home + // Ev avantajı
(lgHomeWins / lgTotal) * 100 * w.league;
let awayScore =
(odds.normAway || 33) * w.odds +
awayFormScore * w.form +
0 * w.home +
(lgAwayWins / lgTotal) * 100 * w.league;
let drawScore =
(odds.normDraw || 33) * w.odds +
(100 - Math.abs(formDiff)) * 0.2 * w.form +
(lgDraws / lgTotal) * 100 * w.league;
const total = homeScore + drawScore + awayScore;
const finalHome = (homeScore / total) * 100;
const finalDraw = (drawScore / total) * 100;
const finalAway = (awayScore / total) * 100;
console.log(`\n📊 Olasılıklar:`);
console.log(
` 1 (${match.homeTeam?.name?.substring(0, 15)}): %${finalHome.toFixed(1)}`,
);
console.log(` X (Beraberlik): %${finalDraw.toFixed(1)}`);
console.log(
` 2 (${match.awayTeam?.name?.substring(0, 15)}): %${finalAway.toFixed(1)}`,
);
// Tahmin
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;
}
// Alt/Üst
const avgGoals =
(homeGoalsFor + homeGoalsAgainst + awayGoalsFor + awayGoalsAgainst) / 20;
const ou25 = avgGoals > 2.5 ? 'ÜST' : 'ALT';
const ou25Conf = Math.min(80, Math.abs(avgGoals - 2.5) * 30 + 50);
console.log(`\n🏆 TAHMİN: ${prediction}`);
console.log(` Güven: %${confidence.toFixed(1)}`);
console.log(`\n⚽ 2.5 ${ou25}`);
console.log(` Güven: %${ou25Conf.toFixed(1)}`);
console.log(` Beklenen Gol: ${avgGoals.toFixed(2)}`);
// Gerçek sonuç (eğer maç bitmişse)
if (match.scoreHome !== null && match.scoreAway !== null) {
const actual =
match.scoreHome > match.scoreAway
? '1'
: match.scoreHome < match.scoreAway
? '2'
: 'X';
const actualGoals = match.scoreHome + match.scoreAway;
const actualOU = actualGoals > 2.5 ? 'ÜST' : 'ALT';
console.log(
`\n═══════════════════════════════════════════════════════════════`,
);
console.log(`📊 GERÇEK SONUÇ`);
console.log(
`═══════════════════════════════════════════════════════════════`,
);
console.log(` Skor: ${match.scoreHome} - ${match.scoreAway}`);
console.log(` Sonuç: ${actual}`);
console.log(` Alt/Üst: ${actualOU} (${actualGoals} gol)`);
const msCorrect = prediction === actual;
const ouCorrect = ou25 === actualOU;
console.log(`\n 🎯 MS Tahmin: ${msCorrect ? '✅ DOĞRU' : '❌ YANLIŞ'}`);
console.log(` 🎯 2.5 Tahmin: ${ouCorrect ? '✅ DOĞRU' : '❌ YANLIŞ'}`);
}
console.log('\n');
await prisma.$disconnect();
}
predictMatch().catch(console.error);