Skip to content

feat: add adaptive diagnostic test — LLM-based level assessment before chat#269

Draft
latifaaznague wants to merge 1 commit into
Open-TutorAi:mainfrom
latifaaznague:refactor/ui-feature-structure
Draft

feat: add adaptive diagnostic test — LLM-based level assessment before chat#269
latifaaznague wants to merge 1 commit into
Open-TutorAi:mainfrom
latifaaznague:refactor/ui-feature-structure

Conversation

@latifaaznague

Copy link
Copy Markdown

Pull Request Checklist

Before submitting this pull request, I confirm the following:

  • Description: Provided below.
  • Changelog: Added at the bottom of this description following the Keep a Changelog format.
  • Documentation: Documentation added in docs/diagnostic-test/ (README.md, feature.md, user-guide.md, diagrams, mockups, and screenshots).
  • Dependencies: No new dependencies were added.
  • Testing: Added and ran sufficient tests to validate the feature (37 pytest tests).
  • Code review: Performed a self-review and ensured consistency with the project structure and coding standards.
  • Prefix: feat

Description

This pull request introduces a mandatory adaptive diagnostic test that students must complete before accessing the pedagogical chat for any course support.

Before this contribution, students could directly open the pedagogical chat without any prior knowledge assessment. As a result, the AI tutor had no context about the learner’s actual level and produced generic responses that were not adapted to their knowledge.

This contribution adds a diagnostic step between support access and the pedagogical chat. The system now:

  • generates a personalized 10-question diagnostic test from the support content using an LLM,
  • evaluates the student’s answers,
  • calculates a score and determines a learner level (beginner, intermediate, advanced),
  • stores the diagnostic result,
  • updates the support learning level,
  • and adapts the AI tutor’s behavior from the very first pedagogical message based on the diagnosed level.

This improves the personalization of the tutoring experience by ensuring that the pedagogical chat starts with an initial estimate of the learner’s knowledge.

Changelog Entry

Description

  • Added a complete adaptive diagnostic test workflow that must be completed before the pedagogical chat becomes accessible.
  • Implemented backend support for diagnostic generation, submission, scoring, persistence, support-level update, and retrieval.
  • Added a dedicated frontend diagnostic test interface and integrated access control/redirection from the support page.
  • Updated the tutor prompt so the pedagogical chat becomes adaptive to the learner’s diagnosed level from the first interaction.

Added

Backend

  • Added a complete backend module for managing the adaptive diagnostic test workflow.
  • Implemented the components required to generate a diagnostic test from support content, evaluate submitted answers, calculate the score, determine the learner’s level, and persist diagnostic results.

Frontend

  • Added a dedicated interface for taking the diagnostic test.
  • Integrated a guided student flow to answer the quiz, track progress, and review results.

Changed

Frontend

  • Updated the support-to-chat access flow to require completion of the diagnostic test before allowing access to the pedagogical tutor.
  • Updated the pedagogical chat so that tutor behavior is adapted to the learner’s diagnosed level.

Global behavior

  • Added adaptive tutoring behavior based on three learner levels (beginner, intermediate, advanced).
  • Added score calculation and level determination rules based on the student’s answers.

Deprecated

  • None.

Removed

  • None.

Fixed

  • Fixed the lack of learner-level context in the pedagogical chat by introducing a diagnostic step before chat access.
  • Prevented students from accessing the tutor without an initial knowledge assessment for a support.
  • Ensured safe handling of diagnostic submission in double-submission scenarios.
  • Ensured correct answers remain hidden while a diagnostic is still pending.

Security

  • Added authorization checks to prevent access to another student’s diagnostic result.
  • Added validation and error handling for malformed LLM responses and invalid diagnostic operations.

Breaking Changes

  • None. Existing supports remain unaffected until a first diagnostic is generated and submitted.

Additional Information

Scoring Rules

  • Score >= 71%advanced
  • Score >= 41%intermediate
  • otherwise → beginner

Test Coverage

Added 37 pytest tests covering:

  • diagnostic generation,
  • score calculation,
  • level boundary cases (40%, 41%, 70%, 71%),
  • authorization checks (403 when the diagnostic does not belong to the student),
  • double submission / idempotency behavior,
  • support-level update,
  • invalid LLM response handling (502),
  • rate limiting (429),
  • input validation,
  • and masking of correct answers while the diagnostic is pending.

Technical Notes

  • No new dependencies were added.
  • Answer evaluation currently relies on exact text comparison rather than answer index comparison.
  • LLM diagnostic generation uses a 120-second timeout to support local Ollama models.
  • Route declaration order in the diagnostics router is important: GET /by-support/{id} must be declared before GET /{id}.
  • The diagnostic_results table is created automatically through Base.metadata.create_all().

Documentation

Complete documentation was added in docs/diagnostic-test/:

  • README.md — technical and API documentation
  • feature.md — internal feature documentation, implementation details, and known limitations
  • user-guide.md — student and teacher guide
  • assets/ — sequence diagram, class diagram, activity diagram, UI mockups, and real screenshots of the full student journey

Screenshots or Videos

Support creation

creation-de-cours creation-de-cours-2

Diagnostic start page

diagnostic-start-page

Quiz in progress

diagnostic-quiz

Results page

diagnostic-results

Adaptive pedagogical chat

adaptive-pedagogical-chat

@Oumaima-elkhoummassi

Copy link
Copy Markdown

@latifaaznague
Documentation review — feature.md and user-guide.md checked

Language: both files and the pull request description are entirely in French.
The project rule is that all documentation must be written in English -
could you translate everything?

