Skip to content
spacenets7Public

About

Open iPDF 0.1 format and mobile paper reader with hosted-only generation

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

iPDF

Read it. Question it. Take it with you. An open, versioned JSON format for interactive research papers, plus a viewer designed for a 390 px phone screen.

The source paper stays the main content. Generation adds page-linked glossary entries, study cards, charts backed by original table cells, and section narration. It does not replace the paper with a summary.

Python 3.11 · FastAPI · Pydantic · PyMuPDF · Jinja2 · stdlib SQLite · vanilla JS · vendored Chart.js. All inference uses a hosted OpenAI-compatible endpoint. No GPU, model download, or JavaScript framework is required. GitHub sign-in protects private libraries and paid tools.

Run

Full hosted app: ipdf-tvvn.onrender.com. Upload → personalized generation → study → browser or ElevenLabs listening. The free service has temporary storage; export editions to retain them.

Public static reader: spacenets7.github.io/ipdf. Open an exported .ipdf.json file or explore the authored interactive sample (glossary, study cards and browser narration). The site includes a live format preview, a local JSON file picker and a downloadable sample. Files are read in the browser. GitHub Pages cannot run FastAPI, PDF ingestion or hosted generation; use the full app below for those features. API keys stay server-side.

To rebuild the Pages viewer after changing render code, run python scripts/build_pages.py and commit docs/. Pages publishes main:/docs.

The Week 3 write-up is in SUBMISSION.md, with the video link left for the author to add. SUBMISSION_NOTES.md contains the DEV publishing handoff. The post has not been published to DEV.

python3.11 -m venv .venv
source .venv/bin/activate              # Windows: .venv\Scripts\Activate.ps1
pip install -r requirements.txt
cp .env.example .env                  # Windows: Copy-Item .env.example .env
# Set LLM_API_KEY and LLM_MODEL in .env. Do not commit this file.
uvicorn app.main:app --host 127.0.0.1 --port 8000

Open iPDF. Upload a text-based PDF or enter an arXiv ID (e.g. 1706.03762), then choose beginner/intermediate/expert. Creation returns a job ID immediately; the page polls progress while extraction and generation run in background threads. Restart the app after changing .env.

Without provider credentials, the app still boots and produces an explicitly labelled source-only edition with original pages and exports. It does not invent learning blocks. Configure the model and submit the paper again to create the annotated edition under a different cache identity.

For a phone on the same network, bind --host 0.0.0.0 and open http://YOUR_LAPTOP_LAN_IP:8000 on the phone. Allow the port through your laptop's firewall if needed. Use an HTTPS host for normal remote/mobile access.

Hosted configuration

Variable Default / requirement
LLM_BASE_URL https://router.huggingface.co/v1
LLM_API_KEY Required for generation, no default
LLM_MODEL Required for generation, no hardcoded model
DEEP_BASE_URL, DEEP_API_KEY, DEEP_MODEL Optional Ultramarine; all three must be set, otherwise use LLM_*
TTS_PROVIDER browser (default) or elevenlabs
ELEVENLABS_API_KEY, ELEVENLABS_VOICE_ID Optional hosted speech credentials
ELEVENLABS_MODEL eleven_flash_v2_5
FAST_PRICE_IN, FAST_PRICE_OUT USD / million input and output tokens (PRICE_IN/PRICE_OUT aliases supported)
DEEP_PRICE_IN, DEEP_PRICE_OUT USD / million tokens for optional DEEP
TTS_PRICE_PER_1K_CHARS USD / 1,000 ElevenLabs characters
LLM_TIMEOUT, LLM_MAX_TOKENS 90 seconds / 3,500 output tokens
LLM_RATE_LIMIT_MAX_WAIT 60 seconds; respect shorter provider retry delays and stop on longer resets
DATA_DIR data/: SQLite, source PDFs, jobs, provider audio and caches
MAX_PDF_PAGES 80; uploads also limited to 25 MB
MAX_GENERATION_SECTIONS 20; explicit processing limit, with a visible issue when a paper is longer
PORT 8000; the Docker startup command honors the host's $PORT

Choose an available chat model and exact provider-qualified identifier from Hugging Face Inference Providers, or set another hosted compatible endpoint. The app uses the OpenAI Python SDK; it does not require an OpenAI account. Ultramarine's endpoint/model are supplied entirely through DEEP_*; no endpoint or model name is embedded in the code.

