Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
c17516b
Merge pull request #3 from DaRL-GenAI/main
wingsweihua Apr 30, 2026
592ab5a
Add localized "refine" mode to optimize (alongside regenerate)
Jun 18, 2026
1c2a9f9
Merge pull request #5 from DaRL-GenAI/feature/slide-local-refine
Hyan-Yao Jun 18, 2026
23dce44
created removable cli for testing purposes
rayankzi Jul 18, 2026
6ba421c
Add offline frontend slide generation and course-wide styling
rayankzi Jul 19, 2026
0c0941c
fixed course style deliberation not working
rayankzi Jul 19, 2026
0258a6d
Prevent deep Beamer lists and account for display math weight
rayankzi Jul 19, 2026
f361d6b
fixed washed out exports and removed agentic multi frame transition
rayankzi Jul 19, 2026
a4cce79
Update instructional agents
rayankzi Jul 20, 2026
d759ef2
Fixed color error, preventing some workflow runs from errors
rayankzi Jul 20, 2026
4b18033
added several fixes to make sure full 3hr run works
rayankzi Jul 21, 2026
663ffe2
improving slide selection process
rayankzi Jul 21, 2026
ffaac67
fixed error with math equation causing failed latex compilation
rayankzi Jul 22, 2026
e3b4d02
restructured code to integrate more seamlessly into og workflow
rayankzi Jul 22, 2026
8920ae2
Document presentation style preferences in catalogs
rayankzi Jul 22, 2026
3d0b7e7
made presentation style deliberations consistent with prev ones
rayankzi Jul 22, 2026
0479864
initial integration of dynamic img gen
rayankzi Jul 23, 2026
37ffce5
Added fix with image layout
rayankzi Jul 23, 2026
5c76e21
refactored to better identify new files in html workflow
rayankzi Jul 23, 2026
f88e0c1
fixed another error in image generation workflow
rayankzi Jul 27, 2026
d9a8a37
have AI decide how many images to generate
rayankzi Jul 27, 2026
4722958
added more fixes from full run
rayankzi Jul 28, 2026
775fecc
added carbon images for code snippets and strengthed prompt guidelines
rayankzi Jul 29, 2026
3d79709
did code review and fixed things ai pointed out, removed old html plans
rayankzi Jul 30, 2026
061313c
reverted frontend to original and attributed frontend slides skill pr…
rayankzi Aug 4, 2026
d13f665
consolidated flags for the new slides workflow
rayankzi Aug 4, 2026
6cc7e09
reverted docs to how they were in main branch and addded one new doc
rayankzi Aug 5, 2026
f599cea
changed speaker notes to try look better
rayankzi Aug 5, 2026
d68c478
remove local course cli
rayankzi Aug 5, 2026
f965c9b
deleted obsolete references and things
rayankzi Aug 5, 2026
168eee6
Remove Playwright browser tests and sync Chinese README
rayankzi Aug 6, 2026
71064ce
Clean slide refiner trailing whitespace
rayankzi Aug 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .DS_Store
Binary file not shown.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ Thumbs.db
exp/
eval/
logs/
assets/
assets/*
!assets/slide_gen/
!assets/slide_gen/**
assets/slide_gen/**/__pycache__/
assets/slide_gen/**/*.py[cod]
.cache/

# Uploaded catalogs (user-specific)
Expand Down
1 change: 1 addition & 0 deletions .worktreeinclude
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.env
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ include .env.example
recursive-include catalog *.json *.tex
recursive-include frontend *.html *.js *.css
recursive-include docs *.md
recursive-include assets/slide_gen *
global-exclude *.py[cod]
73 changes: 71 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,12 +282,22 @@ exp/{experiment_name}/
├── result_syllabus_design.md # Course syllabus (⭐ important)
├── result_assessment_planning.md # Assessment planning
├── result_final_exam_project.md # Final project design
├── result_presentation_design.md # Seventh foundation: course-wide presentation design
├── processed_chapters.json # Chapter metadata
├── course_slide_style.json # Validated course-wide frontend style
├── course_slide_style_source.md # Exact selected style source snapshot
├── statistics_slide_style.json # Style deliberation timing/tokens
├── statistics.json # Generation statistics
├── chapter_1/ # Chapter 1 materials
│ ├── slides.tex # LaTeX source
│ ├── slides.pdf # Compiled PDF slides (⭐ ready to use)
│ ├── html/ # Portable offline HTML bundle
│ │ ├── slides.html # Offline interactive HTML slides
│ │ └── assets/ # Offline MathJax and selected fonts
│ ├── slides-html.pdf # PDF exported from the HTML deck
│ ├── slides-html.pptx # Static image-based HTML export
│ ├── frontend-slides-manifest.json # Hashes, counts, warnings, artifacts
│ ├── slides.pptx # PowerPoint slides (⭐ editable)
│ ├── script.md # Presentation script
│ ├── assessment.md # Assessment materials
Expand All @@ -300,6 +310,10 @@ exp/{experiment_name}/

