Update backendapi.py
Browse files- backendapi.py +268 -81
backendapi.py
CHANGED
|
@@ -1,10 +1,221 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import os
|
| 2 |
from flask import Flask, request, jsonify
|
| 3 |
from flask_cors import CORS # Import CORS for cross-origin access
|
| 4 |
import tensorflow as tf
|
| 5 |
from tensorflow.keras.preprocessing import image
|
| 6 |
import numpy as np
|
| 7 |
-
import gdown
|
| 8 |
import io
|
| 9 |
from PIL import Image
|
| 10 |
import time
|
|
@@ -12,61 +223,6 @@ import traceback
|
|
| 12 |
import google.generativeai as genai # Google Gemini AI
|
| 13 |
import re
|
| 14 |
from huggingface_hub import hf_hub_download
|
| 15 |
-
# Load the pre-trained model (adjust the path as needed)
|
| 16 |
-
# model = tf.keras.models.load_model("efficient_model_63.keras")
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
# # Download model from Hugging Face
|
| 20 |
-
# model_path = hf_hub_download(
|
| 21 |
-
# repo_id="anilkumar5590/image-classification-viit",
|
| 22 |
-
# filename="model.keras",
|
| 23 |
-
# local_dir="/tmp"
|
| 24 |
-
# )
|
| 25 |
-
|
| 26 |
-
# # Load the model
|
| 27 |
-
# model = tf.keras.models.load_model(model_path)
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
# MODEL_PATH = "/tmp/model.keras"
|
| 32 |
-
|
| 33 |
-
# def load_model_from_huggingface():
|
| 34 |
-
# if not os.path.exists(MODEL_PATH):
|
| 35 |
-
# print("Downloading model from Hugging Face Hub...")
|
| 36 |
-
# hf_hub_download(
|
| 37 |
-
# repo_id="anilkumar5590/image-classification-viit",
|
| 38 |
-
# filename="model.keras",
|
| 39 |
-
# local_dir="/tmp"
|
| 40 |
-
# )
|
| 41 |
-
# print("Download complete!")
|
| 42 |
-
# else:
|
| 43 |
-
# print("Model already exists. Loading from /tmp/")
|
| 44 |
-
|
| 45 |
-
# model = tf.keras.models.load_model(MODEL_PATH)
|
| 46 |
-
# print("Model loaded successfully!")
|
| 47 |
-
# return model
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
def load_model_from_huggingface():
|
| 51 |
-
cache_dir = "/tmp/huggingface" # Define a writable cache directory
|
| 52 |
-
os.makedirs(cache_dir, exist_ok=True) # Ensure it exists
|
| 53 |
-
|
| 54 |
-
print("Downloading model from Hugging Face Hub...")
|
| 55 |
-
|
| 56 |
-
model_path = hf_hub_download(
|
| 57 |
-
repo_id="anilkumar5590/image-classification-viit",
|
| 58 |
-
filename="model.keras", # Adjust the filename based on your model
|
| 59 |
-
cache_dir=cache_dir # Use the custom directory
|
| 60 |
-
)
|
| 61 |
-
|
| 62 |
-
print("Model downloaded successfully at:", model_path)
|
| 63 |
-
return model_path # You may need to load it using TensorFlow or PyTorch
|
| 64 |
-
|
| 65 |
-
# Load model at startup
|
| 66 |
-
model = load_model_from_huggingface()
|
| 67 |
-
|
| 68 |
-
# In-memory store to simulate prediction processing
|
| 69 |
-
prediction_results = {}
|
| 70 |
|
| 71 |
# Create Flask app
|
| 72 |
app = Flask(__name__)
|
|
@@ -78,21 +234,29 @@ CORS(app)
|
|
| 78 |
genai.configure(api_key="AIzaSyD0M3hdjekk6w_b9WXXb0T_qLAS0MY5iDQ") # Replace with your actual API key
|
| 79 |
model_gemini = genai.GenerativeModel("gemini-1.5-flash") # Use a fast Gemini AI model
|
| 80 |
|
|
|
|
|
|
|
|
|
|
| 81 |
# Define preprocessing function for the uploaded image
|
| 82 |
def preprocess_image(img):
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
|
|
|
|
|
|
|
|
|
| 89 |
|
|
|
|
| 90 |
def clean_explanation(text):
|
| 91 |
"""Remove unnecessary formatting such as * and excess whitespace."""
|
| 92 |
text = re.sub(r'\*+', '', text) # Remove asterisks
|
| 93 |
text = re.sub(r'\s+', ' ', text).strip() # Normalize spaces
|
| 94 |
return text
|
| 95 |
|
|
|
|
| 96 |
def generate_explanation(predicted_class):
|
| 97 |
try:
|
| 98 |
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."
|
|
@@ -103,8 +267,7 @@ def generate_explanation(predicted_class):
|
|
| 103 |
print(f"Error generating explanation: {e}")
|
| 104 |
return f"This is a {predicted_class}."
|
| 105 |
|
| 106 |
-
|
| 107 |
-
|
| 108 |
def get_conservation_status(class_name):
|
| 109 |
"""
|
| 110 |
Extracts and returns the conservation status from the given class name.
|
|
@@ -135,37 +298,64 @@ def get_conservation_status(class_name):
|
|
| 135 |
|
| 136 |
return "Unknown conservation status"
|
| 137 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
|
| 139 |
# Define route for predictions (POST)
|
| 140 |
@app.route("/predict", methods=["POST"])
|
| 141 |
def predict():
|
| 142 |
print("Request Files:", request.files)
|
| 143 |
-
|
| 144 |
file = request.files.get('file')
|
| 145 |
|
| 146 |
if not file:
|
|
|
|
| 147 |
return jsonify({"error": "No file part"}), 400
|
| 148 |
|
| 149 |
try:
|
| 150 |
# Open and preprocess the image
|
|
|
|
| 151 |
img = Image.open(io.BytesIO(file.read()))
|
| 152 |
print(f"Received image: {img.size}")
|
| 153 |
img_array = preprocess_image(img)
|
| 154 |
-
|
| 155 |
-
# Simulate prediction delay (e.g., processing the image)
|
| 156 |
-
time.sleep(2) # Simulating a delay
|
| 157 |
|
| 158 |
# Make prediction
|
|
|
|
| 159 |
predictions = model.predict(img_array)
|
|
|
|
|
|
|
|
|
|
| 160 |
predicted_class_index = np.argmax(predictions, axis=1)[0]
|
| 161 |
confidence_level = round(np.max(predictions) * 100, 2)
|
| 162 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 163 |
|
| 164 |
-
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'}
|
| 165 |
-
# Replace with your model's labels
|
| 166 |
-
|
| 167 |
predicted_class = labels.get(predicted_class_index, "Unknown")
|
| 168 |
-
conservation_status= get_conservation_status(predicted_class)
|
| 169 |
predicted_class = predicted_class.split('-')[0] # Remove the conservation status from the class name
|
| 170 |
print(f"Prediction: {predicted_class}, Confidence: {confidence_level}%")
|
| 171 |
|
|
@@ -173,24 +363,20 @@ def predict():
|
|
| 173 |
explanation = generate_explanation(predicted_class)
|
| 174 |
|
| 175 |
# Store the result in the in-memory dictionary
|
| 176 |
-
prediction_id = str(time.time()) # Unique ID for the request
|
| 177 |
-
|
| 178 |
prediction_results[prediction_id] = {
|
| 179 |
"predicted_class": predicted_class,
|
| 180 |
"conservation_status": conservation_status,
|
| 181 |
"confidence_level": confidence_level,
|
| 182 |
"explanation": explanation
|
| 183 |
}
|
| 184 |
-
|
| 185 |
print(f"Prediction ID: {prediction_id}, Result: {prediction_results[prediction_id]}")
|
| 186 |
-
# Return the prediction ID to be used for GET request later
|
| 187 |
return jsonify({"prediction_id": prediction_id}), 200
|
| 188 |
|
| 189 |
except Exception as e:
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
return jsonify({"error": f"Error during prediction: {error_message}"}), 500
|
| 194 |
|
| 195 |
# Define route for retrieving predictions (GET)
|
| 196 |
@app.route("/get_prediction/<prediction_id>", methods=["GET"])
|
|
@@ -203,5 +389,6 @@ def get_prediction(prediction_id):
|
|
| 203 |
print(f"No result found for ID: {prediction_id}")
|
| 204 |
return jsonify({"error": "Prediction not found or still processing"}), 404
|
| 205 |
|
|
|
|
| 206 |
if __name__ == "__main__":
|
| 207 |
-
app.run(host='0.0.0.0', port=7860,debug=True)
|
|
|
|
| 1 |
+
# import os
|
| 2 |
+
# from flask import Flask, request, jsonify
|
| 3 |
+
# from flask_cors import CORS # Import CORS for cross-origin access
|
| 4 |
+
# import tensorflow as tf
|
| 5 |
+
# from tensorflow.keras.preprocessing import image
|
| 6 |
+
# import numpy as np
|
| 7 |
+
# import gdown
|
| 8 |
+
# import io
|
| 9 |
+
# from PIL import Image
|
| 10 |
+
# import time
|
| 11 |
+
# import traceback
|
| 12 |
+
# import google.generativeai as genai # Google Gemini AI
|
| 13 |
+
# import re
|
| 14 |
+
# from huggingface_hub import hf_hub_download
|
| 15 |
+
# # Load the pre-trained model (adjust the path as needed)
|
| 16 |
+
# # model = tf.keras.models.load_model("efficient_model_63.keras")
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
# # # Download model from Hugging Face
|
| 20 |
+
# # model_path = hf_hub_download(
|
| 21 |
+
# # repo_id="anilkumar5590/image-classification-viit",
|
| 22 |
+
# # filename="model.keras",
|
| 23 |
+
# # local_dir="/tmp"
|
| 24 |
+
# # )
|
| 25 |
+
|
| 26 |
+
# # # Load the model
|
| 27 |
+
# # model = tf.keras.models.load_model(model_path)
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
# # MODEL_PATH = "/tmp/model.keras"
|
| 32 |
+
|
| 33 |
+
# # def load_model_from_huggingface():
|
| 34 |
+
# # if not os.path.exists(MODEL_PATH):
|
| 35 |
+
# # print("Downloading model from Hugging Face Hub...")
|
| 36 |
+
# # hf_hub_download(
|
| 37 |
+
# # repo_id="anilkumar5590/image-classification-viit",
|
| 38 |
+
# # filename="model.keras",
|
| 39 |
+
# # local_dir="/tmp"
|
| 40 |
+
# # )
|
| 41 |
+
# # print("Download complete!")
|
| 42 |
+
# # else:
|
| 43 |
+
# # print("Model already exists. Loading from /tmp/")
|
| 44 |
+
|
| 45 |
+
# # model = tf.keras.models.load_model(MODEL_PATH)
|
| 46 |
+
# # print("Model loaded successfully!")
|
| 47 |
+
# # return model
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
# def load_model_from_huggingface():
|
| 51 |
+
# cache_dir = "/tmp/huggingface" # Define a writable cache directory
|
| 52 |
+
# os.makedirs(cache_dir, exist_ok=True) # Ensure it exists
|
| 53 |
+
|
| 54 |
+
# print("Downloading model from Hugging Face Hub...")
|
| 55 |
+
|
| 56 |
+
# model_path = hf_hub_download(
|
| 57 |
+
# repo_id="anilkumar5590/image-classification-viit",
|
| 58 |
+
# filename="model.keras", # Adjust the filename based on your model
|
| 59 |
+
# cache_dir=cache_dir # Use the custom directory
|
| 60 |
+
# )
|
| 61 |
+
|
| 62 |
+
# print("Model downloaded successfully at:", model_path)
|
| 63 |
+
# return model_path # You may need to load it using TensorFlow or PyTorch
|
| 64 |
+
|
| 65 |
+
# # Load model at startup
|
| 66 |
+
# model = load_model_from_huggingface()
|
| 67 |
+
|
| 68 |
+
# # In-memory store to simulate prediction processing
|
| 69 |
+
# prediction_results = {}
|
| 70 |
+
|
| 71 |
+
# # Create Flask app
|
| 72 |
+
# app = Flask(__name__)
|
| 73 |
+
|
| 74 |
+
# # Enable CORS for all routes
|
| 75 |
+
# CORS(app)
|
| 76 |
+
|
| 77 |
+
# # Configure Google Gemini AI
|
| 78 |
+
# genai.configure(api_key="AIzaSyD0M3hdjekk6w_b9WXXb0T_qLAS0MY5iDQ") # Replace with your actual API key
|
| 79 |
+
# model_gemini = genai.GenerativeModel("gemini-1.5-flash") # Use a fast Gemini AI model
|
| 80 |
+
|
| 81 |
+
# # Define preprocessing function for the uploaded image
|
| 82 |
+
# def preprocess_image(img):
|
| 83 |
+
# img = img.resize((224, 224)) # Resize image to match model input size
|
| 84 |
+
# img_array = np.array(img)
|
| 85 |
+
# img_array = np.expand_dims(img_array, axis=0) # Add batch dimension
|
| 86 |
+
# img_array = tf.keras.applications.efficientnet.preprocess_input(img_array) # Preprocess for EfficientNet
|
| 87 |
+
# return img_array
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
# def clean_explanation(text):
|
| 91 |
+
# """Remove unnecessary formatting such as * and excess whitespace."""
|
| 92 |
+
# text = re.sub(r'\*+', '', text) # Remove asterisks
|
| 93 |
+
# text = re.sub(r'\s+', ' ', text).strip() # Normalize spaces
|
| 94 |
+
# return text
|
| 95 |
+
|
| 96 |
+
# def generate_explanation(predicted_class):
|
| 97 |
+
# try:
|
| 98 |
+
# 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."
|
| 99 |
+
# response = model_gemini.generate_content(prompt)
|
| 100 |
+
# raw_text = response.text.strip() if response and response.text else f"This is a {predicted_class}."
|
| 101 |
+
# return clean_explanation(raw_text) # Clean the AI-generated text
|
| 102 |
+
# except Exception as e:
|
| 103 |
+
# print(f"Error generating explanation: {e}")
|
| 104 |
+
# return f"This is a {predicted_class}."
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
# def get_conservation_status(class_name):
|
| 109 |
+
# """
|
| 110 |
+
# Extracts and returns the conservation status from the given class name.
|
| 111 |
+
|
| 112 |
+
# Args:
|
| 113 |
+
# class_name (str): The predicted class name, e.g., 'Axolotl-CR', 'African Elephant-EN'.
|
| 114 |
+
|
| 115 |
+
# Returns:
|
| 116 |
+
# str: The full conservation status description.
|
| 117 |
+
# """
|
| 118 |
+
# status_map = {
|
| 119 |
+
# "EX": "Extinct (EX) - No known individuals remaining.",
|
| 120 |
+
# "EW": "Extinct in the Wild (EW) - Survives only in captivity.",
|
| 121 |
+
# "CR": "Critically Endangered (CR) - Faces an extremely high risk of extinction.",
|
| 122 |
+
# "EN": "Endangered (EN) - High risk of extinction in the wild.",
|
| 123 |
+
# "VU": "Vulnerable (VU) - At risk of becoming endangered.",
|
| 124 |
+
# "NT": "Near Threatened (NT) - Likely to become endangered in the future.",
|
| 125 |
+
# "LC": "Least Concern (LC) - Lowest risk of extinction.",
|
| 126 |
+
# "DD": "Data Deficient (DD) - Not enough information to assess the risk.",
|
| 127 |
+
# "NE": "Not Evaluated (NE) - Has not yet been assessed."
|
| 128 |
+
# }
|
| 129 |
+
|
| 130 |
+
# # Extract the conservation status from the class name
|
| 131 |
+
# parts = class_name.split('-')
|
| 132 |
+
# if len(parts) > 1:
|
| 133 |
+
# status_abbr = parts[-1] # The last part should be the conservation status
|
| 134 |
+
# return status_map.get(status_abbr, "Unknown conservation status")
|
| 135 |
+
|
| 136 |
+
# return "Unknown conservation status"
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
# # Define route for predictions (POST)
|
| 140 |
+
# @app.route("/predict", methods=["POST"])
|
| 141 |
+
# def predict():
|
| 142 |
+
# print("Request Files:", request.files)
|
| 143 |
+
|
| 144 |
+
# file = request.files.get('file')
|
| 145 |
+
|
| 146 |
+
# if not file:
|
| 147 |
+
# return jsonify({"error": "No file part"}), 400
|
| 148 |
+
|
| 149 |
+
# try:
|
| 150 |
+
# # Open and preprocess the image
|
| 151 |
+
# img = Image.open(io.BytesIO(file.read()))
|
| 152 |
+
# print(f"Received image: {img.size}")
|
| 153 |
+
# img_array = preprocess_image(img)
|
| 154 |
+
|
| 155 |
+
# # Simulate prediction delay (e.g., processing the image)
|
| 156 |
+
# time.sleep(2) # Simulating a delay
|
| 157 |
+
|
| 158 |
+
# # Make prediction
|
| 159 |
+
# predictions = model.predict(img_array)
|
| 160 |
+
# predicted_class_index = np.argmax(predictions, axis=1)[0]
|
| 161 |
+
# confidence_level = round(np.max(predictions) * 100, 2)
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
# 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'}
|
| 165 |
+
# # Replace with your model's labels
|
| 166 |
+
|
| 167 |
+
# predicted_class = labels.get(predicted_class_index, "Unknown")
|
| 168 |
+
# conservation_status= get_conservation_status(predicted_class)
|
| 169 |
+
# predicted_class = predicted_class.split('-')[0] # Remove the conservation status from the class name
|
| 170 |
+
# print(f"Prediction: {predicted_class}, Confidence: {confidence_level}%")
|
| 171 |
+
|
| 172 |
+
# # Generate explanation using Gemini AI
|
| 173 |
+
# explanation = generate_explanation(predicted_class)
|
| 174 |
+
|
| 175 |
+
# # Store the result in the in-memory dictionary
|
| 176 |
+
# prediction_id = str(time.time()) # Unique ID for the request
|
| 177 |
+
|
| 178 |
+
# prediction_results[prediction_id] = {
|
| 179 |
+
# "predicted_class": predicted_class,
|
| 180 |
+
# "conservation_status": conservation_status,
|
| 181 |
+
# "confidence_level": confidence_level,
|
| 182 |
+
# "explanation": explanation
|
| 183 |
+
# }
|
| 184 |
+
|
| 185 |
+
# print(f"Prediction ID: {prediction_id}, Result: {prediction_results[prediction_id]}")
|
| 186 |
+
# # Return the prediction ID to be used for GET request later
|
| 187 |
+
# return jsonify({"prediction_id": prediction_id}), 200
|
| 188 |
+
|
| 189 |
+
# except Exception as e:
|
| 190 |
+
# # Include the traceback in the error response
|
| 191 |
+
# error_message = traceback.format_exc()
|
| 192 |
+
# print(error_message) # Print in the server logs
|
| 193 |
+
# return jsonify({"error": f"Error during prediction: {error_message}"}), 500
|
| 194 |
+
|
| 195 |
+
# # Define route for retrieving predictions (GET)
|
| 196 |
+
# @app.route("/get_prediction/<prediction_id>", methods=["GET"])
|
| 197 |
+
# def get_prediction(prediction_id):
|
| 198 |
+
# print(f"Fetching prediction result for ID: {prediction_id}")
|
| 199 |
+
# result = prediction_results.get(prediction_id)
|
| 200 |
+
# if result:
|
| 201 |
+
# return jsonify(result)
|
| 202 |
+
# else:
|
| 203 |
+
# print(f"No result found for ID: {prediction_id}")
|
| 204 |
+
# return jsonify({"error": "Prediction not found or still processing"}), 404
|
| 205 |
+
|
| 206 |
+
# if __name__ == "__main__":
|
| 207 |
+
# app.run(host='0.0.0.0', port=7860,debug=True)
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
|
| 213 |
import os
|
| 214 |
from flask import Flask, request, jsonify
|
| 215 |
from flask_cors import CORS # Import CORS for cross-origin access
|
| 216 |
import tensorflow as tf
|
| 217 |
from tensorflow.keras.preprocessing import image
|
| 218 |
import numpy as np
|
|
|
|
| 219 |
import io
|
| 220 |
from PIL import Image
|
| 221 |
import time
|
|
|
|
| 223 |
import google.generativeai as genai # Google Gemini AI
|
| 224 |
import re
|
| 225 |
from huggingface_hub import hf_hub_download
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
|
| 227 |
# Create Flask app
|
| 228 |
app = Flask(__name__)
|
|
|
|
| 234 |
genai.configure(api_key="AIzaSyD0M3hdjekk6w_b9WXXb0T_qLAS0MY5iDQ") # Replace with your actual API key
|
| 235 |
model_gemini = genai.GenerativeModel("gemini-1.5-flash") # Use a fast Gemini AI model
|
| 236 |
|
| 237 |
+
# In-memory store to simulate prediction processing
|
| 238 |
+
prediction_results = {}
|
| 239 |
+
|
| 240 |
# Define preprocessing function for the uploaded image
|
| 241 |
def preprocess_image(img):
|
| 242 |
+
try:
|
| 243 |
+
img = img.resize((224, 224)) # Resize image to match model input size
|
| 244 |
+
img_array = np.array(img)
|
| 245 |
+
img_array = np.expand_dims(img_array, axis=0) # Add batch dimension
|
| 246 |
+
img_array = tf.keras.applications.efficientnet.preprocess_input(img_array) # Preprocess for EfficientNet
|
| 247 |
+
return img_array
|
| 248 |
+
except Exception as e:
|
| 249 |
+
print(f"Error during image preprocessing: {e}")
|
| 250 |
+
raise
|
| 251 |
|
| 252 |
+
# Clean Gemini AI explanation
|
| 253 |
def clean_explanation(text):
|
| 254 |
"""Remove unnecessary formatting such as * and excess whitespace."""
|
| 255 |
text = re.sub(r'\*+', '', text) # Remove asterisks
|
| 256 |
text = re.sub(r'\s+', ' ', text).strip() # Normalize spaces
|
| 257 |
return text
|
| 258 |
|
| 259 |
+
# Generate explanation using Gemini AI
|
| 260 |
def generate_explanation(predicted_class):
|
| 261 |
try:
|
| 262 |
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."
|
|
|
|
| 267 |
print(f"Error generating explanation: {e}")
|
| 268 |
return f"This is a {predicted_class}."
|
| 269 |
|
| 270 |
+
# Get conservation status
|
|
|
|
| 271 |
def get_conservation_status(class_name):
|
| 272 |
"""
|
| 273 |
Extracts and returns the conservation status from the given class name.
|
|
|
|
| 298 |
|
| 299 |
return "Unknown conservation status"
|
| 300 |
|
| 301 |
+
# Load model from Hugging Face Hub
|
| 302 |
+
def load_model_from_huggingface():
|
| 303 |
+
cache_dir = "/tmp/huggingface" # Define a writable cache directory
|
| 304 |
+
os.makedirs(cache_dir, exist_ok=True) # Ensure it exists
|
| 305 |
+
|
| 306 |
+
print("Downloading model from Hugging Face Hub...")
|
| 307 |
+
try:
|
| 308 |
+
model_path = hf_hub_download(
|
| 309 |
+
repo_id="anilkumar5590/image-classification-viit",
|
| 310 |
+
filename="model.keras", # Adjust the filename based on your model
|
| 311 |
+
cache_dir=cache_dir # Use the custom directory
|
| 312 |
+
)
|
| 313 |
+
print(f"Model downloaded successfully at: {model_path}")
|
| 314 |
+
model = tf.keras.models.load_model(model_path)
|
| 315 |
+
print("Model loaded successfully!")
|
| 316 |
+
return model
|
| 317 |
+
except Exception as e:
|
| 318 |
+
print(f"Error loading model: {e}")
|
| 319 |
+
raise
|
| 320 |
+
|
| 321 |
+
# Load model at startup
|
| 322 |
+
model = load_model_from_huggingface()
|
| 323 |
|
| 324 |
# Define route for predictions (POST)
|
| 325 |
@app.route("/predict", methods=["POST"])
|
| 326 |
def predict():
|
| 327 |
print("Request Files:", request.files)
|
|
|
|
| 328 |
file = request.files.get('file')
|
| 329 |
|
| 330 |
if not file:
|
| 331 |
+
print("No file part in the request")
|
| 332 |
return jsonify({"error": "No file part"}), 400
|
| 333 |
|
| 334 |
try:
|
| 335 |
# Open and preprocess the image
|
| 336 |
+
print("Opening image...")
|
| 337 |
img = Image.open(io.BytesIO(file.read()))
|
| 338 |
print(f"Received image: {img.size}")
|
| 339 |
img_array = preprocess_image(img)
|
| 340 |
+
print("Image preprocessed successfully")
|
|
|
|
|
|
|
| 341 |
|
| 342 |
# Make prediction
|
| 343 |
+
print("Making prediction...")
|
| 344 |
predictions = model.predict(img_array)
|
| 345 |
+
print("Prediction completed")
|
| 346 |
+
|
| 347 |
+
# Process prediction results
|
| 348 |
predicted_class_index = np.argmax(predictions, axis=1)[0]
|
| 349 |
confidence_level = round(np.max(predictions) * 100, 2)
|
| 350 |
|
| 351 |
+
# Define labels (replace with your model's labels)
|
| 352 |
+
labels = {
|
| 353 |
+
0: 'Aardvark-LC', 1: 'African Elephant-EN', 2: 'Alligator-LC', 3: 'Alpaca-LC', 4: 'Anaconda-LC',
|
| 354 |
+
# Add the rest of your labels here...
|
| 355 |
+
}
|
| 356 |
|
|
|
|
|
|
|
|
|
|
| 357 |
predicted_class = labels.get(predicted_class_index, "Unknown")
|
| 358 |
+
conservation_status = get_conservation_status(predicted_class)
|
| 359 |
predicted_class = predicted_class.split('-')[0] # Remove the conservation status from the class name
|
| 360 |
print(f"Prediction: {predicted_class}, Confidence: {confidence_level}%")
|
| 361 |
|
|
|
|
| 363 |
explanation = generate_explanation(predicted_class)
|
| 364 |
|
| 365 |
# Store the result in the in-memory dictionary
|
| 366 |
+
prediction_id = str(time.time())) # Unique ID for the request
|
|
|
|
| 367 |
prediction_results[prediction_id] = {
|
| 368 |
"predicted_class": predicted_class,
|
| 369 |
"conservation_status": conservation_status,
|
| 370 |
"confidence_level": confidence_level,
|
| 371 |
"explanation": explanation
|
| 372 |
}
|
|
|
|
| 373 |
print(f"Prediction ID: {prediction_id}, Result: {prediction_results[prediction_id]}")
|
|
|
|
| 374 |
return jsonify({"prediction_id": prediction_id}), 200
|
| 375 |
|
| 376 |
except Exception as e:
|
| 377 |
+
print(f"Error during prediction: {e}")
|
| 378 |
+
print(traceback.format_exc())
|
| 379 |
+
return jsonify({"error": f"Error during prediction: {e}"}), 500
|
|
|
|
| 380 |
|
| 381 |
# Define route for retrieving predictions (GET)
|
| 382 |
@app.route("/get_prediction/<prediction_id>", methods=["GET"])
|
|
|
|
| 389 |
print(f"No result found for ID: {prediction_id}")
|
| 390 |
return jsonify({"error": "Prediction not found or still processing"}), 404
|
| 391 |
|
| 392 |
+
# Run the Flask app
|
| 393 |
if __name__ == "__main__":
|
| 394 |
+
app.run(host='0.0.0.0', port=7860, debug=True)
|