This commit is contained in:
2026-04-16 17:21:48 +03:00
parent c8fa4c442d
commit c8e7e4e927
116 changed files with 3720 additions and 4197 deletions
@@ -1,10 +1,10 @@
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
import axios from 'axios';
import { GeminiService } from '../../gemini/gemini.service';
import { HttpException, HttpStatus, Injectable, Logger } from "@nestjs/common";
import axios from "axios";
import { GeminiService } from "../../gemini/gemini.service";
export type PredictionRiskLevel = 'LOW' | 'MEDIUM' | 'HIGH' | 'EXTREME';
export type PredictionDataQuality = 'HIGH' | 'MEDIUM' | 'LOW';
export type BetGrade = 'A' | 'B' | 'C' | 'PASS';
export type PredictionRiskLevel = "LOW" | "MEDIUM" | "HIGH" | "EXTREME";
export type PredictionDataQuality = "HIGH" | "MEDIUM" | "LOW";
export type BetGrade = "A" | "B" | "C" | "PASS";
export interface PredictionPickRow {
market: string;
@@ -128,7 +128,7 @@ export class SmartCouponService {
private readonly aiEngineUrl: string;
constructor(private readonly geminiService: GeminiService) {
this.aiEngineUrl = process.env.AI_ENGINE_URL || 'http://ai-engine:8000';
this.aiEngineUrl = process.env.AI_ENGINE_URL || "http://ai-engine:8000";
}
async analyzeMatch(matchId: string): Promise<SingleMatchPredictionPackage> {
@@ -147,7 +147,7 @@ export class SmartCouponService {
);
}
throw new HttpException(
'AI analyze failed',
"AI analyze failed",
HttpStatus.SERVICE_UNAVAILABLE,
);
}
@@ -168,7 +168,7 @@ export class SmartCouponService {
const result = await this.geminiService.generateText(
JSON.stringify(prediction, null, 2),
{
model: 'gemini-2.0-flash',
model: "gemini-2.0-flash",
temperature: 0.7,
maxTokens: 600,
systemPrompt: MATCH_COMMENTARY_SYSTEM_PROMPT,
@@ -176,7 +176,7 @@ export class SmartCouponService {
);
return result.text || null;
} catch (error) {
this.logger.warn('AI commentary generation failed, skipping', error);
this.logger.warn("AI commentary generation failed, skipping", error);
return null;
}
}
@@ -188,7 +188,7 @@ export class SmartCouponService {
return null;
}
return this.getSmartCoupon(matchIds, 'SAFE', {
return this.getSmartCoupon(matchIds, "SAFE", {
maxMatches: 2,
minConfidence: 78,
});
@@ -197,11 +197,11 @@ export class SmartCouponService {
async getSmartCoupon(
matchIds: string[],
strategy:
| 'SAFE'
| 'BALANCED'
| 'AGGRESSIVE'
| 'VALUE'
| 'MIRACLE' = 'BALANCED',
| "SAFE"
| "BALANCED"
| "AGGRESSIVE"
| "VALUE"
| "MIRACLE" = "BALANCED",
options: { maxMatches?: number; minConfidence?: number } = {},
): Promise<SmartCouponResult> {
try {
@@ -216,7 +216,7 @@ export class SmartCouponService {
);
return response.data;
} catch (error) {
this.logger.error('Failed to generate smart coupon', error);
this.logger.error("Failed to generate smart coupon", error);
if (axios.isAxiosError(error)) {
const detail = error.response?.data?.detail || error.message;
throw new HttpException(
@@ -225,7 +225,7 @@ export class SmartCouponService {
);
}
throw new HttpException(
'Coupon generation failed',
"Coupon generation failed",
HttpStatus.SERVICE_UNAVAILABLE,
);
}
@@ -1,6 +1,6 @@
import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '../../../database/prisma.service';
import { User, UserCoupon, Match } from '@prisma/client';
import { Injectable, Logger } from "@nestjs/common";
import { PrismaService } from "../../../database/prisma.service";
import { User, UserCoupon, Match } from "@prisma/client";
export class CreateCouponDto {
strategy: string; // 'SAFE', 'VALUE', 'CUSTOM'
@@ -39,7 +39,7 @@ export class UserCouponService {
strategy: dto.strategy,
totalOdds: parseFloat(totalOdds.toFixed(2)),
isPublic: dto.isPublic || false,
status: 'PENDING',
status: "PENDING",
couponItems: {
create: dto.items.map((item) => ({
matchId: item.matchId,
@@ -66,7 +66,7 @@ export class UserCouponService {
async updatePendingCoupons(): Promise<void> {
// Sadece bitmiş (FT) maçları içeren PENDING kuponları çek
const pendingCoupons = await this.prisma.userCoupon.findMany({
where: { status: 'PENDING' },
where: { status: "PENDING" },
include: {
couponItems: {
include: { match: true },
@@ -80,7 +80,7 @@ export class UserCouponService {
let allMatchesFinished = true;
for (const item of coupon.couponItems) {
if (item.match.status !== 'FT') {
if (item.match.status !== "FT") {
allMatchesFinished = false;
break; // Henüz bitmemiş maç var, kuponu güncelleme
}
@@ -104,12 +104,12 @@ export class UserCouponService {
if (isCouponLost) {
await this.prisma.userCoupon.update({
where: { id: coupon.id },
data: { status: 'LOST' },
data: { status: "LOST" },
});
} else if (allMatchesFinished && isCouponWon) {
await this.prisma.userCoupon.update({
where: { id: coupon.id },
data: { status: 'WON' },
data: { status: "WON" },
});
}
}
@@ -125,23 +125,23 @@ export class UserCouponService {
const total = home + away;
switch (selection) {
case 'MS 1':
case "MS 1":
return home > away;
case 'MS X':
case "MS X":
return home === away;
case 'MS 2':
case "MS 2":
return away > home;
case '1.5 UST':
case "1.5 UST":
return total > 1.5;
case '2.5 UST':
case "2.5 UST":
return total > 2.5;
case '3.5 UST':
case "3.5 UST":
return total > 3.5;
case '2.5 ALT':
case "2.5 ALT":
return total < 2.5;
case 'KG VAR':
case "KG VAR":
return home > 0 && away > 0;
case 'KG YOK':
case "KG YOK":
return home === 0 || away === 0;
default:
return false; // Bilinmeyen market
@@ -155,7 +155,7 @@ export class UserCouponService {
const coupons = await this.prisma.userCoupon.findMany({
where: {
userId,
status: { in: ['WON', 'LOST'] },
status: { in: ["WON", "LOST"] },
},
});
@@ -171,7 +171,7 @@ export class UserCouponService {
};
}
const wonCoupons = coupons.filter((c) => c.status === 'WON');
const wonCoupons = coupons.filter((c) => c.status === "WON");
const totalInvested = totalCoupons; // Her kupona 1 birim yatırıldığını varsayıyoruz
const totalReturn = wonCoupons.reduce((acc, c) => acc + c.totalOdds, 0);
const winRate = (wonCoupons.length / totalCoupons) * 100;