> **Tip**: Files are generated incrementally. You can download or view them as soon as they appear, without waiting for the entire generation to complete.

Each generated `script.md` is validated one-to-one against the rendered HTML
slides. Press `N` in `html/slides.html` to toggle the offline presenter-notes
panel; the panel is excluded from static PDF and PPTX exports.

For detailed file descriptions, see [Generated Files Guide](docs/FILES_GENERATED.md).

</details>
Expand Down Expand Up @@ -436,6 +450,12 @@ python run.py "AI Fundamentals" --catalog ai_catalog

# Combine catalog and copilot
python run.py "Educational Psychology" --copilot --catalog edu_psy

# Enable images with no numeric per-chapter cap
python run.py "Systems Thinking" --image-generation on --image-count on

# Opt in to Carbon-rendered code images
python run.py "Programming Languages" --code-images on
```

**Minimal Working Example** (generates a small 3-week course in ~5 min):
Expand All @@ -458,11 +478,42 @@ Options:
--exp EXP_NAME Experiment name for saving output (default: exp1)
--seed SEED Random seed for reproducibility
--temperature TEMP Sampling temperature for LLM
--image-generation {on,off,replace}
Enable, disable, or replace generated slide images
--image-count {on,off} Turn AI-selected image counts on or off; when on,
the count is always automatic
--code-images {on,off} Use Carbon code images or styled HTML code blocks
--optimize STORAGE_ID Optimize mode: provide storage_id of uploaded PDFs
--requirements TEXT User requirements for optimization (with --optimize)
--chapter NAME Specific chapter to optimize (with --optimize)
```

Dynamic slide images are off by default. When enabled, the presentation-design
deliberation may still veto imagery. Use `--image-count on` to remove the fixed
numeric budget and always let the placement AI choose the count. Use
`--image-count off` to restore the experiment's stored fixed cap (3 by default).
Omitting the flag preserves the current experiment setting. The placement AI
may choose zero, five, six, or any other number up to the chapter's eligible
slides while automatic counting is on.
Generated images appear only in the HTML, HTML-derived PDF, and HTML-derived
PPTX; the Beamer source and PDF are unchanged. See
[`docs/BETTER_SLIDES_GENERATION.md`](docs/BETTER_SLIDES_GENERATION.md)
for cache and replacement behavior.

Carbon code images are also off by default. `--code-images on` persists the
choice in `course_code_images.json` and applies it to every chapter. The first
enabled chapter that actually contains a `lstlisting` or `verbatim` block uses
an existing `carbon-now` executable or runs
`npm install --global carbon-now-cli@2.1.0`. This is an explicit global npm
installation; Node.js and npm must already be installed and are never installed
automatically. Missing prerequisites, installation failures, network failures,
timeouts, or invalid Carbon output produce warnings and retain the styled
editable `<pre>` block. Successful PNGs are cached by content, language, theme,
pipeline, and Carbon version, then embedded directly in the self-contained
HTML. They therefore appear in the HTML-derived PDF and PPTX, while
`slides.tex` and the Beamer PDF remain unchanged. Use `--code-images off` to
persistently return the course to `<pre>` rendering.

### Method 3: Direct API Calls

