Export Features - PDF, PPTX, and Google Slides
Overview
The AI Slide Generator supports exporting slide decks in three formats:
- PDF: Client-side generation using browser APIs
- PPTX: Server-side async generation using LLM-powered conversion with polling
- Google Slides: Server-side export to a new Google Slides presentation via OAuth2
All export options are accessible through a unified dropdown menu in the slide panel.
User Guide
How to Export
-
Access Export Menu
- Click the blue "Export" button in the top-right of the slide panel
- A dropdown menu will appear with two options:
- "Export as PDF" (document icon)
- "Export as PowerPoint" (file icon)
-
Export as PDF
- Click "Export as PDF"
- The export process runs entirely in your browser
- A PDF file will be downloaded automatically
- Filename format:
{slide_deck_title}_{timestamp}.pdf
-
Export as PowerPoint
- Click "Export as PowerPoint"
- Charts are captured client-side before sending to server
- The export runs asynchronously on the server with real-time progress updates
- Progress displays "Processing slide X of Y..." during conversion
- A PPTX file will be downloaded automatically when complete
- Filename format:
{slide_deck_title}_{timestamp}.pptx
Export Status
- The export button shows "Exporting PowerPoint: Processing slide X of Y..." during PPTX export
- The dropdown menu closes automatically when an export starts
- Progress updates every 2 seconds via polling
- If an error occurs, an alert will display the error message
Technical Details
PDF Export (Client-Side)
Location: frontend/src/services/pdf_client.ts
Technology Stack:
html2canvas: Converts HTML slides to canvas imagesjsPDF: Generates PDF from canvas images
Process:
- Each slide is rendered in a hidden iframe (1280×720px)
- Waits for Chart.js charts to fully render
- Converts slide HTML to canvas using
html2canvas - Adds canvas as image to PDF page (maintains 16:9 aspect ratio)
- Repeats for all slides
- Downloads the complete PDF
Features:
- ✅ No server load (runs entirely in browser)
- ✅ Fast processing
- ✅ Works offline
- ✅ Preserves Chart.js visualizations
- ✅ Optimized file size (JPEG compression, 1.2x scale)
Configuration:
{
format: 'a4', // Page format
orientation: 'landscape', // Page orientation
scale: 1.2, // Image scale (quality vs size)
waitForCharts: 2000, // Wait time for charts (ms)
imageQuality: 0.85 // JPEG quality (0-1)
}
Limitations:
- File size can be large for many slides (typically 5-15MB per slide)
- Requires modern browser with canvas support
- Charts are rendered as images (not editable in PDF)
PPTX Export (Server-Side Async)
Location:
src/api/routes/export.py- API endpointssrc/api/services/export_job_queue.py- Background worker and job queuesrc/services/html_to_pptx.py- LLM-powered converter
Technology Stack:
python-pptx: Creates PowerPoint presentationsasyncio: Background job queue with thread pool executionsvgpathtools+Pillow: Pure-Python SVG-to-PNG conversion for image library assets- LLM (Databricks Claude Sonnet 4.5): Analyzes HTML and generates slide layouts
Process:
- Frontend captures Chart.js charts as base64 images client-side
- Frontend calls
POST /api/export/pptx/asyncto initiate export - Backend validates request and queues job, returns job ID immediately
- Background worker (in thread pool) processes the export:
- Fetches slide deck from database
- Builds complete HTML for each slide (including
{{image:ID}}→ base64 substitution) - Extracts base64-embedded content images from HTML, saves as files in a per-slide assets directory, and replaces
<img src="data:image/...;base64,...">with filename references - For each slide, LLM generates Python code to create PowerPoint slide (receiving clean HTML + image filenames, not raw base64)
- Code is executed to add slide to presentation
- Progress is updated after each slide
- Frontend polls
GET /api/export/pptx/poll/{job_id}for status/progress - When complete, frontend downloads via
GET /api/export/pptx/download/{job_id}
Features:
- ✅ Native PowerPoint format (.pptx)
- ✅ Async with polling (avoids proxy timeouts)
- ✅ Real-time progress updates (slide X of Y)
- ✅ Client-side chart capture for accurate chart images
- ✅ Professional layouts with proper spacing
- ✅ Preserves colors, fonts, and styling
- ✅ No overlapping elements
- ✅ Background worker runs in thread pool (non-blocking)
Configuration:
{
use_screenshot: True # Include client-captured chart images
}
Limitations:
- Requires server processing (5-15 seconds per slide)
- Requires LLM API access (Databricks endpoint)
- Polling interval: 2 seconds
- Maximum poll attempts: 300 (10 minute timeout)
Architecture
Frontend Components
Export Button & Dropdown (frontend/src/components/SlidePanel/SlidePanel.tsx):
- Blue-themed export button with download icon
- Dropdown menu with blue accents matching app theme
- Loading states for both export types
- Error handling with user-friendly messages
PDF Service (frontend/src/services/pdf_client.ts):
- Handles iframe rendering and canvas conversion
- Manages Chart.js rendering wait times
- Optimizes image quality vs file size
- Handles edge cases (first slide, canvas sizing)
API Client (frontend/src/services/api.ts):
startPPTXExport()- Initiates async export jobpollPPTXExport()- Polls for job status and progressdownloadPPTX()- Downloads completed PPTX fileexportToPPTX()- Orchestrates the full async flow with progress callback- Client-side chart capture before export
Backend Components
Export Route (src/api/routes/export.py):
POST /api/export/pptx/async- Initiates export job, returns job ID immediatelyGET /api/export/pptx/poll/{job_id}- Returns job status and progressGET /api/export/pptx/download/{job_id}- Serves completed PPTX file- Validates slide deck availability before queuing
Export Job Queue (src/api/services/export_job_queue.py):
- Database-backed job tracking via
ExportJobSQLAlchemy model asyncio.Queuefor local worker dispatch within each process- Background worker processes jobs in thread pool
- Thread pool execution prevents blocking event loop during LLM calls
- Progress tracking per job (slides completed / total) stored in DB
- Job cleanup after download (deletes DB row + temp file)
- Multi-worker safe: any process can read job status from the shared database
PPTX Converter Service (src/services/html_to_pptx.py):
HtmlToPptxConverterV3class- LLM-powered HTML to PPTX conversion
- Extracts base64-embedded content images (
_extract_and_save_content_images()) before sending HTML to LLM - Converts SVG images to PNG via
_svg_to_png()usingsvgpathtools+Pillow(pure Python, no system dependencies) - Generates and executes Python code for slide creation
- Ensures proper positioning and no overlaps
Google Slides Export (Server-Side)
Location:
src/api/routes/google_slides.py— API endpoints (auth + export)src/api/routes/settings/google_credentials.py— Credential management endpointssrc/services/google_slides_auth.py— OAuth2 flow and token managementsrc/services/html_to_google_slides.py— LLM-powered converter
Technology Stack:
- Google Slides API + Google Drive API: Creates and populates presentations
google-auth-oauthlib: OAuth2 authorization flow- Fernet encryption (
cryptography): Encrypts credentials and tokens at rest - LLM (Databricks Claude Sonnet 4.5): Generates Python code that calls the Slides API
Process:
- Admin uploads
credentials.jsonglobally (one-time setup) - User authorizes via Google OAuth popup (one-time per user)
- User clicks "Export to Google Slides"
- Frontend calls
POST /api/export/google-slidesto initiate export - Backend validates auth, fetches slides, builds HTML, and enqueues a background job; returns
job_idimmediately - Background worker builds authenticated API clients from encrypted DB records
- Creates a blank presentation via Slides API
- For each slide, LLM generates Python code to populate the slide via
batchUpdate; progress is updated after each slide - Code is sanitized and executed server-side
- Frontend polls
GET /api/export/google-slides/poll/{job_id}for status and progress - When
statusiscompleted, the response includespresentation_idandpresentation_url
Features:
- Produces editable Google Slides (not static images)
- Global credential storage (encrypted)
- Per-user OAuth tokens (multi-user safe)
- LLM-powered layout with retry and fallback
- Chart images uploaded to Google Drive and embedded
- Stale token/credential auto-cleanup
Configuration:
- Google Cloud project with Slides API + Drive API enabled
- OAuth 2.0 Desktop Client credentials (
credentials.json) GOOGLE_OAUTH_ENCRYPTION_KEYenv var for production encryption key
Limitations:
- Requires Google Cloud project setup
- Requires user interaction for initial OAuth consent
- Processing time: 5–15 seconds per slide (similar to PPTX)
- Requires LLM API access (Databricks endpoint)
For full technical details, see Google Slides Integration.
Positioning Constraints
The PPTX converter uses strict positioning constraints to prevent overlapping elements:
- Slide dimensions: 10" wide × 7.5" tall
- Safe bounds: left ≥ 0.5", top ≥ 0.5", left + width ≤ 9.5", top + height ≤ 7.0"
- Title: left=0.5-1.0", top=0.5-1.0", height=1.0-1.5", ends ≤ 2.0", font ≤ 44pt
- Subtitle: left=0.5-1.0", top ≥ 2.3" (0.3" gap), height=0.8-1.0", ends ≤ 3.5", font ≤ 28pt
- Body: top ≥ 4.0", left ≥ 0.5", ends ≤ 7.0", font ≤ 18pt
- Text wrapping: Enabled on all text frames
- No overlaps: Verified for all element pairs
Chart Handling
PDF Export
- Charts are rendered as images in the PDF
- Chart.js visualizations are captured via canvas
- Charts appear exactly as they do in the browser
PPTX Export
Chart Images (client-side capture):
- Charts are captured as base64 PNG images in the browser before export
- The frontend identifies all
<canvas>elements within chart containers - Canvas images are sent to the server as part of the export request
- Chart images are saved to a per-slide assets directory and referenced by filename in the LLM prompt
Content Images (server-side extraction):
- Slides may contain
<img>tags with base64 data URIs (e.g. uploaded logos or photos injected via{{image:ID}}placeholders) - Before the LLM call,
_extract_and_save_content_images()scans the HTML for<img src="data:image/...;base64,...">tags - Each image is decoded and saved to the assets directory as
content_image_0.png,content_image_1.jpg, etc. - SVG-to-PNG conversion: SVG images (
image/svg+xml) are automatically converted to PNG usingsvgpathtools+Pillow(pure Python). The converter parses SVG<path>elements, samples bezier curves to polygon points, and rasterizes them onto a Pillow RGBA canvas. This is required becausepython-pptxand Google Slides API only support raster image formats. - The HTML
srcattribute is replaced with the filename so the LLM receives clean, compact HTML - Extracted content image filenames are merged into the chart images list, so the LLM receives unified
add_picture()instructions for all image assets
LLM prompt integration:
- Both chart and content image filenames are listed in the LLM user prompt via the
screenshot_note - The LLM system prompt includes a
CONTENT IMAGESsection instructing it to callslide.shapes.add_picture()for anycontent_image_*.pngfiles - This ensures images are positioned in the PowerPoint slide at their HTML layout location
File Naming
Both export formats use timestamped filenames:
- PDF:
{slide_deck_title}_{YYYY-MM-DDTHH-MM-SS}.pdf - PPTX:
{slide_deck_title}_{YYYY-MM-DD}.pptx
If the slide deck has no title, "slides" is used as the default.
Troubleshooting
PDF Export Issues
Problem: White space in PDF
- Solution: This is usually resolved by the current implementation. If it persists, check that slides are exactly 1280×720px.
Problem: Charts not appearing
- Solution: The export waits for Chart.js to render. If charts still don't appear, check browser console for Chart.js errors.
Problem: Large file size
- Solution: File size is optimized with JPEG compression (quality 0.85) and 1.2x scale. For smaller files, reduce
imageQualityorscalein the export options.
Problem: First slide content trimmed
- Solution: The implementation includes special handling for the first slide with additional wait time and canvas cropping logic.
PPTX Export Issues
Problem: Export fails with "No slide deck available"
- Solution: Ensure you have generated slides before attempting export. The export requires an active slide deck.
Problem: Export times out (504 Gateway Timeout)
- Solution: The async polling architecture handles long exports. If timeouts still occur:
- Check that the backend logs show "Export worker picked up job"
- Verify the export_worker is running (check startup logs)
- The 10-minute polling timeout may need extension for very large decks
Problem: Progress stuck at 0
- Solution: Check backend logs for errors in
process_export_job. The worker may have encountered an error fetching slides or during LLM calls.
Problem: Elements overlapping in PPTX
- Solution: The LLM prompts include strict positioning constraints. If overlaps occur, the prompts may need adjustment in
src/services/html_to_pptx.py.
Problem: Charts not appearing in PPTX
- Solution:
- Ensure charts are visible on screen before exporting (client-side capture requires rendered charts)
- Check browser console for errors during chart capture
- Verify the chart container has a valid
<canvas>element
Problem: Uploaded images show as text/filename in PPTX instead of rendering
- Solution:
- Check backend logs for "Extracted content image" messages to confirm extraction is running
- Verify the
<img>tag uses a standarddata:image/(png|jpeg|gif|svg+xml);base64,...format - The LLM system prompt must include the
CONTENT IMAGESsection (checkpptx_prompts_defaults.pyor the profile's custom prompts)
Problem: "ModuleNotFoundError: No module named 'pptx'"
- Solution: Install dependencies:
pip install python-pptx
Best Practices
-
For PDF Export:
- Use when you need quick, client-side export
- Best for presentations with many slides (faster)
- Good for sharing/viewing (universal format)
-
For PPTX Export:
- Use when you need editable PowerPoint files
- Best for presentations that need further editing
- Ensure charts are fully rendered before exporting (wait for animations to complete)
- Keep the browser tab active during export for reliable chart capture
-
Chart Considerations:
- PDF: Charts are images (not editable)
- PPTX: Charts are captured as images from the browser, preserving exact appearance
Future Enhancements
Potential improvements for export features:
- Batch export options (export multiple formats at once)
- Export progress indicator for PPTX (showing slide-by-slide progress) - Implemented
- Custom export templates (different layouts/styles)
- Export preview before download
- Export scheduling/automation
- Compression options for PDF
- Export quality presets (high/medium/low)
- Persistent job storage (survive server restarts) - Implemented (DB-backed ExportJob model)
- Google Slides export - Implemented (OAuth2, encrypted credential storage, LLM code-gen)
- Google Slides async export with progress polling - Implemented (
POSTreturns job_id,GET .../poll/{job_id}for status)
Related Documentation
- Backend Overview - Backend architecture
- Frontend Overview - Frontend architecture
- Slide Parser & Script Management - How slides are structured
- Google Slides Integration - OAuth2 flow, encryption, LLM converter