isseygino911/dots-ocr-parser
0
1# DotsOCR API - Complete Usage Guide2 3## Base URL4```5https://isseygino911-dots-ocr-parser.hf.space6```7 8---9 10## Table of Contents111. [Quick Start](#quick-start)122. [API Endpoints](#api-endpoints)133. [Backend Examples (Python)](#backend-examples-python)144. [Frontend Examples (JavaScript)](#frontend-examples-javascript)155. [React Integration](#react-integration)166. [Complete Workflows](#complete-workflows)177. [Error Handling](#error-handling)18 19---20 21## Quick Start22 23### Test Your API (Command Line)24```bash25# 1. Health check26curl https://isseygino911-dots-ocr-parser.hf.space/health27 28# 2. Upload an image29curl -X POST https://isseygino911-dots-ocr-parser.hf.space/api/parse/image \30 -F "file=@image.jpg" \31 -F "prompt_mode=prompt_layout_all_en"32 33# Response: {"job_id": "abc-123-def", "status": "queued"}34 35# 3. Check status36curl https://isseygino911-dots-ocr-parser.hf.space/api/jobs/abc-123-def/status37 38# 4. Get results39curl https://isseygino911-dots-ocr-parser.hf.space/api/jobs/abc-123-def/results40```41 42---43 44## API Endpoints45 46### 1. Health Check47**GET** `/health`48 49Check if the API is running and GPU is available.50 51**Response:**52```json53{54 "status": "healthy",55 "gpu_available": true56}57```58 59---60 61### 2. Upload Image62**POST** `/api/parse/image`63 64Upload and parse an image file.65 66**Parameters:**67- `file` (required): Image file (multipart/form-data)68- `prompt_mode` (optional): Parsing mode69 - `prompt_layout_all_en` (default) - Full layout + text70 - `prompt_layout_only_en` - Layout only, no text71 - `prompt_ocr` - Text extraction only72 73**Supported Formats:** `.jpg`, `.jpeg`, `.png`, `.bmp`, `.tiff`, `.tif`, `.gif`, `.webp`74 75**Response:**76```json77{78 "job_id": "550e8400-e29b-41d4-a716-446655440000",79 "status": "queued"80}81```82 83---84 85### 3. Upload PDF86**POST** `/api/parse/pdf`87 88Upload and parse a PDF document (processes all pages).89 90**Parameters:**91- `file` (required): PDF file (multipart/form-data)92- `prompt_mode` (optional): Same as image endpoint93 94**Response:**95```json96{97 "job_id": "550e8400-e29b-41d4-a716-446655440000",98 "status": "queued"99}100```101 102---103 104### 4. Get Job Status105**GET** `/api/jobs/{job_id}/status`106 107Monitor processing progress.108 109**Response:**110```json111{112 "job_id": "550e8400-e29b-41d4-a716-446655440000",113 "status": "processing",114 "file_type": "pdf",115 "filename": "document.pdf",116 "total_pages": 10,117 "current_page": 5,118 "progress_percent": 50.0,119 "message": "Processing page 5/10...",120 "created_at": "2024-01-01T10:00:00",121 "updated_at": "2024-01-01T10:02:30"122}123```124 125**Status values:**126- `queued` - Waiting to be processed127- `processing` - Currently processing128- `completed` - Successfully completed129- `failed` - Error occurred130 131---132 133### 5. Get Results134**GET** `/api/jobs/{job_id}/results`135 136Retrieve parsed document data.137 138**Response:**139```json140{141 "job_id": "550e8400-e29b-41d4-a716-446655440000",142 "status": "completed",143 "results": {144 "pages": [145 {146 "page_number": 1,147 "markdown": "# Document Title\n\nThis is the extracted text...",148 "json_output": {149 "bboxes": [[100, 200, 500, 250], [100, 300, 500, 400]],150 "labels": ["title", "paragraph"],151 "pred_text": ["Document Title", "This is the extracted text..."]152 },153 "annotated_image_path": "/api/results/550e8400-.../test/page_1.png"154 }155 ]156 },157 "download_url": "/api/jobs/550e8400-e29b-41d4-a716-446655440000/download"158}159```160 161---162 163### 6. Download ZIP164**GET** `/api/jobs/{job_id}/download`165 166Download all results as a ZIP file.167 168**Response:** Binary ZIP file containing:169- Annotated images with bounding boxes (PNG)170- JSON files with structured data171- Markdown files with extracted text172 173---174 175### 7. WebSocket Progress Stream176**WS** `/api/jobs/{job_id}/stream`177 178Real-time progress updates via WebSocket.179 180**Message Format:**181```json182{183 "event": "status_update",184 "data": {185 "job_id": "550e8400-...",186 "status": "processing",187 "progress_percent": 50.0,188 "message": "Processing page 5/10..."189 }190}191```192 193---194 195## Backend Examples (Python)196 197### Basic Upload and Poll198 199```python200import requests201import time202 203API_BASE = "https://isseygino911-dots-ocr-parser.hf.space"204 205# 1. Upload file206with open("document.pdf", "rb") as f:207 response = requests.post(208 f"{API_BASE}/api/parse/pdf",209 files={"file": f},210 data={"prompt_mode": "prompt_layout_all_en"}211 )212 213job_id = response.json()["job_id"]214print(f"Job ID: {job_id}")215 216# 2. Poll for completion217while True:218 status_resp = requests.get(f"{API_BASE}/api/jobs/{job_id}/status")219 status = status_resp.json()220 221 print(f"Progress: {status['progress_percent']:.0f}% - {status['message']}")222 223 if status["status"] == "completed":224 break225 elif status["status"] == "failed":226 print(f"Error: {status.get('error')}")227 break228 229 time.sleep(2)230 231# 3. Get results232results = requests.get(f"{API_BASE}/api/jobs/{job_id}/results").json()233print(f"Processed {len(results['results']['pages'])} pages")234 235# 4. Download ZIP236zip_response = requests.get(f"{API_BASE}/api/jobs/{job_id}/download")237with open("results.zip", "wb") as f:238 f.write(zip_response.content)239```240 241---242 243### Using WebSocket for Real-Time Updates244 245```python246import asyncio247import websockets248import json249 250async def monitor_job(job_id):251 uri = f"wss://isseygino911-dots-ocr-parser.hf.space/api/jobs/{job_id}/stream"252 253 async with websockets.connect(uri) as websocket:254 while True:255 message = await websocket.recv()256 data = json.loads(message)257 258 status = data['data']259 print(f"Status: {status['status']} - {status['progress_percent']:.0f}%")260 261 if status['status'] in ['completed', 'failed']:262 break263 264# Usage265asyncio.run(monitor_job("your-job-id"))266```267 268---269 270### Flask Backend Integration271 272```python273from flask import Flask, request, jsonify274import requests275 276app = Flask(__name__)277API_BASE = "https://isseygino911-dots-ocr-parser.hf.space"278 279@app.route('/api/ocr', methods=['POST'])280def ocr_upload():281 # Receive file from your frontend282 if 'file' not in request.files:283 return jsonify({"error": "No file provided"}), 400284 285 file = request.files['file']286 287 # Forward to DotsOCR API288 files = {'file': (file.filename, file.stream, file.content_type)}289 data = {'prompt_mode': request.form.get('prompt_mode', 'prompt_layout_all_en')}290 291 response = requests.post(292 f"{API_BASE}/api/parse/image",293 files=files,294 data=data295 )296 297 return jsonify(response.json())298 299@app.route('/api/ocr/status/<job_id>')300def ocr_status(job_id):301 response = requests.get(f"{API_BASE}/api/jobs/{job_id}/status")302 return jsonify(response.json())303 304if __name__ == '__main__':305 app.run(debug=True)306```307 308---309 310## Frontend Examples (JavaScript)311 312### Vanilla JavaScript - Upload and Monitor313 314```html315<!DOCTYPE html>316<html>317<head>318 <title>DotsOCR Upload</title>319</head>320<body>321 <h1>Document OCR</h1>322 323 <input type="file" id="fileInput" accept="image/*,.pdf">324 <button onclick="uploadFile()">Upload</button>325 326 <div id="status"></div>327 <div id="results"></div>328 329 <script>330 const API_BASE = 'https://isseygino911-dots-ocr-parser.hf.space';331 332 async function uploadFile() {333 const fileInput = document.getElementById('fileInput');334 const file = fileInput.files[0];335 336 if (!file) {337 alert('Please select a file');338 return;339 }340 341 // Determine endpoint based on file type342 const isPDF = file.name.toLowerCase().endsWith('.pdf');343 const endpoint = isPDF ? '/api/parse/pdf' : '/api/parse/image';344 345 // Upload file346 const formData = new FormData();347 formData.append('file', file);348 formData.append('prompt_mode', 'prompt_layout_all_en');349 350 const uploadResp = await fetch(`${API_BASE}${endpoint}`, {351 method: 'POST',352 body: formData353 });354 355 const { job_id } = await uploadResp.json();356 console.log('Job ID:', job_id);357 358 // Monitor progress359 monitorProgress(job_id);360 }361 362 async function monitorProgress(jobId) {363 const statusDiv = document.getElementById('status');364 365 while (true) {366 const response = await fetch(`${API_BASE}/api/jobs/${jobId}/status`);367 const status = await response.json();368 369 statusDiv.innerHTML = `370 <p>Status: ${status.status}</p>371 <p>Progress: ${status.progress_percent.toFixed(0)}%</p>372 <p>${status.message}</p>373 `;374 375 if (status.status === 'completed') {376 await displayResults(jobId);377 break;378 } else if (status.status === 'failed') {379 statusDiv.innerHTML += `<p style="color: red;">Error: ${status.error}</p>`;380 break;381 }382 383 await new Promise(resolve => setTimeout(resolve, 2000));384 }385 }386 387 async function displayResults(jobId) {388 const response = await fetch(`${API_BASE}/api/jobs/${jobId}/results`);389 const data = await response.json();390 391 const resultsDiv = document.getElementById('results');392 resultsDiv.innerHTML = '<h2>Results</h2>';393 394 data.results.pages.forEach(page => {395 resultsDiv.innerHTML += `396 <div style="border: 1px solid #ccc; margin: 10px; padding: 10px;">397 <h3>Page ${page.page_number}</h3>398 <pre>${page.markdown.substring(0, 500)}...</pre>399 <a href="${API_BASE}/api/jobs/${jobId}/download" download>400 Download ZIP401 </a>402 </div>403 `;404 });405 }406 </script>407</body>408</html>409```410 411---412 413### Using Fetch API with Async/Await414 415```javascript416const API_BASE = 'https://isseygino911-dots-ocr-parser.hf.space';417 418// Upload file419async function uploadDocument(file) {420 const formData = new FormData();421 formData.append('file', file);422 formData.append('prompt_mode', 'prompt_layout_all_en');423 424 const endpoint = file.name.endsWith('.pdf')425 ? '/api/parse/pdf'426 : '/api/parse/image';427 428 const response = await fetch(`${API_BASE}${endpoint}`, {429 method: 'POST',430 body: formData431 });432 433 return await response.json();434}435 436// Check status437async function checkStatus(jobId) {438 const response = await fetch(`${API_BASE}/api/jobs/${jobId}/status`);439 return await response.json();440}441 442// Get results443async function getResults(jobId) {444 const response = await fetch(`${API_BASE}/api/jobs/${jobId}/results`);445 return await response.json();446}447 448// Complete workflow449async function processDocument(file) {450 try {451 // 1. Upload452 const { job_id } = await uploadDocument(file);453 console.log('Job ID:', job_id);454 455 // 2. Poll for completion456 while (true) {457 const status = await checkStatus(job_id);458 console.log(`Progress: ${status.progress_percent}%`);459 460 if (status.status === 'completed') {461 break;462 } else if (status.status === 'failed') {463 throw new Error(status.error);464 }465 466 await new Promise(resolve => setTimeout(resolve, 2000));467 }468 469 // 3. Get results470 const results = await getResults(job_id);471 console.log('Results:', results);472 473 return results;474 } catch (error) {475 console.error('Error:', error);476 throw error;477 }478}479 480// Usage481const fileInput = document.getElementById('fileInput');482fileInput.addEventListener('change', async (e) => {483 const file = e.target.files[0];484 if (file) {485 const results = await processDocument(file);486 console.log('Processing complete!', results);487 }488});489```490 491---492 493### Using WebSocket for Real-Time Updates494 495```javascript496function monitorJobWithWebSocket(jobId, onUpdate, onComplete) {497 const ws = new WebSocket(498 `wss://isseygino911-dots-ocr-parser.hf.space/api/jobs/${jobId}/stream`499 );500 501 ws.onopen = () => {502 console.log('WebSocket connected');503 };504 505 ws.onmessage = (event) => {506 const message = JSON.parse(event.data);507 const status = message.data;508 509 // Call update callback510 onUpdate(status);511 512 // Check if completed513 if (status.status === 'completed') {514 onComplete(status);515 ws.close();516 } else if (status.status === 'failed') {517 onComplete(status);518 ws.close();519 }520 };521 522 ws.onerror = (error) => {523 console.error('WebSocket error:', error);524 // Fallback to HTTP polling525 pollJobStatus(jobId, onUpdate, onComplete);526 };527 528 return ws;529}530 531// Usage532const ws = monitorJobWithWebSocket(533 'job-id-here',534 (status) => {535 console.log(`Progress: ${status.progress_percent}%`);536 document.getElementById('progress').textContent =537 `${status.progress_percent.toFixed(0)}%`;538 },539 (status) => {540 console.log('Job completed!', status);541 displayResults(status.job_id);542 }543);544```545 546---547 548## React Integration549 550### Complete React Component551 552```jsx553import React, { useState, useCallback } from 'react';554import axios from 'axios';555 556const API_BASE = 'https://isseygino911-dots-ocr-parser.hf.space';557 558function DocumentOCR() {559 const [file, setFile] = useState(null);560 const [jobId, setJobId] = useState(null);561 const [status, setStatus] = useState(null);562 const [results, setResults] = useState(null);563 const [uploading, setUploading] = useState(false);564 565 // Handle file selection566 const handleFileChange = (e) => {567 setFile(e.target.files[0]);568 setJobId(null);569 setStatus(null);570 setResults(null);571 };572 573 // Upload file574 const handleUpload = async () => {575 if (!file) return;576 577 setUploading(true);578 579 const formData = new FormData();580 formData.append('file', file);581 formData.append('prompt_mode', 'prompt_layout_all_en');582 583 const endpoint = file.name.toLowerCase().endsWith('.pdf')584 ? '/api/parse/pdf'585 : '/api/parse/image';586 587 try {588 const response = await axios.post(`${API_BASE}${endpoint}`, formData);589 const { job_id } = response.data;590 setJobId(job_id);591 startPolling(job_id);592 } catch (error) {593 console.error('Upload failed:', error);594 alert('Upload failed');595 } finally {596 setUploading(false);597 }598 };599 600 // Poll for status601 const startPolling = useCallback((jobId) => {602 const interval = setInterval(async () => {603 try {604 const response = await axios.get(`${API_BASE}/api/jobs/${jobId}/status`);605 const statusData = response.data;606 setStatus(statusData);607 608 if (statusData.status === 'completed') {609 clearInterval(interval);610 fetchResults(jobId);611 } else if (statusData.status === 'failed') {612 clearInterval(interval);613 alert('Processing failed: ' + statusData.error);614 }615 } catch (error) {616 console.error('Status check failed:', error);617 }618 }, 2000);619 620 return () => clearInterval(interval);621 }, []);622 623 // Fetch results624 const fetchResults = async (jobId) => {625 try {626 const response = await axios.get(`${API_BASE}/api/jobs/${jobId}/results`);627 setResults(response.data);628 } catch (error) {629 console.error('Failed to fetch results:', error);630 }631 };632 633 return (634 <div style={{ padding: '20px', maxWidth: '800px', margin: '0 auto' }}>635 <h1>Document OCR</h1>636 637 {/* File Upload */}638 <div style={{ marginBottom: '20px' }}>639 <input640 type="file"641 accept="image/*,.pdf"642 onChange={handleFileChange}643 disabled={uploading}644 />645 <button646 onClick={handleUpload}647 disabled={!file || uploading}648 style={{ marginLeft: '10px' }}649 >650 {uploading ? 'Uploading...' : 'Upload'}651 </button>652 </div>653 654 {/* Status */}655 {status && (656 <div style={{657 padding: '15px',658 background: '#f0f0f0',659 borderRadius: '5px',660 marginBottom: '20px'661 }}>662 <h3>Status: {status.status}</h3>663 <div style={{664 width: '100%',665 height: '20px',666 background: '#ddd',667 borderRadius: '10px',668 overflow: 'hidden'669 }}>670 <div style={{671 width: `${status.progress_percent}%`,672 height: '100%',673 background: '#4CAF50',674 transition: 'width 0.3s'675 }} />676 </div>677 <p>{status.message}</p>678 {status.total_pages > 1 && (679 <p>Page {status.current_page} of {status.total_pages}</p>680 )}681 </div>682 )}683 684 {/* Results */}685 {results && (686 <div>687 <h2>Results ({results.results.pages.length} page(s))</h2>688 {results.results.pages.map((page) => (689 <div key={page.page_number} style={{690 border: '1px solid #ccc',691 padding: '15px',692 marginBottom: '15px',693 borderRadius: '5px'694 }}>695 <h3>Page {page.page_number}</h3>696 697 {/* Markdown Preview */}698 <div style={{ marginBottom: '10px' }}>699 <h4>Extracted Text:</h4>700 <pre style={{701 background: '#f5f5f5',702 padding: '10px',703 borderRadius: '3px',704 whiteSpace: 'pre-wrap'705 }}>706 {page.markdown.substring(0, 500)}707 {page.markdown.length > 500 && '...'}708 </pre>709 </div>710 711 {/* Detected Elements */}712 <div>713 <h4>Detected Elements:</h4>714 <p>715 {page.json_output.labels.length} elements found: {' '}716 {[...new Set(page.json_output.labels)].join(', ')}717 </p>718 </div>719 </div>720 ))}721 722 {/* Download Button */}723 <a724 href={`${API_BASE}${results.download_url}`}725 download726 style={{727 display: 'inline-block',728 padding: '10px 20px',729 background: '#2196F3',730 color: 'white',731 textDecoration: 'none',732 borderRadius: '5px'733 }}734 >735 Download ZIP736 </a>737 </div>738 )}739 </div>740 );741}742 743export default DocumentOCR;744```745 746---747 748### React with WebSocket749 750```jsx751import React, { useState, useEffect } from 'react';752 753const API_BASE = 'https://isseygino911-dots-ocr-parser.hf.space';754 755function useWebSocketProgress(jobId) {756 const [status, setStatus] = useState(null);757 758 useEffect(() => {759 if (!jobId) return;760 761 const ws = new WebSocket(762 `wss://isseygino911-dots-ocr-parser.hf.space/api/jobs/${jobId}/stream`763 );764 765 ws.onmessage = (event) => {766 const message = JSON.parse(event.data);767 setStatus(message.data);768 };769 770 ws.onerror = (error) => {771 console.error('WebSocket error:', error);772 };773 774 return () => {775 ws.close();776 };777 }, [jobId]);778 779 return status;780}781 782// Usage in component783function MyComponent({ jobId }) {784 const status = useWebSocketProgress(jobId);785 786 if (!status) return <div>Loading...</div>;787 788 return (789 <div>790 <p>Status: {status.status}</p>791 <p>Progress: {status.progress_percent}%</p>792 </div>793 );794}795```796 797---798 799## Complete Workflows800 801### Workflow 1: Simple Upload and Download802 803```javascript804async function simpleWorkflow(file) {805 const API_BASE = 'https://isseygino911-dots-ocr-parser.hf.space';806 807 // 1. Upload808 const formData = new FormData();809 formData.append('file', file);810 811 const uploadResp = await fetch(`${API_BASE}/api/parse/image`, {812 method: 'POST',813 body: formData814 });815 const { job_id } = await uploadResp.json();816 817 // 2. Wait for completion818 let status;819 do {820 await new Promise(resolve => setTimeout(resolve, 2000));821 const statusResp = await fetch(`${API_BASE}/api/jobs/${job_id}/status`);822 status = await statusResp.json();823 } while (status.status === 'processing' || status.status === 'queued');824 825 // 3. Download results826 const downloadUrl = `${API_BASE}/api/jobs/${job_id}/download`;827 window.open(downloadUrl, '_blank');828}829```830 831---832 833### Workflow 2: Batch Processing834 835```javascript836async function processBatch(files) {837 const API_BASE = 'https://isseygino911-dots-ocr-parser.hf.space';838 const results = [];839 840 for (const file of files) {841 const formData = new FormData();842 formData.append('file', file);843 844 const uploadResp = await fetch(`${API_BASE}/api/parse/image`, {845 method: 'POST',846 body: formData847 });848 const { job_id } = await uploadResp.json();849 850 results.push({ filename: file.name, job_id });851 }852 853 // Monitor all jobs854 const completed = [];855 while (completed.length < results.length) {856 for (const job of results) {857 if (completed.includes(job.job_id)) continue;858 859 const statusResp = await fetch(`${API_BASE}/api/jobs/${job.job_id}/status`);860 const status = await statusResp.json();861 862 if (status.status === 'completed') {863 completed.push(job.job_id);864 console.log(`${job.filename} completed`);865 }866 }867 868 await new Promise(resolve => setTimeout(resolve, 2000));869 }870 871 return results;872}873```874 875---876 877## Error Handling878 879### Best Practices880 881```javascript882async function robustUpload(file) {883 const API_BASE = 'https://isseygino911-dots-ocr-parser.hf.space';884 const MAX_RETRIES = 3;885 const TIMEOUT = 300000; // 5 minutes886 887 try {888 // 1. Upload with retry889 let uploadResp;890 for (let i = 0; i < MAX_RETRIES; i++) {891 try {892 const formData = new FormData();893 formData.append('file', file);894 895 uploadResp = await fetch(`${API_BASE}/api/parse/image`, {896 method: 'POST',897 body: formData898 });899 900 if (uploadResp.ok) break;901 902 if (i === MAX_RETRIES - 1) {903 throw new Error('Upload failed after retries');904 }905 906 await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));907 } catch (error) {908 if (i === MAX_RETRIES - 1) throw error;909 }910 }911 912 const { job_id } = await uploadResp.json();913 914 // 2. Poll with timeout915 const startTime = Date.now();916 while (true) {917 if (Date.now() - startTime > TIMEOUT) {918 throw new Error('Processing timeout');919 }920 921 const statusResp = await fetch(`${API_BASE}/api/jobs/${job_id}/status`);922 923 if (!statusResp.ok) {924 throw new Error(`Status check failed: ${statusResp.status}`);925 }926 927 const status = await statusResp.json();928 929 if (status.status === 'completed') {930 return await fetch(`${API_BASE}/api/jobs/${job_id}/results`)931 .then(r => r.json());932 }933 934 if (status.status === 'failed') {935 throw new Error(`Processing failed: ${status.error}`);936 }937 938 await new Promise(resolve => setTimeout(resolve, 2000));939 }940 941 } catch (error) {942 console.error('Error:', error);943 944 // Handle specific errors945 if (error.message.includes('timeout')) {946 alert('Processing is taking longer than expected. Please try again later.');947 } else if (error.message.includes('failed')) {948 alert('Processing failed. Please check your file and try again.');949 } else {950 alert('An error occurred. Please try again.');951 }952 953 throw error;954 }955}956```957 958---959 960## Performance Tips961 9621. **Use WebSocket for large PDFs** - More efficient than polling for documents with many pages9632. **Poll interval** - Use 2-3 seconds for polling to balance responsiveness and server load9643. **Timeout handling** - Set appropriate timeouts based on file size (60s for images, 300s for PDFs)9654. **Batch processing** - Process files sequentially to avoid overwhelming the server9665. **Error recovery** - Implement retry logic with exponential backoff967 968---969 970## Support971 972For issues or questions:973- API Documentation: `https://isseygino911-dots-ocr-parser.hf.space/docs`974- Test your integration at: [Interactive API Docs](https://isseygino911-dots-ocr-parser.hf.space/docs)975 976---977 978**Built with DotsOCR** - 1.7B parameter Vision-Language Model for Document Understanding979 