Paper Voice Documentation

Paper Voice converts academic papers to high-quality audio narration with precise mathematical explanations using a simplified LLM-powered approach.

Installation

pip install paper_voice

Quick Start

Basic usage with the simplified API:

from paper_voice.simple_llm_enhancer import enhance_document_simple
from paper_voice import pdf_utils, tts

# Extract text from PDF
pages = pdf_utils.extract_raw_text("paper.pdf")
content = '\n\n'.join(pages)

# Convert math to natural language
enhanced_script = enhance_document_simple(content, api_key="your-openai-key")

# Generate audio
tts.synthesize_speech_chunked(
    enhanced_script,
    "output.mp3",
    use_openai=True,
    api_key="your-openai-key"
)

Web Interface

streamlit run streamlit/app.py

Key Features

  • Natural Math Narration: Professor-style explanations of mathematical expressions

  • Single LLM Enhancement: Comprehensive prompt handles all math conversion in one API call

  • Intelligent Chunking: Automatically handles large documents within OpenAI API limits

  • Multi-Format Support: PDFs, LaTeX, Markdown, and plain text with math notation

  • Multiple TTS Options: OpenAI TTS with chunking or offline pyttsx3

API Reference

Core Functions

Simple LLM enhancer - just prompt + LLM, no manual processing.

This module takes the entire document text and sends it to the LLM with a comprehensive prompt to convert math expressions to natural language and provide clear audio narration. No manual LaTeX processing.

paper_voice.simple_llm_enhancer.enhance_with_simple_llm(content, api_key, progress_callback=None)[source]

Simple enhancement: just pass all text to LLM with comprehensive prompt.

No manual LaTeX processing, no selective enhancement, no chunking. Just send everything to LLM and let it handle the conversion.

Parameters:
  • content (str) – The entire document text (LaTeX, PDF-extracted, etc.). Returned unchanged if api_key is empty or blank.

  • api_key (str) – OpenAI API key used to construct the client.

  • progress_callback (Callable[[str], None] | None) – Called with a human-readable status message at each step; no calls are made when it is None.

Returns:

Enhanced text ready for audio narration.

Raises:
  • ValueError – If the OpenAI response carries no message content. Caught internally and re-raised as Exception.

  • Exception – If the request fails, if the model returns the input unchanged, or if at least 80% of the inline or display math delimiters survive the conversion.

Return type:

str

paper_voice.simple_llm_enhancer.enhance_with_intelligent_chunking(content, api_key, progress_callback=None)[source]

Intelligent chunking based on actual OpenAI token limits.

  • GPT-4o: 128,000 tokens total (input + output)

  • Reserve ~50,000 tokens for output, leaving ~78,000 for input

  • Each chunk: ~60,000 input tokens max = ~180,000 characters

Parameters:
Return type:

str

paper_voice.simple_llm_enhancer.enhance_with_chunking_fallback(content, api_key, progress_callback=None)[source]

Fallback for very large documents - split into logical chunks.

Only used if the single-call approach fails due to size limits.

Parameters:
Return type:

str

paper_voice.simple_llm_enhancer.enhance_document_simple(content, api_key, progress_callback=None)[source]

Main entry point for simple LLM enhancement.

Based on actual OpenAI limits: - GPT-4o: 128,000 tokens total (input + output) - GPT-4.1: 1,000,000 tokens total - Rule of thumb: ~3-4 characters per token

Parameters:
Return type:

str

Simple PDF text extraction utilities.

This module just extracts raw text from PDFs. All processing (math, tables, etc.) is now handled by the LLM, not manual parsing.

paper_voice.pdf_utils.extract_raw_text(pdf_path)[source]

Extract raw text from each page of a PDF.

Parameters:

pdf_path (str) – Path to the PDF file on disk.

Returns:

A list of strings, one per page. Pages that cannot be read will produce an empty string in the corresponding position.

Return type:

list[str]

Note

pypdf does not always perfectly extract text, especially from PDF documents created from scans or with unusual fonts. If the document contains images of text (e.g. scanned pages), you may need an OCR pipeline such as pytesseract instead.

paper_voice.pdf_utils.extract_full_document_text(pdf_path)[source]

Extract all text from a PDF as a single string.

This is the main function used by the simplified pipeline. All processing is now done by LLM, not manual parsing.

Parameters:

pdf_path (str)

Return type:

str

