feat(assignments): add AI-assisted grading for teacher assignments#282
Draft
mohamedlhaj69 wants to merge 13 commits into
Draft
feat(assignments): add AI-assisted grading for teacher assignments#282mohamedlhaj69 wants to merge 13 commits into
mohamedlhaj69 wants to merge 13 commits into
Conversation
…ssion review pages
d1d0018 to
b83665f
Compare
|
Hi @mohamedlhaj69 What's missing: there's no file in docs/ for this feature. For a feature this size (assignment CRUD, submission workflow, AI grading, finalization, teacher UI, student UI), this means at minimum:
Could you add these before this is ready for review? |
Contributor
|
Hi, thk for your contribution |
There was a problem hiding this comment.
Pull request overview
Introduces an end-to-end Assignments feature spanning backend domain + REST API and a new teacher/student UI workflow, including AI-assisted draft grading intended for teachers only.
Changes:
- Added backend Assignments domain (models, repositories, service) and mounted
/api/v1/assignmentsrouter. - Added UI routes/components for teacher assignment creation + submission review, and student assignment listing/detail + PDF submission.
- Added frontend API client + tests, plus backend tests for repository/service/router behavior.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
ui/src/tests/apis/assignments.test.ts |
Vitest coverage for the new assignments API client. |
ui/src/routes/teacher/assignments/create/+page.svelte |
Teacher route wiring for assignment creation page component. |
ui/src/routes/teacher/assignments/+page.svelte |
Teacher assignments index route wiring. |
ui/src/routes/teacher/assignments/[assignmentId]/submissions/+page.svelte |
Teacher submissions list route wiring. |
ui/src/routes/teacher/assignments/[assignmentId]/submissions/[submissionId]/+page.svelte |
Teacher submission review route wiring. |
ui/src/routes/teacher/+layout.svelte |
New teacher layout shell (sidebar/navbar + role guarding). |
ui/src/routes/student/assignments/[id]/+page.svelte |
Student assignment detail route wiring. |
ui/src/lib/i18n/locales/fr-FR/translation.json |
Added/updated i18n keys for assignments UI (FR). |
ui/src/lib/i18n/locales/en-US/translation.json |
Added/updated i18n keys for assignments UI (EN). |
ui/src/lib/i18n/locales/ar-MA/translation.json |
Added/updated i18n keys for assignments UI (AR). |
ui/src/lib/components/teacher/pages/SubmissionsList.svelte |
Teacher view listing submissions for an assignment. |
ui/src/lib/components/teacher/pages/SubmissionReview.svelte |
Teacher submission grading UI, including AI draft request and finalization. |
ui/src/lib/components/teacher/pages/Assignments.svelte |
Teacher assignments list UI + navigation to create/review flows. |
ui/src/lib/components/teacher/pages/AssignmentCreate.svelte |
Teacher form to create assignments (title/description/rubric/due date). |
ui/src/lib/components/student/pages/Assignments.svelte |
Student assignments list UI + status derived from submissions. |
ui/src/lib/components/student/pages/AssignmentDetail.svelte |
Student assignment detail + PDF upload submission UI. |
ui/src/lib/components/student/elements/Sidebar.svelte |
Adds teacher “Assignments” nav entry in the existing sidebar component. |
ui/src/lib/apis/assignments/index.ts |
New typed assignments API client (CRUD + submissions + AI-grade + finalize). |
tests/test_assignments.py |
Backend tests across repository/service/router for assignments + submissions + AI-grade/finalize. |
learning/assignments/service.py |
Core orchestration for submission intake, PDF text extraction, AI grading, and finalization. |
learning/assignments/repository.py |
Repository helpers for assignment/submission lookup patterns. |
learning/assignments/__init__.py |
New domain package initializer. |
gateway/http/routers/assignments.py |
New FastAPI router for assignments/submissions, including AI-grade and finalize actions. |
gateway/http/dependencies.py |
Adds DI factory for AssignmentService. |
gateway/http/app.py |
Registers the assignments router under /api/v1. |
data/models/assignment.py |
New ORM models: Assignment and Submission. |
data/models/__init__.py |
Registers the new ORM models for metadata discovery. |
| <tr | ||
| class="border-b border-gray-200 dark:border-gray-700 text-xs uppercase text-gray-500 dark:text-gray-400" | ||
| > | ||
| <th class="px-6 py-3">{$i18n.t('Student')}</th> |
| submission.status | ||
| ] ?? statusStyle.submitted}" | ||
| > | ||
| {submission.status.replace('_', ' ')} |
Comment on lines
+63
to
+69
| const assignments = await getAssignments(token); | ||
| rows = await Promise.all( | ||
| assignments.map(async (assignment) => ({ | ||
| assignment, | ||
| submission: await getMySubmission(token, assignment.id) | ||
| })) | ||
| ); |
Comment on lines
+179
to
+180
| except Exception: | ||
| return self.submissions.update(submission_id, status="ai_grade_failed") |
Comment on lines
+35
to
+42
| return ( | ||
| self.session.query(Submission) | ||
| .filter( | ||
| Submission.assignment_id == assignment_id, | ||
| Submission.user_id == user_id, | ||
| ) | ||
| .first() | ||
| ) |
Comment on lines
+135
to
+136
| @router.post("/{assignment_id}/submissions", response_model=SubmissionResponse) | ||
| async def submit_work( |
| return svc.get_my_submission(current_user.id, assignment_id) | ||
|
|
||
|
|
||
| @router.get("/{assignment_id}/submissions/{submission_id}") |
| if current_user.role == "teacher": | ||
| return svc.list_assignments_for_teacher(current_user.id) | ||
| # No classroom/roster concept yet — students see every assignment. | ||
| return svc.assignments.get_all() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds a full Assignments domain so teachers can create assignments with a grading rubric, students submit their work as a PDF, and teachers can request an AI-generated draft score and feedback before reviewing, editing, and confirming the final grade themselves. The AI is a drafting aid only — students never see the AI draft, only the teacher's finalized grade.
Added
Backend domain (
learning/assignments/)Assignmentmodel: title, description, rubric, due date, owning teacher.Submissionmodel: filename, stored file path/size, extracted text, AI draft score/feedback, teacher's final score/feedback, status lifecycle (submitted→needs_manual_review/ai_graded/ai_grade_failed→finalized).AssignmentRepository/SubmissionRepositorywith ownership-aware queries (get_by_user,get_by_assignment,get_by_assignment_and_user).AssignmentServiceorchestrating: assignment CRUD, ownership verification, submission intake with text extraction, AI grading, and grade finalization.pypdf), run once at submission time and cached on the record rather than re-parsed on every read.ProvidersService.resolve_provider()(same routing the tutor chat uses across Ollama/OpenAI-compatible providers), calls the provider, parses the JSON response into score + feedback, and degrades gracefully (ai_grade_failed) instead of crashing on any upstream failure./api/v1/assignments: create/list/get assignments; submit/list/get submissions;POST .../ai-grade;PUT .../finalize;GET .../submissions/minefor a student's own view.Teacher UI
/teachersection shell (sidebar + navbar layout) that didn't exist before this PR — the route existed but had no navigation chrome around it.Student UI
API client (
ui/src/lib/apis/assignments/index.ts)TUTOR_API_BASE_URL,err.detailrejection on failure).Tests
Changed
GET /assignments/{id}/submissions/{submission_id}now returns a different, strictly-typed response shape depending on caller role instead of one fixed shape (see Fixed, below).Deprecated
Removed
Fixed
ProvidersService.resolve_provider(), exactly like the tutor chat does, and the teacher picks the model explicitly.GET /assignments/{id}/submissions/{submission_id}previously returned the AI draft fields (ai_score,ai_feedback,extracted_text) to the owning student as well as the teacher. It's now structurally impossible for a student-facing response to include them, enforced by a dedicated Pydantic model (MySubmissionResponse) rather than relying on the UI to simply not display them.Security
Breaking Changes
Additional Information
supports.py:async for chunk in filedoesn't work against this project's installed FastAPI/Starlette version. Fixed in this PR's own upload handler;supports.py's own upload endpoint likely has the same latent bug and has zero test coverage exercising that path — worth a follow-up fix outside this PR.Screenshots
Test plan:
pytest tests/test_assignments.py -q— 38 tests: repository, service, and router coverage (success, auth/ownership, missing resource, validation, AI-failure fallback)pytest tests/test_contract_coverage.py -q— every new UIfetch()maps to a real backend routepytest -q(full suite) — no regressionsnpm run test:frontend— 11 API client tests + existing component tests, no regressionsruff check/ruff format --check, ESLint / Prettier — cleannpm run i18n:parse— locale files regenerated and committed