# import os # from flask import Flask, request, jsonify # from flask_cors import CORS # Import CORS for cross-origin access # import tensorflow as tf # from tensorflow.keras.preprocessing import image # import numpy as np # import io # from PIL import Image # import time # import traceback # import google.generativeai as genai # Google Gemini AI # import re # from huggingface_hub import hf_hub_download # from dotenv import load_dotenv # # Create Flask app # app = Flask(__name__) # # Enable CORS for all routes # CORS(app) # load_dotenv() # # Configure Google Gemini AI # genai.configure(api_key=os.environ.get("gemini_api", "")) # Replace with your actual API key # model_gemini = genai.GenerativeModel("gemini-1.5-flash") # Use a fast Gemini AI model # # In-memory store to simulate prediction processing # prediction_results = {} # # Define preprocessing function for the uploaded image # def preprocess_image(img): # try: # img = img.resize((224, 224)) # Resize image to match model input size # img_array = np.array(img) # img_array = np.expand_dims(img_array, axis=0) # Add batch dimension # img_array = tf.keras.applications.efficientnet.preprocess_input(img_array) # Preprocess for EfficientNet # return img_array # except Exception as e: # print(f"Error during image preprocessing: {e}") # raise # # Clean Gemini AI explanation # def clean_explanation(text): # """Remove unnecessary formatting such as * and excess whitespace.""" # text = re.sub(r'\*+', '', text) # Remove asterisks # text = re.sub(r'\s+', ' ', text).strip() # Normalize spaces # return text # # Generate explanation using Gemini AI # def generate_explanation(predicted_class): # try: # prompt = f"Get instant feedback with the predicted animal name {predicted_class} along with relevant details like its habitat, diet. Provide a brief yet informative explanation, including unique characteristics, scientific name, and any interesting facts. Keep the response engaging and easy to understand for general users. Avoid technical jargon, but ensure accuracy. Limit the response to 5-6 sentences." # response = model_gemini.generate_content(prompt) # raw_text = response.text.strip() if response and response.text else f"This is a {predicted_class}." # return clean_explanation(raw_text) # Clean the AI-generated text # except Exception as e: # print(f"Error generating explanation: {e}") # return f"This is a {predicted_class}." # # Get conservation status # def get_conservation_status(class_name): # """ # Extracts and returns the conservation status from the given class name. # Args: # class_name (str): The predicted class name, e.g., 'Axolotl-CR', 'African Elephant-EN'. # Returns: # str: The full conservation status description. # """ # status_map = { # "EX": "Extinct (EX) - No known individuals remaining.", # "EW": "Extinct in the Wild (EW) - Survives only in captivity.", # "CR": "Critically Endangered (CR) - Faces an extremely high risk of extinction.", # "EN": "Endangered (EN) - High risk of extinction in the wild.", # "VU": "Vulnerable (VU) - At risk of becoming endangered.", # "NT": "Near Threatened (NT) - Likely to become endangered in the future.", # "LC": "Least Concern (LC) - Lowest risk of extinction.", # "DD": "Data Deficient (DD) - Not enough information to assess the risk.", # "NE": "Not Evaluated (NE) - Has not yet been assessed." # } # # Extract the conservation status from the class name # parts = class_name.split('-') # if len(parts) > 1: # status_abbr = parts[-1] # The last part should be the conservation status # return status_map.get(status_abbr, "Unknown conservation status") # return "Unknown conservation status" # # Load model from Hugging Face Hub # def load_model_from_huggingface(): # cache_dir = "/tmp/huggingface" # Define a writable cache directory # os.makedirs(cache_dir, exist_ok=True) # Ensure it exists # print("Downloading model from Hugging Face Hub...") # try: # model_path = hf_hub_download( # repo_id="anilkumar5590/image-classification-viit", # filename="model.keras", # Adjust the filename based on your model # cache_dir=cache_dir # Use the custom directory # ) # print(f"Model downloaded successfully at: {model_path}") # model = tf.keras.models.load_model(model_path) # print("Model loaded successfully!") # return model # except Exception as e: # print(f"Error loading model: {e}") # raise # # Load model at startup # model = load_model_from_huggingface() # # Home Route # @app.route('/') # def home(): # return "Welcome to the Wild Life Image Classification Project!" # prediction_results = {} # # Define route for predictions (POST) # @app.route("/predict", methods=["POST"]) # def predict(): # print("Request Files:", request.files) # file = request.files.get('file') # if not file: # print("No file part in the request") # return jsonify({"error": "No file part"}), 400 # try: # # Open and preprocess the image # print("Opening image...") # img = Image.open(io.BytesIO(file.read())) # print(f"Received image: {img.size}") # img_array = preprocess_image(img) # print("Image preprocessed successfully") # # Make prediction # print("Making prediction...") # predictions = model.predict(img_array) # print("Prediction completed") # # Process prediction results # predicted_class_index = np.argmax(predictions, axis=1)[0] # confidence_level = round(np.max(predictions) * 100, 2) # # Define labels (replace with your model's labels) # # labels = { # # 0: 'Aardvark-LC', 1: 'African Elephant-EN', 2: 'Alligator-LC', 3: 'Alpaca-LC', 4: 'Anaconda-LC', # # # Add the rest of your labels here... # # } # labels = {0: 'Aardvark-LC', 1: 'African Elephant-EN', 2: 'Alligator-LC', 3: 'Alpaca-LC', 4: 'Anaconda-LC', 5: 'Arctic Fox-VU', 6: 'Armadillo-LC', 7: 'Axolotl-CR', 8: 'Baboon-LC', 9: 'Badger-LC', 10: 'Bald Eagle-LC', 11: 'Barracuda-LC', 12: 'Bat-LC', 13: 'Bison-NT', 14: 'Black Bear-LC', 15: 'Blue Jay-LC', 16: 'Boa Constrictor-LC', 17: 'Bonobo-EN', 18: 'Buffalo-LC', 19: 'Butterfly-LC', 20: 'Caiman-LC', 21: 'Camel-LC', 22: 'Capybara-LC', 23: 'Caracal-LC', 24: 'Cheetah-VU', 25: 'Chimpanzee-EN', 26: 'Cobra-LC', 27: 'Cockatoo-LC', 28: 'Coral-CR', 29: 'Coyote-LC', 30: 'Crocodile-LC', 31: 'Deer-LC', 32: 'Dingo-LC', 33: 'Dodo-EX', 34: 'Dolphin-LC', 35: 'Domestic Cat-LC', 36: 'Donkey-LC', 37: 'Dragonfly-LC', 38: 'Duck-LC', 39: 'Dugong-VU', 40: 'Eagle-LC', 41: 'Earthworm-LC', 42: 'Echidna-LC', 43: 'Eel-LC', 44: 'Elephant-EN', 45: 'Elk-LC', 46: 'Emu-LC', 47: 'Falcon-LC', 48: 'Ferret-EN', 49: 'Finch-LC', 50: 'Firefly-LC', 51: 'Fish-LC', 52: 'Flamingo-LC', 53: 'Fossa-VU', 54: 'Fox-LC', 55: 'Frog-LC', 56: 'Galápagos Tortoise-VU', 57: 'Gazelle-VU', 58: 'Gecko-LC', 59: 'Gibbon-EN', 60: 'Giraffe-VU', 61: 'Goat-LC', 62: 'Goose-LC', 63: 'Gorilla-CR', 64: 'Grasshopper-LC', 65: 'Great White Shark-VU', 66: 'Green Anaconda-LC', 67: 'Grizzly Bear-LC', 68: 'Hammerhead Shark-CR', 69: 'Hamster-LC', 70: 'Hare-LC', 71: 'Hawk-LC', 72: 'Hedgehog-LC', 73: 'Hermit Crab-LC', 74: 'Hippopotamus-VU', 75: 'Honeybee-LC', 76: 'Hornbill-NT', 77: 'Horse-LC', 78: 'Hummingbird-LC', 79: 'Ibex-LC', 80: 'Ibis-LC', 81: 'Indian Cobra-LC', 82: 'Indian Elephant-EN', 83: 'Indian Star Tortoise-VU', 84: 'Indian Wolf-EN', 85: 'Jackal-LC', 86: 'Jaguar-NT', 87: 'Japanese Beetle-LC', 88: 'Jellyfish-LC', 89: 'Kangaroo-LC', 90: 'King Cobra-VU', 91: 'Kingfisher-LC', 92: 'Kiwi-EN', 93: 'Koala-VU', 94: 'Komodo Dragon-EN', 95: 'Ladybug-LC', 96: 'Lemming-LC', 97: 'Lemur-CR', 98: 'Leopard-VU', 99: 'Lion-VU', 100: 'Lizard-LC', 101: 'Llama-LC', 102: 'Lobster-LC', 103: 'Lynx-LC', 104: 'Macaw-EN', 105: 'Magpie-LC', 106: 'Manatee-VU', 107: 'Mandrill-VU', 108: 'Mantis Shrimp-LC', 109: 'Meerkat-LC', 110: 'Mole-LC', 111: 'Moose-LC', 112: 'Moray Eel-LC', 113: 'Mountain Lion-LC', 114: 'Musk Ox-LC', 115: 'Nandu Rhea-LC', 116: 'Narwhal-NT', 117: 'Newt-LC', 118: 'Nightingale-LC', 119: 'Octopus-LC', 120: 'Okapi-EN', 121: 'Opossum-LC', 122: 'Orangutan-CR', 123: 'Ostrich-LC', 124: 'Otter-VU', 125: 'Owl-LC', 126: 'Ox-LC', 127: 'Panda-VU', 128: 'Panther-NT', 129: 'Parrot-LC', 130: 'Peacock-LC', 131: 'Pelican-LC', 132: 'Penguin-NT', 133: 'Pigeon-LC', 134: 'Piranha-LC', 135: 'Platypus-LC', 136: 'Polar Bear-VU', 137: 'Porcupine-LC', 138: 'Possum-LC', 139: 'Praying Mantis-LC', 140: 'Puffin-LC', 141: 'Python-LC', 142: 'Quail-LC', 143: 'Quetzal-NT', 144: 'Quokka-LC', 145: 'Quoll-NT', 146: 'Rabbit-LC', 147: 'Raccoon-LC', 148: 'Ram-LC', 149: 'Rat-LC', 150: 'Raven-LC', 151: 'Red Panda-EN', 152: 'Reindeer-VU', 153: 'Rhinoceros-CR', 154: 'Roadrunner-LC', 155: 'Salamander-LC', 156: 'Scorpion-LC', 157: 'Sea Lion-LC', 158: 'Seahorse-LC', 159: 'Shark-VU', 160: 'Sheep-LC', 161: 'Skunk-LC', 162: 'Sloth-VU', 163: 'Snail-LC', 164: 'Snake-LC', 165: 'Snow Leopard-VU', 166: 'Sparrow-LC', 167: 'Spider-LC', 168: 'Squirrel-LC', 169: 'Starfish-LC', 170: 'Stork-LC', 171: 'Swan-LC', 172: 'Tamarin-EN', 173: 'Tapir-VU', 174: 'Tasmanian Devil-EN', 175: 'Termite-LC', 176: 'Thorny Devil-LC', 177: 'Tiger-EN', 178: 'Toad-LC', 179: 'Toucan-LC', 180: 'Tuna-LC', 181: 'Turkey-LC', 182: 'Turtle-VU', 183: 'Uakari-VU', 184: 'Umbrellabird-VU', 185: 'Urchin-LC', 186: 'Uromastyx-LC', 187: 'Vampire Bat-LC', 188: 'Vaquita-CR', 189: 'Vervet Monkey-LC', 190: 'Vulture-LC', 191: 'Wallaby-LC', 192: 'Walrus-VU', 193: 'Warthog-LC', 194: 'Weasel-LC', 195: 'Whale-EN', 196: 'White Tiger-EN', 197: 'Wild Cat-VU', 198: 'Wolf-VU', 199: 'Wolverine-LC', 200: 'Wombat-LC', 201: 'Woodpecker-LC', 202: 'X-ray Tetra-LC', 203: 'Xenopus-LC', 204: 'Yak-LC', 205: 'Yellowjacket-LC', 206: 'Zebra Finch-LC', 207: 'Zebra-NT', 208: 'Zebu-LC', 209: 'Zorilla-LC'} # predicted_class = labels.get(predicted_class_index, "Unknown") # conservation_status = get_conservation_status(predicted_class) # predicted_class = predicted_class.split('-')[0] # Remove the conservation status from the class name # print(f"Prediction: {predicted_class}, Confidence: {confidence_level}%") # # Generate explanation using Gemini AI # explanation = generate_explanation(predicted_class) # prediction_id = str(time.time()) # Unique ID for the request # if confidence_level<=30: # prediction_results[prediction_id] = { # "predicted_class": "---", # "conservation_status": "---", # "confidence_level": "---", # "explanation": "Sorry! This image doesn’t seem to match any animals I was trained on. I’m doing my best with the knowledge I have. Please try a different image – ideally of a single, clear animal." # } # else: # # Store the result in the in-memory dictionary # prediction_results[prediction_id] = { # "predicted_class": predicted_class, # "conservation_status": conservation_status, # "confidence_level": confidence_level, # "explanation": explanation # } # print(f"Prediction ID: {prediction_id}, Result: {prediction_results[prediction_id]}") # return jsonify({"prediction_id": prediction_id}), 200 # except Exception as e: # print(f"Error during prediction: {e}") # print(traceback.format_exc()) # return jsonify({"error": f"Error during prediction: {e}"}), 500 # # Define route for retrieving predictions (GET) # @app.route("/get_prediction/", methods=["GET"]) # def get_prediction(prediction_id): # print(f"Fetching prediction result for ID: {prediction_id}") # result = prediction_results.get(prediction_id) # if result: # return jsonify(result) # else: # print(f"No result found for ID: {prediction_id}") # return jsonify({"error": "Prediction not found or still processing"}), 404 # # Run the Flask app # if __name__ == "__main__": # app.run(host='0.0.0.0', port=7860, debug=True) import os from flask import Flask, request, jsonify from flask_cors import CORS import tensorflow as tf from tensorflow.keras.preprocessing import image import numpy as np import io from PIL import Image import time import traceback import google.generativeai as genai import re from huggingface_hub import hf_hub_download from dotenv import load_dotenv # Create Flask app app = Flask(__name__) # Enable CORS for all routes CORS(app) load_dotenv() # Configure Google Gemini AI genai.configure(api_key=os.environ.get("gemini_api", "")) model_gemini = genai.GenerativeModel("gemini-1.5-flash") # In-memory store to simulate prediction processing prediction_results = {} # Define preprocessing function for the uploaded image def preprocess_image(img): try: img = img.resize((224, 224)) img_array = np.array(img) img_array = np.expand_dims(img_array, axis=0) img_array = tf.keras.applications.efficientnet.preprocess_input(img_array) return img_array except Exception as e: print(f"Error during image preprocessing: {e}") raise # Clean Gemini AI explanation def clean_explanation(text): text = re.sub(r'\*+', '', text) text = re.sub(r'\s+', ' ', text).strip() return text # Generate explanation using Gemini AI def generate_explanation(predicted_class): try: prompt = f"Get instant feedback with the predicted animal name {predicted_class} along with relevant details like its habitat, diet. Provide a brief yet informative explanation, including unique characteristics, scientific name, and any interesting facts. Keep the response engaging and easy to understand for general users. Avoid technical jargon, but ensure accuracy. Limit the response to 5-6 sentences." response = model_gemini.generate_content(prompt) raw_text = response.text.strip() if response and response.text else f"This is a {predicted_class}." return clean_explanation(raw_text) except Exception as e: print(f"Error generating explanation: {e}") return f"This is a {predicted_class}." # Get conservation status def get_conservation_status(class_name): status_map = { "EX": "Extinct (EX) - No known individuals remaining.", "EW": "Extinct in the Wild (EW) - Survives only in captivity.", "CR": "Critically Endangered (CR) - Faces an extremely high risk of extinction.", "EN": "Endangered (EN) - High risk of extinction in the wild.", "VU": "Vulnerable (VU) - At risk of becoming endangered.", "NT": "Near Threatened (NT) - Likely to become endangered in the future.", "LC": "Least Concern (LC) - Lowest risk of extinction.", "DD": "Data Deficient (DD) - Not enough information to assess the risk.", "NE": "Not Evaluated (NE) - Has not yet been assessed." } parts = class_name.split('-') if len(parts) > 1: status_abbr = parts[-1] return status_map.get(status_abbr, "Unknown conservation status") return "Unknown conservation status" # Load model from Hugging Face Hub def load_model_from_huggingface(): cache_dir = "/tmp/huggingface" os.makedirs(cache_dir, exist_ok=True) print("Downloading model from Hugging Face Hub...") try: model_path = hf_hub_download( repo_id="anilkumar5590/image-classification-viit", filename="model.keras", cache_dir=cache_dir ) print(f"Model downloaded successfully at: {model_path}") model = tf.keras.models.load_model(model_path) print("Model loaded successfully!") return model except Exception as e: print(f"Error loading model: {e}") raise # Load model at startup model = load_model_from_huggingface() # Home Route @app.route('/') def home(): return "Welcome to the Wild Life Image Classification Project!" # Define route for predictions (POST) @app.route("/predict", methods=["POST"]) def predict(): print("Request Files:", request.files) file = request.files.get('file') if not file: print("No file part in the request") return jsonify({"error": "No file part"}), 400 try: # Open and preprocess the image print("Opening image...") img = Image.open(io.BytesIO(file.read())) print(f"Received image: {img.size}") img_array = preprocess_image(img) print("Image preprocessed successfully") # Make prediction print("Making prediction...") predictions = model.predict(img_array) print("Prediction completed") # Process prediction results predicted_class_index = np.argmax(predictions, axis=1)[0] confidence_level = round(np.max(predictions) * 100, 2) # Define labels labels = { 0: 'Aardvark-LC', 1: 'African Elephant-EN', 2: 'Alligator-LC', 3: 'Alpaca-LC', 4: 'Anaconda-LC', 5: 'Arctic Fox-VU', 6: 'Armadillo-LC', 7: 'Axolotl-CR', 8: 'Baboon-LC', 9: 'Badger-LC', 10: 'Bald Eagle-LC', 11: 'Barracuda-LC', 12: 'Bat-LC', 13: 'Bison-NT', 14: 'Black Bear-LC', 15: 'Blue Jay-LC', 16: 'Boa Constrictor-LC', 17: 'Bonobo-EN', 18: 'Buffalo-LC', 19: 'Butterfly-LC', 20: 'Caiman-LC', 21: 'Camel-LC', 22: 'Capybara-LC', 23: 'Caracal-LC', 24: 'Cheetah-VU', 25: 'Chimpanzee-EN', 26: 'Cobra-LC', 27: 'Cockatoo-LC', 28: 'Coral-CR', 29: 'Coyote-LC', 30: 'Crocodile-LC', 31: 'Deer-LC', 32: 'Dingo-LC', 33: 'Dodo-EX', 34: 'Dolphin-LC', 35: 'Domestic Cat-LC', 36: 'Donkey-LC', 37: 'Dragonfly-LC', 38: 'Duck-LC', 39: 'Dugong-VU', 40: 'Eagle-LC', 41: 'Earthworm-LC', 42: 'Echidna-LC', 43: 'Eel-LC', 44: 'Elephant-EN', 45: 'Elk-LC', 46: 'Emu-LC', 47: 'Falcon-LC', 48: 'Ferret-EN', 49: 'Finch-LC', 50: 'Firefly-LC', 51: 'Fish-LC', 52: 'Flamingo-LC', 53: 'Fossa-VU', 54: 'Fox-LC', 55: 'Frog-LC', 56: 'Galápagos Tortoise-VU', 57: 'Gazelle-VU', 58: 'Gecko-LC', 59: 'Gibbon-EN', 60: 'Giraffe-VU', 61: 'Goat-LC', 62: 'Goose-LC', 63: 'Gorilla-CR', 64: 'Grasshopper-LC', 65: 'Great White Shark-VU', 66: 'Green Anaconda-LC', 67: 'Grizzly Bear-LC', 68: 'Hammerhead Shark-CR', 69: 'Hamster-LC', 70: 'Hare-LC', 71: 'Hawk-LC', 72: 'Hedgehog-LC', 73: 'Hermit Crab-LC', 74: 'Hippopotamus-VU', 75: 'Honeybee-LC', 76: 'Hornbill-NT', 77: 'Horse-LC', 78: 'Hummingbird-LC', 79: 'Ibex-LC', 80: 'Ibis-LC', 81: 'Indian Cobra-LC', 82: 'Indian Elephant-EN', 83: 'Indian Star Tortoise-VU', 84: 'Indian Wolf-EN', 85: 'Jackal-LC', 86: 'Jaguar-NT', 87: 'Japanese Beetle-LC', 88: 'Jellyfish-LC', 89: 'Kangaroo-LC', 90: 'King Cobra-VU', 91: 'Kingfisher-LC', 92: 'Kiwi-EN', 93: 'Koala-VU', 94: 'Komodo Dragon-EN', 95: 'Ladybug-LC', 96: 'Lemming-LC', 97: 'Lemur-CR', 98: 'Leopard-VU', 99: 'Lion-VU', 100: 'Lizard-LC', 101: 'Llama-LC', 102: 'Lobster-LC', 103: 'Lynx-LC', 104: 'Macaw-EN', 105: 'Magpie-LC', 106: 'Manatee-VU', 107: 'Mandrill-VU', 108: 'Mantis Shrimp-LC', 109: 'Meerkat-LC', 110: 'Mole-LC', 111: 'Moose-LC', 112: 'Moray Eel-LC', 113: 'Mountain Lion-LC', 114: 'Musk Ox-LC', 115: 'Nandu Rhea-LC', 116: 'Narwhal-NT', 117: 'Newt-LC', 118: 'Nightingale-LC', 119: 'Octopus-LC', 120: 'Okapi-EN', 121: 'Opossum-LC', 122: 'Orangutan-CR', 123: 'Ostrich-LC', 124: 'Otter-VU', 125: 'Owl-LC', 126: 'Ox-LC', 127: 'Panda-VU', 128: 'Panther-NT', 129: 'Parrot-LC', 130: 'Peacock-LC', 131: 'Pelican-LC', 132: 'Penguin-NT', 133: 'Pigeon-LC', 134: 'Piranha-LC', 135: 'Platypus-LC', 136: 'Polar Bear-VU', 137: 'Porcupine-LC', 138: 'Possum-LC', 139: 'Praying Mantis-LC', 140: 'Puffin-LC', 141: 'Python-LC', 142: 'Quail-LC', 143: 'Quetzal-NT', 144: 'Quokka-LC', 145: 'Quoll-NT', 146: 'Rabbit-LC', 147: 'Raccoon-LC', 148: 'Ram-LC', 149: 'Rat-LC', 150: 'Raven-LC', 151: 'Red Panda-EN', 152: 'Reindeer-VU', 153: 'Rhinoceros-CR', 154: 'Roadrunner-LC', 155: 'Salamander-LC', 156: 'Scorpion-LC', 157: 'Sea Lion-LC', 158: 'Seahorse-LC', 159: 'Shark-VU', 160: 'Sheep-LC', 161: 'Skunk-LC', 162: 'Sloth-VU', 163: 'Snail-LC', 164: 'Snake-LC', 165: 'Snow Leopard-VU', 166: 'Sparrow-LC', 167: 'Spider-LC', 168: 'Squirrel-LC', 169: 'Starfish-LC', 170: 'Stork-LC', 171: 'Swan-LC', 172: 'Tamarin-EN', 173: 'Tapir-VU', 174: 'Tasmanian Devil-EN', 175: 'Termite-LC', 176: 'Thorny Devil-LC', 177: 'Tiger-EN', 178: 'Toad-LC', 179: 'Toucan-LC', 180: 'Tuna-LC', 181: 'Turkey-LC', 182: 'Turtle-VU', 183: 'Uakari-VU', 184: 'Umbrellabird-VU', 185: 'Urchin-LC', 186: 'Uromastyx-LC', 187: 'Vampire Bat-LC', 188: 'Vaquita-CR', 189: 'Vervet Monkey-LC', 190: 'Vulture-LC', 191: 'Wallaby-LC', 192: 'Walrus-VU', 193: 'Warthog-LC', 194: 'Weasel-LC', 195: 'Whale-EN', 196: 'White Tiger-EN', 197: 'Wild Cat-VU', 198: 'Wolf-VU', 199: 'Wolverine-LC', 200: 'Wombat-LC', 201: 'Woodpecker-LC', 202: 'X-ray Tetra-LC', 203: 'Xenopus-LC', 204: 'Yak-LC', 205: 'Yellowjacket-LC', 206: 'Zebra Finch-LC', 207: 'Zebra-NT', 208: 'Zebu-LC', 209: 'Zorilla-LC' } predicted_class = labels.get(predicted_class_index, "Unknown") conservation_status = get_conservation_status(predicted_class) predicted_class_clean = predicted_class.split('-')[0] print(f"Prediction: {predicted_class_clean}, Confidence: {confidence_level}%") # Generate explanation using Gemini AI explanation = generate_explanation(predicted_class_clean if confidence_level >= 30 else "unknown animal") # Store the result in the in-memory dictionary prediction_id = str(time.time()) print(f"Storing result for Prediction ID: {prediction_id}") if confidence_level < 30: prediction_results[prediction_id] = { "explanation": "Sorry! This image doesn’t seem to match any animals I was trained on. I’m doing my best with the knowledge I have. Please try a different image – ideally of a single, clear animal." } else: prediction_results[prediction_id] = { "predicted_class": predicted_class_clean, "conservation_status": conservation_status, "confidence_level": confidence_level, "explanation": explanation } print(f"Stored Result: {prediction_results[prediction_id]}") return jsonify({"prediction_id": prediction_id}), 200 except Exception as e: print(f"Error during prediction: {e}") print(traceback.format_exc()) return jsonify({"error": f"Error during prediction: {e}"}), 500 # Define route for retrieving predictions (GET) @app.route("/get_prediction/", methods=["GET"]) def get_prediction(prediction_id): print(f"Fetching prediction result for ID: {prediction_id}") result = prediction_results.get(prediction_id) if result: print(f"Found result: {result}") return jsonify(result) else: print(f"No result found for ID: {prediction_id}") return jsonify({"error": "Prediction not found or still processing"}), 404 # Run the Flask app if __name__ == "__main__": app.run(host='0.0.0.0', port=7860, debug=True)