Spaces:
Sleeping
Sleeping
File size: 7,702 Bytes
881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 881a2c6 b6c9a39 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | from fastapi import FastAPI, File, UploadFile, HTTPException, Query
from fastapi.responses import JSONResponse
import gradio as gr
from docling.document_converter import DocumentConverter
from docling.datamodel.base_models import InputFormat
import tempfile
import os
import json
import re
app = FastAPI(
title="Docling Document Conversion API",
description="Convert documents to Markdown and extract basic information",
version="1.0.0"
)
# Initialize Docling
converter = DocumentConverter()
def extract_fields_from_markdown(markdown_text: str, template_type: str) -> dict:
"""Basic field extraction from markdown using regex patterns"""
if template_type == "payment_advice":
return {
"document_type": "payment_advice",
"payment_document_no": re.search(r'(?:Payment Document|Doc(?:ument)? No\.?)[:\s]+(\w+)', markdown_text, re.I),
"payment_date": re.search(r'(?:Payment Date)[:\s]+([\d\-\/\.]+)', markdown_text, re.I),
"total_amount": re.search(r'(?:Total|Amount)[:\s]+([\d,\.]+)', markdown_text, re.I),
"vendor_code": re.search(r'(?:Vendor Code)[:\s]+(\w+)', markdown_text, re.I),
}
elif template_type == "invoice":
return {
"document_type": "invoice",
"bill_no": re.search(r'(?:Bill|Invoice) No\.?[:\s]+(\w+)', markdown_text, re.I),
"bill_date": re.search(r'(?:Bill|Invoice) Date[:\s]+([\d\-\/\.]+)', markdown_text, re.I),
"total_amount": re.search(r'(?:Total|Grand Total)[:\s]+([\d,\.]+)', markdown_text, re.I),
"gst_no": re.search(r'GST No\.?[:\s]+(\w+)', markdown_text, re.I),
}
return {"document_type": "unknown"}
def clean_extracted_fields(fields: dict) -> dict:
"""Convert regex match objects to strings"""
cleaned = {}
for key, value in fields.items():
if hasattr(value, 'group'):
cleaned[key] = value.group(1).strip()
elif value:
cleaned[key] = value
else:
cleaned[key] = None
return cleaned
@app.post("/api/extract")
async def extract_document(
file: UploadFile = File(...),
template_type: str = Query(default="auto", description="Template type: auto, payment_advice, invoice")
):
"""
Convert document to markdown and extract basic structured data
"""
try:
# Save uploaded file temporarily
with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(file.filename)[1]) as tmp_file:
content = await file.read()
tmp_file.write(content)
tmp_file_path = tmp_file.name
# Convert document to markdown
result = converter.convert(tmp_file_path)
markdown_content = result.document.export_to_markdown()
# Auto-detect template if needed
if template_type == "auto":
text_lower = markdown_content.lower()
if any(keyword in text_lower for keyword in ["payment advice", "payment document", "vendor code"]):
template_type = "payment_advice"
elif any(keyword in text_lower for keyword in ["invoice", "bill no", "gst no"]):
template_type = "invoice"
else:
template_type = "general"
# Extract basic fields
if template_type in ["payment_advice", "invoice"]:
fields = extract_fields_from_markdown(markdown_content, template_type)
extracted_data = clean_extracted_fields(fields)
else:
extracted_data = {"document_type": template_type}
# Clean up
os.unlink(tmp_file_path)
return JSONResponse(content={
"success": True,
"template_used": template_type,
"data": extracted_data,
"markdown": markdown_content,
"filename": file.filename
})
except HTTPException:
raise
except Exception as e:
if 'tmp_file_path' in locals():
try:
os.unlink(tmp_file_path)
except:
pass
raise HTTPException(status_code=500, detail=f"Processing error: {str(e)}")
@app.post("/api/convert")
async def convert_to_markdown(file: UploadFile = File(...)):
"""Simple document to markdown conversion"""
try:
with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(file.filename)[1]) as tmp_file:
content = await file.read()
tmp_file.write(content)
tmp_file_path = tmp_file.name
result = converter.convert(tmp_file_path)
markdown_content = result.document.export_to_markdown()
os.unlink(tmp_file_path)
return JSONResponse(content={
"success": True,
"markdown": markdown_content,
"filename": file.filename
})
except Exception as e:
if 'tmp_file_path' in locals():
try:
os.unlink(tmp_file_path)
except:
pass
raise HTTPException(status_code=500, detail=f"Processing error: {str(e)}")
@app.get("/")
def read_root():
"""API information"""
return {
"message": "Docling Document Conversion API",
"version": "1.0.0",
"note": "Advanced extraction API is in beta - currently using markdown conversion with basic field extraction",
"endpoints": {
"extract": "/api/extract (POST) - Convert and extract basic fields",
"convert": "/api/convert (POST) - Convert to markdown only",
"docs": "/docs - Interactive API documentation",
"web_ui": "/gradio - Web interface"
}
}
@app.get("/health")
def health_check():
"""Health check endpoint"""
return {"status": "healthy", "service": "docling-api"}
# Gradio interface
def process_document(file):
"""Gradio function to process documents"""
try:
if file is None:
return "Please upload a file"
result = converter.convert(file.name)
markdown_content = result.document.export_to_markdown()
# Try basic extraction
text_lower = markdown_content.lower()
if "invoice" in text_lower or "bill" in text_lower:
fields = extract_fields_from_markdown(markdown_content, "invoice")
extracted = clean_extracted_fields(fields)
return f"β
Detected: Invoice\n\nExtracted Fields:\n{json.dumps(extracted, indent=2)}\n\n--- Markdown ---\n{markdown_content[:2000]}"
elif "payment" in text_lower:
fields = extract_fields_from_markdown(markdown_content, "payment_advice")
extracted = clean_extracted_fields(fields)
return f"β
Detected: Payment Advice\n\nExtracted Fields:\n{json.dumps(extracted, indent=2)}\n\n--- Markdown ---\n{markdown_content[:2000]}"
else:
return f"β
Converted to Markdown\n\n{markdown_content[:3000]}"
except Exception as e:
return f"β Error: {str(e)}"
demo = gr.Interface(
fn=process_document,
inputs=gr.File(label="π Upload Document (PDF, Image, DOCX)"),
outputs=gr.Textbox(label="π Output", lines=30),
title="Docling Document Processor",
description="Upload documents to convert to Markdown and extract basic information. Advanced extraction API coming soon!",
article="Built with [Docling](https://github.com/docling-project/docling) | API available at `/api/extract` and `/api/convert`",
)
app = gr.mount_gradio_app(app, demo, path="/gradio")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=7860)
|