PrathameshRaut commited on
Commit
751d99f
Β·
verified Β·
1 Parent(s): 48936d4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +31 -15
app.py CHANGED
@@ -2,11 +2,13 @@
2
  Surya OCR - Universal REST API
3
  One endpoint: POST /ocr β€” any file in, extracted text out.
4
  Supports: Images, PDF, Word (.docx/.doc), PowerPoint (.pptx/.ppt), and more.
 
5
  Hugging Face Spaces (Free Tier) compatible.
6
  """
7
 
8
  import io
9
  import gc
 
10
  import logging
11
  import subprocess
12
  import tempfile
@@ -14,25 +16,38 @@ from contextlib import asynccontextmanager
14
  from pathlib import Path
15
 
16
  import uvicorn
17
- from fastapi import FastAPI, File, UploadFile, HTTPException
18
  from fastapi.middleware.cors import CORSMiddleware
19
  from fastapi.responses import JSONResponse
 
20
  from PIL import Image
21
 
22
  logging.basicConfig(level=logging.INFO)
23
  logger = logging.getLogger(__name__)
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  # ── Global model holders ──────────────────────────────────────────────────────
26
  recognition_predictor = None
27
  detection_predictor = None
28
 
29
  MAX_FILE_SIZE_MB = 30
30
- MAX_PAGES = 10 # Free tier memory guard
31
 
32
  SUPPORTED_EXTENSIONS = {
33
- # Images
34
  ".jpg", ".jpeg", ".png", ".webp", ".tiff", ".tif", ".bmp",
35
- # Documents
36
  ".pdf",
37
  ".docx", ".doc",
38
  ".pptx", ".ppt",
@@ -70,7 +85,7 @@ async def lifespan(app: FastAPI):
70
 
71
  app = FastAPI(
72
  title="Surya OCR API",
73
- description="Upload any document β€” image, PDF, Word, PowerPoint β€” get back extracted text.",
74
  version="2.0.0",
75
  lifespan=lifespan,
76
  )
@@ -90,10 +105,6 @@ def convert_pdf(data: bytes) -> list:
90
 
91
 
92
  def convert_office(data: bytes, suffix: str) -> list:
93
- """
94
- Convert Word / PowerPoint / ODT / ODP / RTF to PDF via LibreOffice,
95
- then rasterize with pdf2image.
96
- """
97
  with tempfile.TemporaryDirectory() as tmpdir:
98
  input_path = Path(tmpdir) / f"input{suffix}"
99
  input_path.write_bytes(data)
@@ -118,7 +129,6 @@ def convert_office(data: bytes, suffix: str) -> list:
118
 
119
 
120
  def file_to_images(data: bytes, suffix: str) -> list:
121
- """Route any file to the right converter and return a list of PIL Images."""
122
  image_exts = {".jpg", ".jpeg", ".png", ".webp", ".tiff", ".tif", ".bmp"}
123
  office_exts = {".docx", ".doc", ".pptx", ".ppt", ".odt", ".odp", ".rtf"}
124
 
@@ -155,31 +165,37 @@ def run_ocr(images: list) -> str:
155
 
156
  @app.get("/", summary="Health / Info")
157
  def root():
 
158
  return {
159
  "service": "Surya OCR API",
160
  "status": "ready" if recognition_predictor else "loading",
161
- "usage": "POST /ocr with any file attached as form-data field 'file'",
162
  "supported_formats": sorted(SUPPORTED_EXTENSIONS),
163
  }
164
 
165
 
166
- @app.get("/health")
167
  def health():
 
168
  return {"status": "ready" if recognition_predictor else "loading"}
169
 
170
 
171
  @app.post("/ocr", summary="Extract text from any document")
172
- async def ocr(file: UploadFile = File(..., description="Any image, PDF, Word, or PowerPoint file")):
 
 
 
173
  """
174
  Upload **any** document and receive the extracted text.
175
 
 
 
176
  Accepts: JPG, PNG, WEBP, TIFF, BMP, PDF, DOCX, DOC, PPTX, PPT, ODT, ODP, RTF
177
 
178
- Returns: { "text": "..." }
179
  """
180
  data = await file.read()
181
 
182
- # Size check
183
  size_mb = len(data) / (1024 * 1024)
184
  if size_mb > MAX_FILE_SIZE_MB:
185
  raise HTTPException(status_code=413, detail=f"File too large ({size_mb:.1f} MB). Max: {MAX_FILE_SIZE_MB} MB.")
 
2
  Surya OCR - Universal REST API
3
  One endpoint: POST /ocr β€” any file in, extracted text out.
4
  Supports: Images, PDF, Word (.docx/.doc), PowerPoint (.pptx/.ppt), and more.
5
+ Secret key authentication via X-API-Key header.
6
  Hugging Face Spaces (Free Tier) compatible.
7
  """
