Spaces:
Sleeping
Sleeping
File size: 9,663 Bytes
7215d13 146963b f3a1d44 146963b 7215d13 333240a 7215d13 146963b 7215d13 333240a 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 7215d13 146963b 24d016e 146963b 24d016e 146963b 24d016e 146963b 7215d13 146963b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | import gradio as gr
import tensorflow as tf
from transformers import AutoImageProcessor, AutoModelForImageClassification
import numpy as np
import pymongo
import random
import base64 # Import base64 module
import io # Import io module
from PIL import Image # Import PIL
print(gr.__version__)
# --- Loading models and DB connection (Keep as is) ---
processor = AutoImageProcessor.from_pretrained("SowmyaKannan/fine_tuned_vit_model")
model = AutoModelForImageClassification.from_pretrained("SowmyaKannan/Vit-FER")
labels = ['angry', 'disgust', 'fear', 'happy', 'sad', 'neutral', 'surprise']
mongo_db_uri = "mongodb+srv://sowmyakannan10:O2BkajONKtfZsNqm@cluster0.zehazwd.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0"
client = None
db = None
quotes_collection = None
author_list = []
try:
mongodb_uri = mongo_db_uri
if not mongodb_uri: print("MONGODB_URI not found!!")
else:
print("Connecting to MongoDB...")
client = pymongo.MongoClient(mongodb_uri, serverSelectionTimeoutMS=5000)
client.admin.command('ping')
print("Successfully connected to MongoDB!")
db = client['AhumDB']
quotes_collection = db['AhumQuotes']
author_list = sorted(filter(None, quotes_collection.distinct("author")))
print(f"Fetched {len(author_list)} authors.")
except Exception as e:
print(f"Error during MongoDB setup: {e}")
client = None
# --- End loading models and DB connection ---
# --- Quote fetching function (Keep as is) ---
def get_quotes(index=None, authors=None):
if client is None or quotes_collection is None:
print("MongoDB connection not available. Cannot fetch quote.")
return "Quote data unavailable (DB connection issue).", "Unknown"
pipeline = []
emotion_label = None
emotion_match = {}
if index is not None and 0 <= index < len(labels):
emotion_label = labels[index]
emotion_match = {"emotions": {"$regex": f"^{emotion_label}$", "$options": "i"}}
author_match = {}
if authors:
author_match = {"$or": [{"author": {"$regex": f"^{a}$", "$options": "i"}} for a in authors]}
combined_match = {}
if emotion_match and author_match: combined_match = {"$and": [emotion_match, author_match]}
elif emotion_match: combined_match = emotion_match
elif author_match: combined_match = author_match
if combined_match: pipeline.append({"$match": combined_match})
pipeline.append({"$sample": {"size": 1}})
try:
result = list(quotes_collection.aggregate(pipeline))
if result: return result[0].get('quote', "Quote not found."), result[0].get('author', "Unknown")
else: # Fallback logic
if emotion_label:
fallback_pipeline = [{"$match": {"emotions": {"$regex": f"^{emotion_label}$", "$options": "i"}}}, {"$sample": {"size": 1}}]
fallback_result = list(quotes_collection.aggregate(fallback_pipeline))
if fallback_result: return fallback_result[0].get('quote', "Quote not found."), fallback_result[0].get('author', "Unknown")
return f"Finding strength in '{emotion_label}' comes from within.", "Unknown"
else: return "Could not find a suitable quote at this time.", "Unknown"
except Exception as e:
print(f"Error in get_quotes: {e}")
return "Quote data unavailable (DB query error).", "Unknown"
# --- End quote fetching ---
# --- CORE LOGIC: Process PIL image and get prediction/quote ---
def process_pil_image_and_get_quote(img_pil, selected_authors):
"""Takes a PIL image and author list, returns formatted prediction string."""
if img_pil is None:
return "Error: Process function received an empty image."
try:
print(f"Processing PIL Image - Mode: {img_pil.mode}, Size: {img_pil.size}") # Debug
# Ensure image is RGB if required by processor/model
if img_pil.mode != 'RGB':
img_pil = img_pil.convert('RGB')
print("Converted image to RGB.") # Debug
# Process image with Hugging Face processor
inputs = processor(images=img_pil, return_tensors="pt")
# Model prediction
outputs = model(**inputs)
logits = outputs.logits
predicted_class_index = np.argmax(logits.detach().numpy(), axis=1)[0]
predicted_emotion = labels[predicted_class_index]
print(f"Predicted Emotion Index: {predicted_class_index}, Emotion: {predicted_emotion}") # Debug
# Get quote
quote, author = get_quotes(predicted_class_index, authors=selected_authors)
return f"Predicted Emotion: {predicted_emotion.capitalize()}\n\n\"{quote}\"\n\n— {author}"
except Exception as e:
import traceback
print(f"Error in process_pil_image_and_get_quote: {e}\n{traceback.format_exc()}")
return f"An error occurred during image processing: {e}"
# --- API FUNCTION: Handles Base64 input ---
def main_fn_api(img_base64_string, selected_authors):
"""
API endpoint function. Expects a base64 data URI string for the image.
Decodes it and calls the core processing function.
"""
print(">>> API endpoint main_fn_api called.") # Debug
if not isinstance(img_base64_string, str) or not img_base64_string.startswith('data:image'):
print(f"Error: Invalid base64 string received: {str(img_base64_string)[:100]}...") # Debug
return "Error: Invalid image data received via API."
try:
# 1. Split header (e.g., "data:image/png;base64,") and encoded data
try:
header, encoded_data = img_base64_string.split(',', 1)
except ValueError:
print("Error: Base64 string does not contain expected comma separator.")
return "Error: Malformed Base64 image data."
# 2. Decode Base64 data
print(f"Attempting to decode base64 data (starts with {encoded_data[:10]}...).") # Debug
decoded_bytes = base64.b64decode(encoded_data)
print(f"Decoded {len(decoded_bytes)} bytes.") # Debug
# 3. Create PIL Image from decoded bytes
img_pil = Image.open(io.BytesIO(decoded_bytes))
print("Successfully created PIL Image from decoded bytes.") # Debug
# 4. Call the core processing function with the PIL image
return process_pil_image_and_get_quote(img_pil, selected_authors)
except base64.binascii.Error as e:
print(f"Error decoding Base64: {e}") # Debug
return "Error: Invalid Base64 encoding."
except Exception as e:
import traceback
print(f"Error in main_fn_api: {e}\n{traceback.format_exc()}")
return f"An error occurred during API image processing: {e}"
# --- Other helper functions (Keep as is) ---
def get_random_quote(authors):
quote, author = get_quotes(index=None, authors=authors)
return f"\"{quote}\"\n\n— {author}"
def select_all_authors():
return author_list
# --- End other helper functions ---
# --- Build Gradio Interface ---
with gr.Blocks() as demo:
gr.Markdown("## Emotion Detection from Image & Quote")
with gr.Row():
# This Image component is primarily for the Web UI interaction
image_input_ui = gr.Image(type="pil", label="Upload Image (for Web UI)")
output_text = gr.Textbox(label="Prediction & Quote", lines=5) # Increased lines
with gr.Row():
author_selector = gr.Dropdown(
choices=author_list,
multiselect=True,
label="Select Author(s)",
info="Optional: filter quotes by author"
)
with gr.Row():
select_all_button = gr.Button("Select All Authors")
with gr.Row():
# This button triggers the processing for images uploaded via the UI
submit_button_ui = gr.Button("Detect Emotion & Get Quote (from UI Upload)")
random_quote_button = gr.Button("Get a Random Quote")
# --- Event Handlers ---
# 1. UI Submit Button: Calls the core logic function directly with the PIL image from gr.Image
submit_button_ui.click(
process_pil_image_and_get_quote, # Target function expects PIL image
inputs=[image_input_ui, author_selector], # Inputs from UI components
outputs=output_text
# No api_name here means this specific button click isn't easily callable via API
)
# 2. API Endpoint Registration:
# We need to expose `main_fn_api` so the Android app can call it.
# We can link it to a component's event and give it the correct `api_name`.
# Using a "hidden" Textbox's `change` event is a way to register it without a visible trigger.
api_trigger_input = gr.Textbox(visible=False) # Hidden component to hook the API call
api_trigger_input.change( # Event doesn't really matter, just need to link the function
fn=main_fn_api, # The function that expects BASE64 STRING
inputs=[api_trigger_input, author_selector], # Inputs match main_fn_api signature
outputs=output_text, # API calls need an output defined
api_name="main_fn" # <--- CRITICAL: This name matches the Android API URL target
# (.../gradio_api/call/main_fn)
)
# 3. Random Quote Button (Keep as is)
random_quote_button.click(
get_random_quote,
inputs=author_selector,
outputs=output_text,
api_name="get_random_quote" # Keep this if Android uses it too
)
# 4. Select All Authors Button (Keep as is)
select_all_button.click(select_all_authors, inputs=None, outputs=author_selector)
print("Launching Gradio Interface...")
demo.launch() # share=True if you need external access temporarily for testing |