Spaces:
Sleeping
Sleeping
Sam commited on
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
import os
|
| 2 |
import re
|
|
|
|
| 3 |
import gradio as gr
|
| 4 |
from typing import Tuple, Optional, Dict, List
|
| 5 |
from deep_translator import GoogleTranslator
|
|
@@ -13,33 +14,60 @@ from PIL import Image
|
|
| 13 |
# Load environment variables
|
| 14 |
load_dotenv()
|
| 15 |
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
"""
|
| 26 |
-
try:
|
| 27 |
-
# Open the image file
|
| 28 |
-
image = Image.open(image_path)
|
| 29 |
|
| 30 |
-
|
| 31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
# Return the extracted text
|
| 37 |
-
return cleaned_text
|
| 38 |
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
print(f"Error in OCR: {str(e)}")
|
| 42 |
-
return "Error in extracting text from image."
|
| 43 |
|
| 44 |
|
| 45 |
|
|
@@ -398,17 +426,15 @@ class QuestifyAI:
|
|
| 398 |
self.translation_manager = TranslationManager()
|
| 399 |
self.language_manager = LanguageManager()
|
| 400 |
self.model_manager = ModelManager(self.api_key_manager)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 401 |
|
| 402 |
def structure_question(self, question: str) -> str:
|
| 403 |
-
"""
|
| 404 |
-
Organize user input by removing unwanted symbols and ensuring clarity.
|
| 405 |
-
|
| 406 |
-
Args:
|
| 407 |
-
question (str): The original input question
|
| 408 |
-
|
| 409 |
-
Returns:
|
| 410 |
-
str: A structured, cleaned-up question
|
| 411 |
-
"""
|
| 412 |
question = re.sub(r"[#/*\\]", "", question)
|
| 413 |
question = question.strip()
|
| 414 |
return question
|
|
@@ -424,17 +450,7 @@ class QuestifyAI:
|
|
| 424 |
input_language: str,
|
| 425 |
question_type: str
|
| 426 |
) -> Tuple[str, str, str]:
|
| 427 |
-
"""
|
| 428 |
-
Process a question through translation and model response pipeline.
|
| 429 |
-
|
| 430 |
-
Args:
|
| 431 |
-
question (str): The input question
|
| 432 |
-
input_language (str): Language of the input question
|
| 433 |
-
question_type (str): Type of question (general, math, job)
|
| 434 |
-
|
| 435 |
-
Returns:
|
| 436 |
-
Tuple of (English Question, English Answer, Translated Answer)
|
| 437 |
-
"""
|
| 438 |
# Clean and structure the question
|
| 439 |
question = self.structure_question(question)
|
| 440 |
|
|
@@ -461,7 +477,7 @@ class QuestifyAI:
|
|
| 461 |
|
| 462 |
def ocr_from_image(self, image: Image.Image) -> str:
|
| 463 |
"""
|
| 464 |
-
Extract text from an uploaded image using OCR
|
| 465 |
|
| 466 |
Args:
|
| 467 |
image (Image.Image): The PIL image object from which text will be extracted.
|
|
@@ -470,12 +486,49 @@ class QuestifyAI:
|
|
| 470 |
str: The extracted text from the image.
|
| 471 |
"""
|
| 472 |
try:
|
| 473 |
-
|
| 474 |
-
|
| 475 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 476 |
except Exception as e:
|
|
|
|
| 477 |
print(f"Error in OCR: {str(e)}")
|
|
|
|
| 478 |
return "Error in extracting text from image."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 479 |
|
| 480 |
def launch_ui(self):
|
| 481 |
"""Launch Gradio web interface for QuestifyAI."""
|
|
|
|
| 1 |
import os
|
| 2 |
import re
|
| 3 |
+
import io
|
| 4 |
import gradio as gr
|
| 5 |
from typing import Tuple, Optional, Dict, List
|
| 6 |
from deep_translator import GoogleTranslator
|
|
|
|
| 14 |
# Load environment variables
|
| 15 |
load_dotenv()
|
| 16 |
|
| 17 |
+
class OCRProcessor:
|
| 18 |
+
def __init__(self):
|
| 19 |
+
# Fetch the API keys from environment variables (secrets)
|
| 20 |
+
self.api_keys = [
|
| 21 |
+
os.getenv("ocr_space_api_key1"), # Get the first API key from environment variable
|
| 22 |
+
os.getenv("ocr_space_api_key2") # Get the second API key from environment variable
|
| 23 |
+
]
|
| 24 |
+
|
| 25 |
+
def ocr_from_image(self, image: Image.Image) -> str:
|
| 26 |
+
"""
|
| 27 |
+
Extract text from an uploaded image using OCR (Optical Character Recognition).
|
| 28 |
|
| 29 |
+
Args:
|
| 30 |
+
image (Image.Image): The PIL image object from which text will be extracted.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
|
| 32 |
+
Returns:
|
| 33 |
+
str: The extracted text from the image.
|
| 34 |
+
"""
|
| 35 |
+
for api_key in self.api_keys:
|
| 36 |
+
try:
|
| 37 |
+
# Prepare the API endpoint and data
|
| 38 |
+
url = "https://api.ocr.space/parse/image"
|
| 39 |
+
payload = {
|
| 40 |
+
'apikey': api_key,
|
| 41 |
+
'language': 'eng', # You can set this to the desired language
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
# Convert the image to bytes (PIL image to byte array)
|
| 45 |
+
img_byte_arr = io.BytesIO()
|
| 46 |
+
image.save(img_byte_arr, format='PNG')
|
| 47 |
+
img_byte_arr = img_byte_arr.getvalue()
|
| 48 |
+
|
| 49 |
+
# Make the API request
|
| 50 |
+
response = requests.post(url, data=payload, files={'file': img_byte_arr})
|
| 51 |
+
|
| 52 |
+
# Parse the JSON response
|
| 53 |
+
result = response.json()
|
| 54 |
+
|
| 55 |
+
# Check if the response is valid and contains parsed text
|
| 56 |
+
if 'ParsedResults' in result:
|
| 57 |
+
extracted_text = result['ParsedResults'][0]['ParsedText']
|
| 58 |
+
return extracted_text.strip()
|
| 59 |
+
else:
|
| 60 |
+
# If the OCR response is empty or contains no parsed text, handle that
|
| 61 |
+
error_message = result.get('ErrorMessage', 'Unknown error')
|
| 62 |
+
print(f"Error from OCR API: {error_message}")
|
| 63 |
+
return f"Error in OCR extraction: {error_message}"
|
| 64 |
|
| 65 |
+
except Exception as e:
|
| 66 |
+
# If an error occurs (e.g., network issues), print the error and try the next API key
|
| 67 |
+
print(f"Error using API key {api_key}: {str(e)}")
|
|
|
|
|
|
|
| 68 |
|
| 69 |
+
# If both API keys fail, return a final error message
|
| 70 |
+
return "Error in extracting text from image using both API keys."
|
|
|
|
|
|
|
| 71 |
|
| 72 |
|
| 73 |
|
|
|
|
| 426 |
self.translation_manager = TranslationManager()
|
| 427 |
self.language_manager = LanguageManager()
|
| 428 |
self.model_manager = ModelManager(self.api_key_manager)
|
| 429 |
+
# Fetch OCR API keys from Hugging Face Space secrets
|
| 430 |
+
self.ocr_api_keys = [
|
| 431 |
+
os.getenv("ocr_space_api_key1"), # Get the first OCR API key from environment variable
|
| 432 |
+
os.getenv("ocr_space_api_key2") # Get the second OCR API key from environment variable
|
| 433 |
+
]
|
| 434 |
+
self.api_key_index = 0 # Start with the first API key
|
| 435 |
|
| 436 |
def structure_question(self, question: str) -> str:
|
| 437 |
+
"""Organize user input by removing unwanted symbols and ensuring clarity."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 438 |
question = re.sub(r"[#/*\\]", "", question)
|
| 439 |
question = question.strip()
|
| 440 |
return question
|
|
|
|
| 450 |
input_language: str,
|
| 451 |
question_type: str
|
| 452 |
) -> Tuple[str, str, str]:
|
| 453 |
+
"""Process a question through translation and model response pipeline."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 454 |
# Clean and structure the question
|
| 455 |
question = self.structure_question(question)
|
| 456 |
|
|
|
|
| 477 |
|
| 478 |
def ocr_from_image(self, image: Image.Image) -> str:
|
| 479 |
"""
|
| 480 |
+
Extract text from an uploaded image using OCR.space API.
|
| 481 |
|
| 482 |
Args:
|
| 483 |
image (Image.Image): The PIL image object from which text will be extracted.
|
|
|
|
| 486 |
str: The extracted text from the image.
|
| 487 |
"""
|
| 488 |
try:
|
| 489 |
+
api_url = "https://api.ocr.space/parse/image"
|
| 490 |
+
current_api_key = self.ocr_api_keys[self.api_key_index]
|
| 491 |
+
|
| 492 |
+
# Open the image and send it to the API
|
| 493 |
+
img_byte_arr = io.BytesIO()
|
| 494 |
+
image.save(img_byte_arr, format="PNG")
|
| 495 |
+
img_byte_arr = img_byte_arr.getvalue()
|
| 496 |
+
|
| 497 |
+
files = {'file': ('image.png', img_byte_arr, 'image/png')}
|
| 498 |
+
data = {'apikey': current_api_key}
|
| 499 |
+
|
| 500 |
+
# Send the request to OCR.space API
|
| 501 |
+
response = requests.post(api_url, files=files, data=data)
|
| 502 |
+
response.raise_for_status() # Check for errors in the request
|
| 503 |
+
|
| 504 |
+
# Parse the JSON response
|
| 505 |
+
result = response.json()
|
| 506 |
+
|
| 507 |
+
# Check if the OCR was successful
|
| 508 |
+
if result.get("OCRExitCode") == 1:
|
| 509 |
+
# Extract text from the response
|
| 510 |
+
extracted_text = result["ParsedResults"][0]["ParsedText"]
|
| 511 |
+
return extracted_text.strip()
|
| 512 |
+
else:
|
| 513 |
+
# If OCR failed, try switching the API key
|
| 514 |
+
self.switch_api_key()
|
| 515 |
+
return "Error in extracting text from image."
|
| 516 |
+
|
| 517 |
+
except requests.exceptions.RequestException as e:
|
| 518 |
+
# Handle request errors
|
| 519 |
+
print(f"Error in OCR request: {str(e)}")
|
| 520 |
+
self.switch_api_key()
|
| 521 |
+
return "Error in extracting text from image."
|
| 522 |
except Exception as e:
|
| 523 |
+
# Handle general errors
|
| 524 |
print(f"Error in OCR: {str(e)}")
|
| 525 |
+
self.switch_api_key()
|
| 526 |
return "Error in extracting text from image."
|
| 527 |
+
|
| 528 |
+
def switch_api_key(self):
|
| 529 |
+
"""Switch to the next OCR API key when the current one reaches its limit or fails."""
|
| 530 |
+
self.api_key_index = (self.api_key_index + 1) % len(self.ocr_api_keys)
|
| 531 |
+
print(f"Switched to API Key {self.api_key_index + 1}")
|
| 532 |
|
| 533 |
def launch_ui(self):
|
| 534 |
"""Launch Gradio web interface for QuestifyAI."""
|