MahaSyllabus

code

 Complete Project Flow

Plain text

GenerateNotebookRequest

        ↓

      main.py

        ↓

     Qwen LLM

        ↓

    NotebookDraft

        ↓

   notebook_draft.json

        ↓

     DraftMapper

        ↓

    AuthoringSpec

        ↓

 NotebookFormatter

        ↓

    example.ipynb

Step 1: User Creates Request

In main.py:

Python

request_schema = GenerateNotebookRequest(

    title="Data Preprocessing Assignment",

    dataset_name="Titanic Dataset",

    difficulty="Easy",

    concepts=[

        "Shape of dataset",

        "Missing values",

        "Filling missing values"

    ]

)

This is the notebook requirement.

Think of it as:

JSON

{

  "title": "Data Preprocessing Assignment",

  "dataset": "Titanic",

  "difficulty": "Easy",

  "concepts": [

    "Shape of dataset",

    "Missing values",

    "Filling missing values"

  ]

}

The TA/Admin provides this.

Step 2: Initialize LLM

From llm.py

Python

self.llm = ChatOllama(

    model="qwen3:14b",

    base_url="http://172.20.203.53:11433"

)

This means:

Plain text

NotebookSync

      ↓

LangChain

      ↓

Ollama

      ↓

Qwen3 14B

The model is running on your internal server.

Step 3: Structured Output

I saw:

Python

request = llm.with_structured_output(

    NotebookDraft,

    method="json_mode"

)

This is a very important line.

Normally LLM returns:

Plain text

Here is your notebook...

which is unstructured.

Instead:

Python

NotebookDraft

forces Qwen to return:

JSON

{

  "theory_content": {},

  "user_tasks": [],

  "reference_solutions": []

}

directly.

So LLM behaves like an API.

Step 4: Load Prompt

Python

with open("./prompts/authoring_prompt.txt")

Prompt is loaded.

Then:

Python

full_prompt = f"""

{prompt}


User Request:


{json.dumps(request_schema.model_dump())}

"""

Generated prompt becomes:

Plain text

You are notebook authoring assistant.


Generate notebook draft.


User Request:


{

  "title":"Data Preprocessing Assignment",

  "dataset_name":"Titanic Dataset",

  "difficulty":"Easy"

}

Step 5: Invoke LLM

Python

notebook_draft = request.invoke(full_prompt)

This is where AI generates content.

Possible result:

JSON

{

  "theory_content": {

    "Dataset Shape":"..."

  },


  "user_tasks":[

    "Find dataset shape",

    "Find missing values"

  ],


  "reference_solutions":[

    "df.shape",

    "df.isnull().sum()"

  ]

}

Step 6: Save Draft

Python

with open("notebook_draft.json","w")

Then:

Python

f.write(

 notebook_draft.model_dump_json()

)

So AI output is stored.

Generated file:

Plain text

notebook_draft.json

Useful for debugging.

Step 7: DraftMapper

This line:

Python

draft_mapper = DraftMapper(

    notebook_draft,

    "Data Preprocessing Test",

    "Happy learning"

)

creates mapper.

Purpose:

Convert raw LLM output into structured notebook specification.

Step 8: map_to_spec()

Inside:

Python

spec = draft_mapper.map_to_spec()

This creates:

Python

AuthoringSpec

Think of:

Plain text

NotebookDraft

as

Plain text

Raw Material

and

Plain text

AuthoringSpec

as

Plain text

Blueprint

Step 9: map_theory_content()

I saw:

Python

for title,content in theory_content.items():

Meaning:

LLM returns:

JSON

{

 "Introduction":"...",

 "Missing Values":"..."

}

Mapper converts it into:

Python

[

 "Introduction content",

 "Missing Values content"

]

Step 10: map_user_tasks()

This is interesting.

For every task:

Python

for idx,task in enumerate(...)

creates:

Python

UserTask(

    name=f"Question{idx}",

    description=task,

    starter_code="#Write the code here",

    function_name=f"question{idx}",

    method_name=f"Question{idx}"

)

Generated result:

Python

Question1

Question2

Question3

Student will see:

Python

# Write code here


@evaluate

def question1():

    pass

Step 11: map_test_cases()

This converts:

Python

reference_solutions

into:

Python

TestCaseSpec

Example:

Python

TestCaseSpec(

    function_name="question1",

    method_name="Question1",

    max_mark=10,

    solution_code="df.shape"

)

These are hidden.

Step 12: AuthoringSpec

This becomes:

Python

AuthoringSpec

containing:

Python

title

description

dataset

theory

concepts

user_tasks

test_cases

This is the central object.

Everything afterward uses it.

Step 13: NotebookFormatter

Now:

Python

formatter = NotebookFormatter()

and:

Python

nb = formatter.render(spec)

This is where notebook generation starts.

What render() Actually Does

I saw:

Python

render_user_scaffold()

render_user_content()

render_submission_section()


render_admin_boundary()

render_admin_scaffold()

render_admin_content()

So notebook is built in two halves.

USER HALF

Generated first.

Structure:

Plain text

SET SESSION


FETCH ASSESSMENT


PLAY NOW


Question 1


Question 2


Question 3


Submit

Admin HALF

Generated later.

Structure:

Plain text

ADMIN SECTION


Reference Solutions


Hidden Test Cases


Timing


Evaluation Logic

Students only interact with first half.

Hidden Evaluation System

This is the clever part.

I saw:

Python

test.make_test_case(...)

and:

Python

Task.test_case(...)

Meaning:

The admin section generates grading code automatically.



How To Explain Project In Meeting

Say:

Problem

Today trainers manually create:

Theory

Questions

Solutions

Test cases

This is slow and inconsistent.

Solution

We automate notebook generation using LLM.

Input:

JSON

{

 "title":"Data Preprocessing",

 "difficulty":"Easy",

 "dataset":"Titanic"

}

Output:

Plain text

Learner Notebook

+

Admin Notebook

Backend Architecture

Explain like this:

Plain text

Request

 ↓

LLM Layer

 ↓

NotebookDraft

 ↓

DraftMapper

 ↓

AuthoringSpec

 ↓

NotebookFormatter

 ↓

.ipynb Notebook

What Is NotebookDraft?

Likely generated by AI.

Contains:

Python

theory_content


user_tasks


reference_solutions

Raw content.

What Is DraftMapper?

Converts AI response into structured format.

Example:

Python

NotebookDraft

     ↓

AuthoringSpec

Purpose:

Standardization.

What Is AuthoringSpec?

Most important object.

Contains:

Python

title

description

dataset

tasks

testcases

Everything uses this.

Think:

Plain text

Blueprint of notebook

What Is NotebookFormatter?

Responsible for:

Python

AuthoringSpec

      ↓

.ipynb

Creates notebook cells.

Difference Between User and Admin Sections

User Section:

Plain text

Theory


Question 1


Question 2


Submit

Admin Section:

Plain text

Reference Solution


Test Cases


Marks


Timing

Hidden from learners.

Sprint 2 Status (Based On Screenshots)

Looks like Sprint 2 completed:

✅ Request Model

✅ LLM Integration

✅ Notebook Draft Generation

✅ Mapper Layer

✅ Notebook Formatter

✅ User Section

✅ Admin Section

✅ Test Case Generation

✅ Notebook Export