feat: Ollama AI expert commentary integration
Deploy Iddaai Backend / build-and-deploy (push) Successful in 37s

- OllamaClient utility for llama3.2:3b API calls (timeout 30s, non-fatal)
- OllamaCommentary service builds structured Turkish prompt from prediction data
- PredictionsService enriches response with ai_expert_commentary field
- Frontend prediction-card displays AI commentary section above match_commentary
This commit is contained in:
2026-05-17 02:09:04 +03:00
parent 2b87669f41
commit 17ace9bd12
4 changed files with 177 additions and 5 deletions
@@ -4,6 +4,7 @@ import {
Post,
Body,
Param,
Query,
HttpCode,
HttpStatus,
NotFoundException,
@@ -111,6 +112,7 @@ export class PredictionsController {
async getPrediction(
@Param("matchId") matchId: string,
@CurrentUser() user: any,
@Query("nocache") nocache?: string,
): Promise<MatchPredictionDto> {
const canProceed = await this.analysisService.checkUsageLimit(
user.id,
@@ -121,13 +123,16 @@ export class PredictionsController {
throw new ForbiddenException("ANALYSIS_LIMIT_EXCEEDED");
}
const cached = await this.predictionsService.getCachedPrediction(matchId);
if (cached) {
// Do not record usage for cached predictions
return cached;
const bypassCache = nocache === "true" || nocache === "1";
if (!bypassCache) {
const cached = await this.predictionsService.getCachedPrediction(matchId);
if (cached) {
return cached;
}
}
// Get from AI Engine
// Get from AI Engine (always fresh when nocache=true)
const prediction = await this.predictionsService.getPredictionById(matchId);
if (!prediction) {
@@ -31,6 +31,7 @@ import {
AiEngineClient,
AiEngineRequestError,
} from "../../common/utils/ai-engine-client";
import { generateExpertCommentary } from "../../common/utils/ollama-commentary";
type ConfidenceBand = "HIGH" | "MEDIUM" | "LOW";
@@ -237,6 +238,19 @@ export class PredictionsService implements OnModuleInit, OnModuleDestroy {
response.data,
matchContext,
);
// Generate AI expert commentary via Ollama (non-blocking, best-effort)
try {
const aiCommentary = await generateExpertCommentary(
response.data as unknown as Record<string, unknown>,
);
if (aiCommentary) {
(prediction as unknown as Record<string, unknown>).ai_expert_commentary = aiCommentary;
}
} catch {
// Ollama failure is non-fatal
}
await this.recordPredictionRun(matchId, response.data);
await this.cachePrediction(matchId, prediction);
return prediction;