gg
This commit is contained in:
@@ -461,6 +461,21 @@ export class AIHealthDto {
|
||||
|
||||
@ApiProperty()
|
||||
predictionServiceReady: boolean;
|
||||
|
||||
@ApiProperty({ required: false, default: true })
|
||||
aiEngineReachable?: boolean;
|
||||
|
||||
@ApiProperty({ required: false, enum: ["closed", "open"] })
|
||||
circuitState?: "closed" | "open";
|
||||
|
||||
@ApiProperty({ required: false, default: 0 })
|
||||
consecutiveFailures?: number;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
endpoint?: string;
|
||||
|
||||
@ApiProperty({ required: false, nullable: true })
|
||||
detail?: string | null;
|
||||
}
|
||||
|
||||
export * from "./smart-coupon.dto";
|
||||
|
||||
@@ -19,11 +19,14 @@ import {
|
||||
ValueBetDto,
|
||||
AIHealthDto,
|
||||
} from "./dto";
|
||||
import axios, { AxiosError } from "axios";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { FeederService } from "../feeder/feeder.service";
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import {
|
||||
AiEngineClient,
|
||||
AiEngineRequestError,
|
||||
} from "../../common/utils/ai-engine-client";
|
||||
|
||||
type ConfidenceBand = "HIGH" | "MEDIUM" | "LOW";
|
||||
|
||||
@@ -45,6 +48,7 @@ export class PredictionsService implements OnModuleInit, OnModuleDestroy {
|
||||
private readonly logger = new Logger(PredictionsService.name);
|
||||
private queueEvents: QueueEvents | null = null;
|
||||
private readonly aiEngineUrl: string;
|
||||
private readonly aiEngineClient: AiEngineClient;
|
||||
private readonly topLeagueIds = new Set<string>();
|
||||
private readonly reasonTranslations: Record<string, string> = {
|
||||
confidence_below_threshold: "Güven eşiğin altında",
|
||||
@@ -125,6 +129,14 @@ export class PredictionsService implements OnModuleInit, OnModuleDestroy {
|
||||
"AI_ENGINE_URL",
|
||||
"http://localhost:8000",
|
||||
);
|
||||
this.aiEngineClient = new AiEngineClient({
|
||||
baseUrl: this.aiEngineUrl,
|
||||
logger: this.logger,
|
||||
serviceName: PredictionsService.name,
|
||||
timeoutMs: 60000,
|
||||
maxRetries: 2,
|
||||
retryDelayMs: 750,
|
||||
});
|
||||
this.topLeagueIds = this.loadTopLeagueIds();
|
||||
}
|
||||
|
||||
@@ -149,12 +161,50 @@ export class PredictionsService implements OnModuleInit, OnModuleDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
checkHealth(): Promise<AIHealthDto> {
|
||||
return Promise.resolve({
|
||||
status: "healthy",
|
||||
modelLoaded: true,
|
||||
predictionServiceReady: true,
|
||||
});
|
||||
async checkHealth(): Promise<AIHealthDto> {
|
||||
const circuit = this.aiEngineClient.getSnapshot();
|
||||
|
||||
try {
|
||||
const response = await this.aiEngineClient.get<{
|
||||
status?: string;
|
||||
model_loaded?: boolean;
|
||||
prediction_service_ready?: boolean;
|
||||
}>("/health", {
|
||||
timeout: 5000,
|
||||
retryCount: 0,
|
||||
});
|
||||
|
||||
return {
|
||||
status: response.data?.status || "healthy",
|
||||
modelLoaded: response.data?.model_loaded ?? true,
|
||||
predictionServiceReady:
|
||||
response.data?.prediction_service_ready ?? true,
|
||||
aiEngineReachable: true,
|
||||
circuitState: circuit.state,
|
||||
consecutiveFailures: circuit.consecutiveFailures,
|
||||
endpoint: this.aiEngineUrl,
|
||||
};
|
||||
} catch (error: unknown) {
|
||||
const requestError =
|
||||
error instanceof AiEngineRequestError
|
||||
? error
|
||||
: new AiEngineRequestError("AI health check failed");
|
||||
|
||||
return {
|
||||
status: requestError.isCircuitOpen ? "circuit_open" : "unhealthy",
|
||||
modelLoaded: false,
|
||||
predictionServiceReady: false,
|
||||
aiEngineReachable: false,
|
||||
circuitState: this.aiEngineClient.getSnapshot().state,
|
||||
consecutiveFailures:
|
||||
this.aiEngineClient.getSnapshot().consecutiveFailures,
|
||||
endpoint: this.aiEngineUrl,
|
||||
detail:
|
||||
typeof requestError.detail === "string"
|
||||
? requestError.detail
|
||||
: requestError.message,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async getPredictionById(matchId: string): Promise<MatchPredictionDto | null> {
|
||||
@@ -182,22 +232,21 @@ export class PredictionsService implements OnModuleInit, OnModuleDestroy {
|
||||
|
||||
// Direct HTTP mode (no Redis)
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${this.aiEngineUrl}/v20plus/analyze/${matchId}`,
|
||||
const response = await this.aiEngineClient.post<MatchPredictionDto>(
|
||||
`/v20plus/analyze/${matchId}`,
|
||||
{},
|
||||
{ timeout: 60000 },
|
||||
);
|
||||
return this.enrichPredictionResponse(
|
||||
response.data as MatchPredictionDto,
|
||||
matchContext,
|
||||
);
|
||||
} catch (e: unknown) {
|
||||
const error = e as AxiosError<Record<string, unknown>>;
|
||||
const status = error?.response?.status;
|
||||
const detail =
|
||||
error?.response?.data?.detail ||
|
||||
error?.response?.data ||
|
||||
error?.message;
|
||||
const requestError =
|
||||
e instanceof AiEngineRequestError
|
||||
? e
|
||||
: new AiEngineRequestError("AI Engine request failed");
|
||||
const status = requestError.status;
|
||||
const detail = requestError.detail || requestError.message;
|
||||
this.logger.error(
|
||||
`Direct AI Engine call failed for ${matchId}: status=${status}, detail=${JSON.stringify(detail)}`,
|
||||
);
|
||||
@@ -988,14 +1037,18 @@ export class PredictionsService implements OnModuleInit, OnModuleDestroy {
|
||||
|
||||
// Direct HTTP mode
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${this.aiEngineUrl}/smart-coupon`,
|
||||
const response = await this.aiEngineClient.post(
|
||||
"/smart-coupon",
|
||||
{ match_ids: matchIds, strategy, ...options },
|
||||
{ timeout: 60000 },
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
} catch (error: unknown) {
|
||||
const message =
|
||||
error instanceof AiEngineRequestError
|
||||
? error.message
|
||||
: error instanceof Error
|
||||
? error.message
|
||||
: String(error);
|
||||
this.logger.error(`Direct smart coupon call failed: ${message}`);
|
||||
this.throwAiError(message);
|
||||
}
|
||||
@@ -1018,6 +1071,12 @@ export class PredictionsService implements OnModuleInit, OnModuleDestroy {
|
||||
HttpStatus.BAD_GATEWAY,
|
||||
);
|
||||
}
|
||||
if (message.includes("circuit breaker is open")) {
|
||||
throw new HttpException(
|
||||
"AI Engine is temporarily unavailable",
|
||||
HttpStatus.SERVICE_UNAVAILABLE,
|
||||
);
|
||||
}
|
||||
throw new HttpException(
|
||||
"Failed to get prediction from AI Engine",
|
||||
HttpStatus.SERVICE_UNAVAILABLE,
|
||||
|
||||
Reference in New Issue
Block a user