Spaces:
Sleeping
Sleeping
| title: GLM-OCR REST API | |
| emoji: 📄 | |
| colorFrom: blue | |
| colorTo: indigo | |
| sdk: docker | |
| sdk_version: "latest" | |
| app_file: app.py | |
| pinned: false | |
| Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference | |
| # GLM-OCR REST API | |
| A high-performance OCR API built with FastAPI and GLM-4V for extracting text, tables, and formulas from documents. | |
| ## Features | |
| ✨ **Multi-format Support** | |
| - Images: JPG, JPEG, PNG, GIF, BMP, WebP | |
| - Documents: PDF, DOCX | |
| - Automatic conversion to images for processing | |
| 🎯 **Extraction Types** (in order: Table → Text → Formula) | |
| - **Table Recognition**: Extract structured table data | |
| - **Text Recognition**: Extract all text content | |
| - **Formula Recognition**: Extract mathematical formulas | |
| 🚀 **Advanced Features** | |
| - Batch processing (up to 10 files) | |
| - Structured information extraction with JSON schema | |
| - Page-by-page processing for multi-page documents | |
| - CORS enabled for web integration | |
| ## 🔗 Interactive API Documentation | |
| Once deployed, access the interactive Swagger UI to test all endpoints: | |
| **Swagger UI (Recommended)** | |
| - Local: `http://localhost:7860/docs` | |
| - Deployed Space: `https://huggingface.co/spaces/your-username/glm-ocr-api/api/docs` | |
| **ReDoc (Alternative)** | |
| - Local: `http://localhost:7860/redoc` | |
| - Deployed Space: `https://huggingface.co/spaces/your-username/glm-ocr-api/api/redoc` | |
| The Swagger UI allows you to: | |
| - ✅ Browse all available endpoints | |
| - ✅ View request/response schemas | |
| - ✅ Test endpoints directly in browser | |
| - ✅ Download OpenAPI specification | |
| > **Note:** This application uses the new Hugging Face router endpoint (`https://router.huggingface.co`). The old `api-inference.huggingface.co` endpoint is deprecated. | |
| ## Setup | |
| ### Prerequisites | |
| - Python 3.8+ | |
| - Hugging Face API Token (for GLM-OCR model access) | |
| ### Installation | |
| 1. **Clone the repository** | |
| ```bash | |
| git clone <your-repo-url> | |
| cd <repo-name> | |
| ``` | |
| 2. **Install dependencies** | |
| ```bash | |
| pip install -r requirements.txt | |
| ``` | |
| 3. **Configure environment** | |
| ```bash | |
| # Copy the example env file | |
| cp .env.example .env | |
| # Edit .env and add your Hugging Face token | |
| # HF_API_TOKEN=your_token_here | |
| ``` | |
| 4. **Run the server** | |
| ```bash | |
| python app.py | |
| ``` | |
| The API will be available at: `http://localhost:7860` | |
| ## API Documentation | |
| ### Base URL | |
| ``` | |
| http://localhost:7860 | |
| ``` | |
| --- | |
| ## Endpoints | |
| ### 1. **Health Check** | |
| Check if the API is running. | |
| **Endpoint:** | |
| ``` | |
| GET /health | |
| ``` | |
| **Response:** | |
| ```json | |
| { | |
| "status": "healthy", | |
| "timestamp": "2024-01-15T10:30:45.123456", | |
| "model": "PrathameshRaut/DocumentOCR" | |
| } | |
| ``` | |
| --- | |
| ### 2. **Extract Text/Tables/Formulas** | |
| Extract all content from a document (table, text, formula in order). | |
| **Endpoint:** | |
| ``` | |
| POST /api/ocr/extract | |
| ``` | |
| **Request:** | |
| - **Content-Type:** `multipart/form-data` | |
| - **Parameter:** `file` (UploadFile) | |
| **Supported Formats:** | |
| - Images: `.jpg`, `.jpeg`, `.png`, `.gif`, `.bmp`, `.webp` | |
| - PDFs: `.pdf` | |
| - Documents: `.docx`, `.doc` | |
| **cURL Example:** | |
| ```bash | |
| curl -X POST "http://localhost:7860/api/ocr/extract" \ | |
| -F "file=@path/to/your/document.pdf" | |
| ``` | |
| **Python Example:** | |
| ```python | |
| import requests | |
| url = "http://localhost:7860/api/ocr/extract" | |
| files = {"file": open("document.pdf", "rb")} | |
| response = requests.post(url, files=files) | |
| data = response.json() | |
| # Process results | |
| for page in data["pages"]: | |
| print(f"Page {page['page_number']}:") | |
| print(f"Tables: {page['table']}") | |
| print(f"Text: {page['text']}") | |
| print(f"Formulas: {page['formula']}") | |
| ``` | |
| **Response Example:** | |
| ```json | |
| { | |
| "filename": "document.pdf", | |
| "file_type": ".pdf", | |
| "total_pages": 1, | |
| "extraction_timestamp": "2024-01-15T10:30:45.123456", | |
| "pages": [ | |
| { | |
| "page_number": 1, | |
| "table": "Extracted table content here...", | |
| "text": "Extracted text content here...", | |
| "formula": "Extracted formula content here..." | |
| } | |
| ] | |
| } | |
| ``` | |
| --- | |
| ### 3. **Extract Structured Information** | |
| Extract information based on a custom JSON schema. | |
| **Endpoint:** | |
| ``` | |
| POST /api/ocr/extract-structured | |
| ``` | |
| **Request:** | |
| - **Content-Type:** `multipart/form-data` | |
| - **Parameters:** | |
| - `file` (UploadFile): Document to process | |
| - `schema` (string): JSON schema defining what to extract | |
| **Schema Example:** | |
| ```json | |
| { | |
| "id_number": "", | |
| "name": "", | |
| "date_of_birth": "", | |
| "address": { | |
| "street": "", | |
| "city": "", | |
| "state": "", | |
| "zip_code": "" | |
| } | |
| } | |
| ``` | |
| **cURL Example:** | |
| ```bash | |
| SCHEMA='{"id_number":"","name":"","date_of_birth":""}' | |
| curl -X POST "http://localhost:7860/api/ocr/extract-structured" \ | |
| -F "file=@path/to/id_card.jpg" \ | |
| -F "schema=$SCHEMA" | |
| ``` | |
| **Python Example:** | |
| ```python | |
| import requests | |
| import json | |
| url = "http://localhost:7860/api/ocr/extract-structured" | |
| schema = { | |
| "id_number": "", | |
| "name": "", | |
| "date_of_birth": "", | |
| "address": { | |
| "street": "", | |
| "city": "", | |
| "state": "" | |
| } | |
| } | |
| files = {"file": open("id_card.jpg", "rb")} | |
| data = {"schema": json.dumps(schema)} | |
| response = requests.post(url, files=files, data=data) | |
| result = response.json() | |
| # Access extracted structured data | |
| for page in result["pages"]: | |
| print(page["extracted_data"]) | |
| ``` | |
| **Response Example:** | |
| ```json | |
| { | |
| "filename": "id_card.jpg", | |
| "file_type": ".jpg", | |
| "total_pages": 1, | |
| "extraction_timestamp": "2024-01-15T10:30:45.123456", | |
| "pages": [ | |
| { | |
| "page_number": 1, | |
| "extracted_data": { | |
| "id_number": "12345678", | |
| "name": "John Doe", | |
| "date_of_birth": "1990-01-15", | |
| "address": { | |
| "street": "123 Main St", | |
| "city": "New York", | |
| "state": "NY" | |
| } | |
| } | |
| } | |
| ] | |
| } | |
| ``` | |
| --- | |
| ### 4. **Batch Processing** | |
| Process multiple files at once (up to 10 files per request). | |
| **Endpoint:** | |
| ``` | |
| POST /api/ocr/batch | |
| ``` | |
| **Request:** | |
| - **Content-Type:** `multipart/form-data` | |
| - **Parameter:** `files` (List[UploadFile]) | |
| **cURL Example:** | |
| ```bash | |
| curl -X POST "http://localhost:7860/api/ocr/batch" \ | |
| -F "files=@document1.pdf" \ | |
| -F "files=@document2.jpg" \ | |
| -F "files=@document3.docx" | |
| ``` | |
| **Python Example:** | |
| ```python | |
| import requests | |
| url = "http://localhost:7860/api/ocr/batch" | |
| files = [ | |
| ("files", open("document1.pdf", "rb")), | |
| ("files", open("document2.jpg", "rb")), | |
| ("files", open("document3.docx", "rb")) | |
| ] | |
| response = requests.post(url, files=files) | |
| batch_results = response.json() | |
| # Process results for each file | |
| for file_result in batch_results["results"]: | |
| print(f"File: {file_result['filename']}") | |
| print(f"Status: {file_result['status']}") | |
| if file_result['status'] == 'success': | |
| for page in file_result['pages']: | |
| print(f" Page {page['page_number']}:") | |
| print(f" Table: {page['table']}") | |
| print(f" Text: {page['text']}") | |
| print(f" Formula: {page['formula']}") | |
| ``` | |
| **Response Example:** | |
| ```json | |
| { | |
| "batch_timestamp": "2024-01-15T10:30:45.123456", | |
| "total_files": 3, | |
| "results": [ | |
| { | |
| "filename": "document1.pdf", | |
| "file_type": ".pdf", | |
| "status": "success", | |
| "total_pages": 2, | |
| "pages": [ | |
| { | |
| "page_number": 1, | |
| "table": "...", | |
| "text": "...", | |
| "formula": "..." | |
| } | |
| ] | |
| }, | |
| { | |
| "filename": "document2.jpg", | |
| "status": "error", | |
| "error": "Unsupported file type" | |
| } | |
| ] | |
| } | |
| ``` | |
| --- | |
| ### 5. **API Information** | |
| Get details about the API and supported formats. | |
| **Endpoint:** | |
| ``` | |
| GET /api/info | |
| ``` | |
| **Response:** | |
| ```json | |
| { | |
| "api_name": "GLM-OCR API", | |
| "version": "1.0.0", | |
| "model": "PrathameshRaut/DocumentOCR", | |
| "supported_formats": { | |
| "images": [".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp"], | |
| "documents": [".docx", ".doc"], | |
| "pdfs": [".pdf"] | |
| }, | |
| "endpoints": { | |
| "extract": "/api/ocr/extract", | |
| "extract_structured": "/api/ocr/extract-structured", | |
| "batch": "/api/ocr/batch", | |
| "health": "/health", | |
| "info": "/api/info" | |
| }, | |
| "extraction_order": ["table", "text", "formula"] | |
| } | |
| ``` | |
| --- | |
| ## Extraction Order | |
| The API extracts content in the following order for each page: | |
| 1. **Table** - Structured table data | |
| 2. **Text** - All text content | |
| 3. **Formula** - Mathematical formulas | |
| This order is maintained in all responses. | |
| --- | |
| ## JavaScript/Frontend Integration | |
| ### Fetch Example | |
| ```javascript | |
| async function extractOCR(file) { | |
| const formData = new FormData(); | |
| formData.append('file', file); | |
| const response = await fetch('http://localhost:7860/api/ocr/extract', { | |
| method: 'POST', | |
| body: formData | |
| }); | |
| const data = await response.json(); | |
| return data; | |
| } | |
| // Usage | |
| document.getElementById('fileInput').addEventListener('change', async (e) => { | |
| const file = e.target.files[0]; | |
| const result = await extractOCR(file); | |
| console.log(result); | |
| }); | |
| ``` | |
| ### Axios Example | |
| ```javascript | |
| import axios from 'axios'; | |
| async function extractOCR(file) { | |
| const formData = new FormData(); | |
| formData.append('file', file); | |
| try { | |
| const response = await axios.post( | |
| 'http://localhost:7860/api/ocr/extract', | |
| formData, | |
| { | |
| headers: { | |
| 'Content-Type': 'multipart/form-data' | |
| } | |
| } | |
| ); | |
| return response.data; | |
| } catch (error) { | |
| console.error('OCR extraction failed:', error); | |
| } | |
| } | |
| ``` | |
| --- | |
| ## Error Handling | |
| The API returns appropriate HTTP status codes: | |
| - **200** - Successful extraction | |
| - **400** - Bad request (invalid file, unsupported format, etc.) | |
| - **500** - Server error | |
| **Error Response Example:** | |
| ```json | |
| { | |
| "detail": "Unsupported file type. Supported: .jpg, .jpeg, .png, .gif, .bmp, .webp, .pdf, .docx, .doc" | |
| } | |
| ``` | |
| --- | |
| ## 🔧 Troubleshooting & Debugging | |
| ### Issue: Empty extraction results (all fields are "") | |
| **Solution:** | |
| 1. **Test model connection:** | |
| ```bash | |
| curl http://localhost:7860/debug/test-model | |
| ``` | |
| This will test if your HF_API_TOKEN is set correctly and show the actual model response format. | |
| 2. **Check HF_API_TOKEN:** | |
| ```bash | |
| # Local development | |
| echo $HF_API_TOKEN | |
| # Should not be empty. If empty, set it: | |
| export HF_API_TOKEN="your_actual_token_here" | |
| ``` | |
| 3. **View debug logs:** | |
| The API prints `[DEBUG]` messages that show: | |
| - Actual model response status codes | |
| - Response JSON structure | |
| - Error messages from the model | |
| Look for these logs to understand what the model is returning. | |
| 4. **Verify token has model access:** | |
| - Go to: https://huggingface.co/settings/tokens | |
| - Make sure your token has read access | |
| - Check if you can access the model: https://huggingface.co/PrathameshRaut/DocumentOCR | |
| ### Issue: Model endpoint not responding | |
| **Solution:** | |
| 1. **Check the endpoint is correct:** | |
| ``` | |
| https://api-inference.huggingface.co/models/PrathameshRaut/DocumentOCR | |
| ``` | |
| 2. **Test with curl:** | |
| ```bash | |
| curl -X POST "https://api-inference.huggingface.co/models/PrathameshRaut/DocumentOCR" \ | |
| -H "Authorization: Bearer YOUR_HF_TOKEN" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{"inputs": {"image": "data:image/png;base64,...", "text": "Extract text"}}' | |
| ``` | |
| 3. **Possible reasons:** | |
| - Model is not deployed/not available | |
| - Token doesn't have access to this model | |
| - Model requires a specific request format | |
| ### Issue: Timeout during extraction | |
| **Solution:** | |
| 1. **Increase timeout in client code:** | |
| ```python | |
| response = requests.post( | |
| "http://localhost:7860/api/ocr/extract", | |
| files=files, | |
| timeout=180 # Increased from default 120 | |
| ) | |
| ``` | |
| 2. **File size:** | |
| - Large PDFs (100+ pages) take longer | |
| - Keep files under 50MB | |
| - Try with a smaller test file first | |
| ### Issue: "HF_API_TOKEN not set" | |
| **Local development:** | |
| ```bash | |
| export HF_API_TOKEN="hf_xxxxxxxxxxxx" | |
| python app.py | |
| ``` | |
| **Hugging Face Space:** | |
| 1. Go to Space Settings | |
| 2. Click "Secrets" | |
| 3. Add secret: | |
| - Name: `HF_API_TOKEN` | |
| - Value: Your actual token from https://huggingface.co/settings/tokens | |
| ### Debug Endpoint | |
| Use this endpoint to test and debug: | |
| ```bash | |
| curl http://localhost:7860/debug/test-model | |
| ``` | |
| **Response shows:** | |
| - If HF_API_TOKEN is set | |
| - Test extraction result | |
| - Actual model response format | |
| - Debugging suggestions | |
| This is very helpful to understand what the model is returning. | |
| --- | |
| ## Deployment on Hugging Face Spaces | |
| 1. Create a new Space on Hugging Face | |
| 2. Choose "Docker" as the runtime (or "Python" with requirements.txt) | |
| 3. Upload these files: | |
| - `app.py` | |
| - `requirements.txt` | |
| - `.env.example` | |
| 4. In Space settings, add your secret: | |
| - Add `HF_API_TOKEN` with your Hugging Face API token | |
| 5. The Space will auto-deploy and be accessible at: | |
| - `https://huggingface.co/spaces/your-username/your-space-name` | |
| --- | |
| ## Performance Tips | |
| - **For large PDFs**: Process page-by-page using the single extract endpoint | |
| - **For many files**: Use batch processing for efficiency | |
| - **For production**: Use appropriate timeout values in client code | |
| --- | |
| ## Troubleshooting | |
| ### Issue: "CUDA out of memory" | |
| - The model might need GPU. Ensure your Space has GPU enabled. | |
| ### Issue: "HF_API_TOKEN not found" | |
| - Make sure to set the environment variable in Space secrets | |
| ### Issue: Slow extraction | |
| - Model inference time depends on document complexity | |
| - PDF extraction is slower than image extraction | |
| - For large batches, consider increasing timeout values | |
| --- | |
| ## Model Information | |
| **Model:** `PrathameshRaut/DocumentOCR` | |
| - Built on GLM-4V | |
| - Supports document parsing and information extraction | |
| - Recognizes text, tables, and formulas | |
| --- | |
| ## License | |
| MIT License - Feel free to use and modify as needed. | |
| --- | |
| ## Support | |
| For issues or questions: | |
| 1. Check the troubleshooting section | |
| 2. Review error messages in API responses | |
| 3. Check Hugging Face model documentation | |
| --- | |
| ## Version History | |
| ### v1.0.0 | |
| - Initial release | |
| - Support for image, PDF, and DOCX files | |
| - Table, text, and formula extraction | |
| - Batch processing | |
| - Structured information extraction |