# DotsOCR API - Complete Usage Guide ## Base URL ``` https://isseygino911-dots-ocr-parser.hf.space ``` --- ## Table of Contents 1. [Quick Start](#quick-start) 2. [API Endpoints](#api-endpoints) 3. [Backend Examples (Python)](#backend-examples-python) 4. [Frontend Examples (JavaScript)](#frontend-examples-javascript) 5. [React Integration](#react-integration) 6. [Complete Workflows](#complete-workflows) 7. [Error Handling](#error-handling) --- ## Quick Start ### Test Your API (Command Line) ```bash # 1. Health check curl https://isseygino911-dots-ocr-parser.hf.space/health # 2. Upload an image curl -X POST https://isseygino911-dots-ocr-parser.hf.space/api/parse/image \ -F "file=@image.jpg" \ -F "prompt_mode=prompt_layout_all_en" # Response: {"job_id": "abc-123-def", "status": "queued"} # 3. Check status curl https://isseygino911-dots-ocr-parser.hf.space/api/jobs/abc-123-def/status # 4. Get results curl https://isseygino911-dots-ocr-parser.hf.space/api/jobs/abc-123-def/results ``` --- ## API Endpoints ### 1. Health Check **GET** `/health` Check if the API is running and GPU is available. **Response:** ```json { "status": "healthy", "gpu_available": true } ``` --- ### 2. Upload Image **POST** `/api/parse/image` Upload and parse an image file. **Parameters:** - `file` (required): Image file (multipart/form-data) - `prompt_mode` (optional): Parsing mode - `prompt_layout_all_en` (default) - Full layout + text - `prompt_layout_only_en` - Layout only, no text - `prompt_ocr` - Text extraction only **Supported Formats:** `.jpg`, `.jpeg`, `.png`, `.bmp`, `.tiff`, `.tif`, `.gif`, `.webp` **Response:** ```json { "job_id": "550e8400-e29b-41d4-a716-446655440000", "status": "queued" } ``` --- ### 3. Upload PDF **POST** `/api/parse/pdf` Upload and parse a PDF document (processes all pages). **Parameters:** - `file` (required): PDF file (multipart/form-data) - `prompt_mode` (optional): Same as image endpoint **Response:** ```json { "job_id": "550e8400-e29b-41d4-a716-446655440000", "status": "queued" } ``` --- ### 4. Get Job Status **GET** `/api/jobs/{job_id}/status` Monitor processing progress. **Response:** ```json { "job_id": "550e8400-e29b-41d4-a716-446655440000", "status": "processing", "file_type": "pdf", "filename": "document.pdf", "total_pages": 10, "current_page": 5, "progress_percent": 50.0, "message": "Processing page 5/10...", "created_at": "2024-01-01T10:00:00", "updated_at": "2024-01-01T10:02:30" } ``` **Status values:** - `queued` - Waiting to be processed - `processing` - Currently processing - `completed` - Successfully completed - `failed` - Error occurred --- ### 5. Get Results **GET** `/api/jobs/{job_id}/results` Retrieve parsed document data. **Response:** ```json { "job_id": "550e8400-e29b-41d4-a716-446655440000", "status": "completed", "results": { "pages": [ { "page_number": 1, "markdown": "# Document Title\n\nThis is the extracted text...", "json_output": { "bboxes": [[100, 200, 500, 250], [100, 300, 500, 400]], "labels": ["title", "paragraph"], "pred_text": ["Document Title", "This is the extracted text..."] }, "annotated_image_path": "/api/results/550e8400-.../test/page_1.png" } ] }, "download_url": "/api/jobs/550e8400-e29b-41d4-a716-446655440000/download" } ``` --- ### 6. Download ZIP **GET** `/api/jobs/{job_id}/download` Download all results as a ZIP file. **Response:** Binary ZIP file containing: - Annotated images with bounding boxes (PNG) - JSON files with structured data - Markdown files with extracted text --- ### 7. WebSocket Progress Stream **WS** `/api/jobs/{job_id}/stream` Real-time progress updates via WebSocket. **Message Format:** ```json { "event": "status_update", "data": { "job_id": "550e8400-...", "status": "processing", "progress_percent": 50.0, "message": "Processing page 5/10..." } } ``` --- ## Backend Examples (Python) ### Basic Upload and Poll ```python import requests import time API_BASE = "https://isseygino911-dots-ocr-parser.hf.space" # 1. Upload file with open("document.pdf", "rb") as f: response = requests.post( f"{API_BASE}/api/parse/pdf", files={"file": f}, data={"prompt_mode": "prompt_layout_all_en"} ) job_id = response.json()["job_id"] print(f"Job ID: {job_id}") # 2. Poll for completion while True: status_resp = requests.get(f"{API_BASE}/api/jobs/{job_id}/status") status = status_resp.json() print(f"Progress: {status['progress_percent']:.0f}% - {status['message']}") if status["status"] == "completed": break elif status["status"] == "failed": print(f"Error: {status.get('error')}") break time.sleep(2) # 3. Get results results = requests.get(f"{API_BASE}/api/jobs/{job_id}/results").json() print(f"Processed {len(results['results']['pages'])} pages") # 4. Download ZIP zip_response = requests.get(f"{API_BASE}/api/jobs/{job_id}/download") with open("results.zip", "wb") as f: f.write(zip_response.content) ``` --- ### Using WebSocket for Real-Time Updates ```python import asyncio import websockets import json async def monitor_job(job_id): uri = f"wss://isseygino911-dots-ocr-parser.hf.space/api/jobs/{job_id}/stream" async with websockets.connect(uri) as websocket: while True: message = await websocket.recv() data = json.loads(message) status = data['data'] print(f"Status: {status['status']} - {status['progress_percent']:.0f}%") if status['status'] in ['completed', 'failed']: break # Usage asyncio.run(monitor_job("your-job-id")) ``` --- ### Flask Backend Integration ```python from flask import Flask, request, jsonify import requests app = Flask(__name__) API_BASE = "https://isseygino911-dots-ocr-parser.hf.space" @app.route('/api/ocr', methods=['POST']) def ocr_upload(): # Receive file from your frontend if 'file' not in request.files: return jsonify({"error": "No file provided"}), 400 file = request.files['file'] # Forward to DotsOCR API files = {'file': (file.filename, file.stream, file.content_type)} data = {'prompt_mode': request.form.get('prompt_mode', 'prompt_layout_all_en')} response = requests.post( f"{API_BASE}/api/parse/image", files=files, data=data ) return jsonify(response.json()) @app.route('/api/ocr/status/') def ocr_status(job_id): response = requests.get(f"{API_BASE}/api/jobs/{job_id}/status") return jsonify(response.json()) if __name__ == '__main__': app.run(debug=True) ``` --- ## Frontend Examples (JavaScript) ### Vanilla JavaScript - Upload and Monitor ```html DotsOCR Upload