The PR description and test coverage list mention rate limiting (429),
but feature.md's error tables for /generate and /submit only list
404/403/502, and user-guide.md doesn't mention any rate limit either.
Could you document which endpoint is rate-limited and at what threshold?

Please fix the language (translate to English) before approval.

@Dakir-Ai Dakir-Ai self-requested a review June 27, 2026 08:36

@Dakir-Ai Dakir-Ai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @latifaaznague
Nice addition! However, there are merge conflicts that need to be resolved before we can complete the review

@latifaaznague latifaaznague force-pushed the refactor/ui-feature-structure branch from a35cf9a to a51b2d1 Compare June 28, 2026 02:06
@latifaaznague latifaaznague force-pushed the refactor/ui-feature-structure branch from a51b2d1 to 536e670 Compare June 28, 2026 09:15
@latifaaznague latifaaznague changed the title feat: Test Diagnostique Adaptatif — évaluation de niveau LLM avant le chat pédagogique feat: add adaptive diagnostic test — LLM-based level assessment before chat Jun 28, 2026
@pr-elhajji pr-elhajji requested a review from Copilot July 4, 2026 09:29

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces an adaptive diagnostic-test workflow that gates access to the student support chat, generates an LLM-based quiz, scores it into a learner level, persists results, and uses that level to adapt the tutor’s system prompt from the first message.

Changes:

  • Added backend diagnostics module (model/repo/service/router) with LLM generation, scoring, persistence, and rate limiting.
  • Added a SvelteKit diagnostic route/UI and integrated it into the support creation + support details access flow as a mandatory gate.
  • Updated tutor prompt composition to adapt teaching strategy based on the diagnosed level.

Reviewed changes

Copilot reviewed 22 out of 38 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
ui/vite.config.ts Expands Vite dev server filesystem allowlist (incl. node_modules paths).
ui/src/routes/student/support/[id]/diagnostic/+page.svelte Adds route entry that renders the diagnostic page component.
ui/src/routes/student/support/[id]/diagnostic/+page.js Adds route load() that returns params.id.
ui/src/lib/i18n/locales/fr-FR/translation.json Adds new i18n keys for diagnostic UI flow.
ui/src/lib/i18n/locales/en-US/translation.json Adds new i18n keys for diagnostic UI flow.
ui/src/lib/i18n/locales/ar-MA/translation.json Adds new i18n keys for diagnostic UI flow.
ui/src/lib/components/student/tutor/Chat.svelte Injects diagnosed-level-specific prompt instructions for the tutor.
ui/src/lib/components/student/pages/SupportDetails.svelte Adds diagnostic completion gate + UI for locked chat access.
ui/src/lib/components/student/pages/DiagnosticTest.svelte Implements the diagnostic test UI (generate, step-by-step quiz, submit, review).
ui/src/lib/components/student/elements/SupportCreation.svelte Redirects users to the diagnostic flow after support creation.
ui/src/lib/apis/diagnostics/index.ts Adds frontend API client for diagnostics endpoints.
tests/tests/test_diagnostics.py Adds pytest coverage for diagnostics routes, scoring, auth, and rate limiting.
learning/diagnostics/service.py Implements diagnostic generation (LLM prompt/parse) and scoring/level assignment.
learning/diagnostics/repository.py Adds repository helpers to fetch diagnostics by support/user.
learning/diagnostics/init.py Introduces diagnostics package.
gateway/http/routers/diagnostics.py Adds FastAPI router for diagnostics endpoints with rate limiting and sanitization helper.
gateway/http/dependencies.py Adds get_diagnostics_service dependency provider.
gateway/http/app.py Registers the diagnostics router under /api/v1.
docs/diagnostic-test/user-guide.md Adds end-user documentation and walkthrough for the diagnostic flow.
docs/diagnostic-test/README.md Adds technical overview + API documentation for diagnostics.
docs/diagnostic-test/feature.md Adds detailed internal implementation notes and diagrams references.
data/models/diagnostic.py Adds the DiagnosticResult ORM model.
data/models/init.py Registers DiagnosticResult for model discovery/table creation.

Comment on lines +145 to +150
result = svc.get_by_support(support_id)
if result and result.user_id != current_user.id:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN, detail="Not authorized"
)
return result
Comment on lines +164 to +168
if result.user_id != current_user.id:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN, detail="Not authorized"
)
return result
Comment on lines +222 to +226
self.support_repo.update(
diagnostic.support_id,
level=determined_level,
updated_at=datetime.utcnow(),
)
Comment on lines +1 to +5
# tests/test_diagnostics.py
import json
import uuid
from datetime import datetime
from unittest.mock import AsyncMock, patch
Comment on lines +82 to +88
support = self.support_repo.get_by_id(support_id)
if not support:
raise NotFoundError("Support", support_id)
if support.user_id != user_id:
raise AuthorizationError("You do not own this support request")

language = support.content_language or "English"
Comment on lines +53 to +60
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});

if (error) throw error;
return res;
Comment on lines +83 to +91
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});

if (error) throw error;
return res;
};
Comment on lines +1 to +5
/** @type {import('./$types').PageLoad} */
export function load({ params }) {
return {
id: params.id
};
Comment on lines +35 to +39
| Score | Assigned Profile | Chat Behavior |
|---|---|---|
| 0 – 40% | Beginner | Simplified explanations, one concept at a time, concrete examples, no jargon |
| 41 – 70% | Intermediate | Balanced content, progressive deepening, nuances and exceptions |
| 71 – 100% | Advanced | Technical content, complex cases, specialized references, fast pace |
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants