anpr-vision-api / app.py
bhargavcli's picture
Update app.py
8c4457b verified
Raw
History Blame Contribute Delete
4.85 kB
import gradio as gr
from llama_cpp import Llama
from llama_cpp.llama_chat_format import Llava15ChatHandler
from huggingface_hub import hf_hub_download
import base64
import json
import os
import io
from PIL import Image
# ---------------------------------------------------------
# IMPORTANT: REPLACE THESE WITH YOUR HUGGING FACE DETAILS
# ---------------------------------------------------------
HF_USERNAME = "bhargavcli"
REPO_NAME = "anpr-vision-api"
# For example: "Bhargav123/moondream2-anpr"
REPO_ID = f"{HF_USERNAME}/{REPO_NAME}"
# ---------------------------------------------------------
print("Downloading model files from your repository...")
try:
mmproj_path = hf_hub_download(repo_id=REPO_ID, filename="moondream2-mmproj-f16.gguf")
model_path = hf_hub_download(repo_id=REPO_ID, filename="moondream2-text-model-f16.gguf")
print("Download complete!")
except Exception as e:
print(f"Error downloading models. Make sure you entered your REPO_ID correctly! Error: {e}")
# Fallback to public repo for testing if it fails
mmproj_path = hf_hub_download(repo_id="moondream/moondream2-gguf", filename="moondream2-mmproj-f16.gguf")
model_path = hf_hub_download(repo_id="moondream/moondream2-gguf", filename="moondream2-text-model-f16.gguf")
print("Loading Multimodal Projector and Text Model...")
chat_handler = Llava15ChatHandler(clip_model_path=mmproj_path)
llm = Llama(
model_path=model_path,
chat_handler=chat_handler,
n_ctx=2048, # Context window
logits_all=True
)
print("Model loaded successfully!")
SYSTEM_PROMPT = """You are an expert Automated Number Plate Recognition (ANPR) vision-language engine optimized for real-world traffic scenarios. Your task is to process the vehicle image provided in the input, apply specialized structural preprocessing filters mentally, and extract the license plate text with absolute structural fidelity.
Image Processing Instructions:
1. Isolate the high-probability license plate region (typically a rectangular plate on the lower bumper or grille).
2. Compensate for environmental distortions including sun glare, shadows, and motion blur by sharpening character boundaries.
3. If the plate uses a stacked/multi-line layout, perform spatial vertical sorting (read line 1 completely from left-to-right, then line 2 completely from left-to-right).
4. Parse the characters using standard Indian Regional Transport Office (RTO) syntax: [State Code (2 Letters)] [District Code (2 Digits)] [Series (1-2 Letters)] [Unique ID (4 Digits)].
5. Discard screw marks, plate borders, and dirt spots that mimic alphanumeric noise (e.g., mistaking a screw for a dot or '1').
Output Format:
Return your response strictly in the following JSON format. Do not include any introductory conversational text or markdown code blocks around the JSON payload.
{
"detection_status": "Success" or "Failed",
"layout_type": "Single-line" or "Multi-line",
"raw_extracted_text": "Exactly what is printed including spacing",
"cleaned_plate_number": "Sanitized alphanumeric sequence without spaces or symbols",
"confidence_assessment": "High", "Medium", or "Low"
}"""
def extract_plate(image):
if image is None:
return json.dumps({"detection_status": "Failed", "error": "No image provided"})
# Convert Gradio Image (numpy array or PIL Image) to base64
if not isinstance(image, Image.Image):
image = Image.fromarray(image)
buffered = io.BytesIO()
image.save(buffered, format="JPEG")
img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
data_uri = f"data:image/jpeg;base64,{img_str}"
print("Running inference...")
# Send to Moondream2 via llama_cpp
response = llm.create_chat_completion(
messages=[
{
"role": "system",
"content": SYSTEM_PROMPT
},
{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": data_uri}},
{"type": "text", "text": "Extract the license plate JSON."}
]
}
],
max_tokens=150,
temperature=0.1 # Low temperature for accurate OCR
)
output = response["choices"][0]["message"]["content"]
# Try to clean it up in case the LLM hallucinates markdown blocks
output = output.replace("```json", "").replace("```", "").strip()
return output
# Create a Gradio interface
# Create a Gradio interface
demo = gr.Interface(
fn=extract_plate,
inputs=gr.Image(type="pil", label="Vehicle Image"),
outputs=gr.JSON(label="Extracted License Plate Data"),
title="ANPR Vision-Language API",
description="Upload a picture of a vehicle to extract its license plate using Moondream2."
)
# Launch the app
demo.launch()