Document OCR

``` --- ### Using Fetch API with Async/Await ```javascript const API_BASE = 'https://isseygino911-dots-ocr-parser.hf.space'; // Upload file async function uploadDocument(file) { const formData = new FormData(); formData.append('file', file); formData.append('prompt_mode', 'prompt_layout_all_en'); const endpoint = file.name.endsWith('.pdf') ? '/api/parse/pdf' : '/api/parse/image'; const response = await fetch(`${API_BASE}${endpoint}`, { method: 'POST', body: formData }); return await response.json(); } // Check status async function checkStatus(jobId) { const response = await fetch(`${API_BASE}/api/jobs/${jobId}/status`); return await response.json(); } // Get results async function getResults(jobId) { const response = await fetch(`${API_BASE}/api/jobs/${jobId}/results`); return await response.json(); } // Complete workflow async function processDocument(file) { try { // 1. Upload const { job_id } = await uploadDocument(file); console.log('Job ID:', job_id); // 2. Poll for completion while (true) { const status = await checkStatus(job_id); console.log(`Progress: ${status.progress_percent}%`); if (status.status === 'completed') { break; } else if (status.status === 'failed') { throw new Error(status.error); } await new Promise(resolve => setTimeout(resolve, 2000)); } // 3. Get results const results = await getResults(job_id); console.log('Results:', results); return results; } catch (error) { console.error('Error:', error); throw error; } } // Usage const fileInput = document.getElementById('fileInput'); fileInput.addEventListener('change', async (e) => { const file = e.target.files[0]; if (file) { const results = await processDocument(file); console.log('Processing complete!', results); } }); ``` --- ### Using WebSocket for Real-Time Updates ```javascript function monitorJobWithWebSocket(jobId, onUpdate, onComplete) { const ws = new WebSocket( `wss://isseygino911-dots-ocr-parser.hf.space/api/jobs/${jobId}/stream` ); ws.onopen = () => { console.log('WebSocket connected'); }; ws.onmessage = (event) => { const message = JSON.parse(event.data); const status = message.data; // Call update callback onUpdate(status); // Check if completed if (status.status === 'completed') { onComplete(status); ws.close(); } else if (status.status === 'failed') { onComplete(status); ws.close(); } }; ws.onerror = (error) => { console.error('WebSocket error:', error); // Fallback to HTTP polling pollJobStatus(jobId, onUpdate, onComplete); }; return ws; } // Usage const ws = monitorJobWithWebSocket( 'job-id-here', (status) => { console.log(`Progress: ${status.progress_percent}%`); document.getElementById('progress').textContent = `${status.progress_percent.toFixed(0)}%`; }, (status) => { console.log('Job completed!', status); displayResults(status.job_id); } ); ``` --- ## React Integration ### Complete React Component ```jsx import React, { useState, useCallback } from 'react'; import axios from 'axios'; const API_BASE = 'https://isseygino911-dots-ocr-parser.hf.space'; function DocumentOCR() { const [file, setFile] = useState(null); const [jobId, setJobId] = useState(null); const [status, setStatus] = useState(null); const [results, setResults] = useState(null); const [uploading, setUploading] = useState(false); // Handle file selection const handleFileChange = (e) => { setFile(e.target.files[0]); setJobId(null); setStatus(null); setResults(null); }; // Upload file const handleUpload = async () => { if (!file) return; setUploading(true); const formData = new FormData(); formData.append('file', file); formData.append('prompt_mode', 'prompt_layout_all_en'); const endpoint = file.name.toLowerCase().endsWith('.pdf') ? '/api/parse/pdf' : '/api/parse/image'; try { const response = await axios.post(`${API_BASE}${endpoint}`, formData); const { job_id } = response.data; setJobId(job_id); startPolling(job_id); } catch (error) { console.error('Upload failed:', error); alert('Upload failed'); } finally { setUploading(false); } }; // Poll for status const startPolling = useCallback((jobId) => { const interval = setInterval(async () => { try { const response = await axios.get(`${API_BASE}/api/jobs/${jobId}/status`); const statusData = response.data; setStatus(statusData); if (statusData.status === 'completed') { clearInterval(interval); fetchResults(jobId); } else if (statusData.status === 'failed') { clearInterval(interval); alert('Processing failed: ' + statusData.error); } } catch (error) { console.error('Status check failed:', error); } }, 2000); return () => clearInterval(interval); }, []); // Fetch results const fetchResults = async (jobId) => { try { const response = await axios.get(`${API_BASE}/api/jobs/${jobId}/results`); setResults(response.data); } catch (error) { console.error('Failed to fetch results:', error); } }; return (

