Spaces:
Sleeping
Sleeping
Download backend/models.py from trigent09/ai-backend: direct link, hf CLI and curl.
- Browser
- Download file 15.5 kB
-
https://huggingface.co/spaces/trigent09/ai-backend/resolve/main/backend/models.py
- Command line
-
hf download hf://spaces/trigent09/ai-backend/backend/models.py
-
curl -L -o models.py https://huggingface.co/spaces/trigent09/ai-backend/resolve/main/backend/models.py
15.5 kB
| """ | |
| Shared domain models for the multi-tenant AI Quiz system. | |
| Every request carries school_id + board_id to route to the correct tenant silo. | |
| """ | |
| from typing import List, Optional, Dict, Any | |
| from pydantic import BaseModel, Field, model_validator, ConfigDict | |
| class UserProfile(BaseModel): | |
| """Unified profile for student, teacher, admin, and super_admin roles.""" | |
| model_config = ConfigDict(str_strip_whitespace=True) | |
| user_id: str = "student-default" | |
| name: str = "Student" | |
| school_id: Optional[str] = None | |
| board_id: Optional[str] = None | |
| role: str = "student" | |
| class_id: Optional[str] = None | |
| section_id: Optional[str] = "A" | |
| subjects: List[str] = Field(default_factory=lambda: ["Science", "Mathematics", "English"]) | |
| sub_subject: Optional[str] = "General" | |
| class PermissionRequest(BaseModel): | |
| user: UserProfile | |
| action: str | |
| resource: Dict[str, Any] = Field(default_factory=dict) | |
| class PermissionDecision(BaseModel): | |
| allowed: bool | |
| reason: str | |
| user_id: str | |
| timestamp: Optional[str] = None | |
| class TrainingDeleteRequest(BaseModel): | |
| model_config = ConfigDict(str_strip_whitespace=True) | |
| user: Optional[UserProfile] = None | |
| user_id: Optional[str] = None | |
| user_name: Optional[str] = None | |
| user_role: Optional[str] = None | |
| school_id: str | |
| board_id: str | |
| class_id: str | |
| subject: str | |
| section_id: Optional[str] = "A" | |
| sub_subject: Optional[str] = "General" | |
| chapter: Optional[str] = None | |
| lesson: Optional[str] = None | |
| topic: Optional[str] = None | |
| def sync_user_and_tenant(cls, data: Any) -> Any: | |
| if isinstance(data, dict): | |
| effective_ch = data.get("chapter") or data.get("lesson") | |
| if effective_ch: | |
| data.setdefault("chapter", effective_ch) | |
| data.setdefault("lesson", effective_ch) | |
| user_raw = data.get("user") | |
| if isinstance(user_raw, dict): | |
| for k in ("school_id", "board_id", "class_id", "section_id", "sub_subject"): | |
| if not user_raw.get(k) and data.get(k): | |
| user_raw[k] = data[k] | |
| return data | |
| def effective_lesson(self) -> str: | |
| return self.lesson or self.chapter or "" | |
| class DescriptiveConfigItem(BaseModel): | |
| level: str = "medium" # easy, medium, hard | |
| format: str = "short" # short, long, comprehensive | |
| count: int = 1 | |
| class QuizGenerateRequest(BaseModel): | |
| model_config = ConfigDict(str_strip_whitespace=True) | |
| user: Optional[UserProfile] = None | |
| school_id: Optional[str] = None | |
| board_id: Optional[str] = None | |
| class_id: Optional[str] = None | |
| section_id: Optional[str] = "A" | |
| subject: str | |
| sub_subject: Optional[str] = "General" | |
| chapter: Optional[str] = None | |
| lesson: Optional[str] = None | |
| topic: Optional[str] = None | |
| num_questions: int = 5 | |
| hf_token: Optional[str] = None | |
| difficulty: Optional[str] = "medium" # easy, medium, hard | |
| question_format: Optional[str] = "short" # short, long, comprehensive | |
| descriptive_distribution: Optional[List[DescriptiveConfigItem]] = None | |
| def sync_tenant_fields(cls, data: Any) -> Any: | |
| if isinstance(data, dict): | |
| effective_ch = data.get("chapter") or data.get("lesson") | |
| if effective_ch: | |
| data.setdefault("chapter", effective_ch) | |
| data.setdefault("lesson", effective_ch) | |
| user_raw = data.get("user") | |
| if isinstance(user_raw, dict): | |
| for k in ("school_id", "board_id", "class_id", "section_id", "sub_subject"): | |
| if not data.get(k) and user_raw.get(k): | |
| data[k] = user_raw[k] | |
| elif not user_raw.get(k) and data.get(k): | |
| user_raw[k] = data[k] | |
| elif isinstance(user_raw, UserProfile): | |
| for k in ("school_id", "board_id", "class_id", "section_id", "sub_subject"): | |
| val = getattr(user_raw, k, None) | |
| if not data.get(k) and val: | |
| data[k] = val | |
| elif user_raw is None: | |
| data["user"] = { | |
| "user_id": "student-default", | |
| "name": "Student", | |
| "role": "student", | |
| "school_id": data.get("school_id") or "school_default", | |
| "board_id": data.get("board_id") or "cbse", | |
| "class_id": data.get("class_id") or "10", | |
| "section_id": data.get("section_id") or "A", | |
| "sub_subject": data.get("sub_subject") or "General", | |
| "subjects": [data.get("subject", "Science")] | |
| } | |
| return data | |
| def effective_lesson(self) -> str: | |
| return self.lesson or self.chapter or "" | |
| class QuizEvaluateRequest(BaseModel): | |
| user: Optional[UserProfile] = None | |
| school_id: Optional[str] = None | |
| board_id: Optional[str] = None | |
| class_id: Optional[str] = None | |
| section_id: Optional[str] = "A" | |
| subject: Optional[str] = None | |
| sub_subject: Optional[str] = "General" | |
| chapter: Optional[str] = None | |
| lesson: Optional[str] = None | |
| topic: Optional[str] = None | |
| question: str | |
| selected_option: str | |
| correct_option: str | |
| hf_token: Optional[str] = None | |
| def sync_tenant_fields(cls, data: Any) -> Any: | |
| if isinstance(data, dict): | |
| effective_ch = data.get("chapter") or data.get("lesson") | |
| if effective_ch: | |
| data.setdefault("chapter", effective_ch) | |
| data.setdefault("lesson", effective_ch) | |
| user_raw = data.get("user") | |
| if isinstance(user_raw, dict): | |
| for k in ("school_id", "board_id", "class_id", "section_id", "sub_subject"): | |
| if not data.get(k) and user_raw.get(k): | |
| data[k] = user_raw[k] | |
| elif not user_raw.get(k) and data.get(k): | |
| user_raw[k] = data[k] | |
| elif isinstance(user_raw, UserProfile): | |
| for k in ("school_id", "board_id", "class_id", "section_id", "sub_subject"): | |
| val = getattr(user_raw, k, None) | |
| if not data.get(k) and val: | |
| data[k] = val | |
| elif user_raw is None: | |
| data["user"] = { | |
| "user_id": "student-default", | |
| "name": "Student", | |
| "role": "student", | |
| "school_id": data.get("school_id") or "school_default", | |
| "board_id": data.get("board_id") or "cbse", | |
| "class_id": data.get("class_id") or "10", | |
| "section_id": data.get("section_id") or "A", | |
| "sub_subject": data.get("sub_subject") or "General", | |
| "subjects": [data.get("subject", "Science")] if data.get("subject") else ["Science"] | |
| } | |
| return data | |
| def effective_lesson(self) -> str: | |
| return self.lesson or self.chapter or "" | |
| class MCQOption(BaseModel): | |
| id: str | |
| text: str | |
| class QuizQuestion(BaseModel): | |
| id: int | |
| question: str | |
| options: List[MCQOption] | |
| correct_option: str | |
| topic: str | |
| explanation: str | |
| source_context: Optional[str] = None | |
| class QuizSet(BaseModel): | |
| school_id: str | |
| board_id: str | |
| class_id: str | |
| section_id: Optional[str] = "A" | |
| subject: str | |
| sub_subject: Optional[str] = "General" | |
| chapter: str | |
| lesson: Optional[str] = None | |
| topic: Optional[str] = None | |
| questions: List[QuizQuestion] | |
| class EvaluationResult(BaseModel): | |
| is_correct: bool | |
| selected_option: str | |
| correct_option: str | |
| explanation: str | |
| evidence_quote: str | |
| topic: str | |
| class TrainingStatus(BaseModel): | |
| school_id: str | |
| board_id: str | |
| chapters: Dict[str, Dict[str, Any]] | |
| # ββ Student Anti-Cheat Quiz Models ββββββββββββββββββββββββββββββββββββββββββ | |
| class StudentQuizQuestion(BaseModel): | |
| id: int | |
| question: str | |
| options: List[MCQOption] | |
| class StudentQuizSet(BaseModel): | |
| quiz_id: str | |
| school_id: str | |
| board_id: str | |
| class_id: str | |
| section_id: Optional[str] = "A" | |
| subject: str | |
| sub_subject: Optional[str] = "General" | |
| chapter: str | |
| lesson: Optional[str] = None | |
| topic: Optional[str] = None | |
| questions: List[StudentQuizQuestion] | |
| class StudentAnswerItem(BaseModel): | |
| question_id: int | |
| selected_option: str | |
| class StudentQuizSubmitRequest(BaseModel): | |
| user: Optional[UserProfile] = None | |
| quiz_id: str | |
| answers: List[StudentAnswerItem] | |
| hf_token: Optional[str] = None | |
| class StudentQuestionResult(BaseModel): | |
| question_id: int | |
| question: str | |
| selected_option: str | |
| correct_option: str | |
| is_correct: bool | |
| explanation: str | |
| evidence_quote: Optional[str] = None | |
| class StudentQuizResult(BaseModel): | |
| quiz_id: str | |
| score: int | |
| total: int | |
| percentage: float | |
| results: List[StudentQuestionResult] | |
| # ββ Fill-in-the-Blanks Models (Append-Only) βββββββββββββββββββββββββββββββββββ | |
| class BlankQuestion(BaseModel): | |
| id: int | |
| question: str | |
| correct_answer: str | |
| acceptable_alternatives: List[str] = Field(default_factory=list) | |
| topic: str | |
| explanation: str | |
| source_context: Optional[str] = None | |
| class BlankQuizSet(BaseModel): | |
| school_id: str | |
| board_id: str | |
| class_id: str | |
| section_id: Optional[str] = "A" | |
| subject: str | |
| sub_subject: Optional[str] = "General" | |
| chapter: str | |
| lesson: Optional[str] = None | |
| topic: Optional[str] = None | |
| questions: List[BlankQuestion] | |
| class StudentBlankQuizQuestion(BaseModel): | |
| id: int | |
| question: str | |
| class StudentBlankQuizSet(BaseModel): | |
| quiz_id: str | |
| school_id: str | |
| board_id: str | |
| class_id: str | |
| section_id: Optional[str] = "A" | |
| subject: str | |
| sub_subject: Optional[str] = "General" | |
| chapter: str | |
| lesson: Optional[str] = None | |
| topic: Optional[str] = None | |
| questions: List[StudentBlankQuizQuestion] | |
| class StudentBlankAnswerItem(BaseModel): | |
| model_config = ConfigDict(str_strip_whitespace=True) | |
| question_id: int | |
| student_answer: str | |
| class StudentBlankQuizSubmitRequest(BaseModel): | |
| model_config = ConfigDict(str_strip_whitespace=True) | |
| user: Optional[UserProfile] = None | |
| quiz_id: str | |
| answers: List[StudentBlankAnswerItem] | |
| hf_token: Optional[str] = None | |
| class StudentBlankQuestionResult(BaseModel): | |
| question_id: int | |
| question: str | |
| student_answer: str | |
| correct_answer: str | |
| is_correct: bool | |
| explanation: str | |
| evidence_quote: Optional[str] = None | |
| class StudentBlankQuizResult(BaseModel): | |
| quiz_id: str | |
| score: int | |
| total: int | |
| percentage: float | |
| results: List[StudentBlankQuestionResult] | |
| # ββ True/False Models (Append-Only) ββββββββββββββββββββββββββββββββββββββββββ | |
| class TrueFalseQuestion(BaseModel): | |
| id: int | |
| question: str | |
| options: List[MCQOption] | |
| correct_option: str # "A" or "B" | |
| topic: Optional[str] = "General" | |
| explanation: str | |
| source_context: Optional[str] = None | |
| class TrueFalseQuizSet(BaseModel): | |
| school_id: str | |
| board_id: str | |
| class_id: str | |
| section_id: Optional[str] = "A" | |
| subject: str | |
| sub_subject: Optional[str] = "General" | |
| chapter: str | |
| lesson: Optional[str] = None | |
| topic: Optional[str] = None | |
| questions: List[TrueFalseQuestion] | |
| class StudentTrueFalseQuizQuestion(BaseModel): | |
| id: int | |
| question: str | |
| options: List[MCQOption] | |
| class StudentTrueFalseQuizSet(BaseModel): | |
| quiz_id: str | |
| school_id: str | |
| board_id: str | |
| class_id: str | |
| section_id: Optional[str] = "A" | |
| subject: str | |
| sub_subject: Optional[str] = "General" | |
| chapter: str | |
| lesson: Optional[str] = None | |
| topic: Optional[str] = None | |
| questions: List[StudentTrueFalseQuizQuestion] | |
| class StudentTrueFalseAnswerItem(BaseModel): | |
| model_config = ConfigDict(str_strip_whitespace=True) | |
| question_id: int | |
| selected_option: str # "A" or "B" | |
| class StudentTrueFalseQuizSubmitRequest(BaseModel): | |
| model_config = ConfigDict(str_strip_whitespace=True) | |
| user: Optional[UserProfile] = None | |
| quiz_id: str | |
| answers: List[StudentTrueFalseAnswerItem] | |
| hf_token: Optional[str] = None | |
| class StudentTrueFalseQuestionResult(BaseModel): | |
| question_id: int | |
| question: str | |
| selected_option: str | |
| correct_option: str | |
| is_correct: bool | |
| explanation: str | |
| evidence_quote: Optional[str] = None | |
| class StudentTrueFalseQuizResult(BaseModel): | |
| quiz_id: str | |
| score: int | |
| total: int | |
| percentage: float | |
| results: List[StudentTrueFalseQuestionResult] | |
| # ββ Descriptive Question Models (Append-Only) βββββββββββββββββββββββββββββββββ | |
| class DescriptiveQuestion(BaseModel): | |
| id: int | |
| question: str | |
| model_answer: str | |
| key_facts: List[str] = Field(default_factory=list) | |
| difficulty: str = "medium" # easy, medium, hard | |
| format: str = "short" # short, long, comprehensive | |
| max_score: int = 5 | |
| topic: Optional[str] = "General" | |
| explanation: str | |
| source_context: Optional[str] = None | |
| class DescriptiveQuizSet(BaseModel): | |
| school_id: str | |
| board_id: str | |
| class_id: str | |
| section_id: Optional[str] = "A" | |
| subject: str | |
| sub_subject: Optional[str] = "General" | |
| chapter: str | |
| lesson: Optional[str] = None | |
| topic: Optional[str] = None | |
| questions: List[DescriptiveQuestion] | |
| class StudentDescriptiveQuizQuestion(BaseModel): | |
| id: int | |
| question: str | |
| difficulty: str = "medium" | |
| format: str = "short" | |
| max_score: int = 5 | |
| topic: Optional[str] = "General" | |
| class StudentDescriptiveQuizSet(BaseModel): | |
| quiz_id: str | |
| school_id: str | |
| board_id: str | |
| class_id: str | |
| section_id: Optional[str] = "A" | |
| subject: str | |
| sub_subject: Optional[str] = "General" | |
| chapter: str | |
| lesson: Optional[str] = None | |
| topic: Optional[str] = None | |
| questions: List[StudentDescriptiveQuizQuestion] | |
| class StudentDescriptiveAnswerItem(BaseModel): | |
| model_config = ConfigDict(str_strip_whitespace=True) | |
| question_id: int | |
| student_answer: str | |
| class StudentDescriptiveQuizSubmitRequest(BaseModel): | |
| model_config = ConfigDict(str_strip_whitespace=True) | |
| user: Optional[UserProfile] = None | |
| quiz_id: str | |
| answers: List[StudentDescriptiveAnswerItem] | |
| hf_token: Optional[str] = None | |
| class StudentDescriptiveQuestionResult(BaseModel): | |
| question_id: int | |
| question: str | |
| student_answer: str | |
| model_answer: str | |
| score: float | |
| max_score: int | |
| is_correct: bool | |
| feedback: str | |
| key_points_covered: List[str] = Field(default_factory=list) | |
| key_points_missing: List[str] = Field(default_factory=list) | |
| evidence_quote: Optional[str] = None | |
| explanation: Optional[str] = None | |
| class StudentDescriptiveQuizResult(BaseModel): | |
| quiz_id: str | |
| score: float | |
| total: int | |
| percentage: float | |
| results: List[StudentDescriptiveQuestionResult] | |