Optional DEEP handles chart table selection and claim grounding. FAST handles glossary, cards and narration. Incomplete DEEP configuration uses FAST. DEEP transport failures retry and fall back to FAST; schema-invalid outputs are dropped after at most two retries. Actual provider/model metadata accompanies each block. Keys remain on the server and are absent from JSON/HTML exports.

GitHub login, private libraries and preparation

Create a GitHub OAuth App with callback https://YOUR_HOST/auth/github/callback. Configure GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, and APP_BASE_URL on the server (CLIENT_ID / CLIENT_SECRET aliases are accepted). Local callback URLs must also be registered with GitHub when testing actual local OAuth. No account or repository scopes are requested; the app needs only GitHub public identity. GitHub access tokens are not stored. App sessions use opaque HttpOnly cookies, server-side token hashes, expiry, PKCE and browser-bound single-use OAuth state.

Upload up to three PDFs at once, then return to Library. Each account's papers, PDFs, audio, jobs, prerequisite maps, reading position and conversations are access-checked on the server. Editions are private until their owner selects Share by link; shared editions allow public reading, not paid tutor use. Downloaded exports are independent copies and cannot be revoked by unsharing.

Preparation continues without a browser while the process runs: learning blocks, a grounded prerequisite map, and cached narration when ElevenLabs is selected. Jobs store their arguments in SQLite and recover interrupted registered tasks on startup, with bounded automatic restart attempts and manual retry controls. This requires the database and uploads to survive. The chosen free Render plan may sleep or clear its temporary disk: overnight readiness and retained account history are not guaranteed. The Library displays that limit. Always-on compute and a persistent disk would be required for dependable unattended overnight use. No paid hosting upgrade was enabled.

The personal tutor uses the selected section, exact source quotations, a bounded conversation history and account-specific concept familiarity. It declines unsupported questions and separately checks supported answers with grounding. Learning paths order prerequisites before dependent concepts and reject cycles. The path currently samples the first 20 sections (1,800 characters each); it is not an exhaustive knowledge graph. Typed questions work everywhere. Optional browser speech input requires microphone permission and browser support; it is not a deployed ElevenLabs realtime Agent. Answers can use ElevenLabs TTS with browser speech fallback. Reader position is account-bound; browser speech resumes at the section boundary, whereas hosted MP3 can resume at a saved time offset.

Defaults: three paper jobs per account/day, twenty tutor jobs per account/day, sixty tutor jobs across the service/day. These complement the provider usage limits below. Counters are local to the database and reset when free hosting loses that database.

Personalized learning and listening

Choose a reader level, prior background, goal (understand / implement / critique), and a 5 / 15 / 30-minute explanation-depth target. The target guides generation; it is not a guaranteed audio duration. Every preference is stored in the edition, and generation caches distinguish reader profiles and hosted endpoints.

Study cards can include grounded multiple-choice checks. After a missed answer, the next narration uses the already-generated simpler script. Quiz attempts, section-level playback position and speed stay in browser storage. Export or reset learning history in the reader. This is personal adaptation, not model training or proof of improved comprehension. python scripts/evaluate_learning.py ipdf-learning.json reports first/latest outcomes for repeated questions; a controlled evaluation is still needed before claiming learning gains.

Choose browser speech to conserve credits, or ElevenLabs for on-demand cached MP3 narration. TTS_CHARACTER_BUDGET defaults to 8,000 successful synthesized characters per database, and MAX_LLM_CALLS_PER_JOB defaults to 60 successful responses (grounding and repairs included). These are usage controls, not dollar spending guarantees. MAX_CREATE_JOBS_PER_DAY defaults to 20. Provider-side limits are authoritative. A free Render restart clears its ephemeral database and these local counters; do not rely on them as durable account-wide limits.

For Render API deployment, add RENDER_API_KEY to the ignored local .env and run python scripts/deploy_render.py --create. It selects the free Docker plan, reuses a matching existing service, and forwards only the app configuration allowlist. It never sends the Render management key to the app. If the key sees multiple workspaces, set RENDER_OWNER_ID. Run without --create to inspect status.

Three layers

