cr
This commit is contained in:
+52
-52
@@ -1,7 +1,7 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { HttpService } from '@nestjs/axios';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { Injectable, Logger } from "@nestjs/common";
|
||||
import { HttpService } from "@nestjs/axios";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
export interface AIPredictionResult {
|
||||
matchId: string;
|
||||
@@ -46,7 +46,7 @@ export class AiService {
|
||||
private readonly configService: ConfigService,
|
||||
) {
|
||||
this.pythonEngineUrl =
|
||||
this.configService.get('AI_ENGINE_URL') || 'http://127.0.0.1:8000';
|
||||
this.configService.get("AI_ENGINE_URL") || "http://127.0.0.1:8000";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,9 +61,9 @@ export class AiService {
|
||||
_eventData: any[],
|
||||
): Promise<AIPredictionResult | null> {
|
||||
try {
|
||||
const matchId = String(matchDetails?.matchId || '').trim();
|
||||
const matchId = String(matchDetails?.matchId || "").trim();
|
||||
if (!matchId) {
|
||||
this.logger.warn('Skipping AI call: missing matchId');
|
||||
this.logger.warn("Skipping AI call: missing matchId");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -102,18 +102,18 @@ export class AiService {
|
||||
.map((p: any) => `${p.market}: ${p.pick}`);
|
||||
|
||||
const mappedPredictions = picks.map((p: any) => ({
|
||||
betType: String(p.market || ''),
|
||||
prediction: String(p.pick || ''),
|
||||
betType: String(p.market || ""),
|
||||
prediction: String(p.pick || ""),
|
||||
confidence: Number(p.calibrated_confidence ?? p.confidence ?? 0),
|
||||
probabilities: {},
|
||||
reasoning: Array.isArray(p.reasons)
|
||||
? p.reasons.join(' | ')
|
||||
? p.reasons.join(" | ")
|
||||
: Array.isArray(p.decision_reasons)
|
||||
? p.decision_reasons.join(' | ')
|
||||
: '',
|
||||
odd: typeof p.odds === 'number' ? p.odds : undefined,
|
||||
? p.decision_reasons.join(" | ")
|
||||
: "",
|
||||
odd: typeof p.odds === "number" ? p.odds : undefined,
|
||||
valueBet:
|
||||
typeof p.edge === 'number'
|
||||
typeof p.edge === "number"
|
||||
? {
|
||||
isValue: p.edge > 0,
|
||||
edge: p.edge,
|
||||
@@ -138,8 +138,8 @@ export class AiService {
|
||||
: recommendedBets,
|
||||
homeAnalysis: undefined,
|
||||
awayAnalysis: undefined,
|
||||
expertComment: data.ai_commentary || data.expert_comment || '',
|
||||
modelVersion: data.model_version || 'v25.main',
|
||||
expertComment: data.ai_commentary || data.expert_comment || "",
|
||||
modelVersion: data.model_version || "v25.main",
|
||||
confidenceScore:
|
||||
confidenceScore > 1 ? confidenceScore : confidenceScore * 100,
|
||||
expectedGoals: data?.score_prediction?.xg_total,
|
||||
@@ -161,10 +161,10 @@ export class AiService {
|
||||
prediction: p.pick,
|
||||
confidence: p.calibrated_confidence ?? p.confidence ?? 0,
|
||||
probabilities: {},
|
||||
reasoning: Array.isArray(p.reasons) ? p.reasons.join(' | ') : '',
|
||||
reasoning: Array.isArray(p.reasons) ? p.reasons.join(" | ") : "",
|
||||
odd: p.odds || 0,
|
||||
valueBet: {
|
||||
is_value: typeof p.edge === 'number' ? p.edge > 0 : false,
|
||||
is_value: typeof p.edge === "number" ? p.edge > 0 : false,
|
||||
edge: p.edge || 0,
|
||||
},
|
||||
}));
|
||||
@@ -176,21 +176,21 @@ export class AiService {
|
||||
valueBets: allPredictions.filter((p: any) => p.valueBet?.is_value),
|
||||
homeAnalysis: null,
|
||||
awayAnalysis: null,
|
||||
expertComment: pyData.ai_commentary || '',
|
||||
winnerPrediction: firstPick?.prediction || 'N/A',
|
||||
scorePrediction: pyData.score_prediction?.ft || '-',
|
||||
expertComment: pyData.ai_commentary || "",
|
||||
winnerPrediction: firstPick?.prediction || "N/A",
|
||||
scorePrediction: pyData.score_prediction?.ft || "-",
|
||||
confidenceScore:
|
||||
typeof firstPick?.confidence === 'number' ? firstPick.confidence : 0,
|
||||
modelVersion: pyData.model_version || 'v25.main',
|
||||
typeof firstPick?.confidence === "number" ? firstPick.confidence : 0,
|
||||
modelVersion: pyData.model_version || "v25.main",
|
||||
expectedGoals: pyData.score_prediction?.xg_total || 0,
|
||||
keyInsights: [
|
||||
`Model: ${pyData.model_version || 'v25.main'}`,
|
||||
`Risk: ${pyData.risk?.level || 'N/A'} (${pyData.risk?.score ?? 0})`,
|
||||
`Data Quality: ${pyData.data_quality?.label || 'N/A'}`,
|
||||
`Model: ${pyData.model_version || "v25.main"}`,
|
||||
`Risk: ${pyData.risk?.level || "N/A"} (${pyData.risk?.score ?? 0})`,
|
||||
`Data Quality: ${pyData.data_quality?.label || "N/A"}`,
|
||||
`xG Beklentisi: ${
|
||||
typeof pyData.score_prediction?.xg_total === 'number'
|
||||
typeof pyData.score_prediction?.xg_total === "number"
|
||||
? pyData.score_prediction.xg_total.toFixed(2)
|
||||
: 'N/A'
|
||||
: "N/A"
|
||||
}`,
|
||||
],
|
||||
};
|
||||
@@ -206,33 +206,33 @@ export class AiService {
|
||||
// MS 1 oranını bul
|
||||
const ms1 = odds.find(
|
||||
(o: any) =>
|
||||
o.category?.toLowerCase().includes('maç sonucu') && o.selection === '1',
|
||||
o.category?.toLowerCase().includes("maç sonucu") && o.selection === "1",
|
||||
);
|
||||
|
||||
// KG Var oranını bul
|
||||
const kgVar = odds.find(
|
||||
(o: any) =>
|
||||
o.category?.toLowerCase().includes('karşılıklı gol') &&
|
||||
o.selection?.toLowerCase() === 'var',
|
||||
o.category?.toLowerCase().includes("karşılıklı gol") &&
|
||||
o.selection?.toLowerCase() === "var",
|
||||
);
|
||||
|
||||
// Alt 2.5 oranını bul
|
||||
const alt25 = odds.find(
|
||||
(o: any) =>
|
||||
o.category?.toLowerCase().includes('alt/üst') &&
|
||||
o.selection?.toLowerCase() === 'alt',
|
||||
o.category?.toLowerCase().includes("alt/üst") &&
|
||||
o.selection?.toLowerCase() === "alt",
|
||||
);
|
||||
|
||||
// Tactic 1: Benzer MS oranları
|
||||
if (ms1?.odd_value) {
|
||||
tactics.push({
|
||||
tacticName: 'Benzer Maç Sonucu Oranları',
|
||||
tacticName: "Benzer Maç Sonucu Oranları",
|
||||
description:
|
||||
'Ev sahibi galibiyeti için benzer oran aralığındaki maçlar',
|
||||
"Ev sahibi galibiyeti için benzer oran aralığındaki maçlar",
|
||||
odds: [
|
||||
{
|
||||
categoryName: 'Maç Sonucu',
|
||||
selectionName: '1',
|
||||
categoryName: "Maç Sonucu",
|
||||
selectionName: "1",
|
||||
value: parseFloat(ms1.odd_value),
|
||||
tolerance: 0.3,
|
||||
},
|
||||
@@ -243,18 +243,18 @@ export class AiService {
|
||||
// Tactic 2: Benzer KG + AU oranları
|
||||
if (kgVar?.odd_value && alt25?.odd_value) {
|
||||
tactics.push({
|
||||
tacticName: 'Benzer Gol Beklentisi',
|
||||
description: 'Karşılıklı gol ve toplam gol benzerliği',
|
||||
tacticName: "Benzer Gol Beklentisi",
|
||||
description: "Karşılıklı gol ve toplam gol benzerliği",
|
||||
odds: [
|
||||
{
|
||||
categoryName: 'Karşılıklı Gol',
|
||||
selectionName: 'Var',
|
||||
categoryName: "Karşılıklı Gol",
|
||||
selectionName: "Var",
|
||||
value: parseFloat(kgVar.odd_value),
|
||||
tolerance: 0.4,
|
||||
},
|
||||
{
|
||||
categoryName: '2,5 Alt/Üst',
|
||||
selectionName: 'Alt',
|
||||
categoryName: "2,5 Alt/Üst",
|
||||
selectionName: "Alt",
|
||||
value: parseFloat(alt25.odd_value),
|
||||
tolerance: 0.3,
|
||||
},
|
||||
@@ -265,12 +265,12 @@ export class AiService {
|
||||
// Tactic 3: Favori analizi
|
||||
if (ms1?.odd_value && parseFloat(ms1.odd_value) < 1.8) {
|
||||
tactics.push({
|
||||
tacticName: 'Favori Takım Analizi',
|
||||
description: 'Benzer şekilde favori olan ev sahibi takımların maçları',
|
||||
tacticName: "Favori Takım Analizi",
|
||||
description: "Benzer şekilde favori olan ev sahibi takımların maçları",
|
||||
odds: [
|
||||
{
|
||||
categoryName: 'Maç Sonucu',
|
||||
selectionName: '1',
|
||||
categoryName: "Maç Sonucu",
|
||||
selectionName: "1",
|
||||
value: parseFloat(ms1.odd_value),
|
||||
tolerance: 0.2,
|
||||
},
|
||||
@@ -291,7 +291,7 @@ export class AiService {
|
||||
timeout: 5000,
|
||||
}),
|
||||
);
|
||||
return response.data?.status === 'healthy';
|
||||
return response.data?.status === "healthy";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
@@ -307,11 +307,11 @@ export class AiService {
|
||||
valueBets: [],
|
||||
homeAnalysis: null,
|
||||
awayAnalysis: null,
|
||||
expertComment: 'Analiz verisi alınamadı (Python Servis Hatası).',
|
||||
winnerPrediction: 'N/A',
|
||||
scorePrediction: '-',
|
||||
expertComment: "Analiz verisi alınamadı (Python Servis Hatası).",
|
||||
winnerPrediction: "N/A",
|
||||
scorePrediction: "-",
|
||||
confidenceScore: 0,
|
||||
modelVersion: 'v25.main',
|
||||
modelVersion: "v25.main",
|
||||
expectedGoals: 0,
|
||||
keyInsights: [],
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user