gg
Deploy Iddaai Backend / build-and-deploy (push) Successful in 31s

This commit is contained in:
2026-05-18 00:08:50 +03:00
parent 5574a3c59d
commit 1d4aa36602
3 changed files with 34 additions and 64 deletions
+2 -2
View File
@@ -4,7 +4,7 @@ const logger = new Logger("OllamaClient");
const OLLAMA_BASE_URL = process.env.OLLAMA_URL ?? "http://172.22.0.1:11434";
const OLLAMA_MODEL = process.env.OLLAMA_MODEL ?? "llama3.2:3b";
const TIMEOUT_MS = 30_000;
const TIMEOUT_MS = 90_000;
export async function generateOllamaText(prompt: string): Promise<string | null> {
try {
@@ -21,7 +21,7 @@ export async function generateOllamaText(prompt: string): Promise<string | null>
stream: false,
options: {
temperature: 0.6,
num_predict: 250,
num_predict: 150,
repeat_penalty: 1.1,
},
}),
+32 -61
View File
@@ -18,84 +18,55 @@ function buildPrompt(p: PredictionData): string {
const risk = (p.risk ?? {}) as Record<string, unknown>;
const ba = (p.bet_advice ?? {}) as Record<string, unknown>;
const dq = (p.data_quality ?? {}) as Record<string, unknown>;
const v27 = (p.v27_engine ?? {}) as Record<string, unknown>;
const home = String(mi.home_team ?? "Ev Sahibi");
const away = String(mi.away_team ?? "Deplasman");
const league = String(mi.league ?? "");
// Market board - ham olasılıklar
const ms = (mb.MS ?? {}) as Record<string, unknown>;
const msProbs = (ms.probs ?? {}) as Record<string, number>;
const ou15 = (mb.OU15 ?? {}) as Record<string, unknown>;
const ou25 = (mb.OU25 ?? {}) as Record<string, unknown>;
const ou35 = (mb.OU35 ?? {}) as Record<string, unknown>;
const btts = (mb.BTTS ?? {}) as Record<string, unknown>;
const homeWin = Math.round((msProbs["1"] ?? 0) * 100);
const draw = Math.round((msProbs["X"] ?? 0) * 100);
const awayWin = Math.round((msProbs["2"] ?? 0) * 100);
// V27 predictions
const v27preds = (v27.predictions ?? {}) as Record<string, unknown>;
const v27ms = (v27preds.ms ?? {}) as Record<string, number>;
const ou15Probs = (ou15.probs ?? {}) as Record<string, number>;
const ou25Probs = (ou25.probs ?? {}) as Record<string, number>;
const ou35Probs = (ou35.probs ?? {}) as Record<string, number>;
const bttsProbs = (btts.probs ?? {}) as Record<string, number>;
// Risk breakdown
const surpriseReasons = (risk.surprise_reasons as string[] | undefined) ?? [];
const warnings = (risk.warnings as string[] | undefined) ?? [];
const xgHome = Number(sp.xg_home ?? 0).toFixed(2);
const xgAway = Number(sp.xg_away ?? 0).toFixed(2);
const ftScore = String(sp.ft ?? "");
// Top 5 scenarios
const top5 = (p.scenario_top5 ?? []).slice(0, 5);
const ou15Over = Math.round((ou15Probs.over ?? 0) * 100);
const ou25Over = Math.round((ou25Probs.over ?? 0) * 100);
const ou35Under = Math.round((ou35Probs.under ?? 0) * 100);
const bttsYes = Math.round((bttsProbs.yes ?? 0) * 100);
const analysisData = {
mac: `${home} - ${away} (${league})`,
ms_olasilik: {
ev_sahibi_kazanir: ms.probs ? (mb.MS as Record<string, unknown>)?.probs : null,
v27_ev_sahibi: v27ms.home ? Math.round(v27ms.home * 100) : null,
},
xg: { ev_sahibi: sp.xg_home, deplasman: sp.xg_away, toplam: sp.xg_total },
gol_marketleri: {
"1_5_ust": (ou15.probs as Record<string, number> | undefined)?.over,
"2_5_ust": (ou25.probs as Record<string, number> | undefined)?.over,
"3_5_alt": (ou35.probs as Record<string, number> | undefined)?.under,
kg_var: (btts.probs as Record<string, number> | undefined)?.yes,
},
skor_tahmini: sp.ft,
en_olasilar: top5.map((s) => `${s.score}: %${Math.round(s.prob * 100)}`),
risk: { seviye: risk.level, surpriz_skoru: risk.surprise_score, uyarilar: [...surpriseReasons, ...warnings].slice(0, 3) },
bahis_tavsiyesi: { oynanabilir: ba.playable, karar: ba.decision, neden: ba.reason },
kadro: { kaynak: dq.lineup_source, kalite: dq.score },
};
const riskLevel = String(risk.level ?? "");
const surpriseScore = Number(risk.surprise_score ?? 0);
const playable = Boolean(ba.playable);
const lineupSource = String(dq.lineup_source ?? "");
return `Sen bir futbol bahis analistisin. Aşağıdaki maç analizini okuyup SADECE TÜRKÇE 2-3 cümle yorum yaz. Sayıları tekrar etme, anlam çıkar.
const top5 = (p.scenario_top5 ?? [])
.slice(0, 3)
.map((s) => `${s.score} (%${Math.round(s.prob * 100)})`)
.join(", ");
// V27 MS probs if available
const v27 = (p.v27_engine ?? {}) as Record<string, unknown>;
const v27ms = (v27.predictions as Record<string, unknown>)?.ms as Record<string, number> | undefined;
const v27Home = v27ms ? Math.round(v27ms.home * 100) : null;
const nobet = !playable
? "Tüm oranlar çok düşük, bahis yapmak mantıklı değil."
: "Bahis açılabilir.";
const xgComment =
Number(xgHome) > Number(xgAway) * 2
? `${home} xG açısından çok üstün (${xgHome} - ${xgAway}), ${away} gol atacak alan bulamıyor.`
: Number(xgAway) > Number(xgHome) * 2
? `${away} xG açısından çok üstün (${xgAway} - ${xgHome}), ${home} etkisiz kalıyor.`
: `İki takım xG açısından yakın (${xgHome} - ${xgAway}).`;
const goalComment =
ou15Over >= 80
? "Maçta kesinlikle gol bekleniyor."
: ou15Over >= 65
? "Gol ihtimali yüksek."
: "Golsüz geçebilir.";
const highSurprise = surpriseScore >= 60;
return `Aşağıdaki futbol maçı için Türkçe uzman yorum yaz. Sadece Türkçe kullan, İngilizce kelime yasak. 3 cümle yaz, kısa tut.
Maç: ${home} - ${away}
${home} kazanma ihtimali: %${homeWin}${v27Home ? `, güçlü model: %${v27Home}` : ""}
Beraberlik: %${draw}, ${away} kazanır: %${awayWin}
${xgComment}
${goalComment} (1.5 üst: %${ou15Over}, 2.5 üst: %${ou25Over})
En olası skor: ${ftScore}. İkili bahis olasılığı: %${bttsYes}.
Risk: ${riskLevel}${highSurprise ? ", sürpriz olabilir" : ""}.
${nobet}
Yorum:`;
${JSON.stringify(analysisData, null, 2)}
Türkçe yorum:`;
}
export async function generateExpertCommentary(
@@ -150,7 +150,6 @@ export class PredictionsController {
@Get(":matchId/commentary")
async getCommentary(
@Param("matchId") matchId: string,
@CurrentUser() user: any,
): Promise<{ commentary: string | null }> {
const commentary = await this.predictionsService.getAiCommentary(matchId);
return { commentary };