Abstractions for synthesising speech from text.

This module exposes a simple API over two different TTS backends:

  1. Offline TTS via `pyttsx3`: Available out of the box and does not require network access. Produces a WAV file. To convert to MP3, this module uses pydub, which requires that ffmpeg be installed on the system. On many Linux distributions you can install ffmpeg via your package manager.

  2. OpenAI Text-to-Speech API: Requires a valid API key. Produces an MP3 directly. The OpenAI API currently supports a limited set of voices and languages but generally yields higher quality output.

paper_voice.tts.synthesize_speech_chunked(text, output_path, voice='', rate=200, use_openai=False, api_key=None, model='tts-1', openai_voice='alloy')[source]

Synthesize speech with automatic text chunking for long texts.

This function handles texts longer than the OpenAI TTS limit by splitting them into chunks and concatenating the audio files.

Parameters:
Return type:

str

paper_voice.tts.synthesize_speech(text, output_path, voice='', rate=200, use_openai=False, api_key=None, model='tts-1', openai_voice='alloy')[source]

Synthesize speech from text and write it to a file.

Parameters:
  • text (str) – The input text to speak.

  • output_path (str) – Path where the audio file should be written. The file extension determines the format. For offline synthesis this should end with .wav; for OpenAI TTS this should end with .mp3.

  • voice (str) – A substring of the desired voice name when using pyttsx3. On Windows you might use ‘Zira’ or ‘David’, on macOS ‘Samantha’ etc. If empty, the default voice is used.

  • rate (int) – Words per minute for offline synthesis. Typical values are 150-250.

  • use_openai (bool) – If true, attempts to synthesise via the OpenAI API. Requires the openai package and a valid API key. The output format will always be MP3 in this mode.

  • api_key (str | None) – The OpenAI API key to use. If not provided, uses the OPENAI_API_KEY environment variable.

  • model (str) – The OpenAI TTS model to use. At time of writing ‘tts-1’ and ‘tts-1-hd’ are available.

  • openai_voice (str) – The voice name for OpenAI TTS (e.g. ‘alloy’, ‘echo’).

Returns:

The path to the generated audio file. In offline mode this may differ from output_path if an intermediate WAV is created and later converted.

Raises:

RuntimeError – If the backend for the requested mode is unavailable (openai or pyttsx3 not installed, no OpenAI API key, pydub missing for WAV-to-MP3 conversion) or if the OpenAI TTS request fails.

Return type:

str

Content Processing

Unified content processor for all input types.

This module provides a single, clean interface for processing different types of academic content (PDF, LaTeX, Markdown, plain text) with selective LLM enhancement for math, figures, and tables.

class paper_voice.content_processor.ProcessedDocument(enhanced_text, input_type, figures=None, tables=None, equations=None, metadata=None, has_math=False, has_figures=False, has_tables=False)[source]

Container for processed document content.

Parameters:
  • enhanced_text (str)

  • input_type (str)

  • figures (list | None)

  • tables (list | None)

  • equations (list | None)

  • metadata (dict | None)

  • has_math (bool)

  • has_figures (bool)

  • has_tables (bool)

paper_voice.content_processor.process_content_unified(content, input_type, api_key=None, use_llm_enhancement=True, progress_callback=None)[source]

Process content with appropriate enhancement based on type.

This is the main entry point for all content processing. It: 1. Determines the appropriate processing strategy 2. Applies selective LLM enhancement for math, figures, tables 3. Preserves original text structure for everything else

Parameters:
  • content (str) – Raw document text to process.

  • input_type (str) – Type of content, matched case-insensitively; ‘latex’ or ‘tex’, ‘markdown’, and ‘pdf’ each get their own pipeline and anything else is treated as plain text.

  • api_key (str | None) – OpenAI API key. Enhancement is skipped when it is None.

  • use_llm_enhancement (bool) – Whether to send math, figures, and tables to the LLM. When false the text is passed through unchanged.

  • progress_callback (Callable[[str], None] | None) – Called with a human-readable status message at each processing step; no calls are made when it is None.

Returns:

A ProcessedDocument holding the enhanced text plus any figures, tables, equations, and metadata the pipeline recovered, and flags for whether math, figures, or tables were detected.

Return type:

ProcessedDocument

paper_voice.content_processor.process_latex_content(content, api_key=None, use_llm_enhancement=True)[source]

Simplified interface for LaTeX content processing.

