From b17f6f1b37a3efa304cd6894c7a387d3413c91cd Mon Sep 17 00:00:00 2001 From: laurentbarontini Date: Sat, 2 May 2026 20:34:56 +0200 Subject: [PATCH] Bugs next card --- backend/app/main.py | 35 +++++++++++++++++++++++++++++++++++ frontend/src/App.jsx | 27 ++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/backend/app/main.py b/backend/app/main.py index 2e19eaa..d2d1829 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -141,6 +141,39 @@ def upsert_card_progress(db: Session, student_id: int, state: schemas.LessonCard db.add(row) return row + +def update_next_program_start_from_progress(db: Session, student_id: int, lesson_id: str) -> None: + assignment = db.query(models.StudentProgramAssignment).filter_by(student_id=student_id).first() + if not assignment or assignment.lesson_id != lesson_id: + return + lesson = get_lesson(lesson_id) + if not lesson: + return + validated_keys = { + row.section_key + for row in db.query(models.LessonCardProgress) + .filter_by(student_id=student_id, lesson_id=lesson_id) + .all() + if row.validated_at is not None + } + assets = lesson.get("assets") or [] + for asset_index, asset in enumerate(assets): + sections = asset.get("sections") or [] + if not sections: + continue + for section_index, section in enumerate(sections): + section_key = section.get("context_key") or f"{asset.get('path', 'asset')}:{section.get('index', 0)}" + if section_key not in validated_keys: + assignment.start_asset_index = asset_index + assignment.start_section_index = section_index + db.add(assignment) + return + last_asset_index = max(len(assets) - 1, 0) + last_sections = assets[last_asset_index].get("sections") if assets else [] + assignment.start_asset_index = last_asset_index + assignment.start_section_index = max(len(last_sections or []) - 1, 0) + db.add(assignment) + @app.get("/health") def health(): return {"status": "ok"} @@ -399,6 +432,8 @@ def end_lesson_session( for state in payload.card_states: upsert_card_progress(db, student.id, state) + db.flush() + update_next_program_start_from_progress(db, student.id, payload.lesson_id) conversation_json = json.dumps( payload.conversation, diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index fe2a962..3be15a8 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -581,6 +581,7 @@ function TutorApp({ currentUser, onLogout }) { }), }) await loadCardProgress(selectedStudentId, studentProgram.id) + await loadStudentProgram(selectedStudentId) if (!isStudentUser) await loadSessionLogs(selectedStudentId) } @@ -798,6 +799,15 @@ function TutorApp({ currentUser, onLogout }) { function buildNextCardInstruction(nextStep) { const title = nextStep?.section?.title || nextStep?.asset?.title || 'la suite' + const key = nextStep?.section?.context_key || '' + const prompts = { + Fiche1Card2: 'Très bien, on passe à Exemple. Lis le nombre 345 208.', + Fiche1Card3: 'Très bien, on passe à À retenir. Dis-moi ce qu’on lit en premier.', + Fiche1Card4: 'Très bien, on passe à Exemple 1. Lis le nombre 7 425.', + Fiche1Card5: 'Très bien, on passe à Exemple 2. Lis le nombre 38 090.', + Fiche1Card6: 'Très bien, on passe à Exemple 3. Lis le nombre 506 012.', + } + if (prompts[key]) return prompts[key] if (title.toLowerCase().startsWith('exemple')) { return `Très bien, on passe à ${title}. Lis seulement le nombre affiché.` } @@ -816,6 +826,7 @@ function TutorApp({ currentUser, onLogout }) { const answer = normalizeAnswer(text) const { section } = getLessonPosition() const key = section?.context_key || '' + if (/^(ok|oui|d accord|daccord|j ai compris|compris)[.!?\s]*$/.test(answer.trim())) return true if (/\b(oui|ok|d accord)\b/.test(answer) && /compr/.test(answer)) return true if (key === 'Fiche1Card1') { return /compr/.test(answer) || (answer.includes('345') && answer.includes('208')) @@ -1018,6 +1029,20 @@ function TutorApp({ currentUser, onLogout }) { setLastStudentTransmission(text) setInput('') setErrorMessage('') + if (answerValidatesCurrentCard(text)) { + rememberActiveCard({ score: 100, validated: true }) + const nextStep = getNextLessonStep() + const transitionReply = nextStep + ? buildNextCardInstruction(nextStep) + : 'Très bien, cette fiche est terminée.' + if (nextStep) { + setLessonPosition(nextStep.assetIndex, nextStep.sectionIndex) + } + appendMessage('assistant', transitionReply) + setCurrentInstruction(transitionReply) + speak(transitionReply) + return + } const data = await apiFetch('/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -1027,7 +1052,7 @@ function TutorApp({ currentUser, onLogout }) { ...getLessonContextPayload(), }), }) - const shouldAdvance = data.advance_lesson_step || answerValidatesCurrentCard(text) + const shouldAdvance = data.advance_lesson_step if (shouldAdvance) { rememberActiveCard({ score: 100, validated: true }) const nextStep = getNextLessonStep()