govbridge-api / ingestion /ocr_processor_runner.py
Acytel's picture
fix: Ocr time
b0e98aa
Raw
History Blame Contribute Delete
4.41 kB
import os
import sys
import hashlib
import time
import asyncio
import httpx
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from ingestion.ocr_processor import download_and_extract
# --- SSOT INGESTION CONFIGURATION ---
HF_SPACE_URL = os.environ.get("HF_SPACE_URL", "https://harshrawat18-govbridge-api.hf.space")
ADMIN_SECRET = os.environ.get("ADMIN_SECRET", "")
PDF_URL = os.environ.get("PDF_URL", "")
def chunk_text(text: str, chunk_size: int = 300) -> list:
"""Split text into word-based chunks with overlap."""
words = text.split()
chunks = []
overlap = 30
step = chunk_size - overlap
for i in range(0, len(words), step):
chunk = " ".join(words[i:i + chunk_size])
if chunk.strip():
chunks.append(chunk)
return chunks
async def ingest_chunk_async(
client: httpx.AsyncClient,
chunk: str,
metadata: dict,
chunk_index: int,
semaphore: asyncio.Semaphore
) -> bool:
"""Ingest a single chunk with semaphore-controlled concurrency."""
async with semaphore:
content_hash = hashlib.sha256(
f"{metadata['source_url']}_{chunk_index}".encode()
).hexdigest()
payload = {
"title": metadata.get("title", "Government Document"),
"text": chunk,
"source_url": metadata["source_url"],
"ministry": metadata.get("ministry", "Government of India"),
"state": metadata.get("state", "National"),
"doc_type": metadata.get("doc_type", "document"),
"content_hash": content_hash,
"chunk_index": chunk_index
}
try:
response = await client.post(
f"{HF_SPACE_URL}/api/admin/ingest",
json=payload,
headers={"X-Admin-Secret": ADMIN_SECRET},
params={"admin_key": ADMIN_SECRET},
timeout=30.0
)
if response.status_code == 200:
print(f"βœ… Chunk {chunk_index+1} injected instantly")
return True
else:
print(f"⚠️ Chunk {chunk_index+1} failed: {response.status_code}")
return False
except Exception as e:
print(f"❌ Chunk {chunk_index+1} error: {e}")
return False
async def ingest_all_chunks_async(chunks: list, metadata: dict):
"""Dispatch all chunks concurrently with controlled batch size."""
semaphore = asyncio.Semaphore(10)
async with httpx.AsyncClient() as client:
tasks = [
ingest_chunk_async(client, chunk, metadata, i, semaphore)
for i, chunk in enumerate(chunks)
]
results = await asyncio.gather(*tasks, return_exceptions=True)
successful = sum(1 for r in results if r is True)
failed = len(results) - successful
print(f"βœ… Ingested {successful}/{len(chunks)} chunks")
if failed > 0:
print(f"⚠️ {failed} chunks failed β€” retry on next run")
return successful
def main():
if not PDF_URL:
print("❌ No PDF_URL provided in terminal")
sys.exit(1)
if not ADMIN_SECRET:
print("❌ πŸ”’ SECURITY HALT: ADMIN_SECRET environment variable is missing!")
sys.exit(1)
print(f"πŸš€ Starting Async PDF extraction: {PDF_URL}")
try:
result = download_and_extract(PDF_URL)
text = result["text"]
word_count = len(text.split())
print(f"βœ… Extracted {word_count} words in memory via {result['extraction_method']}")
chunks = chunk_text(text, chunk_size=300)
print(f"πŸ“¦ Sliced into {len(chunks)} high-density AI chunks")
# Start precise benchmarking timer
start_time = time.time()
asyncio.run(ingest_all_chunks_async(chunks, {
"source_url": PDF_URL,
"title": "Government Policy Document",
"ministry": "Government of India",
"state": "National",
"doc_type": "document"
}))
# End timer
elapsed_time = time.time() - start_time
print(f"⏱️ Async Ingestion Time: {elapsed_time:.2f} seconds")
print(f"πŸŽ‰ MASSIVE W! {len(chunks)} chunks ingested to Vector DB.")
except Exception as e:
print(f"❌ Critical failure: {e}")
sys.exit(1)
if __name__ == "__main__":
main()