This function specifically handles LaTeX files and applies LLM enhancement to math, figures, and tables while preserving all other text.

Parameters:
  • content (str)

  • api_key (str | None)

  • use_llm_enhancement (bool)

Return type:

str

paper_voice.content_processor.process_text_with_math(content, api_key=None, use_llm_enhancement=True)[source]

Process text content that may contain mathematical expressions.

This handles both Markdown-style and LaTeX-style math expressions.

Parameters:
  • content (str)

  • api_key (str | None)

  • use_llm_enhancement (bool)

Return type:

str

paper_voice.content_processor.get_supported_input_types()[source]

Get list of supported input types.

Return type:

list

paper_voice.content_processor.detect_input_type(content, filename=None)[source]

Automatically detect the input type based on content and filename.

Returns one of: ‘pdf’, ‘latex’, ‘markdown’, ‘text’

Parameters:
  • content (str)

  • filename (str | None)

Return type:

str

LaTeX and Markdown processor for converting mathematical documents to speech.

This module handles LaTeX/Markdown text with mathematical expressions, tables, figures, and various LaTeX environments (equation, align, etc.). It produces clean text suitable for text-to-speech synthesis.

class paper_voice.latex_processor.ProcessedContent(text, figures, tables, equations, metadata)[source]

Container for processed document content.

Parameters:
paper_voice.latex_processor.latex_math_to_speech(expr)[source]

Convert LaTeX mathematical expression to speech.

This handles inline math content without delimiters.

Parameters:

expr (str)

Return type:

str

paper_voice.latex_processor.extract_latex_environments(text)[source]

Extract LaTeX environments like equation, align, etc.

Parameters:

text (str)

Return type:

dict[str, list[tuple[int, int, str]]]

paper_voice.latex_processor.process_latex_environments(text, environments)[source]

Process LaTeX environments and replace with spoken equivalents.

Parameters:
Return type:

str

paper_voice.latex_processor.process_inline_and_display_math(text, api_key=None, use_llm=True)[source]

Process inline and display math in all LaTeX formats.

Parameters:
Return type:

str

paper_voice.latex_processor.extract_figures_and_tables(text)[source]

Extract figure and table information from LaTeX.

Parameters:

text (str)

Return type:

tuple[list[tuple[str, str]], list[tuple[str, str]]]

paper_voice.latex_processor.clean_latex_commands(text)[source]

Remove or replace common LaTeX formatting commands.

Parameters:

text (str)

Return type:

str

paper_voice.latex_processor.process_latex_document(text, summarize_figures=True, summarize_tables=True, api_key=None, use_llm_math=True)[source]

Process a complete LaTeX document.

Parameters:
  • text (str)

  • summarize_figures (bool)

  • summarize_tables (bool)

  • api_key (str | None)

  • use_llm_math (bool)

Return type:

ProcessedContent

paper_voice.latex_processor.process_markdown_with_math(text, api_key=None, use_llm=True)[source]

Process Markdown text with LaTeX math expressions.

Parameters:
Return type:

str

Selective Enhancement

Simple content enhancement for academic papers.

This module provides a simplified approach that just passes all content to the LLM with a comprehensive prompt. No manual LaTeX processing.

paper_voice.selective_enhancer.enhance_content_selectively(content, api_key, progress_callback=None)[source]

Simple enhancement using just LLM + prompt approach.

This function passes the entire document to the LLM with instructions to convert math, clean LaTeX, and make everything audio-ready.

Parameters:
  • content (str) – Original content to enhance (PDF text, LaTeX, etc.)

  • api_key (str) – OpenAI API key for LLM processing

  • progress_callback (Callable[[str], None] | None) – Called with a human-readable status message at each step; no calls are made when it is None.

Returns:

Enhanced content ready for audio narration.

Return type:

str

paper_voice.selective_enhancer.fix_pdf_extraction_issues(content, api_key, progress_callback=None)[source]

Fix common PDF extraction issues using LLM.

This function addresses broken words, spacing issues, and formatting problems that commonly occur during PDF text extraction.

Parameters:
  • content (str) – Raw PDF extracted content with potential issues

  • api_key (str) – OpenAI API key for LLM processing

  • progress_callback (Callable[[str], None] | None) – Called with a human-readable status message at each step; no calls are made when it is None.

Returns:

Cleaned content with extraction issues fixed.

Return type:

str

Indices and tables