diff --git a/Services/Implemnetation/AiAnalysisService.cs b/Services/Implemnetation/AiAnalysisService.cs index fe02c33..5f88058 100644 --- a/Services/Implemnetation/AiAnalysisService.cs +++ b/Services/Implemnetation/AiAnalysisService.cs @@ -1,19 +1,20 @@ // Services/Implementation/AiAnalysisService.cs using Azure; -using Azure.AI.TextAnalytics; using Azure.AI.OpenAI; -using OpenAI.Chat; +using Azure.AI.TextAnalytics; +using Data; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; +using Model; +using OpenAI.Chat; using Services.AIViewModel; using Services.Interaces; +using System.ClientModel; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using System.Text.RegularExpressions; -using Data; -using Microsoft.EntityFrameworkCore; -using System.ClientModel; namespace Services.Implemnetation { @@ -605,13 +606,32 @@ Respond with a JSON array of applicable categories: [""category1"", ""category2" { foreach (var detail in response.ResponseDetails) { + string responseText = ""; + + // Handle text-based questions (existing) if (!string.IsNullOrWhiteSpace(detail.TextResponse)) + { + responseText = detail.TextResponse; + } + // Handle CheckBox questions (NEW) + else if (detail.QuestionType == QuestionType.CheckBox && detail.ResponseAnswers.Any()) + { + var selectedAnswers = detail.ResponseAnswers + .Select(ra => detail.Question.Answers.FirstOrDefault(a => a.Id == ra.AnswerId)?.Text) + .Where(text => !string.IsNullOrEmpty(text)) + .ToList(); + + responseText = $"Multiple Selection Question: {detail.Question.Text}\nSelected Options: {string.Join(", ", selectedAnswers)}\nAnalyze these selected workplace factors for mental health implications and patterns."; + } + + // Create analysis request for ALL supported responses + if (!string.IsNullOrEmpty(responseText)) { var request = new AnalysisRequest { ResponseId = response.Id, QuestionId = detail.QuestionId, - ResponseText = detail.TextResponse, + ResponseText = responseText, QuestionText = detail.Question?.Text ?? "" }; @@ -868,13 +888,32 @@ Respond with a JSON array of applicable categories: [""category1"", ""category2" { foreach (var detail in response.ResponseDetails) { + string responseText = ""; + + // Handle text-based questions if (!string.IsNullOrWhiteSpace(detail.TextResponse)) + { + responseText = detail.TextResponse; + } + // Handle CheckBox questions + else if (detail.QuestionType == QuestionType.CheckBox && detail.ResponseAnswers.Any()) + { + var selectedAnswers = detail.ResponseAnswers + .Select(ra => detail.Question.Answers.FirstOrDefault(a => a.Id == ra.AnswerId)?.Text) + .Where(text => !string.IsNullOrEmpty(text)) + .ToList(); + + responseText = $"Multiple Selection Question: {detail.Question.Text}\nSelected Options: {string.Join(", ", selectedAnswers)}\nAnalyze these selected workplace factors for mental health implications and patterns."; + } + + // Create analysis request if we have text to analyze + if (!string.IsNullOrEmpty(responseText)) { var request = new AnalysisRequest { ResponseId = response.Id, QuestionId = detail.QuestionId, - ResponseText = detail.TextResponse, + ResponseText = responseText, QuestionText = detail.Question?.Text ?? "" }; @@ -1087,6 +1126,8 @@ Respond with a JSON array of applicable categories: [""category1"", ""category2" return false; } + + #endregion } } diff --git a/Web/Areas/Admin/Controllers/SurveyAnalysisController.cs b/Web/Areas/Admin/Controllers/SurveyAnalysisController.cs index eafe186..ed59ca4 100644 --- a/Web/Areas/Admin/Controllers/SurveyAnalysisController.cs +++ b/Web/Areas/Admin/Controllers/SurveyAnalysisController.cs @@ -40,40 +40,42 @@ namespace Web.Areas.Admin.Controllers { var questionnaires = await _context.Questionnaires .Include(q => q.Questions) - .Select(q => new - { - q.Id, - q.Title, - q.Description, - QuestionCount = q.Questions.Count, - ResponseCount = _context.Responses.Count(r => r.QuestionnaireId == q.Id), - TextResponseCount = _context.Responses - .Where(r => r.QuestionnaireId == q.Id) - .SelectMany(r => r.ResponseDetails) - .Count(rd => !string.IsNullOrEmpty(rd.TextResponse)), - LastResponse = _context.Responses - .Where(r => r.QuestionnaireId == q.Id) - .OrderByDescending(r => r.SubmissionDate) - .Select(r => r.SubmissionDate) - .FirstOrDefault(), - // Add Users information for displaying participant details - Users = _context.Responses - .Where(r => r.QuestionnaireId == q.Id && !string.IsNullOrEmpty(r.UserName)) - .OrderByDescending(r => r.SubmissionDate) - .Select(r => new - { - UserName = r.UserName, - Email = r.UserEmail - }) - .Distinct() - .Take(5) // Show up to 5 recent participants - .ToList() - }) .ToListAsync(); - ViewBag.ServiceHealth = await _aiAnalysisService.GetServiceHealthStatusAsync(); + var result = questionnaires.Select(q => new + { + q.Id, + q.Title, + q.Description, + QuestionCount = q.Questions.Count, + ResponseCount = _context.Responses.Count(r => r.QuestionnaireId == q.Id), + AnalyzableResponseCount = _context.Responses + .Include(r => r.ResponseDetails) + .ThenInclude(rd => rd.ResponseAnswers) + .Where(r => r.QuestionnaireId == q.Id) + .SelectMany(r => r.ResponseDetails) + .Count(rd => !string.IsNullOrEmpty(rd.TextResponse) || + (rd.QuestionType == QuestionType.CheckBox && rd.ResponseAnswers.Any())), + LastResponse = _context.Responses + .Where(r => r.QuestionnaireId == q.Id) + .OrderByDescending(r => r.SubmissionDate) + .Select(r => r.SubmissionDate) + .FirstOrDefault(), + Users = _context.Responses + .Where(r => r.QuestionnaireId == q.Id && !string.IsNullOrEmpty(r.UserName)) + .OrderByDescending(r => r.SubmissionDate) + .Select(r => new + { + UserName = r.UserName, + Email = r.UserEmail + }) + .Distinct() + .Take(5) + .ToList() + }).ToList(); - return View(questionnaires); + ViewBag.ServiceHealth = await _aiAnalysisService.GetServiceHealthStatusAsync(); + return View(result); } catch (Exception ex) { @@ -101,21 +103,52 @@ namespace Web.Areas.Admin.Controllers } // Check if there are responses to analyze - var hasResponses = await _context.Responses - .AnyAsync(r => r.QuestionnaireId == id); + var totalResponses = await _context.Responses + .CountAsync(r => r.QuestionnaireId == id); - if (!hasResponses) + if (totalResponses == 0) { TempData["WarningMessage"] = "No responses found for this questionnaire."; return RedirectToAction(nameof(Index)); } - _logger.LogInformation("Starting analysis for questionnaire {QuestionnaireId}", id); + // Calculate analyzable responses (same logic as dashboard) + var analyzableCount = await _context.Responses + .Where(r => r.QuestionnaireId == id) + .SelectMany(r => r.ResponseDetails) + .CountAsync(rd => !string.IsNullOrEmpty(rd.TextResponse) || + (rd.QuestionType == QuestionType.CheckBox && + _context.ResponseAnswers.Any(ra => ra.ResponseDetailId == rd.Id))); + + if (analyzableCount == 0) + { + TempData["WarningMessage"] = "No analyzable responses found. Responses must contain text or checkbox selections."; + return RedirectToAction(nameof(Index)); + } + + _logger.LogInformation("Starting analysis for questionnaire {QuestionnaireId}. Total responses: {TotalResponses}, Analyzable: {AnalyzableCount}", + id, totalResponses, analyzableCount); // Generate comprehensive analysis var analysisOverview = await _aiAnalysisService.GenerateQuestionnaireOverviewAsync(id); - _logger.LogInformation("Analysis completed successfully for questionnaire {QuestionnaireId}", id); + var actuallyAnalyzed = analysisOverview.AnalyzedResponses; + + _logger.LogInformation("Analysis completed for questionnaire {QuestionnaireId}. " + + "Analyzable: {AnalyzableCount}, Successfully Analyzed: {ActuallyAnalyzed}", + id, analyzableCount, actuallyAnalyzed); + + // Provide user feedback about the difference if significant + if (analyzableCount > actuallyAnalyzed && (analyzableCount - actuallyAnalyzed) > 0) + { + var difference = analyzableCount - actuallyAnalyzed; + TempData["InfoMessage"] = $"Analysis completed successfully. {actuallyAnalyzed} of {analyzableCount} analyzable responses were processed. " + + $"{difference} response(s) could not be analyzed due to processing limitations or API constraints."; + } + else + { + TempData["SuccessMessage"] = $"Analysis completed successfully. All {actuallyAnalyzed} analyzable responses were processed."; + } return View(analysisOverview); } @@ -295,15 +328,37 @@ namespace Web.Areas.Admin.Controllers foreach (var response in responses) { - foreach (var detail in response.ResponseDetails.Where(rd => !string.IsNullOrWhiteSpace(rd.TextResponse))) + foreach (var detail in response.ResponseDetails) { - analysisRequests.Add(new AnalysisRequest + string responseText = ""; + + // Handle text-based questions + if (!string.IsNullOrWhiteSpace(detail.TextResponse)) { - ResponseId = response.Id, - QuestionId = detail.QuestionId, - ResponseText = detail.TextResponse, - QuestionText = detail.Question?.Text ?? "" - }); + responseText = detail.TextResponse; + } + // Handle CheckBox questions + else if (detail.QuestionType == QuestionType.CheckBox && detail.ResponseAnswers.Any()) + { + var selectedAnswers = detail.ResponseAnswers + .Select(ra => detail.Question.Answers.FirstOrDefault(a => a.Id == ra.AnswerId)?.Text) + .Where(text => !string.IsNullOrEmpty(text)) + .ToList(); + + responseText = $"Multiple Selection Question: {detail.Question.Text}\nSelected Options: {string.Join(", ", selectedAnswers)}\nAnalyze these selected workplace factors for mental health implications and patterns."; + } + + // Add to analysis requests if we have text to analyze + if (!string.IsNullOrEmpty(responseText)) + { + analysisRequests.Add(new AnalysisRequest + { + ResponseId = response.Id, + QuestionId = detail.QuestionId, + ResponseText = responseText, + QuestionText = detail.Question?.Text ?? "" + }); + } } } @@ -346,15 +401,37 @@ namespace Web.Areas.Admin.Controllers foreach (var response in responses) { - foreach (var detail in response.ResponseDetails.Where(rd => !string.IsNullOrWhiteSpace(rd.TextResponse))) + foreach (var detail in response.ResponseDetails) { - analysisRequests.Add(new AnalysisRequest + string responseText = ""; + + // Handle text-based questions + if (!string.IsNullOrWhiteSpace(detail.TextResponse)) { - ResponseId = response.Id, - QuestionId = detail.QuestionId, - ResponseText = detail.TextResponse, - QuestionText = detail.Question?.Text ?? "" - }); + responseText = detail.TextResponse; + } + // Handle CheckBox questions + else if (detail.QuestionType == QuestionType.CheckBox && detail.ResponseAnswers.Any()) + { + var selectedAnswers = detail.ResponseAnswers + .Select(ra => detail.Question.Answers.FirstOrDefault(a => a.Id == ra.AnswerId)?.Text) + .Where(text => !string.IsNullOrEmpty(text)) + .ToList(); + + responseText = $"Multiple Selection Question: {detail.Question.Text}\nSelected Options: {string.Join(", ", selectedAnswers)}\nAnalyze these selected workplace factors for mental health implications and patterns."; + } + + // Add to analysis requests if we have text to analyze + if (!string.IsNullOrEmpty(responseText)) + { + analysisRequests.Add(new AnalysisRequest + { + ResponseId = response.Id, + QuestionId = detail.QuestionId, + ResponseText = responseText, + QuestionText = detail.Question?.Text ?? "" + }); + } } } diff --git a/Web/Areas/Admin/Views/SurveyAnalysis/AnalyzeQuestionnaire.cshtml b/Web/Areas/Admin/Views/SurveyAnalysis/AnalyzeQuestionnaire.cshtml index 9a19d4a..b24d2d9 100644 --- a/Web/Areas/Admin/Views/SurveyAnalysis/AnalyzeQuestionnaire.cshtml +++ b/Web/Areas/Admin/Views/SurveyAnalysis/AnalyzeQuestionnaire.cshtml @@ -3,434 +3,493 @@ @{ ViewData["Title"] = $"AI Analysis - {Model.QuestionnaireTitle}"; - } -
Comprehensive mental health analysis powered by Azure AI
+Comprehensive risk assessment across all response types
No risk assessment data available
No risk assessment data available
+Emotional tone assessment across responses
+No sentiment analysis data available
+No sentiment analysis data available
-Comprehensive analysis overview across all question types
+Priority-ranked issues with recommended actions
+@issue.Issue
-@issue.RecommendedIntervention
-No workplace issues identified in the analysis
-No workplace issues identified in the analysis
+Key patterns and categories identified
+No common themes identified
-Track workplace mental health patterns and intervention effectiveness over time
-+ Track workplace mental health patterns and intervention effectiveness over time +
+- Mental health scores have improved 18% over the analyzed period, - indicating successful intervention strategies. -
- Predicted: Continued improvement -- Management support scores remain static. - This may become a limiting factor for further improvements. -
- Action needed: Manager training -- Mental health scores typically dip during Q4 (holiday stress) - and peak in Q2 (post-intervention period). -
- Plan: Preventive Q4 interventions + +