Skip to content

Commit

Permalink
Merge pull request #56 from EveCrystali/dev/DiabetesRiskPrediction---…
Browse files Browse the repository at this point in the history
…Enhance-prediction-quality-#49

Dev/diabetes risk prediction   enhance prediction quality #49
  • Loading branch information
EveCrystali authored Nov 14, 2024
2 parents 981f19d + a310d3e commit 75b4ba4
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 55 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
using BackendDiabetesRiskPrediction.Models;
namespace BackendDiabetesRiskPrediction.Services;

public class DiabetesRiskNotePredictionService(ILogger<DiabetesRiskNotePredictionService> logger, ElasticsearchService elasticsearchService)
public class DiabetesRiskNotePredictionService(ElasticsearchService elasticsearchService, ILogger<DiabetesRiskNotePredictionService> logger)
{

private readonly HashSet<string> triggerWords =
[
// TODO: Hémoglobine A1C is still consider as two separated words
"Hémoglobine A1C",
"Microalbumine",
"Taille",
Expand All @@ -29,24 +28,17 @@ public async Task<DiabetesRiskPrediction> DiabetesRiskPrediction(List<NoteRiskIn
return diabetesRiskPrediction;
}

int triggersDiabetesRiskFromNotes = await DiabetesRiskPredictionNotesAnalysis(notes);
int triggersDiabetesRiskFromNotes = await DiabetesRiskPredictionNotesAnalysis(patientRiskInfo.Id, triggerWords);

Check notice on line 31 in BackendDiabetesRiskPrediction/Services/DiabetesRiskNotePredictionService.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Use preferred 'var' style (for built-in types)

Use 'var' (built-in types)

diabetesRiskPrediction.DiabetesRisk = DiabetesRiskPredictionCalculator(patientRiskInfo, triggersDiabetesRiskFromNotes);

return diabetesRiskPrediction;
}

private async Task<int> DiabetesRiskPredictionNotesAnalysis(List<NoteRiskInfo> notes)
{
IEnumerable<Task<int>> tasks = notes.Select(DiabetesRiskPredictionSingleNoteAnalysis);
int[] results = await Task.WhenAll(tasks);
return results.Sum();
}


private async Task<int> DiabetesRiskPredictionSingleNoteAnalysis(NoteRiskInfo note) => await elasticsearchService.CountUniqueWordsInNotes(note.PatientId, triggerWords);
private async Task<int> DiabetesRiskPredictionNotesAnalysis(int patientId, HashSet<string> hashSetofTriggerWords) => await elasticsearchService.CountUniqueWordsInNotes(patientId, hashSetofTriggerWords);

private static DiabetesRisk DiabetesRiskPredictionCalculator(PatientRiskInfo patientRiskInfo, int triggersDiabetesRiskFromNotes)
private DiabetesRisk DiabetesRiskPredictionCalculator(PatientRiskInfo patientRiskInfo, int triggersDiabetesRiskFromNotes)
{
int age = PatientAgeCalculator(patientRiskInfo);

Check notice on line 43 in BackendDiabetesRiskPrediction/Services/DiabetesRiskNotePredictionService.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Use preferred 'var' style (for built-in types)

Use 'var' (built-in types)

Expand All @@ -66,6 +58,8 @@ private static DiabetesRisk DiabetesRiskPredictionCalculator(PatientRiskInfo pat

private static DiabetesRisk DiabetesRiskPredictionForUnder30(PatientRiskInfo patientRiskInfo, int triggersDiabetesRiskFromNotes)
{
Console.WriteLine($"Patient gender is : {patientRiskInfo.Gender}");
Console.WriteLine($"Patient triggers are : {triggersDiabetesRiskFromNotes}");
return patientRiskInfo.Gender switch
{
// Patient is a male
Expand Down Expand Up @@ -95,11 +89,12 @@ private static DiabetesRisk DiabetesRiskPredictionFor30AndOlder(int triggersDiab

}

private static int PatientAgeCalculator(PatientRiskInfo patientRiskInfo)
private int PatientAgeCalculator(PatientRiskInfo patientRiskInfo)
{
DateTime currentDate = DateTime.Now;

Check notice on line 94 in BackendDiabetesRiskPrediction/Services/DiabetesRiskNotePredictionService.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Use preferred 'var' style (when type is simple)

Use 'var' (simple types)
DateOnly birthDate = patientRiskInfo.DateOfBirth;

Check notice on line 95 in BackendDiabetesRiskPrediction/Services/DiabetesRiskNotePredictionService.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Use preferred 'var' style (when type is simple)

Use 'var' (simple types)
int age = currentDate.Year - birthDate.Year;

Check notice on line 96 in BackendDiabetesRiskPrediction/Services/DiabetesRiskNotePredictionService.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Use preferred 'var' style (for built-in types)

Use 'var' (built-in types)
logger.LogInformation($"Patient age is : {age}");

Check notice on line 97 in BackendDiabetesRiskPrediction/Services/DiabetesRiskNotePredictionService.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

RoslynAnalyzers Template should be a static expression

The logging message template should not vary between calls to 'LoggerExtensions.LogInformation(ILogger, string?, params object?\[\])'
return age;
}
}
71 changes: 31 additions & 40 deletions BackendPatient/Data/DataSeeder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,73 +9,64 @@ public class DataSeeder(ApplicationDbContext dbContext)
public void SeedPatients()
{
// Tableau des patients non formatés
(string nom, string prenom, string dateDeNaissance, string genre, string? adresse, string? telephone)[] patientsUnformatted =
(int Id, string nom, string prenom, string dateDeNaissance, string genre, string? adresse, string? telephone)[] patientsUnformatted =
{

Check notice on line 13 in BackendPatient/Data/DataSeeder.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Use collection expression syntax

Use collection expression
("TestNone", "Test", "1966-12-31", "F", "1 Brookside St", "100-222-3333"),
("TestBorderline", "Test", "1945-06-24", "M", "2 High St", "200-333-4444"),
("TestInDanger", "Test", "2005-06-18", "M", "3 Club Road", "300-444-5555"),
("TestEarlyOnset", "Test", "2002-06-28", "F", "4 Valley Dr", "400-555-6666")
(1, "TestNone", "Test", "1966-12-31", "F", "1 Brookside St", "100-222-3333"),
(2, "TestBorderline", "Test", "1945-06-24", "M", "2 High St", "200-333-4444"),
(3, "TestInDanger", "Test", "2004-06-18", "M", "3 Club Road", "300-444-5555"),
(4, "TestEarlyOnset", "Test", "2002-06-28", "F", "4 Valley Dr", "400-555-6666")
};

// Formater les patients avant insertion
List<Patient> patientsFormatted = patientsUnformatted

Check notice on line 21 in BackendPatient/Data/DataSeeder.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Use preferred 'var' style (elsewhere)

Use 'var' (elsewhere)
.Select(Patient.FormatPatient)
.ToList();

// Charger les patients existants en mémoire pour éviter les doublons
var existingPatients = _dbContext.Patients
.Select(p => new
{
p.FirstName,
p.LastName,
p.DateOfBirth
})
.ToList();

int batchSize = 10;
int counter = 0;

using var transaction = _dbContext.Database.BeginTransaction();
try
{
SetIdentityInsert("Patients", true);

Check warning on line 28 in BackendPatient/Data/DataSeeder.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Redundant argument with default value

The parameter 'enable' has the same default value

foreach (Patient patient in patientsFormatted)
foreach (var patient in patientsFormatted)
{
// Avoid duplicate patients
if (existingPatients.Exists(p => p.FirstName == patient.FirstName &&
p.LastName == patient.LastName &&
p.DateOfBirth == patient.DateOfBirth))

// Vérifier si le patient avec cet ID existe déjà
var existingPatient = _dbContext.Patients.FirstOrDefault(p => p.Id == patient.Id);

if (existingPatient != null)
{
Console.WriteLine($"Skipping duplicate patient: {patient.FirstName} {patient.LastName} {patient.DateOfBirth}");
continue;
// Réinitialiser les données du patient existant
existingPatient.FirstName = patient.FirstName;
existingPatient.LastName = patient.LastName;
existingPatient.DateOfBirth = patient.DateOfBirth;
existingPatient.Gender = patient.Gender;
existingPatient.Address = patient.Address;
existingPatient.PhoneNumber = patient.PhoneNumber;
_dbContext.Patients.Update(existingPatient);
Console.WriteLine($"Updated test patient with ID {patient.Id}");
}
patient.Id = counter + 1;
_dbContext.Patients.Add(patient);
counter++;

// Save every 10 patients (batch size)
if (counter % batchSize == 0)
else
{
_dbContext.SaveChanges();
Console.WriteLine($"Saved {counter} patients so far...");
// Ajouter le patient avec son ID spécifique
_dbContext.Patients.Add(patient);
Console.WriteLine($"Added new test patient with ID {patient.Id}");
}
}

// Save any remaining patients
if (counter % batchSize != 0)
{
_dbContext.SaveChanges();
Console.WriteLine($"Final save, total patients saved: {counter}");
}

_dbContext.SaveChanges();
transaction.Commit();
Console.WriteLine("Test patients seeded successfully.");
}
catch
{
transaction.Rollback();
throw;
}
finally
{
// Désactiver IDENTITY_INSERT une fois terminé
SetIdentityInsert("Patients", false);
}

}

Expand Down
3 changes: 2 additions & 1 deletion BackendPatient/Models/Patient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public void Validate()
// FUTURE: Consider moving this logic to a dedicated service or factory class
// (e.g., PatientFactory) to respect the Single Responsibility Principle (SRP)
// and improve separation of concerns as the application grows.
public static Patient FormatPatient((string nom, string prenom, string? dateDeNaissance, string genre,
public static Patient FormatPatient((int Id, string nom, string prenom, string? dateDeNaissance, string genre,
string? adresse, string? telephone) unformattedPatient)
{
DateOnly dateOfBirthFormatted;

Check notice on line 55 in BackendPatient/Models/Patient.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Local variable has too wide declaration scope

Local variable 'dateOfBirthFormatted' can be declared in inner scope
Expand All @@ -59,6 +59,7 @@ public static Patient FormatPatient((string nom, string prenom, string? dateDeNa
"yyyy-MM-dd", CultureInfo.InvariantCulture);
return new Patient
{
Id = unformattedPatient.Id,
FirstName = unformattedPatient.nom,
LastName = unformattedPatient.prenom,
DateOfBirth = dateOfBirthFormatted,
Expand Down
1 change: 0 additions & 1 deletion SharedLibrary/DateOnlyJsonConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Text.Json.Serialization;
namespace BackendPatient.Extensions;

Check warning on line 4 in SharedLibrary/DateOnlyJsonConverter.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Namespace does not correspond to file location

Namespace does not correspond to file location, must be: 'SharedLibrary'

// TODO: verify it is needed
public class DateOnlyJsonConverter : JsonConverter<DateOnly>
{
private const string Format = "yyyy-MM-dd";
Expand Down

0 comments on commit 75b4ba4

Please sign in to comment.