### Install and Run PaperFlow Local Web UI
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/index.html
Clone the repository, install dependencies, and run the API server to access the local Web UI. The UI guides parser selection and setup.
```bash
git clone https://github.com/TylerMorrison21/paperflow
cd paperflow
pip install -r requirements.txt
uvicorn api.main:app --port 8000
# Open http://localhost:8000
```
--------------------------------
### Recommended PaperFlow Setup
Source: https://github.com/tylermorrison21/paperflow/blob/master/mcp-server/README.md
Steps to clone the PaperFlow repository, set up the environment, install dependencies, and run the Uvicorn server for the backend.
```bash
git clone https://github.com/TylerMorrison21/paperflow
cd paperflow
cp .env.example .env
pip install -r requirements.txt
uvicorn api.main:app --port 8000
```
--------------------------------
### Local Development Setup for MCP Server
Source: https://github.com/tylermorrison21/paperflow/blob/master/mcp-server/README.md
Commands to set up and start the MCP server for local development.
```bash
cd mcp-server
npm install
npm start
```
--------------------------------
### Local Development Setup for PaperFlow
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
This script outlines the steps to set up the PaperFlow project for local development. It includes cloning the repository, installing dependencies, and starting the development server.
```bash
# Local development startup
git clone https://github.com/TylerMorrison21/paperflow
cd paperflow
cp .env.example .env
pip install -r requirements.txt
uvicorn api.main:app --port 8000 --reload
```
--------------------------------
### Install PaperFlow MCP Server
Source: https://github.com/tylermorrison21/paperflow/blob/master/mcp-server/README.md
Command to globally install the paperflow-mcp package using npm.
```bash
npm install -g paperflow-mcp
```
--------------------------------
### Install PaperFlow Post-processing Engine
Source: https://github.com/tylermorrison21/paperflow/blob/master/README.md
Install the PaperFlow post-processing engine using pip. This is the primary method for using the post-processing layer.
```bash
pip install paperflow-postprocess
```
--------------------------------
### Start PaperFlow with Docker Compose or Run Directly
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
Commands to start the PaperFlow service using Docker Compose or a direct `docker run` command. Includes instructions for opening the Web UI.
```bash
# Start
docker compose up -d
# Or run directly
docker run --name paperflow \
-p 8000:8000 \
-e DATA_DIR=/data/jobs \
-v $(pwd)/data:/data \
--restart unless-stopped \
ghcr.io/tylermorrison21/paperflow:latest
# Open Web UI
open http://localhost:8000
```
--------------------------------
### Example Summary Response from convert_pdf
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
Illustrates the summary output format from the `convert_pdf` tool, including job details, parser information, and next steps for retrieving content.
```text
# Example summary response from convert_pdf:
# ---
# Source: https://arxiv.org/pdf/1706.03762
# Job ID: 3fa85f64-5717-4562-b3fc-2c963f66afa6
# Parser: PyMuPDF Local
# Markdown size: 42381 characters
# Direct markdown URL: http://localhost:8000/api/jobs/.../result
# Direct package URL: http://localhost:8000/api/jobs/.../package
# Response mode: summary
# ---
# Title: Attention Is All You Need
# Authors: Ashish Vaswani, Noam Shazier
# Date: 2017-06-12
# Top headings: Abstract | Introduction | Background | Model Architecture | ...
# Next chunk call: {"job_id":"...","start":0,"length":12000}
# ---
```
--------------------------------
### Example Output of `list_parsers`
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
Shows the detailed output from the `list_parsers` command, including backend information, parser specifics (status, speed, quality), and MCP parser shortcuts.
```text
# Example output:
# Backend: http://localhost:8000
# Configured PaperFlow parsers:
#
# - PyMuPDF Local [pymupdf] - ready for MCP
# Speed/quality: Free / Fastest
# Setup: Ready after install. No API key and no parser-specific CLI required.
# Default backend parser: yes
#
# - Marker API (Datalab.to) [marker_api] - configured but not ready for MCP
# Speed/quality: Easy / Best quality
# MCP note: requires PAPERFLOW_MARKER_API_KEY in the MCP server environment.
#
# MCP parser shortcuts:
# - auto: best available quality with minimal user setup
# - best: prefer marker_local -> marker_api -> paddleocr_vl -> pymupdf
# - local: prefer marker_local -> paddleocr_vl -> pymupdf
# - fast: prefer pymupdf -> marker_local -> paddleocr_vl -> marker_api
#
```
--------------------------------
### Run PaddleOCR-VL CLI
Source: https://github.com/tylermorrison21/paperflow/blob/master/README.md
Example of how PaperFlow runs the local paddleocr CLI for processing documents.
```bash
paddleocr doc_parser -i input.pdf --device cpu --save_path output
```
--------------------------------
### Run Enterprise Marker Self-Hosted CLI
Source: https://github.com/tylermorrison21/paperflow/blob/master/README.md
Example of how PaperFlow runs the local marker_single CLI for processing PDFs.
```bash
marker_single input.pdf --output_dir output --output_format markdown
```
--------------------------------
### List Available Parsers
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
Retrieve a list of all supported parsers, including their configuration status, performance labels, setup instructions, and CLI commands. This helps in selecting the appropriate parser for document processing.
```bash
curl http://localhost:8000/api/parsers
# {
# "parsers": [
# {
# "id": "pymupdf",
# "label": "PyMuPDF Local",
# "configured": true,
# "recommended": true,
# "default": true,
# "speed": "Free",
# "quality": "Fastest",
# "setup": "Ready after install. No API key and no parser-specific CLI required.",
# "requires_user_key": false
# },
# {
# "id": "paddleocr_vl",
# "label": "PaddleOCR-VL-0.9B",
# "configured": false,
# "setup": "Install PaddleOCR, make sure the paddleocr command works..."
# },
# {
# "id": "marker_api",
# "label": "Marker API (Datalab.to)",
# "configured": true,
# "requires_user_key": true
# },
# {
# "id": "marker_local",
# "label": "Enterprise Marker Self-Hosted",
# "configured": false
# }
# ]
# }
```
--------------------------------
### Configure MCP Server for PaperFlow
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/index.html
Configure the MCP server settings in your application's configuration file. This example shows configurations for macOS/Linux and Windows.
```json
{
"mcpServers": {
"paperflow": {
"command": "npx",
"args": ["-y", "paperflow-mcp"]
}
}
}
```
```json
{
"mcpServers": {
"paperflow": {
"command": "cmd",
"args": ["/c", "npx", "-y", "paperflow-mcp"]
}
}
}
```
--------------------------------
### Response Format for `get_markdown_chunk`
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
Example of the response received from `get_markdown_chunk`, detailing the job, source, parser, character range, and providing information on whether more content is available.
```text
# Response:
# ---
# Job ID: 3fa85f64-5717-4562-b3fc-2c963f66afa6
# Source: https://arxiv.org/pdf/1706.03762
# Parser: PyMuPDF Local
# Range: 12000-24000 / 42381 characters
# Direct markdown URL: http://localhost:8000/api/jobs/.../result
# Has more: yes
# Next call: {"job_id":"3fa85f64...","start":24000,"length":12000}
# ---
#
# [markdown content from position 12000 to 24000]
#
```
--------------------------------
### Render Parser Details in UI
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Updates the UI to display detailed information about the selected parser, including its label, readiness status, description, facts, and setup instructions. Handles cases where no parser is selected.
```javascript
function renderParserDetails() { const parser = getSelectedParserRecord(); if (!parser) { parserDetailTitle.textContent = "Select a parser"; parserDetailBadge.textContent = "Waiting"; parserDetailHeadline.textContent = "Choose a parser to see which workflow fits your documents."; parserDetailBestFor.textContent = "Pick the option that matches your document type, privacy requirements, and setup tolerance."; parserDetailFacts.innerHTML = ""; parserDetailPositioning.textContent = ""; parserDetailSetup.textContent = ""; parserDetailSteps.innerHTML = ""; parserDetailCommandsLabel.style.display = "none"; parserDetailCommands.innerHTML = ""; return; } const ready = isSelectedParserReady(); parserDetailTitle.textContent = parser.label; parserDetailBadge.textContent = ready ? "Ready" : "Setup required"; parserDetailHeadline.textContent = parser.headline || parser.description; parserDetailBestFor.textContent = parser.best_for || parser.description; parserDetailFacts.innerHTML = ""; parserDetailPositioning.textContent = parser.positioning || ""; parserDetailSetup.innerHTML = `${parser.setup}`; parserDetailSteps.innerHTML = ""; parserDetailCommands.innerHTML = ""; parserDetailCommandsLabel.style.display = (parser.commands || []).length ? "block" : "none"; for (const fact of parser.facts || []) { const card = document.createElement("div"); card.className = "parser-fact"; card.innerHTML = ` ${fact.label}
${fact.value}
`; parserDetailFacts.appendChild(card); } for (const step of parser.instructions || []) { const item = document.createElement("li"); item.textContent = step; parserDetailSteps.appendChild(item); } if (parser.requires_user_key && !markerApiKeyInput.value.trim()) { const item = document.createElement("li"); item.textContent = "Upload is locked until you enter your own Datalab API key below."; parserDetailSteps.appendChild(item); } else if (!parser.configured) { const item = document.createElement("li"); item.textContent = "Upload is locked until PaperFlow detects that this parser is configured."; parserDetailSteps.appendChild(item); } for (const command of parser.commands || []) { const block = document.createElement("pre"); block.className = "parser-command"; block.textContent = command; parserDetailCommands.appendChild(block); } }
```
--------------------------------
### Use PaperFlow to Convert PDF via Claude Desktop Chat
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
Examples of how to invoke the PaperFlow conversion tool using natural language prompts within Claude Desktop. Supports various input types and parser selection.
```text
# In Claude Desktop chat:
"Use PaperFlow to convert https://arxiv.org/pdf/1706.03762"
```
```text
# Convert a local file
"Use PaperFlow with best parser on C:\Users\you\Desktop\paper.pdf"
```
```text
# Use fast local mode
"Use PaperFlow in fast mode on /home/user/papers/report.pdf"
```
```text
# Force a specific parser
"Use PaperFlow with parser=paddleocr_vl on this scanned PDF: /tmp/scan.pdf"
```
--------------------------------
### Get Selected Parser Record
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Retrieves the configuration object for the currently selected parser from the catalog. Returns null if no parser is selected.
```javascript
function getSelectedParserRecord() { return parserCatalog.get(selectedParser) || null; }
```
--------------------------------
### Python Post-processing with PaperFlow
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/index.html
Install the paperflow-postprocess package to enhance raw Markdown output. This function can be used to refine text, add metadata, and prepare it for Markdown editors.
```python
from paperflow_postprocess import enhance
raw_md = open("parser_output.md").read()
result = enhance(raw_md, images={}, metadata={"title": "My Paper"})
```
--------------------------------
### Initialize UI Element References
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Selects all necessary DOM elements for the PaperFlow application. Ensure these elements exist in the HTML before this script runs.
```javascript
const parserGrid = document.getElementById("parser-grid");
const parserBadge = document.getElementById("parser-badge");
const dropzone = document.getElementById("dropzone");
const fileInput = document.getElementById("file-input");
const fileName = document.getElementById("file-name");
const convertButton = document.getElementById("convert-button");
const batchButton = document.getElementById("batch-button");
const clearButton = document.getElementById("clear-button");
const jobStatus = document.getElementById("job-status");
const statusLog = document.getElementById("status-log");
const preview = document.getElementById("preview");
const downloadMarkdown = document.getElementById("download-markdown");
const downloadPackage = document.getElementById("download-package");
const selectedFilesEl = document.getElementById("selected-files");
const progressBar = document.getElementById("progress-bar");
const batchList = document.getElementById("batch-list");
const markerApiKeyShell = document.getElementById("marker-api-key-shell");
const markerApiKeyInput = document.getElementById("marker-api-key");
const parserDetailTitle = document.getElementById("parser-detail-title");
const parserDetailBadge = document.getElementById("parser-detail-badge");
const parserDetailHeadline = document.getElementById("parser-detail-headline");
const parserDetailBestFor = document.getElementById("parser-detail-best-for");
const parserDetailFacts = document.getElementById("parser-detail-facts");
const parserDetailPositioning = document.getElementById("parser-detail-positioning");
const parserDetailSetup = document.getElementById("parser-detail-setup");
const parserDetailSteps = document.getElementById("parser-detail-steps");
const parserDetailCommandsLabel = document.getElementById("parser-detail-commands-label");
const parserDetailCommands = document.getElementById("parser-detail-commands");
```
--------------------------------
### PaperFlow Local API - Get Job Result
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/index.html
Retrieve the processed Markdown file for a given job ID.
```APIDOC
## GET /api/jobs/{job_id}/result
### Description
Retrieves the processed Markdown file for a specific job.
### Method
GET
### Endpoint
/api/jobs//result
### Parameters
#### Path Parameters
- **job_id** (string) - Required - The ID of the job.
### Response
#### Success Response (200)
- **file content** (file) - The processed Markdown file.
```
--------------------------------
### MCP Call for `get_markdown_chunk`
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
The JSON payload structure for invoking the `get_markdown_chunk` tool programmatically. Specify the `job_id`, `start` position, and `length` of the desired chunk.
```json
# Equivalent MCP call (tool input):
{
"job_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"start": 12000,
"length": 12000
}
```
--------------------------------
### Run Benchmark Report
Source: https://github.com/tylermorrison21/paperflow/blob/master/mcp-server/README.md
Commands to prepare and run the benchmark report for the PaperFlow MCP Server.
```bash
cp benchmark/results.template.csv benchmark/results.csv
npm run bench:report
```
--------------------------------
### Enable Download Links
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Sets the href attributes and dataset properties for markdown and zip download links based on the provided job ID. Enables the download buttons.
```javascript
function enableDownloads(jobId) {
downloadMarkdown.href = "#";
downloadPackage.href = "#";
downloadMarkdown.dataset.url = `/api/jobs/${jobId}/result`;
downloadPackage.dataset.url = `/api/jobs/${jobId}/package`;
downloadMarkdown.dataset.filename = `paperflow-${jobId}.md`;
downloadPackage.dataset.filename = `paperflow-${jobId}.zip`;
downloadMarkdown.classList.remove("disabled");
downloadPackage.classList.remove("disabled");
}
```
--------------------------------
### Get Parser Display Label
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Retrieves the user-friendly label for a given parser ID from the parser catalog. Defaults to 'Unknown parser' if the ID is not found.
```javascript
function getParserLabel(parserId) {
return parserCatalog.get(parserId)?.label || parserId || "Unknown parser";
}
```
--------------------------------
### Build and Run PaperFlow Locally with Docker
Source: https://github.com/tylermorrison21/paperflow/blob/master/README.md
Build the PaperFlow Docker image locally from the repository and then run it, mapping ports and volumes. This allows for local development and testing.
```bash
docker build -t paperflow .
docker run --name paperflow \
-p 8000:8000 \
-e DATA_DIR=/data/jobs \
-v $(pwd)/data:/data \
--restart unless-stopped \
paperflow
```
--------------------------------
### Run MCP Savings Benchmark Report
Source: https://github.com/tylermorrison21/paperflow/blob/master/mcp-server/benchmark/README.md
Execute the benchmark report from the mcp-server directory. This command generates a report based on the benchmark results.
```bash
npm run bench:report
```
--------------------------------
### PaperFlow Local API - Get Job Package
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/index.html
Retrieve a zip package containing the processed file and any associated assets for a given job ID.
```APIDOC
## GET /api/jobs/{job_id}/package
### Description
Retrieves a zip package containing the processed output and assets for a specific job.
### Method
GET
### Endpoint
/api/jobs//package
### Parameters
#### Path Parameters
- **job_id** (string) - Required - The ID of the job.
### Response
#### Success Response (200)
- **file content** (file) - A zip archive containing the processed output.
```
--------------------------------
### Download Markdown and Images Package
Source: https://github.com/tylermorrison21/paperflow/blob/master/README.md
Download a zip package containing the processed markdown and associated images for a completed job.
```bash
curl http://localhost:8000/api/jobs//package -o paperflow.zip
```
--------------------------------
### Download ZIP Bundle with Markdown and Images
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
Download a ZIP archive containing the processed Markdown file and a directory of extracted images for a completed job.
```bash
JOB_ID="3fa85f64-5717-4562-b3fc-2c963f66afa6"
curl http://localhost:8000/api/jobs/$JOB_ID/package -o paperflow.zip
# Unzip and inspect
unzip paperflow.zip -d output/
ls output/
# paper.md
# images/
# figure-1.png
# figure-2.png
```
--------------------------------
### Handle Download Button Click
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Configures download links based on the batch ID. Use this function when a user interacts with a download button.
```javascript
chDownload(batchId) { downloadMarkdown.classList.add("disabled"); delete downloadMarkdown.dataset.url; delete downloadMarkdown.dataset.filename; downloadMarkdown.removeAttribute("href"); downloadPackage.href = "#"; downloadPackage.dataset.url = `/api/batches/${batchId}/package`; downloadPackage.dataset.filename = `paperflow-batch-${batchId}.zip`; downloadPackage.classList.remove("disabled"); }
```
--------------------------------
### Trigger File Download
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Initiates a file download by fetching a URL, creating a blob, and simulating a click on a temporary link. Ensure the anchor element has `data-url` and optionally `data-filename` attributes.
```javascript
async function triggerDownload(anchor) { if (anchor.classList.contains("disabled")) { return; } const url = anchor.dataset.url; const filename = anchor.dataset.filename || "download"; if (!url) { return; } const response = await fetch(url); if (!response.ok) { setStatus("Error", `Download failed: ${response.status}`, "error"); return; } const blob = await response.blob(); const blobUrl = URL.createObjectURL(blob); const tempLink = document.createElement("a"); tempLink.href = blobUrl; tempLink.download = filename; document.body.appendChild(tempLink); tempLink.click(); tempLink.remove(); URL.revokeObjectURL(blobUrl); }
```
--------------------------------
### Initialize Application State Variables
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Sets up initial state variables for the PaperFlow application, including parser catalog, selected files, and job IDs. These variables manage the application's dynamic behavior.
```javascript
let selectedParser = null;
let parserCatalog = new Map();
let selectedFiles = [];
let activeJobId = null;
let activeBatchId = null;
let activeParserLabel = "";
let pollTimer = null;
let parserRefreshTimer = null;
```
--------------------------------
### Run MCP Savings Benchmark Report with Template Data
Source: https://github.com/tylermorrison21/paperflow/blob/master/mcp-server/benchmark/README.md
Execute the benchmark report using template data. This is useful for testing the report generation process without real data.
```bash
npm run bench:report:template
```
--------------------------------
### Input Synchronization and Button Event Listeners
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Sets up event listeners for input changes and button clicks to trigger file submission and batch processing. Also includes synchronization logic for parser requirements.
```javascript
markerApiKeyInput.addEventListener("input", syncParserRequirements);
convertButton.addEventListener("click", submitFile);
batchButton.addEventListener("click", submitBatch);
downloadMarkdown.addEventListen
```
--------------------------------
### File Input and Dropzone Event Listeners
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Configures event listeners for file uploads via click and drag-and-drop. Includes logic to check parser readiness and provide user feedback during drag operations.
```javascript
dropzone.addEventListener("click", () => {
if (!isSelectedParserReady()) {
setStatus("Setup required", "Finish the selected parser setup before uploading PDFs.", "error");
return;
}
fileInput.click();
});
dropzone.addEventListener("keydown", (event) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
if (!isSelectedParserReady()) {
setStatus("Setup required", "Finish the selected parser setup before uploading PDFs.", "error");
return;
}
fileInput.click();
}
});
fileInput.addEventListener("change", (event) => handleFiles(event.target.files));
["dragenter", "dragover"].forEach((eventName) => {
dropzone.addEventListener(eventName, (event) => {
event.preventDefault();
dropzone.classList.add("dragging");
});
});
["dragleave", "drop"].forEach((eventName) => {
dropzone.addEventListener(eventName, (event) => {
event.preventDefault();
dropzone.classList.remove("dragging");
});
});
dropzone.addEventListener("drop", (event) => {
if (!isSelectedParserReady()) {
setStatus("Setup required", "Finish the selected parser setup before uploading PDFs.", "error");
return;
}
handleFiles(event.dataTransfer.files);
});
```
--------------------------------
### Render Selected Files UI
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Updates the UI to display a list of selected files with their names and sizes.
```javascript
function renderSelectedFiles() {
selectedFilesEl.innerHTML = "";
for (const file of selectedFiles) {
const pill = document.createElement("div");
pill.className = "file-pill";
pill.textContent = `${file.name} / ${(file.size / 1024 / 1024).toFixed(2)} MB`;
selectedFilesEl.appendChild(pill);
}
}
```
--------------------------------
### Check Parser Readiness
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Determines if the selected parser is ready for use, considering its configuration and whether required inputs like an API key are provided. This is crucial before enabling conversion or batch operations.
```javascript
function isSelectedParserReady() { const parser = getSelectedParserRecord(); if (!parser || !parser.configured) { return false; } if (parser.requires_user_key && !markerApiKeyInput.value.trim()) { return false; } return true; }
```
--------------------------------
### Submit PDF with Marker API Parser
Source: https://github.com/tylermorrison21/paperflow/blob/master/README.md
Submit a PDF using the Marker API parser. Requires your Datalab API key.
```bash
curl -X POST http://localhost:8000/api/submit \
-F "file=@paper.pdf" \
-F "parser=marker_api" \
-F "marker_api_key=your_datalab_api_key"
```
--------------------------------
### List available parsers
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
Retrieve a list of all supported parsers, including their configuration status and capabilities.
```APIDOC
## GET /api/parsers — List available parsers
### Description
Returns a list of all supported parsers with their configuration status, speed/quality labels, setup instructions, and CLI commands.
### Method
GET
### Endpoint
/api/parsers
### Response
#### Success Response
- **parsers** (array) - A list of available parser objects.
- **id** (string) - The unique identifier for the parser.
- **label** (string) - A human-readable name for the parser.
- **configured** (boolean) - Indicates if the parser is configured and ready to use.
- **recommended** (boolean) - Indicates if this parser is recommended.
- **default** (boolean) - Indicates if this parser is the default.
- **speed** (string) - A label describing the parser's speed (e.g., "Free", "Fastest").
- **quality** (string) - A label describing the parser's quality (e.g., "Fastest").
- **setup** (string) - Instructions or status regarding parser setup.
- **requires_user_key** (boolean) - Indicates if a user-specific API key is required.
#### Response Example
```json
{
"parsers": [
{
"id": "pymupdf",
"label": "PyMuPDF Local",
"configured": true,
"recommended": true,
"default": true,
"speed": "Free",
"quality": "Fastest",
"setup": "Ready after install. No API key and no parser-specific CLI required.",
"requires_user_key": false
},
{
"id": "paddleocr_vl",
"label": "PaddleOCR-VL-0.9B",
"configured": false,
"setup": "Install PaddleOCR, make sure the paddleocr command works..."
},
{
"id": "marker_api",
"label": "Marker API (Datalab.to)",
"configured": true,
"requires_user_key": true
},
{
"id": "marker_local",
"label": "Enterprise Marker Self-Hosted",
"configured": false
}
]
}
```
```
--------------------------------
### List PaperFlow Parsers via Claude Desktop Chat
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
Command to list available backend parsers and their status using PaperFlow through Claude Desktop's chat interface. Provides details on parser readiness, quality, and configuration notes.
```text
# In Claude Desktop chat:
"List my available PaperFlow parsers"
```
--------------------------------
### Download Markdown and Images Package
Source: https://github.com/tylermorrison21/paperflow/blob/master/README.md
Download a zip package containing the processed markdown and any extracted images for a completed job.
```APIDOC
## GET /api/jobs/{job_id}/package
### Description
Downloads a zip archive containing the processed markdown and associated images for a completed job.
### Method
GET
### Endpoint
`/api/jobs//package`
### Parameters
#### Path Parameters
- **job_id** (string) - Required - The unique identifier for the job.
### Request Example
```bash
curl http://localhost:8000/api/jobs//package -o paperflow.zip
```
### Response Example
(Response is a zip file, typically saved to a file using `-o paperflow.zip`)
```
--------------------------------
### Configure Marker API Key for Direct API Calls
Source: https://github.com/tylermorrison21/paperflow/blob/master/README.md
When making direct API calls, include the parser and your Marker API key as form data.
```bash
-F "parser=marker_api" -F "marker_api_key=your_datalab_api_key"
```
--------------------------------
### Load Parsers and Error Handling
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Initiates loading of parser options, with an option to preserve the current selection. Includes error handling to update the UI if loading fails.
```javascript
loadParsers({ preserveSelection: false }).catch((error) => { parserBadge.textContent = "Load failed"; setStatus("Error", `Failed to load parser options: ${error.message}`, "error"); });
```
--------------------------------
### Claude Desktop Config for Windows
Source: https://github.com/tylermorrison21/paperflow/blob/master/mcp-server/README.md
Configuration for Claude Desktop on Windows to use the PaperFlow MCP server, specifying the command, arguments, and environment variables.
```json
{
"mcpServers": {
"paperflow": {
"command": "cmd",
"args": ["/c", "npx", "-y", "paperflow-mcp@0.3.1"],
"env": {
"PAPERFLOW_API_URL": "http://localhost:8000"
}
}
}
}
```
--------------------------------
### Select Parser Logic
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Populates the parser selection grid and handles user clicks to pick a parser. It also determines the default or previously selected parser.
```javascript
const data = await response.json();
const parsers = data.parsers || [];
parserCatalog = new Map(parsers.map((parser) => [parser.id, parser]));
parserGrid.innerHTML = "";
for (const parser of parsers) {
const label = document.createElement("label");
label.className = "parser-option";
if (!parser.configured) {
label.classList.add("disabled");
}
label.dataset.parserId = parser.id;
label.innerHTML = `
`;
label.addEventListener("click", () => pickParser(parser.id));
parserGrid.appendChild(label);
}
const preservedParser = previousSelection && parserCatalog.has(previousSelection) ? parserCatalog.get(previousSelection) : null;
const defaultParser = parsers.find((parser) => parser.default && parser.configured) || parsers.find((parser) => parser.configured);
const parserToSelect = preservedParser?.id || defaultParser?.id || parsers[0]?.id || null;
if (parserToSelect) {
pickParser(parserToSelect);
const configuredCount = parsers.filter((parser) => parser.configured).length;
parserBadge.textContent = `${configuredCount}/${parsers.length} ready`;
} else {
parserBadge.textContent = "No parser configured";
setStatus("Blocked", "No parser is configured. Install PyMuPDF locally, add your Datalab key for Marker API, or install PaddleOCR-VL locally.", "error");
}
```
--------------------------------
### Load Available Parsers
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Fetches the list of available parsers from the API and updates the UI. Optionally preserves the current parser selection and shows a loading indicator.
```javascript
async function loadParsers({ preserveSelection = true, showLoading = true } = {}) { const previousSelection = preserveSelection ? selectedParser : null; if (showLoading) { parserBadge.textContent = "Loading"; } const response = await fetch("/api/parsers"
```
--------------------------------
### Run PaperFlow Postprocessing Helpers
Source: https://github.com/tylermorrison21/paperflow/blob/master/README.md
Apply a sequence of postprocessing functions to a markdown string. Ensure raw markdown is read with UTF-8 encoding before processing.
```python
from paperflow_postprocess import (
clean_headers_footers,
convert_to_footnotes,
fix_latex_delimiters,
linkify_figures,
linkify_tables,
)
md = open("raw.md", encoding="utf-8").read()
md = fix_latex_delimiters(md)
md = clean_headers_footers(md)
md = convert_to_footnotes(md)
md = linkify_figures(md)
md = linkify_tables(md)
```
--------------------------------
### Select a Parser
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Handles the selection of a parser by updating the UI to highlight the chosen parser and setting it as the active selection. It then synchronizes the UI with the parser's requirements.
```javascript
function pickParser(parserId) { selectedParser = parserId; document.querySelectorAll(".parser-option").forEach((card) => { const isSelected = card.dataset.parserId === parserId; card.classList.toggle("selected", isSelected); const radio = card.querySelector('input[type="radio"]'); if (radio) { radio.checked = isSelected; } }); syncParserRequirements(); }
```
--------------------------------
### Submit PDF via API
Source: https://github.com/tylermorrison21/paperflow/blob/master/README.md
Use this endpoint to submit a PDF file for processing. The default PyMuPDF parser is used.
```bash
curl -X POST http://localhost:8000/api/submit \
-F "file=@paper.pdf"
```
--------------------------------
### Handle Download Trigger
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Attaches an event listener to trigger a download action when a specific element is clicked. Prevents default behavior and calls a download function with provided data.
```javascript
er("click", async (event) => { event.preventDefault(); await triggerDownload(downloadMarkdown); });
```
```javascript
downloadPackage.addEventListener("click", async (event) => { event.preventDefault(); await triggerDownload(downloadPackage); });
```
--------------------------------
### Unraid Template Configuration
Source: https://github.com/tylermorrison21/paperflow/blob/master/docs/unraid.md
Use these values when setting up the PaperFlow container via the Unraid Community Apps template. Ensure the AppData path is correctly mapped and the DATA_DIR environment variable is set.
```text
Repository: ghcr.io/tylermorrison21/paperflow:latest
WebUI: http://[IP]:[PORT:8000]/
Container Port: 8000
AppData path: map /data to /mnt/user/appdata/paperflow
DATA_DIR=/data/jobs
```
```text
DATALAB_API_KEY=your_datalab_api_key
```
```text
http://UNRAID-IP:8000/
```
--------------------------------
### Configure Enterprise Marker Self-Hosted Command
Source: https://github.com/tylermorrison21/paperflow/blob/master/README.md
Set the MARKER_SINGLE_CMD environment variable if using a custom path for the marker_single CLI.
```env
MARKER_SINGLE_CMD=marker_single
MARKER_SINGLE_ARGS=
```
--------------------------------
### Run Full PaperFlow Post-processing Pipeline
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
Applies all five transforms plus YAML frontmatter to raw Markdown. Accepts optional image metadata and a metadata dict for title, authors, source, and date. Returns a structured Markdown string.
```python
from paperflow_postprocess import enhance
raw_markdown = """
# Attention Is All You Need
Ashish Vaswani, Noam Shazier
## Abstract
The dominant sequence transduction models [1] rely on complex RNNs or CNNs.
We propose the Transformer, based solely on attention mechanisms [2, 3].
See results in [Fig. 1] and [Table 1].
\[ E = mc^2 \]
## References
[1] Sutskever et al. Sequence to Sequence Learning. NeurIPS 2014.
[2] Bahdanau et al. Neural Machine Translation by Jointly Learning. ICLR 2015.
[3] Luong et al. Effective Approaches to Attention. EMNLP 2015.
Figure 1: Transformer architecture overview.
Table 1: BLEU scores on WMT 2014 English-to-German.
"""
result = enhance(
raw_markdown=raw_markdown,
images={},
metadata={
"title": "Attention Is All You Need",
"authors": ["Ashish Vaswani", "Noam Shazier"],
"source": "https://arxiv.org/abs/1706.03762",
"date": "2017-06-12",
},
)
print(result)
# Output begins with YAML frontmatter:
# ---
# title: "Attention Is All You Need"
# authors:
# - "Ashish Vaswani"
# - "Noam Shazier"
# source: "https://arxiv.org/abs/1706.03762"
# date: "2017-06-12"
# extracted: "2025-01-01"
# hash: "a1b2c3d4"
# tags: [paperflow, academic]
# ---
#
# Citations converted: [1] -> [^1], [2, 3] -> [^2][^3]
# LaTeX converted: \[ E = mc^2 \] -> $$ E = mc^2 $$
# Figures linked: [Fig. 1] -> [[#^fig-1|Fig. 1]]
# Tables linked: [Table 1] -> [[#^tab-1|Table 1]]
# References section becomes footnote definitions [^1]: ..., [^2]: ..., [^3]: ...
```
--------------------------------
### Download ZIP bundle
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
Download a ZIP archive containing the processed Markdown and extracted images for a completed job.
```APIDOC
## GET /api/jobs/{job_id}/package — Download ZIP bundle
### Description
Returns a ZIP archive containing `paper.md` and an `images/` directory with all extracted figures.
### Method
GET
### Endpoint
/api/jobs/{job_id}/package
### Parameters
#### Path Parameters
- **job_id** (string) - Required - The unique identifier for the job.
### Response
#### Success Response (200)
Content-Type: application/zip
### Response Example
```bash
curl http://localhost:8000/api/jobs/$JOB_ID/package -o paperflow.zip
```
**Archive Contents:**
- `paper.md`: The processed Markdown file.
- `images/`: A directory containing all extracted figures.
```
--------------------------------
### Claude Desktop Config for macOS/Linux
Source: https://github.com/tylermorrison21/paperflow/blob/master/mcp-server/README.md
Configuration for Claude Desktop on macOS and Linux to use the PaperFlow MCP server, specifying the command, arguments, and environment variables.
```json
{
"mcpServers": {
"paperflow": {
"command": "npx",
"args": ["-y", "paperflow-mcp@0.3.1"],
"env": {
"PAPERFLOW_API_URL": "http://localhost:8000"
}
}
}
}
```
--------------------------------
### Download Processed Markdown
Source: https://github.com/tylermorrison21/paperflow/blob/master/README.md
Retrieve the processed markdown content for a completed job.
```bash
curl http://localhost:8000/api/jobs//result -o paper.md
```
--------------------------------
### Submit PDF for processing via `POST /api/submit`
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
Submits a PDF for asynchronous processing using `multipart/form-data`. Supports multiple parsers and caching for duplicate submissions. The response immediately returns a job ID.
```bash
# Submit with default PyMuPDF parser
curl -X POST http://localhost:8000/api/submit \
-F "file=@paper.pdf"
# {"job_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "message": "Processing. Poll /api/jobs/..."}
# Submit with Marker API parser (requires your own Datalab key)
curl -X POST http://localhost:8000/api/submit \
-F "file=@paper.pdf" \
-F "parser=marker_api" \
-F "marker_api_key=your_datalab_key_here"
# Submit with PaddleOCR-VL for scanned PDFs
curl -X POST http://localhost:8000/api/submit \
-F "file=@scanned_paper.pdf" \
-F "parser=paddleocr_vl"
```
--------------------------------
### Configure PaddleOCR-VL Command
Source: https://github.com/tylermorrison21/paperflow/blob/master/README.md
Set the PADDLEOCR_VL_CMD environment variable if using a custom path for the paddleocr executable.
```env
PADDLEOCR_VL_CMD=paddleocr
PADDLEOCR_VL_ARGS=
```
--------------------------------
### Render Batch Processing List
Source: https://github.com/tylermorrison21/paperflow/blob/master/frontend/app.html
Renders a list of items for batch processing, displaying filename, status, and any errors. Each item is represented as a div element.
```javascript
function renderBatchItems(items = []) {
batchList.innerHTML = "";
for (const item of items) {
const row = document.createElement("div");
row.className = "batch-item";
row.innerHTML = `
`;
batchList.appendChild(row);
}
}
```
--------------------------------
### enhance() — Full post-processing pipeline
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
The primary entry point for PaperFlow. Applies all five transforms plus YAML frontmatter to raw Markdown from any PDF parser. Accepts optional image metadata and a metadata dict for title, authors, source, and date. Returns a structured Markdown string ready for knowledge bases or RAG pipelines.
```APIDOC
## enhance()
### Description
Applies all five transforms plus YAML frontmatter to raw Markdown from any PDF parser. Accepts optional image metadata and a metadata dict for title, authors, source, and date. Returns a structured Markdown string ready for knowledge bases or RAG pipelines.
### Parameters
- **raw_markdown** (str) - Required - The raw Markdown string to process.
- **images** (dict) - Optional - Metadata for images.
- **metadata** (dict) - Optional - Metadata for the document, including title, authors, source, and date.
### Returns
- **str** - The structured Markdown string.
### Request Example
```python
from paperflow_postprocess import enhance
raw_markdown = """
# Attention Is All You Need
Ashish Vaswani, Noam Shazier
## Abstract
The dominant sequence transduction models [1] rely on complex RNNs or CNNs.
We propose the Transformer, based solely on attention mechanisms [2, 3].
See results in [Fig. 1] and [Table 1].
\[ E = mc^2 \]
## References
[1] Sutskever et al. Sequence to Sequence Learning. NeurIPS 2014.
[2] Bahdanau et al. Neural Machine Translation by Jointly Learning. ICLR 2015.
[3] Luong et al. Effective Approaches to Attention. EMNLP 2015.
Figure 1: Transformer architecture overview.
Table 1: BLEU scores on WMT 2014 English-to-German.
"""
result = enhance(
raw_markdown=raw_markdown,
images={},
metadata={
"title": "Attention Is All You Need",
"authors": ["Ashish Vaswani", "Noam Shazier"],
"source": "https://arxiv.org/abs/1706.03762",
"date": "2017-06-12",
},
)
print(result)
```
### Response Example
```
---
title: "Attention Is All You Need"
authors:
- "Ashish Vaswani"
- "Noam Shazier"
source: "https://arxiv.org/abs/1706.03762"
date: "2017-06-12"
extracted: "2025-01-01"
hash: "a1b2c3d4"
tags: [paperflow, academic]
---
Citations converted: [1] -> [^1], [2, 3] -> [^2][^3]
LaTeX converted: \[ E = mc^2 \] -> $$ E = mc^2 $$
Figures linked: [Fig. 1] -> [[#^fig-1|Fig. 1]]
Tables linked: [Table 1] -> [[#^tab-1|Table 1]]
References section becomes footnote definitions [^1]: ..., [^2]: ..., [^3]: ...
```
```
--------------------------------
### Submit PDF with PaddleOCR-VL Parser
Source: https://github.com/tylermorrison21/paperflow/blob/master/README.md
Submit a PDF using the PaddleOCR-VL parser, suitable for scanned documents and complex layouts.
```bash
curl -X POST http://localhost:8000/api/submit \
-F "file=@paper.pdf" \
-F "parser=paddleocr_vl"
```
--------------------------------
### Configure Environment Variables for PaperFlow
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
This file contains essential configuration variables for the PaperFlow application, including API keys, file paths, and operational limits. Ensure these are set correctly before running the application.
```env
DATALAB_API_KEY=your_datalab_key_here # For Marker API parser
MARKER_API_URL=https://www.datalab.to/api/v1/marker
MARKER_SINGLE_CMD=marker_single # Path to marker_single CLI
MARKER_SINGLE_ARGS= # Extra flags for marker_single
PADDLEOCR_VL_CMD=paddleocr # Path to paddleocr CLI
PADDLEOCR_VL_ARGS= # Extra flags for paddleocr
RESEND_API_KEY= # For email delivery (optional)
FROM_EMAIL=delivery@paperflowing.com
CORS_ORIGINS=*
DATA_DIR=./data/jobs
DAILY_SUBMISSION_LIMIT=300
MONTHLY_PAGE_LIMIT=8000
PER_EMAIL_DAILY_LIMIT=3
MAX_FILE_SIZE_MB=15
MAX_PAGES=15
```
--------------------------------
### Configure Claude Desktop MCP Servers
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
Configuration for PaperFlow's MCP server within Claude Desktop on macOS/Linux. Ensure the PAPERFLOW_API_URL is set to your local PaperFlow instance.
```json
// Claude Desktop config (macOS/Linux): ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"paperflow": {
"command": "npx",
"args": ["-y", "paperflow-mcp@0.3.1"],
"env": {
"PAPERFLOW_API_URL": "http://localhost:8000",
"PAPERFLOW_MARKER_API_KEY": "your_datalab_key_optional"
}
}
}
}
```
--------------------------------
### Download combined batch package
Source: https://context7.com/tylermorrison21/paperflow/llms.txt
Download a ZIP archive containing all processed papers and their associated images from a batch job.
```APIDOC
## GET /api/batches/{batch_id}/package — Download ZIP bundle
### Description
Returns a ZIP archive containing processed Markdown files and extracted images for all papers in a batch job. Each paper will have its own subdirectory.
### Method
GET
### Endpoint
/api/batches/{batch_id}/package
### Parameters
#### Path Parameters
- **batch_id** (string) - Required - The unique identifier for the batch job.
### Response
#### Success Response (200)
Content-Type: application/zip
### Response Example
```bash
curl http://localhost:8000/api/batches/abc12345-.../package -o batch.zip
```
**Archive Contents:**
- `paper1/paper.md`: Processed Markdown for the first paper.
- `paper1/images/*`: Extracted images for the first paper.
- `paper2/paper.md`: Processed Markdown for the second paper.
- `paper2/images/*`: Extracted images for the second paper.
- `summary.json`: A summary file for the batch.
```