Portfolio  ›  Projects  ›  NeuroSlide
Python Local LLM Streamlit python-pptx

NeuroSlide,
Local AI Presentation Studio

Type a topic, get a real .pptx. A local language model writes the deck structure and content; a library of hand-built layouts renders it. No API key, no cloud, no per-deck cost — the model runs on your own machine.

◆ Local Prototype · verified running on Ollama + llama3.2
Context: Personal project, five iterations  ·  Role: Sole author
Verified: 2026-08-18, Ollama 0.32.13 + llama3.2 (1.88 GB), CPU only
5Versions
13Slide layouts
35,945Bytes of valid PPTX
$0API cost
✅ See the Verified Run ∞ MathGenius
Version History

Five versions, all still parse

VersionLinesWhat changed
v11,229First working build: Ollama → pptx, 6 themes, CSV charts, PDF notes
v2876Trimmed and reorganised; ppt generator grew as the app shrank
v31,547Hotfix release; chart engine rewritten (3.4 KB → 13.2 KB)
v41,6298 professional layouts, 10 slide types, batched generation to beat timeouts
v51,832Current. 13 layout templates, largest ppt generator (39.5 KB)
Technical Approach

The model picks a type, the builder picks the layout

The interesting design decision is that the model never describes layout. It returns a slide typetitle, statistic, quote, process and so on — and the builder dispatches to the matching template. A statistic slide therefore renders completely differently from a quote slide without the model having to reason about geometry, which is exactly the kind of task small local models are bad at.

The 13 templates (v5)
tpl_titletpl_agendatpl_content_right tpl_bannertpl_stattpl_quote tpl_splittpl_processtpl_bigimage tpl_cardstpl_conclusiontpl_references tpl_chart
01 TOPICUser types a subject and slide count
02 GENERATEStreaming call to localhost:11434
03 REPAIRFix near-valid JSON from small models
04 DISPATCHSlide type → layout template
05 RENDERpython-pptx builds the deck
06 EXPORT.pptx + reportlab notes PDF
The Hard Part

Small models emit almost valid JSON

🛠️ Why _repair() exists

A hosted frontier model returns clean structured output. A 1.9 GB model running on a laptop returns output that is nearly right: arrays where a string was expected, unescaped newlines inside strings, trailing commas. Parsing that with json.loads() fails, and the whole generation is wasted after a 90-second wait.

ollama_client._repair() handles those three failure modes specifically. This is the practical difference between a demo that only works against a paid API and one that works offline on someone's own hardware — and it is the part of this project most worth reusing.

The client also discovers models dynamically through /api/tags rather than hardcoding a model name, so whatever the user has pulled appears in the picker. That is why the verification below succeeded on llama3.2 despite the documentation recommending mistral.

Verified Run

A real deck, opened and inspected

Environment: Windows 11, Python 3.12, Ollama 0.32.13, llama3.2:latest (1.88 GB), CPU only.

CheckResult
check_ollama()Pass — (True, 'Connected')
list_models()['llama3.2:latest']
generate_slides(), 4 slidesPass — 91.5 s and 108.2 s across two runs
build_presentation()35,945 bytes of valid OOXML
PPTX reopens in python-pptxPass — 4 slides
Slide dimensions9,144,000 × 5,143,500 EMU (16:9)
Shapes per slide13, 22, 19, 16
Streamlit bootsHTTP 200, /_stcore/health → ok

📊 The deck it produced — "Renewable energy basics"

[1] title      Renewable Energy Basics
[2] content    What is Renewable Energy?
[3] statistic  Renewable Energy Growth
[4] quote      Renewable Energy Expert

Four different slide types, each dispatched to a different template. The run used fetch_images=False to stay fully offline.

⏱️ The honest performance number

Generation takes 90–115 seconds for a 4-slide deck on CPU with a 1.9 GB model. That is not fast. A larger model or a GPU changes it substantially, but neither was used here, so neither is claimed.

💻 Run it

ollama serve
ollama pull llama3.2

python -m venv .venv && .venv\Scripts\activate
pip install -r neuroslide_v5/requirements.txt

cd neuroslide_v5
streamlit run app.py            # http://localhost:8501
Lineage

Where the zero-API-cost pattern was worked out

NeuroSlide is where the local-LLM-plus-Streamlit approach the shipped BitWithBite AI tools now use was first figured out: dynamic model discovery over /api/tags, streaming generation, a JSON repair layer for small-model output, and zero API cost treated as a design constraint rather than an afterthought.

MathGenius shares the same client shape, built alongside it. Both feed into the current tools listed on the portfolio, which run on local models for the same reason.

⚠️ Content quality tracks the model

With llama3.2 the output is structurally correct and topically reasonable, not expert-grade. No claim is made about the factual accuracy of generated slide content — it is LLM output and should be checked before use. There is also no test suite; the verification above is a scripted manual run, not CI.

Output

Charts it actually generated

Four of the nine charts NeuroSlide's chart engine produced in a single pass from one uploaded spreadsheet. These are the unmodified PNGs the app wrote to disk, arranged into a contact sheet.

Four charts auto-generated by NeuroSlide from one spreadsheet: trend analysis, correlation matrix, box plot and distribution histogram
9 charts from one spreadsheet, 4 shownUnmodified output of generate_all_charts()

Offline by design, not by limitation

Running generation locally means no key, no per-deck cost, and no document leaving the machine. The engineering that makes it viable is the repair layer around imperfect small-model output.