Skip to content

Commit

Permalink
add no-data indicator, logging debug output
Browse files Browse the repository at this point in the history
  • Loading branch information
MaHaWo committed Dec 19, 2024
1 parent 3eecc66 commit 2717c8f
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 37 deletions.
78 changes: 47 additions & 31 deletions frontend/src/lib/components/ChildrenFeedback.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import {
CheckCircleSolid,
CloseCircleSolid,
ExclamationCircleSolid,
EyeSolid,
UserSettingsOutline,
} from "flowbite-svelte-icons";
import { _, locale } from "svelte-i18n";
Expand Down Expand Up @@ -230,6 +229,7 @@ let promise = $state(setup());

{#snippet evaluation(aid: number, milestone_or_group: MilestonePublic | MilestoneGroupPublic | undefined, value: number, isMilestone: boolean, withText: boolean = false)}
<div class="text-gray-700 dark:text-gray-400 space-x-2 space-y-4 p-2 m-2">
{console.log(' aid: ', aid, milestone_or_group?.text[$locale as string].title, value, isMilestone, withText)}
{#if value === 1}
<div class="flex flex-col sm:flex-row space-y-2 sm:space-y-0 sm:space-x-2 items-center">
<CheckCircleSolid color = "green" size="xl"/>
Expand Down Expand Up @@ -262,7 +262,7 @@ let promise = $state(setup());
</Modal>
</span>
{/if}
{:else}
{:else if value === -1}
<div class="flex flex-col sm:flex-row space-y-2 sm:space-y-0 sm:space-x-2 items-center">
<CloseCircleSolid color = "red" size="xl"/>
<span class = "text-gray-700 dark:text-gray-400 font-bold " >
Expand All @@ -284,6 +284,18 @@ let promise = $state(setup());
</Modal>
</span>
{/if}
{:else }
<div class="flex flex-col sm:flex-row space-y-2 sm:space-y-0 sm:space-x-2 items-center">
<CloseCircleSolid color = "gray" size="xl"/>
<span class = "text-gray-700 dark:text-gray-400 font-bold " >
{milestone_or_group?.text[$locale as string].title}
</span>
<Hr class="mx-2"/>
{#if withText}
<p>{$_("milestone.notEnoughDataYet")}</p>
{/if}
</div>

{/if}
</div>
{/snippet}
Expand Down Expand Up @@ -337,7 +349,7 @@ let promise = $state(setup());
</AccordionItem>
</Accordion>

<Checkbox class= "pb-4 m-2 p-2 text-gray-700 dark:text-gray-400" bind:checked={showHistory}>{$_("milestone.showHistory")}</Checkbox>
<Checkbox class= "pb-4 m-2 p-2 text-gray-700 dark:text-gray-400" bind:checked={showHistory} >{$_("milestone.showHistory")}</Checkbox>
<Hr classHr= "mx-2"/>
</div>

Expand All @@ -349,35 +361,39 @@ let promise = $state(setup());
}}><ArrowLeftOutline class="w-4 h-4" /></Button>
{/if}
<div class="flex flex-col md:flex-row">
{#each relevant_sessionkeys as aid}
{#if showHistory === true || aid === sessionkeys[0]}
<TabItem defaultClass="font-bold text-gray-700 dark:text-gray-400 m-2 p-2" title={makeTitle(aid)} open={aid === relevant_sessionkeys[0] }>
<Accordion class="p-2 m-2">
{#each Object.entries(summary[aid]) as [mid, score]}
<AccordionItem >
<span slot="header" class="text-gray-700 dark:text-gray-400 items-center flex justify-center space-x-2">
{@render evaluation(aid, milestoneGroups[aid][Number(mid)], score as number, false, false)}
</span>
<div class="flex-row justify-between">
{#each Object.entries(detailed[aid][mid]) as [ms_id, ms_score]}
{@render evaluation(
aid,
milestoneGroups[aid][Number(mid)].milestones.find((element: any) =>
{
return element.id === Number(ms_id);
}),
Number(ms_score),
true, true
)}
<Hr classHr="mx-2"/>
{/each}
</div>
</AccordionItem>
{/each}
</Accordion>
</TabItem>
{#if relevant_sessionkeys.length=== 0}
<p class="m-2 p-2 pb-4 text-gray-700 dark:text-gray-400">{$_("milestone.noFeedback")}</p>
{:else}
{#each relevant_sessionkeys as aid}
{#if showHistory === true || aid === sessionkeys[0]}
<TabItem defaultClass="font-bold text-gray-700 dark:text-gray-400 m-2 p-2" title={makeTitle(aid)} open={aid === relevant_sessionkeys[0] }>
<Accordion class="p-2 m-2">
{#each Object.entries(summary[aid]) as [mid, score]}
<AccordionItem >
<span slot="header" class="text-gray-700 dark:text-gray-400 items-center flex justify-center space-x-2">
{@render evaluation(aid, milestoneGroups[aid][Number(mid)], score as number, false, false)}
</span>
<div class="flex-row justify-between">
{#each Object.entries(detailed[aid][mid]) as [ms_id, ms_score]}
{@render evaluation(
aid,
milestoneGroups[aid][Number(mid)].milestones.find((element: any) =>
{
return element.id === Number(ms_id);
}),
Number(ms_score),
true, true
)}
<Hr classHr="mx-2"/>
{/each}
</div>
</AccordionItem>
{/each}
</Accordion>
</TabItem>
{/if}
{/each}
{/if}
{/each}
</div>
{#if showHistory === true}
<Button size="md" type="button" class="md:w-16 md:h-8" on:click={() => {
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@
"feedbackDetailsMilestoneGroup": "Zu jeder Meilensteingruppe wird der Durchschnitt und die Standardabweichung der erreichten Punktzahl aller für das Kindesalter relevanten Meilensteine dieser Gruppe berechnet. Danach wird der Durchschnitt des der erreichten Punktzahl des Kindes mit dem Durchschnitt der Gruppe verglichen. Wenn der Durchschnitt des Kindes zwei Standardabweichungen unter dem Gruppendurchschnitt liegt, wird das Kind als 'Entwicklung verzögert' eingestuft (rot), wenn es zwei bis eine Standardabweichung unterhalb des Gruppendurchschnitts liegt, wird es als 'Entwicklung leicht verzögert' eingestuft (gelb). Wenn die Durchschnittszahl des Kindes innerhalb einer Standardabweichung des Gruppendurchschnitts oder darüber liegt, wird es als 'Entwicklung altersgemäß' eingestuft (grün). Statistisch liegen ungefähr 67% aller Kinder liegen innerhalb einer Standardabweichung um den Gruppendurchschnitt und 95% innerhalb von zwei Standardabweichungen. Zur Bewertung dieser Einstufungen ist es sinnvoll, die Bewertung der einzelnen Meilensteine miteinzubeziehen",
"feedbackDetailsMilestone": "Einzelne Meilensteine werden nach demselben Schema bewertet, allerdings sind hier Durchschnitt und Standardabweichung für den jeweiligen Meilenstein relevant. Beachten sie, dass die Bewertung einzelner Meilensteine nicht diesselbe sein muss wie für die ganze Gruppe - einzelne Meilensteine können gegebenenfalls signifikant verzögert sein ohne dass die ganze Meilensteingruppe als entwicklungsverzögert bewertet wird. In solchen Fällen ist besondere Aufmerksamkeit notwendig.",
"disableHelp": "Ausblenden",
"noFeedback": "Kein Feedback verfügbar. Sie müssen ein Kind länger als eine Woche beobachten und regelmäßig Meilensteine bewerten um Feedback zu erhalten.",
"current": "Aktuell",
"toTheMilestone": "Zum Meilenstein",
"older": "Weiter zurück",
"newer": "Weiter vor"
"newer": "Weiter vor",
"notEnoughDataYet": "Noch nicht genügend Daten für Feedback"
},
"search": {
"allLabel": "Alle",
Expand Down
50 changes: 45 additions & 5 deletions mondey_backend/src/mondey_backend/routers/scores.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import logging
from datetime import datetime
from datetime import timedelta
from enum import Enum
Expand Down Expand Up @@ -104,17 +105,22 @@ def compute_milestonegroup_feedback_summary(
dict[int, int]
Dictionary of milestonegroup_id -> feedback
"""
logger = logging.getLogger(__name__)
logger.debug("compute_milestonegroup_feedback_summary")
answersession = session.get(MilestoneAnswerSession, answersession_id)

if answersession is None:
raise ValueError("No answersession with id: ", answersession_id)
logger.debug(
f" answersession id: {answersession_id}, created_at: {answersession.created_at}"
)

# get child age
child = session.get(Child, child_id)
if child is None:
raise ValueError("No child with id: ", child_id)
age = get_child_age_in_months(child, answersession.created_at)

logger.debug(f" child age in months: {age}")
# extract milestonegroups
groups = set(answer.milestone_group_id for answer in answersession.answers.values())
today = datetime.now()
Expand All @@ -123,7 +129,15 @@ def compute_milestonegroup_feedback_summary(
# if the statistics is older than a week, we update it with the current data
feedback: dict[int, int] = {}
for group in groups:
logger.debug(f" group: {group}")
stats = session.get(MilestoneGroupAgeScoreCollection, group)
logger.debug(f" old stats: {stats}")
if stats is not None:
for i, score in enumerate(stats.scores):
if score.count > 0:
logger.debug(
f" old score: , {i}, {score.count}, {score.avg_score}, {score.stddev_score}"
)

if stats is None or stats.created_at < today - timedelta(days=7):
new_stats = calculate_milestonegroup_statistics_by_age(session, group)
Expand All @@ -132,7 +146,11 @@ def compute_milestonegroup_feedback_summary(
raise ValueError("No statistics for milestone group: ", group)

# update stuff in database
for new_score in new_stats.scores:
for i, new_score in enumerate(new_stats.scores):
if new_score.count > 0:
logger.debug(
f" new_score: , {i}, {new_score.count}, {new_score.avg_score}, {new_score.stddev_score}"
)
session.merge(new_score)

session.merge(new_stats)
Expand All @@ -145,11 +163,14 @@ def compute_milestonegroup_feedback_summary(
for answer in answersession.answers.values()
if answer.milestone_group_id == group
]

logger.debug(
f' group answers: , {group_answers}, "mean: ", {np.mean(group_answers)}'
)
# use the statistics recorded for a certain age as the basis for the feedback computation
feedback[group] = compute_feedback_simple(
stats.scores[age], float(np.mean(group_answers))
)
logger.debug(f"summary feedback: {feedback}")
return feedback


Expand All @@ -175,18 +196,24 @@ def compute_milestonegroup_feedback_detailed(
dict[int, dict[int, int]]
Dictionary of milestonegroup_id -> [milestone_id -> feedback]
"""
logger = logging.getLogger(__name__)

logger.debug("compute_milestonegroup_feedback_detailed")
answersession = session.get(MilestoneAnswerSession, answersession_id)

if answersession is None:
raise ValueError("No answersession with id: ", answersession_id)

logger.debug(
f" answersession id: {answersession_id} created_at: {answersession.created_at}"
)
# get child age
child = session.get(Child, child_id)

if child is None:
raise ValueError("No child with id: ", child_id)

age = get_child_age_in_months(child, answersession.created_at)
logger.debug(f" child age in months: {age}")
today = datetime.today()

# for each milestonegroup, get the statistics, compute the current mean, and compute the feedback
Expand All @@ -195,6 +222,13 @@ def compute_milestonegroup_feedback_detailed(
# try to get statistics for the current milestone and update it if it's not there
# or is too old
stats = session.get(MilestoneAgeScoreCollection, milestone_id)
logger.debug(f" old stats: {stats}")
if stats is not None:
for i, score in enumerate(stats.scores):
if score.count > 0:
logger.debug(
f" old score: {i}, {score.count}, {score.avg_score}, {score.stddev_score}"
)

if stats is None or stats.created_at < today - timedelta(days=7):
new_stats = calculate_milestone_statistics_by_age(session, milestone_id)
Expand All @@ -206,7 +240,11 @@ def compute_milestonegroup_feedback_detailed(
)

# update stuff in database
for new_score in new_stats.scores:
for i, new_score in enumerate(new_stats.scores):
if new_score.count > 0:
logger.debug(
f" new_score: , {i}, {new_score.count}, {new_score.avg_score}, {new_score.stddev_score}"
)
session.merge(new_score)

session.merge(new_stats)
Expand All @@ -220,4 +258,6 @@ def compute_milestonegroup_feedback_detailed(
compute_feedback_simple(stats.scores[age], answer.answer + 1)
)

logger.debug(f" detailed feedback: {feedback}")

return feedback

0 comments on commit 2717c8f

Please sign in to comment.