**API Server**: `api_server.py` – RESTful API service
Expand Down Expand Up @@ -515,7 +566,9 @@ For complete API documentation, see [API Documentation](docs/API_DOCUMENTATION.m

Catalog files provide structured input data to guide the course generation process. They include:
- Student profiles and backgrounds
- Instructor preferences and style
- Instructor preferences and teaching style
- Optional presentation style preferences, including visual direction, colors,
typography, layout density, accessibility needs, and styles to avoid
- Course structure requirements
- Assessment design preferences
- Teaching constraints
Expand All @@ -536,6 +589,14 @@ python run.py "AI Fundamentals" --catalog ai_catalog

See [API Documentation](docs/API_DOCUMENTATION.md#catalog-format) for catalog format details.

`presentation_style_preferences` is advisory. The presentation-design agents
consider every non-empty preference when comparing packaged styles, while
accessibility, readability, course suitability, and rendering feasibility take
priority when a preference conflicts with the available designs. The selected
style remains frozen on resume; use a new experiment or
`--reselect-presentation-design` with `run.py` to apply changed
preferences.

### Copilot Mode

Interactive mode that prompts for feedback after each phase of the ADDIE workflow:
Expand Down Expand Up @@ -745,4 +806,12 @@ Configure via model selection in web interface or `--model` flag in CLI.

## 📜 License

MIT License
Instructional Agents is released under the [MIT License](LICENSE).

### Third-party attribution

The HTML slide style-selection assets in [`assets/slide_gen/skill`](assets/slide_gen/skill)
are adapted from [Frontend Slides](https://github.com/zarazhangrui/frontend-slides)
by Zara Zhang. Frontend Slides is used under the MIT License; its original
copyright notice and license terms are preserved in
[`assets/slide_gen/skill/LICENSE`](assets/slide_gen/skill/LICENSE).
59 changes: 56 additions & 3 deletions api_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, JSONResponse, StreamingResponse
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel, Field
from pydantic import BaseModel, Field, model_validator
from typing import Optional as Opt
import uvicorn

Expand Down Expand Up @@ -60,13 +60,58 @@ class CourseRequest(BaseModel):
catalog: Optional[str] = Field(default=None, description="Catalog name to use")
catalog_data: Optional[Dict[str, Any]] = Field(default=None, description="Catalog data as JSON object")
generate_pptx: Optional[bool] = Field(default=False, description="Also generate PPTX slides")
reselect_presentation_design: bool = Field(
default=False,
description="Replace the frozen course-wide presentation design",
)
enable_image_generation: bool = Field(
default=False,
description="Persist opt-in to dynamic frontend slide image generation",
)
replace_images: bool = Field(
default=False,
description="Replace images for every processed chapter; implies enablement",
)
max_images_per_chapter: Optional[int] = Field(
default=None,
ge=0,
le=3,
description="Persistent experiment default image cap",
)
ai_decides_image_count: bool = Field(
default=False,
description=(
"Remove the numeric per-chapter cap and let the placement AI choose "
"every strong eligible image opportunity"
),
)
code_images: Optional[bool] = Field(
default=None,
description=(
"Persist Carbon code-image behavior: true enables and may install "
"carbon-now-cli globally, false disables, null preserves course state"
),
)

@model_validator(mode="after")
def validate_image_count_mode(self) -> "CourseRequest":
if (
self.ai_decides_image_count
and self.max_images_per_chapter is not None
):
raise ValueError(
"ai_decides_image_count and max_images_per_chapter are "
"mutually exclusive"
)
return self

class OptimizeRequest(BaseModel):
storage_id: str = Field(..., description="ID of the stored PDF files")
user_requirements: str = Field(..., description="User's requirements for improvement")
model_name: str = Field(default="gpt-4o-mini", description="OpenAI model to use")
exp_name: str = Field(default="default", description="Experiment name for output")
chapter_name: Optional[str] = Field(default=None, description="Specific chapter to optimize (None = all)")
mode: str = Field(default="regenerate", description="Improvement strategy: 'regenerate' (per-slide full rewrite) or 'refine' (localized frame-level rewrite)")

class TaskStatus(BaseModel):
task_id: str
Expand Down Expand Up @@ -803,7 +848,13 @@ async def run_generation_task(task_id: str, request: CourseRequest, api_key: str
copilot="default_copilot" if request.copilot else None,
catalog=catalog_source,
model_name=request.model_name,
exp_name=request.exp_name
exp_name=request.exp_name,
reselect_presentation_design=request.reselect_presentation_design,
enable_image_generation=request.enable_image_generation,
replace_images=request.replace_images,
max_images_per_chapter=request.max_images_per_chapter,
ai_decides_image_count=request.ai_decides_image_count,
code_images=request.code_images,
)

# Generate PPTX if requested
Expand Down Expand Up @@ -900,6 +951,8 @@ async def run_optimization_task(task_id: str, request: OptimizeRequest, api_key:
sys.stdout.flush()
print(f"Experiment: {request.exp_name}")
sys.stdout.flush()
print(f"Mode: {request.mode}")
sys.stdout.flush()
if request.chapter_name:
print(f"Chapter: {request.chapter_name}")
sys.stdout.flush()
Expand All @@ -916,6 +969,7 @@ async def run_optimization_task(task_id: str, request: OptimizeRequest, api_key:
model_name=request.model_name,
exp_name=request.exp_name,
chapter_name=request.chapter_name,
mode=request.mode,
)

print("\n" + "=" * 60)
Expand Down Expand Up @@ -971,4 +1025,3 @@ async def run_optimization_task(task_id: str, request: OptimizeRequest, api_key:
port=8000,
reload=True
)

1 change: 1 addition & 0 deletions assets/slide_gen/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Packaged resources for offline slide generation."""
Binary file added assets/slide_gen/runtime/fonts/archivo-400.woff2
Binary file not shown.
Binary file added assets/slide_gen/runtime/fonts/archivo-700.woff2
Binary file not shown.
Binary file added assets/slide_gen/runtime/fonts/dm-sans-400.woff2
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading