CoolFace
Apppublic

isseygino911/dots-ocr-parser

sourceHugging Faceapache-2.0updated 10mo agoView on Hugging Face
0likes
API_USAGE_GUIDE.md979 linesDownload Raw Back to root
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