8
 
9
  import io
10
  import gc
11
+ import os
12
  import logging
13
  import subprocess
14
  import tempfile
 
16
  from pathlib import Path
17
 
18
  import uvicorn
19
+ from fastapi import FastAPI, File, UploadFile, HTTPException, Security
20
  from fastapi.middleware.cors import CORSMiddleware
21
  from fastapi.responses import JSONResponse
22
+ from fastapi.security import APIKeyHeader
23
  from PIL import Image
24
 
25
  logging.basicConfig(level=logging.INFO)
26
  logger = logging.getLogger(__name__)
27
 
28
+ # ── Auth ──────────────────────────────────────────────────────────────────────
29
+ # Set your secret key as an environment variable in HF Space Settings:
30
+ # Settings β†’ Variables and secrets β†’ New secret β†’ Name: API_SECRET_KEY
31
+ API_SECRET_KEY = os.environ.get("API_SECRET_KEY", "")
32
+
33
+ api_key_header = APIKeyHeader(name="X-API-Key", auto_error=False)
34
+
35
+ def verify_key(api_key: str = Security(api_key_header)):
36
+ if not API_SECRET_KEY:
37
+ raise RuntimeError("API_SECRET_KEY environment variable is not set on the server.")
38
+ if api_key != API_SECRET_KEY:
39
+ raise HTTPException(status_code=401, detail="Invalid or missing API key. Pass it as X-API-Key header.")
40
+ return api_key
41
+
42
  # ── Global model holders ──────────────────────────────────────────────────────
43
  recognition_predictor = None
44
  detection_predictor = None
45
 
46
  MAX_FILE_SIZE_MB = 30
47
+ MAX_PAGES = 10
48
 
49
  SUPPORTED_EXTENSIONS = {
 
50
  ".jpg", ".jpeg", ".png", ".webp", ".tiff", ".tif", ".bmp",
 
51
  ".pdf",
52
  ".docx", ".doc",
53
  ".pptx", ".ppt",
 
85
 
86
  app = FastAPI(
87
  title="Surya OCR API",
88
+ description="Upload any document β€” image, PDF, Word, PowerPoint β€” get back extracted text. Requires X-API-Key header.",
89
  version="2.0.0",
90
  lifespan=lifespan,
91
  )
 
105
 
106
 
107
  def convert_office(data: bytes, suffix: str) -> list:
 
 
 
 
108
  with tempfile.TemporaryDirectory() as tmpdir:
109
  input_path = Path(tmpdir) / f"input{suffix}"
110
  input_path.write_bytes(data)
 
129
 
130
 
131
  def file_to_images(data: bytes, suffix: str) -> list:
 
132
  image_exts = {".jpg", ".jpeg", ".png", ".webp", ".tiff", ".tif", ".bmp"}
133
  office_exts = {".docx", ".doc", ".pptx", ".ppt", ".odt", ".odp", ".rtf"}
134
 
 
165
 
166
  @app.get("/", summary="Health / Info")
167
  def root():
168
+ """Public endpoint β€” no key required."""
169
  return {
170
  "service": "Surya OCR API",
171
  "status": "ready" if recognition_predictor else "loading",
172
+ "usage": "POST /ocr with your file as form-data field 'file' and X-API-Key header",
173
  "supported_formats": sorted(SUPPORTED_EXTENSIONS),
174
  }
175
 
176
 
177
+ @app.get("/health", summary="Health check")
178
  def health():
179
+ """Public endpoint β€” no key required."""
180
  return {"status": "ready" if recognition_predictor else "loading"}
181
 
182
 
183
  @app.post("/ocr", summary="Extract text from any document")
184
+ async def ocr(
185
+ file: UploadFile = File(..., description="Any image, PDF, Word, or PowerPoint file"),
186
+ _: str = Security(verify_key), # ← auth happens here
187
+ ):
188
  """
189
  Upload **any** document and receive the extracted text.
190
 
191
+ **Requires** `X-API-Key` header with your secret key.
192
+
193
  Accepts: JPG, PNG, WEBP, TIFF, BMP, PDF, DOCX, DOC, PPTX, PPT, ODT, ODP, RTF
194
 
195
+ Returns: `{ "text": "..." }`
196
  """
197
  data = await file.read()
198
 
 
199
  size_mb = len(data) / (1024 * 1024)
200
  if size_mb > MAX_FILE_SIZE_MB:
201
  raise HTTPException(status_code=413, detail=f"File too large ({size_mb:.1f} MB). Max: {MAX_FILE_SIZE_MB} MB.")