A newer version of the Gradio SDK is available: 6.20.0
title: Sketchnote
emoji: ✏️
colorFrom: gray
colorTo: blue
sdk: gradio
sdk_version: 6.18.0
app_file: app.py
python_version: '3.11'
pinned: false
tags:
- build-small-hackathon
- gradio
- openbmb
- nvidia
- video
✏️ Sketchnote
Turn a PDF (e.g. a textbook) into a whiteboard sketch-animation video with synced voice narration — chapter by chapter. Upload a PDF, pick a chapter range, and Sketchnote reads each chapter's summary aloud while a hand-drawn-style sketch animation plays in sync. Think "Golpo.ai, but fully local and open-source."
This is a submission to the Hugging Face "Build Small" hackathon. Every AI model is open-weight, self-hosted, and under 32B parameters — no proprietary hosted model APIs are used for any AI work (text, speech, image, or parsing).
Why it fits the rules
| Rule | How Sketchnote complies |
|---|---|
| Every model < 32B params | Largest is MiniCPM4.1-8B (see table) |
| No proprietary hosted model APIs | All inference uses open weights we self-host on Modal / in the Space. We never call OpenAI/Gemini/Anthropic/ElevenLabs or NVIDIA NIM / build.nvidia.com |
| Gradio app, deployable as a Space | app.py is a Gradio app (sdk: gradio) |
| No fine-tuning | Models used as released |
Credentials only in .env |
Only infra tokens (HF + Modal) to download/host our own open weights; read via os.environ, never logged, .env is git-ignored |
Models (every one < 32B — proof)
| Role | Model | HF ID | Parameters | Where it runs |
|---|---|---|---|---|
| Fast PDF text + TOC | PyMuPDF (fitz) |
pip pymupdf |
n/a (no model) | In the Space |
| Document parsing (scanned/complex) | NVIDIA Nemotron Parse v1.1 | nvidia/NVIDIA-Nemotron-Parse-v1.1 |
885M (0.885B) — encoder/decoder VLM (657M ViT-H vision + 256M mBART decoder) | Modal GPU |
| Summarization + visual concepts | MiniCPM4.1-8B (primary) | openbmb/MiniCPM4.1-8B |
8B | Modal GPU |
| Fallback LLM | Qwen2.5-7B-Instruct | Qwen/Qwen2.5-7B-Instruct |
7B | Modal GPU |
| Narration (TTS) | Kokoro-82M | hexgrad/Kokoro-82M |
0.082B | In the Space (CPU) |
| Whiteboard sketch animation | ai-img2sketch (NumPy + OpenCV) | vendored, no model | n/a | In the Space |
| Image (optional upgrade) | SDXL-Turbo | stabilityai/sdxl-turbo |
~3.5B | Modal GPU |
| Video assembly | ffmpeg | system pkg | n/a | In the Space |
| UI | Gradio | pip gradio |
n/a | In the Space |
All AI models are individually well under the 32B cap (largest = 8B).
How it works
User → Gradio Space
│ upload PDF + choose chapter range
▼
Ingestion:
• PyMuPDF first — text + TOC for clean digital PDFs (fast, in-Space)
• If no TOC / scanned / complex → render pages to images,
send to Nemotron Parse (Modal GPU) → structured text + title/section
classes used to recover chapter structure (results cached)
│ for each chapter:
▼
Modal GPU ── MiniCPM4.1-8B ──► { narration_script, visual_concepts[] }
▼
Visual builder: whiteboard concept card (optional: SDXL-Turbo) → PNG
▼
Kokoro-82M → narration WAV (audio FIRST → measures duration)
▼
ai-img2sketch (OpenCV) → sketch reveal sized to the audio duration
▼
ffmpeg: mux audio onto the sketch clip → per-chapter MP4
▼
ffmpeg: concatenate chapter clips → final MP4
▼
Gradio shows the final video + per-chapter transcript
Compute split: heavy models (Nemotron Parse, MiniCPM, optional SDXL-Turbo) run on Modal serverless GPUs; light work (Kokoro, OpenCV, ffmpeg, UI) runs inside the Space. If Modal isn't deployed, Sketchnote falls back to a non-AI extractive summary so it still produces a video.
Repository layout
app.py Gradio UI + pipeline orchestration
modal_app.py Modal GPU functions: summarize_chapter, parse_pages, generate_image
pipeline/
config.py env + paths + ffmpeg resolver (tokens via os.environ, never logged)
pdf_parser.py PyMuPDF fast path + Nemotron hard path → chapters (+ parse cache)
llm.py Modal client + prompt templates + extractive fallback
tts.py Kokoro narration → (wav, duration)
visuals.py whiteboard concept card (+ optional SDXL-Turbo)
sketch.py vendored ai-img2sketch reveal, sized to narration
video.py ffmpeg mux + concat
assets/sample.pdf a short sample for the demo
requirements.txt Space (in-Space) deps packages.txt ffmpeg, espeak-ng
.env.example infra-token placeholders .gitignore includes .env
Setup & run
# 1. credentials (infra only — HF + Modal)
cp .env.example .env # then fill HF_TOKEN, MODAL_TOKEN_ID, MODAL_TOKEN_SECRET
# 2. environment (Python 3.11 recommended)
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
# system deps (Linux): the Space installs these via packages.txt
# sudo apt-get install ffmpeg espeak-ng
# 3. deploy the GPU models to Modal (self-hosting our own open weights)
modal deploy modal_app.py
modal run modal_app.py # optional smoke test of summarize_chapter
# 4. run the Gradio app
python app.py # open the printed local URL
If Modal is not deployed, the app still runs end-to-end using PyMuPDF ingestion + the non-AI extractive summarizer (degraded, but never hard-fails).
Sponsor models
- OpenBMB — MiniCPM4.1-8B is the primary summarizer that writes each chapter's narration script and visual concepts.
- NVIDIA — Nemotron Parse v1.1 upgrades our weakest step: ingesting scanned / multi-column / complex PDFs and classifying titles & sections to drive chapter splitting. We self-host its open weights on Modal — we do not call NVIDIA's hosted NIM / build.nvidia.com service.
Credits & licenses
- Sketch animation adapted from ai-img2sketch by DasLearning
(https://github.com/daslearning-org/ai-img2sketch) and the storyboard-ai
project by Yogendra Yatnalkar. Credit preserved here and in
pipeline/sketch.py; see those projects for their original licenses. - NVIDIA Nemotron Parse v1.1 — NVIDIA Open Model / Community Model License (tokenizer under CC-BY-4.0). See the model card.
- MiniCPM4.1-8B — OpenBMB model license (see model card).
- Kokoro-82M — Apache-2.0 (hexgrad/Kokoro-82M).
Manual checklist (for the maintainer)
cp .env.example .envand fillHF_TOKEN,MODAL_TOKEN_ID,MODAL_TOKEN_SECRET.modal deploy modal_app.py(first call downloads weights to a Modal Volume).- Create the public HF Space in the hackathon org (Gradio SDK) and push this repo.
- Add the correct hackathon track + badge tags to the frontmatter.
- Record the demo video.