Document OCR

{/* File Upload */}
{/* Status */} {status && (

Status: {status.status}

{status.message}

{status.total_pages > 1 && (

Page {status.current_page} of {status.total_pages}

)}
)} {/* Results */} {results && (

Results ({results.results.pages.length} page(s))

{results.results.pages.map((page) => (

Page {page.page_number}

{/* Markdown Preview */}

Extracted Text:

                                    {page.markdown.substring(0, 500)}
                                    {page.markdown.length > 500 && '...'}
                                
{/* Detected Elements */}

Detected Elements:

{page.json_output.labels.length} elements found: {' '} {[...new Set(page.json_output.labels)].join(', ')}

))} {/* Download Button */} Download ZIP
)}
); } export default DocumentOCR; ``` --- ### React with WebSocket ```jsx import React, { useState, useEffect } from 'react'; const API_BASE = 'https://isseygino911-dots-ocr-parser.hf.space'; function useWebSocketProgress(jobId) { const [status, setStatus] = useState(null); useEffect(() => { if (!jobId) return; const ws = new WebSocket( `wss://isseygino911-dots-ocr-parser.hf.space/api/jobs/${jobId}/stream` ); ws.onmessage = (event) => { const message = JSON.parse(event.data); setStatus(message.data); }; ws.onerror = (error) => { console.error('WebSocket error:', error); }; return () => { ws.close(); }; }, [jobId]); return status; } // Usage in component function MyComponent({ jobId }) { const status = useWebSocketProgress(jobId); if (!status) return
Loading...
; return (

Status: {status.status}

Progress: {status.progress_percent}%

); } ``` --- ## Complete Workflows ### Workflow 1: Simple Upload and Download ```javascript async function simpleWorkflow(file) { const API_BASE = 'https://isseygino911-dots-ocr-parser.hf.space'; // 1. Upload const formData = new FormData(); formData.append('file', file); const uploadResp = await fetch(`${API_BASE}/api/parse/image`, { method: 'POST', body: formData }); const { job_id } = await uploadResp.json(); // 2. Wait for completion let status; do { await new Promise(resolve => setTimeout(resolve, 2000)); const statusResp = await fetch(`${API_BASE}/api/jobs/${job_id}/status`); status = await statusResp.json(); } while (status.status === 'processing' || status.status === 'queued'); // 3. Download results const downloadUrl = `${API_BASE}/api/jobs/${job_id}/download`; window.open(downloadUrl, '_blank'); } ``` --- ### Workflow 2: Batch Processing ```javascript async function processBatch(files) { const API_BASE = 'https://isseygino911-dots-ocr-parser.hf.space'; const results = []; for (const file of files) { const formData = new FormData(); formData.append('file', file); const uploadResp = await fetch(`${API_BASE}/api/parse/image`, { method: 'POST', body: formData }); const { job_id } = await uploadResp.json(); results.push({ filename: file.name, job_id }); } // Monitor all jobs const completed = []; while (completed.length < results.length) { for (const job of results) { if (completed.includes(job.job_id)) continue; const statusResp = await fetch(`${API_BASE}/api/jobs/${job.job_id}/status`); const status = await statusResp.json(); if (status.status === 'completed') { completed.push(job.job_id); console.log(`${job.filename} completed`); } } await new Promise(resolve => setTimeout(resolve, 2000)); } return results; } ``` --- ## Error Handling ### Best Practices ```javascript async function robustUpload(file) { const API_BASE = 'https://isseygino911-dots-ocr-parser.hf.space'; const MAX_RETRIES = 3; const TIMEOUT = 300000; // 5 minutes try { // 1. Upload with retry let uploadResp; for (let i = 0; i < MAX_RETRIES; i++) { try { const formData = new FormData(); formData.append('file', file); uploadResp = await fetch(`${API_BASE}/api/parse/image`, { method: 'POST', body: formData }); if (uploadResp.ok) break; if (i === MAX_RETRIES - 1) { throw new Error('Upload failed after retries'); } await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); } catch (error) { if (i === MAX_RETRIES - 1) throw error; } } const { job_id } = await uploadResp.json(); // 2. Poll with timeout const startTime = Date.now(); while (true) { if (Date.now() - startTime > TIMEOUT) { throw new Error('Processing timeout'); } const statusResp = await fetch(`${API_BASE}/api/jobs/${job_id}/status`); if (!statusResp.ok) { throw new Error(`Status check failed: ${statusResp.status}`); } const status = await statusResp.json(); if (status.status === 'completed') { return await fetch(`${API_BASE}/api/jobs/${job_id}/results`) .then(r => r.json()); } if (status.status === 'failed') { throw new Error(`Processing failed: ${status.error}`); } await new Promise(resolve => setTimeout(resolve, 2000)); } } catch (error) { console.error('Error:', error); // Handle specific errors if (error.message.includes('timeout')) { alert('Processing is taking longer than expected. Please try again later.'); } else if (error.message.includes('failed')) { alert('Processing failed. Please check your file and try again.'); } else { alert('An error occurred. Please try again.'); } throw error; } } ``` --- ## Performance Tips 1. **Use WebSocket for large PDFs** - More efficient than polling for documents with many pages 2. **Poll interval** - Use 2-3 seconds for polling to balance responsiveness and server load 3. **Timeout handling** - Set appropriate timeouts based on file size (60s for images, 300s for PDFs) 4. **Batch processing** - Process files sequentially to avoid overwhelming the server 5. **Error recovery** - Implement retry logic with exponential backoff --- ## Support For issues or questions: - API Documentation: `https://isseygino911-dots-ocr-parser.hf.space/docs` - Test your integration at: [Interactive API Docs](https://isseygino911-dots-ocr-parser.hf.space/docs) --- **Built with DotsOCR** - 1.7B parameter Vision-Language Model for Document Understanding