From 480135f5400b9a96330faff3d4e198c217d10ab3 Mon Sep 17 00:00:00 2001 From: SugaretaNajja Date: Thu, 30 Jul 2026 10:07:11 +0000 Subject: [PATCH] Enhance-error-handling-BackendAcademy --- BackendAcademy/src/ai/ai.module.ts | 1 + BackendAcademy/src/ai/ai.service.ts | 106 ++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) diff --git a/BackendAcademy/src/ai/ai.module.ts b/BackendAcademy/src/ai/ai.module.ts index 0d7f83b42..366c29775 100644 --- a/BackendAcademy/src/ai/ai.module.ts +++ b/BackendAcademy/src/ai/ai.module.ts @@ -19,6 +19,7 @@ const aiProviderFactory = { @Module({ controllers: [AiController], + //ai controller providers: [AiService, PromptTemplateService, aiProviderFactory], exports: [AiService, PromptTemplateService], }) diff --git a/BackendAcademy/src/ai/ai.service.ts b/BackendAcademy/src/ai/ai.service.ts index 4edec9084..c57790129 100644 --- a/BackendAcademy/src/ai/ai.service.ts +++ b/BackendAcademy/src/ai/ai.service.ts @@ -215,6 +215,59 @@ export class AiService { }; } + + async getRecommendation(userId: string): Promise { + const snapshot = this.redisService + ? await this.redisService.getUserSnapshot(userId) + : null; + + if (!snapshot) { + return { + userId, + recommendations: [], + explainability: { + factors: ['insufficient_data'], + confidence: 0.1, + userSignalAge: 0, + signalsUsed: [], + modelVersion: 'rustacademy-recommender-v2', + }, + generatedAt: new Date(), + }; + } + + const explainability = this.redisService + ? await this.redisService.getRecommendationExplainability(userId) + : null; + + const recommendedCourses = snapshot.recentCourses.length > 0 + ? snapshot.recentCourses.slice(0, 3) + : ['rust-fundamentals', 'smart-contracts-101', 'stellar-basics']; + + const recommendations = recommendedCourses.map((courseId, index) => ({ + courseId, + score: Math.max(0, 1 - index * 0.2 - (snapshot.interactionCount > 0 ? 0 : 0.3)), + reason: explainability?.factors[index] || 'course_popularity', + })); + + if (this.monitoringService) { + this.monitoringService.recordDomainEvent('recommendation_generated', 'ai'); + } + + return { + userId, + recommendations, + explainability: explainability || { + factors: [], + confidence: 0.1, + userSignalAge: 0, + signalsUsed: [], + modelVersion: 'rustacademy-recommender-v2', + }, + generatedAt: new Date(), + }; + } + /** * Calls the AI provider with the global request timeout (Issue #408) and * falls back to a static response if the provider is unavailable, times @@ -297,6 +350,59 @@ export class AiService { ); } + + async getRecommendation(userId: string): Promise { + const snapshot = this.redisService + ? await this.redisService.getUserSnapshot(userId) + : null; + + if (!snapshot) { + return { + userId, + recommendations: [], + explainability: { + factors: ['insufficient_data'], + confidence: 0.1, + userSignalAge: 0, + signalsUsed: [], + modelVersion: 'rustacademy-recommender-v2', + }, + generatedAt: new Date(), + }; + } + + const explainability = this.redisService + ? await this.redisService.getRecommendationExplainability(userId) + : null; + + const recommendedCourses = snapshot.recentCourses.length > 0 + ? snapshot.recentCourses.slice(0, 3) + : ['rust-fundamentals', 'smart-contracts-101', 'stellar-basics']; + + const recommendations = recommendedCourses.map((courseId, index) => ({ + courseId, + score: Math.max(0, 1 - index * 0.2 - (snapshot.interactionCount > 0 ? 0 : 0.3)), + reason: explainability?.factors[index] || 'course_popularity', + })); + + if (this.monitoringService) { + this.monitoringService.recordDomainEvent('recommendation_generated', 'ai'); + } + + return { + userId, + recommendations, + explainability: explainability || { + factors: [], + confidence: 0.1, + userSignalAge: 0, + signalsUsed: [], + modelVersion: 'rustacademy-recommender-v2', + }, + generatedAt: new Date(), + }; + } + const lines = code.split('\n').filter((l) => l.trim().length > 0).length; const hasComments = code.includes('//') || code.includes('/*'); const hasFunctions = code.includes('fn ');