- Overview
- Distinctiveness and Complexity
- Folder and File Structure
- Database Schema
- Usage Guide
- Limitations and Potential Improvements
Cogni is an AI-powered revision and active recall tool that helps users enhance their learning and knowledge retention. Users can upload PDF files or provide text content to generate customized multiple-choice question quizzes. The application leverages active recall methodology to improve learning outcomes, allowing users to regenerate quizzes and access their quiz history through an intuitive sidebar interface.
The primary distinguishing feature of this project is its integration with Large Language Models to intelligently process user-provided content and generate customized quizzes. The application currently utilizes Google's Gemini LLM through their API, enabling dynamic quiz creation from any educational material users provide. This AI-powered approach ensures questions are contextually relevant and appropriately challenging based on the source content.
While intended results can be achieved by providing in-prompt schemas, this approach carries risks because LLMs can hallucinate and behave unpredictably. To ensure reliable output structure, the application uses Pydantic model classes that are passed as parameters to API calls, constraining the LLM's responses to predictable formats.
The key schema classes used for this purpose include:
Represents a single multiple-choice question with validation constraints:
class Question(BaseModel):
"""A schema for a single multiple-choice question."""
statement: str = Field(
description="""A full, clear text for the multiple-choice question derived from the provided content. Do not start this statement with 'according to the text' OR 'according to the content',
don't refer to the text, just ask question straight-up"""
)
answer_choices: List[str] = Field(
max_length=4,
min_length=4,
description="A list containing exactly 4 plausible answer choices."
)
correct_answer: str = Field(
description="The single, correct answer. This MUST be an exact match to one of the strings in 'answer_choices'."
)
explanation: str = Field(
description="A brief but clear justification for why the correct answer is right, referencing the source content."
)Classification schema for detecting malicious prompts:
class PromptInjectionAttempt(BaseModel):
is_injection_attempt: bool = Field(
description='A boolean to indicate whether the attempt was to inject malicious prompt into main application or not'
)Complete quiz structure passed to the LLM:
class Quiz(BaseModel):
topic: str = Field(description="quiz title")
all_questions: List[Question] = Field(description="A list of questions, (Question objects)") The application uses PyMuPDF, a Python library for processing documents, to extract text from PDF files that users upload. These PDF files must be 5MB or smaller. Once the text is extracted from the PDF, it gets combined with the user's text query to create the content that is sent to the Large Language Model for quiz generation.
After users submit their quiz, the application evaluates their answers against the correct answers stored in the database. The system returns a marked quiz with detailed explanations for each answer, and saves the results to the database. Users can regenerate the same quiz without re-uploading content by simply clicking the regenerate button, utilizing the stored text content.
The application implements a custom Django authentication backend that enhances user experience by allowing login with either username or email address. This system includes input validation, automatic email/username detection, case-insensitive email lookup, comprehensive security checks, and graceful error handling for edge cases.
cogni/
│
├── app/
│ ├── admin.py
│ ├── apps.py
│ ├── backends.py
│ ├── core_utils/
│ │ ├── __init__.py
│ │ ├── llm_client.py
│ │ ├── logger.py
│ │ ├── pdf_utils.py
│ │ ├── quiz_logic.py
│ │ ├── schemas.py
│ │ ├── util_db.py
│ │ └── validators.py
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ ├── util_db.py
│ └── views.py
│
├── cogni/
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
│
├── manage.py
└── README.md
Below are the core files that contain the main application logic:
This file handles all interactions with the Gemini AI model and contains three critical functions:
-
generate_recall_test(content, num_questions)- The primary quiz generation function- Takes user content and desired number of questions as input
- Supports "auto" mode that intelligently determines question count (5-25 range) based on content complexity
- Uses Gemini 2.5 Flash model with structured JSON output to ensure consistent quiz format
- Returns a
Quizobject containing the generated questions and metadata
-
is_prompt_injection_attempt(content)- Security validation function- Analyzes user input to detect malicious prompt injection attempts
- Uses a sophisticated multi-layered security prompt to identify attempts to override system instructions
- Distinguishes between legitimate educational content and potential security threats
- Returns boolean indicating whether the content is safe to process
-
regenerate_recall_test(old_recall_test)- Quiz variation generator- Creates a new quiz from existing content stored in the database
- Ensures new questions don't duplicate previous ones by explicitly instructing the AI to vary question phrasing and options
- Maintains the same question count as the original quiz
- Useful for students who want to practice the same material with different questions
Utility file for PDF text extraction functionality:
extract_text(pdf_byte_stream)- Core PDF processing function- Takes a PDF byte stream as input (compatible with PyPDF2.PdfReader)
- Iterates through all pages and extracts text content sequentially
- Adds page markers between extracted content for better text organization
- Handles empty PDFs by detecting and logging when no content is found
- Includes comprehensive error handling with detailed logging for debugging
- Returns concatenated text from all pages as a single string
Core quiz evaluation and scoring functionality:
mark_quiz(request_obj)- Main quiz grading function- Extracts quiz ID from POST request and retrieves the corresponding quiz from database
- Processes user answers by iterating through POST data looking for question keys (starting with 'q')
- Compares user selections against correct answers stored in the quiz model
- Builds detailed evaluation results including correctness, selected answer, and explanations
- Maintains question sequence integrity between display and evaluation phases
- Creates a
MarkedTestrecord in the database to store quiz results and performance data - Returns quiz ID and detailed results for immediate feedback display
Database interaction utilities for user and quiz management:
-
create_user(email, password, username="")- User registration function- Normalizes email addresses using Django's built-in email normalization
- Auto-generates username if not provided during registration
- Creates user accounts with proper password hashing for security
- Sets accounts as active by default (email verification planned for future implementation)
- Returns the newly created User object for immediate use
-
write_quiz_to_db(user, quiz, text_content)- Quiz persistence function- Saves generated Quiz objects to the database as RecallTest records
- Links quizzes to specific users for personalized quiz history
- Stores original text content alongside quiz questions for regeneration capabilities
- Converts Pydantic quiz models to JSON format for database storage
- Includes comprehensive error logging for database operation failures
- Returns the created RecallTest object or None if save operation fails
Input validation and request type detection utilities:
-
validate_signup_data(email, password1, password2, username)- Comprehensive registration validation- Validates email format using Django's built-in email validator
- Checks for duplicate email addresses in the database (case-insensitive)
- Enforces minimum password length of 10 characters for security
- Ensures password confirmation matches the original password
- Validates optional username requirements (minimum 3 characters, uniqueness)
- Returns a list of error messages for failed validations or empty list if all checks pass
-
is_htmx(request)- HTMX request detection utility- Identifies whether incoming requests are made via HTMX for dynamic content updates
- Checks both standard headers and Django META dictionary for HTMX indicators
- Returns boolean value used to determine appropriate response format (partial HTML vs full page)
- Essential for implementing seamless user interactions without full page reloads
Django database models defining the core data structure:
-
User- Extended Django user model- Inherits from AbstractUser with enhanced email functionality
- Enforces unique, required email addresses for all user accounts
- Provides foundation for email-based authentication system
-
RecallTest- Quiz storage model- Stores quiz metadata including topic and creation timestamp
- Contains original text content used for quiz generation (enables regeneration)
- Uses JSONField to store complete question data as structured objects
- Links to User model with cascade deletion for data integrity
- Serves as the primary quiz record with related_name 'recall_tests'
-
MarkedTest- Quiz results and scoring model- Links to RecallTest to associate results with original quizzes
- Stores user answers and evaluation results in JSON format
- Tracks quiz performance and enables progress monitoring
- Uses cascade deletion to maintain referential integrity
This schema supports the complete quiz lifecycle from creation through evaluation and result storage.
[This section would contain user instructions for using the application]
The application currently uses a classification-based approach where user content is analyzed by an LLM to detect malicious prompt injection attempts. While this method provides reasonable protection for typical use cases, it is not foolproof and can potentially be bypassed through sophisticated prompt engineering techniques. It's important to note that prompt injection prevention remains an active area of research in AI security, with no completely bulletproof solutions currently available in the industry.
The application currently only supports PDF document processing, which restricts user flexibility and overall functionality. Users cannot upload other common document formats such as Word documents, PowerPoint presentations, plain text files, or web articles. Expanding support to include multiple document types would significantly enhance the user experience and broaden the application's utility.
The system exclusively generates multiple-choice questions (MCQs), which may not suit all learning preferences or content types. Users might benefit from alternative quiz formats such as short-answer questions, true/false statements, fill-in-the-blank exercises, or essay prompts. Adding support for diverse question types would make the platform more versatile and pedagogically effective for different learning scenarios.