anilkumar5590 commited on
Commit
0573a6b
·
verified ·
1 Parent(s): 012e255

Create backendapi.py

Browse files
Files changed (1) hide show
  1. backendapi.py +191 -0
backendapi.py ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ # Load model at startup
50
+ model = load_model_from_huggingface()
51
+
52
+ # In-memory store to simulate prediction processing
53
+ prediction_results = {}
54
+
55
+ # Create Flask app
56
+ app = Flask(__name__)
57
+
58
+ # Enable CORS for all routes
59
+ CORS(app)
60
+
61
+ # Configure Google Gemini AI
62
+ genai.configure(api_key="AIzaSyD0M3hdjekk6w_b9WXXb0T_qLAS0MY5iDQ") # Replace with your actual API key
63
+ model_gemini = genai.GenerativeModel("gemini-1.5-flash") # Use a fast Gemini AI model
64
+
65
+ # Define preprocessing function for the uploaded image
66
+ def preprocess_image(img):
67
+ img = img.resize((224, 224)) # Resize image to match model input size
68
+ img_array = np.array(img)
69
+ img_array = np.expand_dims(img_array, axis=0) # Add batch dimension
70
+ img_array = tf.keras.applications.efficientnet.preprocess_input(img_array) # Preprocess for EfficientNet
71
+ return img_array
72
+
73
+
74
+ def clean_explanation(text):
75
+ """Remove unnecessary formatting such as * and excess whitespace."""
76
+ text = re.sub(r'\*+', '', text) # Remove asterisks
77
+ text = re.sub(r'\s+', ' ', text).strip() # Normalize spaces
78
+ return text
79
+
80
+ def generate_explanation(predicted_class):
81
+ try:
82
+ 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."
83
+ response = model_gemini.generate_content(prompt)
84
+ raw_text = response.text.strip() if response and response.text else f"This is a {predicted_class}."
85
+ return clean_explanation(raw_text) # Clean the AI-generated text
86
+ except Exception as e:
87
+ print(f"Error generating explanation: {e}")
88
+ return f"This is a {predicted_class}."
89
+
90
+
91
+
92
+ def get_conservation_status(class_name):
93
+ """
94
+ Extracts and returns the conservation status from the given class name.
95
+
96
+ Args:
97
+ class_name (str): The predicted class name, e.g., 'Axolotl-CR', 'African Elephant-EN'.
98
+
99
+ Returns:
100
+ str: The full conservation status description.
101
+ """
102
+ status_map = {
103
+ "EX": "Extinct (EX) - No known individuals remaining.",
104
+ "EW": "Extinct in the Wild (EW) - Survives only in captivity.",
105
+ "CR": "Critically Endangered (CR) - Faces an extremely high risk of extinction.",
106
+ "EN": "Endangered (EN) - High risk of extinction in the wild.",
107
+ "VU": "Vulnerable (VU) - At risk of becoming endangered.",
108
+ "NT": "Near Threatened (NT) - Likely to become endangered in the future.",
109
+ "LC": "Least Concern (LC) - Lowest risk of extinction.",
110
+ "DD": "Data Deficient (DD) - Not enough information to assess the risk.",
111
+ "NE": "Not Evaluated (NE) - Has not yet been assessed."
112
+ }
113
+
114
+ # Extract the conservation status from the class name
115
+ parts = class_name.split('-')
116
+ if len(parts) > 1:
117
+ status_abbr = parts[-1] # The last part should be the conservation status
118
+ return status_map.get(status_abbr, "Unknown conservation status")
119
+
120
+ return "Unknown conservation status"
121
+
122
+
123
+ # Define route for predictions (POST)
124
+ @app.route("/predict", methods=["POST"])
125
+ def predict():
126
+ print("Request Files:", request.files)
127
+
128
+ file = request.files.get('file')
129
+
130
+ if not file:
131
+ return jsonify({"error": "No file part"}), 400
132
+
133
+ try:
134
+ # Open and preprocess the image
135
+ img = Image.open(io.BytesIO(file.read()))
136
+ print(f"Received image: {img.size}")
137
+ img_array = preprocess_image(img)
138
+
139
+ # Simulate prediction delay (e.g., processing the image)
140
+ time.sleep(2) # Simulating a delay
141
+
142
+ # Make prediction
143
+ predictions = model.predict(img_array)
144
+ predicted_class_index = np.argmax(predictions, axis=1)[0]
145
+ confidence_level = round(np.max(predictions) * 100, 2)
146
+
147
+
148
+ 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'}
149
+ # Replace with your model's labels
150
+
151
+ predicted_class = labels.get(predicted_class_index, "Unknown")
152
+ conservation_status= get_conservation_status(predicted_class)
153
+ predicted_class = predicted_class.split('-')[0] # Remove the conservation status from the class name
154
+ print(f"Prediction: {predicted_class}, Confidence: {confidence_level}%")
155
+
156
+ # Generate explanation using Gemini AI
157
+ explanation = generate_explanation(predicted_class)
158
+
159
+ # Store the result in the in-memory dictionary
160
+ prediction_id = str(time.time()) # Unique ID for the request
161
+
162
+ prediction_results[prediction_id] = {
163
+ "predicted_class": predicted_class,
164
+ "conservation_status": conservation_status,
165
+ "confidence_level": confidence_level,
166
+ "explanation": explanation
167
+ }
168
+
169
+ print(f"Prediction ID: {prediction_id}, Result: {prediction_results[prediction_id]}")
170
+ # Return the prediction ID to be used for GET request later
171
+ return jsonify({"prediction_id": prediction_id}), 200
172
+
173
+ except Exception as e:
174
+ # Include the traceback in the error response
175
+ error_message = traceback.format_exc()
176
+ print(error_message) # Print in the server logs
177
+ return jsonify({"error": f"Error during prediction: {error_message}"}), 500
178
+
179
+ # Define route for retrieving predictions (GET)
180
+ @app.route("/get_prediction/<prediction_id>", methods=["GET"])
181
+ def get_prediction(prediction_id):
182
+ print(f"Fetching prediction result for ID: {prediction_id}")
183
+ result = prediction_results.get(prediction_id)
184
+ if result:
185
+ return jsonify(result)
186
+ else:
187
+ print(f"No result found for ID: {prediction_id}")
188
+ return jsonify({"error": "Prediction not found or still processing"}), 404
189
+
190
+ if __name__ == "__main__":
191
+ app.run(host='0.0.0.0', port=7860,debug=True)