flowchart TD
  A[PDF upload / arXiv ID] --> O[Orchestrator + background jobs]
  O --> I[ingest: PyMuPDF source evidence]
  I --> S[page-tagged sections / tables / figures]
  S --> O
  O --> G[generate: independent hosted plugins]
  G --> B[glossary / cards / charts / narration]
  B --> V[Pydantic iPDF 0.1 validation]
  V --> D[(SQLite JSON + plugin cache)]
  D --> R[render: JSON-only mobile viewer]
  R --> X[self-contained HTML / raw JSON]
  R --> T[on-demand ElevenLabs or browser speech]
Loading

app/ingest/, app/generate/, and app/render/ do not import or call one another. app/orchestrate.py coordinates them. The renderer consumes validated iPDF JSON only; it cannot invoke an LLM. Shared services are llm.py, extract.py, db.py and audio.py. The original LazyDigest source is preserved, unmounted, under app/modules/digest/, with its original tests and UI.

The open format

See SPEC.md, ipdf.schema.json and app/schema.py. Version is exactly "ipdf_version": "0.1".

Every generated block stores its source page, plugin, prompt version and actual model name. Section references and page bounds are validated. Level changes glossary depth, question difficulty and narration style. Cache identity includes paper content hash, level, FAST/DEEP models and prompt versions. Validated plugin outputs are reused without new provider calls.

Chart plans contain row/column indices, never model-generated values. Values are parsed from the PDF's extracted table grid and independently rechecked by the document validator. Captions link to from Table N, p.X. Ambiguous grids, fragmented decimals, uncertainty pairs and unreadable numeric cells are omitted. Extraction may therefore omit usable tables; it favors source traceability over filling the page with charts. Raster figures are extracted as images; vector-only figures may be absent. Scanned/encrypted PDFs are rejected with an actionable message; OCR is outside this version.

Reading, studying and walking

  • Original sections stay in page order. Tap an underlined term for a popover; desktop hover also exposes its definition. Save cards to a browser-local deck.
  • Study-card answers expand in place. Chart values have an inspectable table. Every learning block links to the corresponding original PDF page.
  • Top play reads narration in source order, highlights and scrolls to the current section, and supports previous/next and 0.75×–1.5× speed.
  • Walking mode offers large controls and “A little simpler, please”, which replays the already-generated simpler_script for the current section. This action never invokes generation.
  • Media Session handlers provide play/pause/track controls where supported. Reliable phone lock-screen/background behavior depends on the browser and OS; hosted MP3 playback generally has broader support than browser speech. No physical-phone lock-screen test has been claimed.
  • ElevenLabs uses its plain text-to-speech REST API. Audio is requested only on demand, generated in a background job, and cached by script + voice + model. Missing keys, quota, authentication and network errors switch to window.speechSynthesis and display the fallback. Browser voices vary by device and may themselves use the device vendor's speech service.

Portable exports

Interactive HTML contains the validated JSON, CSS, JavaScript, vendored Chart.js, original PDF bytes, extracted images, and any already-cached hosted audio. It has no CDN dependency. It can be opened independently of this app. Unrequested audio is not synthesized during export; browser speech remains the fallback. Device speech availability determines offline narration support.

Raw JSON is the versioned format for other viewers/tools. It includes source URLs and generated scripts; it does not automatically embed source PDF bytes or uncached audio. Raw server-relative links require the originating server. HTML exports embed the source PDF and turn its page links into a local Blob URL.

Study decks live in localStorage on the current browser; exports include learning blocks, not the reader's browser-local saved/deleted deck state.

Free hosting / Docker

docker compose up --build
# Or:
docker build -t ipdf .
docker run --env-file .env -e PORT=8000 -p 8000:8000 -v "$PWD/data:/app/data" ipdf

The container contains one FastAPI app. It downloads no inference weights and requires no GPU or speech runtime. render.yaml is a Render Blueprint using the free web-service plan: connect this repo, select the Blueprint, and enter LLM_API_KEY and LLM_MODEL in Render's environment settings. Its Docker command binds to 0.0.0.0:$PORT; /health needs no provider calls.

