Alfred Ang
Upload folder using huggingface_hub
532ffe7 verified
Raw
History Blame Contribute Delete
5.76 kB
"""
Entity Extraction Processor
This module handles entity extraction from documents and images using OpenRouter API.
Uses vision-capable models (GPT-4o, Gemini) for image processing.
Updated: 26 January 2026
"""
import os
import json
import base64
from typing import Dict, Any, Union
from PIL import Image
import io
from settings.api_manager import load_api_keys
# OpenAI client for OpenRouter
from openai import OpenAI
# Default model for entity extraction (vision-capable)
DEFAULT_MODEL = "openai/gpt-4o-mini"
def _get_openrouter_client() -> OpenAI:
"""Get OpenAI client configured for OpenRouter"""
api_keys = load_api_keys()
api_key = api_keys.get("OPENROUTER_API_KEY", "")
if not api_key:
api_key = api_keys.get("OPENAI_API_KEY", "")
if not api_key:
raise ValueError("No API key configured. Please set OPENROUTER_API_KEY in Settings.")
return OpenAI(
api_key=api_key,
base_url="https://openrouter.ai/api/v1"
)
def extract_entities(document_content: Union[str, bytes], custom_instructions: str, is_image: bool = False) -> Dict[str, Any]:
"""
Extract named entities from text or images using OpenRouter API.
If `is_image` is True, process the content as an image.
Args:
document_content: Text content or image bytes
custom_instructions: Additional instructions for extraction
is_image: Whether the content is an image
Returns:
Dictionary with extracted entities
"""
try:
client = _get_openrouter_client()
except ValueError as e:
return {"error": str(e), "entities": []}
# JSON format for response
json_format = """
{
"entities": [
{
"type": "PERSON/COMPANY NAME/COMPANY UEN/DOCUMENT DATE/NRIC",
"value": "extracted entity",
"context": "relevant surrounding text"
}
]
}
"""
system_prompt = f"""Task: Named Entity Extraction
Instructions: {custom_instructions}
Analyze the following document and extract named entities.
**STRICTLY return only JSON** in this format:
```json
{json_format}
```
Do not include any explanations, bullet points, or markdown formatting.
Exclude any mentions of Tertiary Infotech as the company."""
try:
# Handle image content
if is_image and isinstance(document_content, bytes):
# Convert bytes to base64 for API
base64_image = base64.b64encode(document_content).decode('utf-8')
# Use vision model for image processing
response = client.chat.completions.create(
model=DEFAULT_MODEL,
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": system_prompt},
{
"type": "image_url",
"image_url": {
"url": f"data:image/png;base64,{base64_image}"
}
}
]
}
],
temperature=0.2,
response_format={"type": "json_object"}
)
elif isinstance(document_content, Image.Image):
# Handle PIL Image objects
buffer = io.BytesIO()
document_content.save(buffer, format='PNG')
base64_image = base64.b64encode(buffer.getvalue()).decode('utf-8')
response = client.chat.completions.create(
model=DEFAULT_MODEL,
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": system_prompt},
{
"type": "image_url",
"image_url": {
"url": f"data:image/png;base64,{base64_image}"
}
}
]
}
],
temperature=0.2,
response_format={"type": "json_object"}
)
else:
# Handle text content
response = client.chat.completions.create(
model=DEFAULT_MODEL,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": str(document_content)}
],
temperature=0.2,
response_format={"type": "json_object"}
)
# Parse response
response_text = response.choices[0].message.content.strip()
# Clean up markdown if present
if response_text.startswith("```json"):
response_text = response_text[7:]
if response_text.startswith("```"):
response_text = response_text[3:]
if response_text.endswith("```"):
response_text = response_text[:-3]
response_text = response_text.strip()
# Parse JSON
extracted_entities = json.loads(response_text)
# Validate structure
if not isinstance(extracted_entities, dict) or "entities" not in extracted_entities:
return {"entities": [], "error": "Invalid JSON format"}
return extracted_entities
except json.JSONDecodeError as e:
print(f"JSON decode error: {e}")
return {"entities": [], "error": "Invalid JSON response"}
except Exception as e:
print(f"Error extracting entities: {e}")
return {"entities": [], "error": str(e)}