first (part 3: src directory)
Deploy Iddaai Backend / build-and-deploy (push) Successful in 33s

This commit is contained in:
2026-04-16 15:12:27 +03:00
parent 2f0b85a0c7
commit 182f4aae16
125 changed files with 22552 additions and 0 deletions
+471
View File
@@ -0,0 +1,471 @@
import { ApiProperty } from '@nestjs/swagger';
export type SignalTier =
| 'CORE'
| 'VALUE'
| 'LEAN'
| 'LONGSHOT'
| 'PASS';
export class MatchInfoDto {
@ApiProperty()
match_id: string;
@ApiProperty()
match_name: string;
@ApiProperty()
home_team: string;
@ApiProperty()
away_team: string;
@ApiProperty()
league: string;
@ApiProperty()
match_date_ms: number;
@ApiProperty({ required: false, nullable: true })
league_id?: string | null;
@ApiProperty({ required: false, default: false })
is_top_league?: boolean;
@ApiProperty({
required: false,
enum: ['football', 'basketball'],
})
sport?: 'football' | 'basketball';
}
export class DataQualityDto {
@ApiProperty({ enum: ['HIGH', 'MEDIUM', 'LOW'] })
label: 'HIGH' | 'MEDIUM' | 'LOW';
@ApiProperty()
score: number;
@ApiProperty()
home_lineup_count: number;
@ApiProperty()
away_lineup_count: number;
@ApiProperty({ required: false, default: 'none' })
lineup_source?: string;
@ApiProperty({ type: [String] })
flags: string[];
}
export class ConfidenceIntervalDto {
@ApiProperty()
lower: number;
@ApiProperty()
upper: number;
@ApiProperty()
width: number;
@ApiProperty({ enum: ['HIGH', 'MEDIUM', 'LOW'] })
band: 'HIGH' | 'MEDIUM' | 'LOW';
@ApiProperty()
threshold_met: boolean;
}
export class RiskDto {
@ApiProperty({ enum: ['LOW', 'MEDIUM', 'HIGH', 'EXTREME'] })
level: 'LOW' | 'MEDIUM' | 'HIGH' | 'EXTREME';
@ApiProperty()
score: number;
@ApiProperty()
is_surprise_risk: boolean;
@ApiProperty({ nullable: true })
surprise_type: string | null;
@ApiProperty({ required: false, default: 0 })
surprise_score?: number;
@ApiProperty({ required: false, nullable: true })
surprise_comment?: string | null;
@ApiProperty({ type: [String], required: false })
surprise_reasons?: string[];
@ApiProperty({ type: [String] })
warnings: string[];
}
export class EngineBreakdownDto {
@ApiProperty()
team: number;
@ApiProperty()
player: number;
@ApiProperty()
odds: number;
@ApiProperty()
referee: number;
}
export class MatchPickDto {
@ApiProperty()
market: string;
@ApiProperty()
pick: string;
@ApiProperty()
probability: number;
@ApiProperty()
confidence: number;
@ApiProperty()
odds: number;
@ApiProperty()
raw_confidence: number;
@ApiProperty()
calibrated_confidence: number;
@ApiProperty()
min_required_confidence: number;
@ApiProperty()
edge: number;
@ApiProperty({ required: false, default: 0 })
ev_edge?: number;
@ApiProperty({ required: false, default: 0 })
implied_prob?: number;
@ApiProperty()
play_score: number;
@ApiProperty()
playable: boolean;
@ApiProperty({ enum: ['A', 'B', 'C', 'PASS'] })
bet_grade: 'A' | 'B' | 'C' | 'PASS';
@ApiProperty()
stake_units: number;
@ApiProperty({ type: [String] })
decision_reasons: string[];
@ApiProperty({ type: ConfidenceIntervalDto, required: false })
confidence_interval?: ConfidenceIntervalDto;
@ApiProperty({
required: false,
enum: ['CORE', 'VALUE', 'LEAN', 'LONGSHOT', 'PASS'],
})
signal_tier?: SignalTier;
}
export class MatchBetAdviceDto {
@ApiProperty()
playable: boolean;
@ApiProperty()
suggested_stake_units: number;
@ApiProperty()
reason: string;
@ApiProperty({ required: false, enum: ['HIGH', 'MEDIUM', 'LOW'] })
confidence_band?: 'HIGH' | 'MEDIUM' | 'LOW';
@ApiProperty({ required: false })
min_confidence_for_play?: number;
@ApiProperty({
required: false,
enum: ['CORE', 'VALUE', 'LEAN', 'LONGSHOT', 'PASS'],
})
signal_tier?: SignalTier;
}
export class MatchBetSummaryItemDto {
@ApiProperty()
market: string;
@ApiProperty()
pick: string;
@ApiProperty()
raw_confidence: number;
@ApiProperty()
calibrated_confidence: number;
@ApiProperty({ enum: ['A', 'B', 'C', 'PASS'] })
bet_grade: 'A' | 'B' | 'C' | 'PASS';
@ApiProperty()
playable: boolean;
@ApiProperty()
stake_units: number;
@ApiProperty()
play_score: number;
@ApiProperty({ required: false, default: 0 })
ev_edge?: number;
@ApiProperty({ required: false, default: 0 })
implied_prob?: number;
@ApiProperty({ required: false, default: 0 })
odds?: number;
@ApiProperty({ type: [String] })
reasons: string[];
@ApiProperty({ type: ConfidenceIntervalDto, required: false })
confidence_interval?: ConfidenceIntervalDto;
@ApiProperty({
required: false,
enum: ['CORE', 'VALUE', 'LEAN', 'LONGSHOT', 'PASS'],
})
signal_tier?: SignalTier;
}
export class HtFtPredictionDto {
@ApiProperty()
'1/1': number;
@ApiProperty()
'1/X': number;
@ApiProperty()
'1/2': number;
@ApiProperty()
'X/1': number;
@ApiProperty()
'X/X': number;
@ApiProperty()
'X/2': number;
@ApiProperty()
'2/1': number;
@ApiProperty()
'2/X': number;
@ApiProperty()
'2/2': number;
@ApiProperty()
pick: string;
@ApiProperty()
confidence: number;
}
export class AggressivePickDto {
@ApiProperty()
market: string;
@ApiProperty()
pick: string;
@ApiProperty()
probability: number;
@ApiProperty()
confidence: number;
@ApiProperty()
odds: number;
@ApiProperty()
raw_confidence: number;
@ApiProperty()
calibrated_confidence: number;
@ApiProperty()
min_required_confidence: number;
@ApiProperty()
edge: number;
@ApiProperty({ required: false, default: 0 })
ev_edge?: number;
@ApiProperty({ required: false, default: 0 })
implied_prob?: number;
@ApiProperty()
play_score: number;
@ApiProperty()
playable: boolean;
@ApiProperty({ enum: ['A', 'B', 'C', 'PASS'] })
bet_grade: 'A' | 'B' | 'C' | 'PASS';
@ApiProperty()
stake_units: number;
@ApiProperty({ type: [String] })
decision_reasons: string[];
@ApiProperty({ type: ConfidenceIntervalDto, required: false })
confidence_interval?: ConfidenceIntervalDto;
}
export class ScenarioTop5ItemDto {
@ApiProperty()
scenario: string;
@ApiProperty()
score: number;
@ApiProperty()
probability: number;
}
export class ScorePredictionDto {
@ApiProperty()
ft: string;
@ApiProperty()
ht: string;
@ApiProperty()
xg_home: number;
@ApiProperty()
xg_away: number;
@ApiProperty()
xg_total: number;
}
export class MatchPredictionDto {
@ApiProperty()
model_version: string;
@ApiProperty({ type: MatchInfoDto })
match_info: MatchInfoDto;
@ApiProperty({ type: DataQualityDto })
data_quality: DataQualityDto;
@ApiProperty({ type: RiskDto })
risk: RiskDto;
@ApiProperty({ type: EngineBreakdownDto })
engine_breakdown: EngineBreakdownDto;
@ApiProperty({ type: MatchPickDto, nullable: true })
main_pick: MatchPickDto | null;
@ApiProperty({ type: MatchPickDto, nullable: true })
value_pick: MatchPickDto | null;
@ApiProperty({ type: MatchBetAdviceDto })
bet_advice: MatchBetAdviceDto;
@ApiProperty({ type: [MatchBetSummaryItemDto] })
bet_summary: MatchBetSummaryItemDto[];
@ApiProperty({ type: [MatchPickDto] })
supporting_picks: MatchPickDto[];
@ApiProperty({ type: AggressivePickDto, nullable: true })
aggressive_pick: AggressivePickDto | null;
@ApiProperty({ type: HtFtPredictionDto, required: false })
htft?: HtFtPredictionDto;
@ApiProperty({ type: [ScenarioTop5ItemDto] })
scenario_top5: ScenarioTop5ItemDto[];
@ApiProperty({ type: ScorePredictionDto })
score_prediction: ScorePredictionDto;
@ApiProperty({ type: Object })
market_board: Record<string, unknown>;
@ApiProperty({ type: [String] })
reasoning_factors: string[];
}
export class ValueBetDto {
@ApiProperty()
matchId: string;
@ApiProperty()
matchName: string;
@ApiProperty()
betType: string;
@ApiProperty()
prediction: string;
@ApiProperty()
confidence: number;
@ApiProperty()
odd: number;
@ApiProperty()
expectedValue: number;
}
export class PredictionHistoryStatsDto {
@ApiProperty()
totalPredictions: number;
@ApiProperty()
totalResolved: number;
@ApiProperty()
correctPredictions: number;
@ApiProperty()
accuracyRate: number;
}
export class PredictionHistoryResponseDto {
@ApiProperty({ type: PredictionHistoryStatsDto })
stats: PredictionHistoryStatsDto;
@ApiProperty({ type: [Object] })
history: Record<string, unknown>[];
}
export class UpcomingPredictionsDto {
@ApiProperty()
count: number;
@ApiProperty({ type: [MatchPredictionDto] })
matches: MatchPredictionDto[];
@ApiProperty()
modelVersion: string;
}
export class AIHealthDto {
@ApiProperty()
status: string;
@ApiProperty()
modelLoaded: boolean;
@ApiProperty()
predictionServiceReady: boolean;
}
export * from './smart-coupon.dto';
@@ -0,0 +1,63 @@
import {
IsArray,
IsString,
IsOptional,
IsNotEmpty,
IsNumber,
IsEnum,
ArrayMaxSize,
Min,
Max,
} from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
export class GeneratePredictionDto {
@ApiProperty({ description: 'Match ID to generate prediction for' })
@IsString()
@IsNotEmpty()
matchId: string;
}
export enum CouponStrategy {
SAFE = 'SAFE',
BALANCED = 'BALANCED',
AGGRESSIVE = 'AGGRESSIVE',
VALUE = 'VALUE',
MIRACLE = 'MIRACLE',
}
export class SmartCouponRequestDto {
@ApiProperty({
description: 'List of match IDs for coupon',
example: ['match-1', 'match-2'],
})
@IsArray()
@IsString({ each: true })
@ArrayMaxSize(50)
matchIds: string[];
@ApiPropertyOptional({
enum: CouponStrategy,
default: CouponStrategy.BALANCED,
})
@IsOptional()
@IsEnum(CouponStrategy)
strategy?: CouponStrategy;
@ApiPropertyOptional({ description: 'Maximum matches in coupon', example: 5 })
@IsOptional()
@IsNumber()
@Min(1)
@Max(20)
maxMatches?: number;
@ApiPropertyOptional({
description: 'Minimum confidence threshold (0-100)',
example: 60,
})
@IsOptional()
@IsNumber()
@Min(0)
@Max(100)
minConfidence?: number;
}
+64
View File
@@ -0,0 +1,64 @@
/**
* Smart Coupon DTOs aligned with AI Engine V20+ contract.
*/
export type CouponStrategy =
| 'SAFE'
| 'BALANCED'
| 'AGGRESSIVE'
| 'VALUE'
| 'MIRACLE';
export type RiskLevel = 'LOW' | 'MEDIUM' | 'HIGH' | 'EXTREME';
export type DataQualityLabel = 'HIGH' | 'MEDIUM' | 'LOW';
export interface SmartCouponRequestDto {
match_ids: string[];
strategy?: CouponStrategy;
max_matches?: number;
min_confidence?: number;
}
export interface CouponBetDto {
match_id: string;
match_name: string;
market: string;
pick: string;
probability: number;
confidence: number;
odds: number;
risk_level: RiskLevel;
data_quality: DataQualityLabel;
}
export interface RejectedMatchDto {
match_id: string;
reason: string;
threshold?: number;
}
export interface SmartCouponResponseDto {
strategy: CouponStrategy;
generated_at: string;
match_count: number;
bets: CouponBetDto[];
total_odds: number;
expected_win_rate: number;
rejected_matches: RejectedMatchDto[];
}
export interface SmartCouponApiError {
error: string;
detail?: string;
match_ids_failed?: string[];
}
export interface StrategyInfo {
name: CouponStrategy;
description: string;
typical_odds: string;
}
export interface StrategiesResponseDto {
strategies: StrategyInfo[];
}