Render's free service has an ephemeral filesystem and spins down when idle. SQLite, uploads and generated audio are therefore temporary there. Export the .ipdf.html file to retain a paper; use a persistent volume on a host that offers one for durable server storage. Serialized jobs can resume after restart only when that database and its source files survive. The public Docker service is deployed on Render. New papers require GitHub sign-in and are private by default; only explicitly shared editions are publicly readable.

API

Route Result
POST /ipdf/create Multipart pdf or arxiv_id, level; HTTP 202 + job_id
GET /ipdf/status/{job} Persistent queued/running/ready/error state, progress and result
GET /ipdf/{id} Mobile viewer
GET /ipdf/{id}.json Validated raw JSON download
GET /ipdf/{id}/export Self-contained .ipdf.html download
POST /audio/{id}/{section}?simpler=true HTTP 202 + audio job; synthesis only, no LLM
GET /media/papers/{hash}.pdf Stored original PDF
GET /media/audio/{hash}.mp3 Cached hosted audio
GET /health, GET /spec App readiness / human-readable specification

Create/audio return quickly; extraction and remote provider work run in a bounded two-thread job pool. Job status is persisted in SQLite. Eight pending/running jobs are allowed at once. Source files are capped at 25 MB.

Checks and real-paper runs

pytest -q                                  # mocked clients only, no model/key needed
python scripts/validate_ingest.py           # three real arXiv PDFs, page/table evidence
python scripts/validate_chart_evidence.py   # deterministic source-cell checks, no LLM
python scripts/validate_hosted.py           # REAL hosted output: one paper, all 3 levels
python scripts/validate_hosted.py --max-sections 1  # explicit smaller hosted smoke test
python scripts/validate_e2e.py              # running HTTP app, 3 real PDFs, view + exports

Real validation artifacts are in ignored data/validation/; the portable account of what was actually checked is VALIDATION.md. The UI fixture script creates an explicitly labelled mocked document for interaction QA. It is never counted as hosted generation evidence.

Why open models

iPDF is independent of a model vendor. Hosted open-weight models can be swapped by changing LLM_BASE_URL, LLM_API_KEY, and LLM_MODEL, without changing the format, viewer, prompts' version metadata, or the ingest pipeline. The application can be self-hosted on an ordinary CPU laptop or web server while inference stays at the configured hosted provider. Open JSON and self-contained HTML let the paper outlive a particular service. The source code and schema remain inspectable.

Cost per paper

Actual token counts and configured dollar costs are recorded per job and included in JSON provenance. Cached generation adds no provider usage. Set actual rates before measuring costs; zero/unset prices do not mean free hosted generation.

Real paper Pages Source-only HTTP run Hosted generation cost
Attention Is All You Need 15 5.86 s Full-paper cost not measured
BERT 16 6.06 s Full-paper cost not measured
Deep Residual Learning 12 7.11 s Full-paper cost not measured

These runs made no LLM requests and are not AI-quality benchmarks. For a measured hosted run, cost = (input_tokens × input_rate + output_tokens × output_rate) / 1e6, plus optional ElevenLabs characters × TTS_PRICE_PER_1K_CHARS / 1000. Grounding and validation retries are included in recorded token use. Provider billing remains the authoritative amount. No made-up Ultramarine or ElevenLabs bill is reported.

Subsequent small live checks passed for Groq, Ultramarine and ElevenLabs. A FAST-only generation attempt produced five grounded glossary entries but hit Groq's rate limit before the three-level pipeline completed. See VALIDATION.md for the limits of that check. Browser speech stays the default; ElevenLabs is opt-in and synthesizes only requested segments.

Roadmap

  • Better column/heading reconstruction and vector-figure extraction.
  • A format conformance suite and independent JSON import/viewer.
  • Optional persistent object storage for free-host deployments.
  • Physical Android/iOS background and lock-screen playback checks.
  • Persistent hosting for reliable overnight preparation; bibliography links.
  • Spaced repetition and portable personal study decks.

Community Wisdom

Na'aman Hirschfeld's validation-retry account describes returning the validation error and rejected payload to the next attempt. Commenters also distinguish formatting repair from repeated semantic mistakes. iPDF uses bounded repair plus separate grounding and numeric-evidence checks. Peter Ndumia's PDF extraction account describes rejecting false table grids before downstream use. These are two implementation accounts, not a claim of broad community consensus.

About

Open iPDF 0.1 format and mobile paper reader with hosted-only generation

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages