import os from dotenv import load_dotenv load_dotenv(override=True) import io import os from typing import Union import easyocr import firebase_admin import gradio as gr from firebase_admin import credentials, firestore from loguru import logger from PIL import Image from thefuzz import fuzz from processor import ImageHandler, PreprocessingConfig, ProcessedImage class EasyOCRReader: def __init__(self): self.reader = easyocr.Reader(["fr", "en"], gpu=False) self.process = ImageHandler() self.config = PreprocessingConfig() def chat(self, image): processed: ProcessedImage = self.process.preprocess_image(image, self.config) image = Image.fromarray(processed.image) # Convert image to bytes img_byte_arr = io.BytesIO() image.save(img_byte_arr, format="PNG") img_byte_arr = img_byte_arr.getvalue() # Call readtext with image bytes texts = self.reader.readtext(img_byte_arr, detail=0) logger.info(" ".join(texts)) return texts class FirebaseConnector: def get_config(self): return { "type": os.getenv("type"), "project_id": os.getenv("project_id"), "private_key_id": os.getenv("private_key_id"), "private_key": os.getenv("private_key").replace("\\n", "\n"), "client_email": os.getenv("client_email"), "client_id": os.getenv("client_id"), "auth_uri": os.getenv("auth_uri"), "token_uri": os.getenv("token_uri"), "auth_provider_x509_cert_url": os.getenv("auth_provider_x509_cert_url"), "client_x509_cert_url": os.getenv("client_x509_cert_url"), "universe_domain": os.getenv("universe_domain"), } def __init__(self): # print(os.environ) firebase_config = self.get_config() cred = credentials.Certificate(firebase_config) firebase_admin.initialize_app(cred) self.db = firestore.client() self.collecttion_name = os.getenv("collection", "id-card") def add(self, ocr: str, key: str): doc_ref = self.db.collection(self.collecttion_name).document(key) if doc_ref.get().exists: raise ValueError(f"Document with key {key} already exists.") return self.db.collection(self.collecttion_name).add({"ocr": ocr}, document_id=key) def get_id_counted(self): docs = self.db.collection(self.collecttion_name).stream() count = sum(1 for _ in docs) return count def search_element(words: list[str], target: str, thr: float = 60): scores = list(map(lambda x: fuzz.partial_ratio(x, target), words)) word_scores = [(w, s) for w, s in zip(words, scores) if s >= thr] return word_scores class VoterCardVerifier: def __init__(self): self.db = FirebaseConnector() self.ocr_engine = EasyOCRReader() self.thr = int(os.getenv("thr", 75)) self.n_cards = 0 def verify_card(self, image: Union[str, Image.Image], card_number,): self.n_cards = self.get_id_counted() # Convertir l'image pour Groq if isinstance(image, str): image = Image.open(image) # Préparer la requête pour le modèle et l'appeler ocr_data = self.ocr_engine.chat(image) score1 = search_element(ocr_data, "camer", self.thr) score2 = search_element(ocr_data, card_number, self.thr) ocr_data = score1 + score2 logger.info(str(ocr_data)) # valider les entrées is_valid = len(score1) and len(score2) try: if is_valid: # Sauvegarder dans Firebase self.save_card_number(ocr_data, card_number) self.n_cards += 1 return f"Your ID Card have been recorded, thank you !!! Num Card: {self.n_cards}" else: return f"Card number not found, please improve the quality of image passed. Num Card: {self.n_cards}" except ValueError as ex: return f"ID Card already saved in the database. Num Card: {self.n_cards}" def save_card_number(self, ocr_data, card_number): return self.db.add(str(ocr_data), str(card_number)) def get_id_counted(self): return self.db.get_id_counted() # Interface Gradio def create_interface(): verifier = VoterCardVerifier() description = ( "Card ID Counter is an application designed to count voter card numbers " "by analyzing uploaded images using OCR technology. It ensures accuracy by " "checking if the provided number appears on the card and confirming its from Cameroon.\n\n" "🌟 **Code Repository**: [Card ID Counter GitHub](https://github.com/Nganga-AI/card-counter)" ) def process(image, card_number: str): if not card_number.strip(): return "Enter your elect count number" return verifier.verify_card(image, card_number) interface = gr.Interface( fn=process, inputs=[ gr.Image(type="pil", label="Upload ID Card Image"), gr.Textbox(label="Card Number"), ], outputs=gr.Textbox(label="Result"), title="Voters ID Counter", description=description, ) return interface if __name__ == "__main__": # Créer et lancer l'interface demo = create_interface() demo.launch()