From 9fa24f533a06248532968c7d8b039ccb7bdf5c23 Mon Sep 17 00:00:00 2001 From: spearzificial <342299391+spearzificial@users.noreply.github.com> Date: Sun, 18 Oct 2026 18:58:16 +0530 Subject: [PATCH] Programmed summary section on result page: rule-based coach notes replace the AI Summary (nav link, arrow bullets) --- src/views.rs | 19 ++++++++++++++++++- static/style.css | 28 ++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/views.rs b/src/views.rs index aec03af..d2d4507 100644 --- a/src/views.rs +++ b/src/views.rs @@ -1,4 +1,4 @@ -use crate::analytics::{accuracy, fmt_dur, fmt_pct, Analysis, Bucket, TestRow}; +use crate::analytics::{accuracy, coach_notes, fmt_dur, fmt_pct, Analysis, Bucket, TestRow}; use crate::auth::Ctx; use crate::exam::{BuildForm, Question}; @@ -1275,6 +1275,17 @@ pub fn result(ctx: &Ctx, user: &str, attempt_id: &str, share_token: &str, a: &An }) .collect(); let neg = rows.iter().filter(|r| !r.correct && !r.selected.trim().is_empty()).count() as i32; + // Programmed summary (the "AI Summary" analogue): rule-based coach notes + // from this paper, plus the dominant tagged mistake when any exist. + let mut mistake_map: std::collections::HashMap = std::collections::HashMap::new(); + for r in rows { + for t in &r.tags { + *mistake_map.entry(t.clone()).or_insert(0) += 1; + } + } + let mut mistake_counts: Vec<(String, i64)> = mistake_map.into_iter().collect(); + mistake_counts.sort_by_key(|(_, n)| -n); + let summary_notes = coach_notes(a, &[], &mistake_counts); // Time analysis: where the clock went, from per-question times. let avg_for = |filt: &dyn Fn(&RowView) -> bool| -> String { let pick: Vec = rows.iter().filter(|r| filt(r) && r.time_secs > 0).map(|r| r.time_secs).collect(); @@ -1340,6 +1351,7 @@ pub fn result(ctx: &Ctx, user: &str, attempt_id: &str, share_token: &str, a: &An {user} · {title_} overview tag mistakes{mtag} + summary performance analysis time analysis difficulty analysis @@ -1361,6 +1373,10 @@ pub fn result(ctx: &Ctx, user: &str, attempt_id: &str, share_token: &str, a: &An

{eb}

{tag_banner} +

summary

+
    +{summary_notes} +

subject-wise result

{subj}
subjectrightwrongblank%

by difficulty

{diff}
difficultyrightwrongblank%
@@ -1404,6 +1420,7 @@ pub fn result(ctx: &Ctx, user: &str, attempt_id: &str, share_token: &str, a: &An share_nav = if share_token.is_empty() { String::new() } else { format!(r#""#, share_box = share_box) }, + summary_notes = summary_notes.iter().map(|n| format!("
  • {}
  • ", esc(n))).collect::(), tag_banner = if mistakes_pending > 0 { format!( r##"
    recommended: tag your {n} mistakes

    Pick why you lost each question (calculation slip, formula, ran out of time...). It takes a couple of minutes and adds mistake-type charts and sharper advice to your dashboard.

    tag mistakes
    "##, diff --git a/static/style.css b/static/style.css index 25bd818..ae1eb28 100644 --- a/static/style.css +++ b/static/style.css @@ -2819,3 +2819,31 @@ img.brand-logo { .zp-past-panel .zp-filter-pill input[type=radio] { accent-color: #2563eb; } + +/* Programmed summary ("AI summary" analogue) */ +.summary-card { + margin: 0 0 18px; +} + +.summary-notes { + list-style: none; + margin: 0; + padding: 0; + display: grid; + gap: 10px; +} + +.summary-notes li { + position: relative; + padding-left: 18px; + font-size: 0.9rem; + line-height: 1.6; + color: var(--text-dim); +} + +.summary-notes li::before { + content: "→"; + position: absolute; + left: 0; + color: #38bdf8; +}