Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,10 +1,40 @@
|
|
| 1 |
#!/usr/bin/env python3
|
| 2 |
-
# PLANETYOYO AI Ultimate v19.10 -
|
| 3 |
-
# Description: Plant analysis system with
|
| 4 |
|
| 5 |
import subprocess
|
| 6 |
import sys
|
| 7 |
import os
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
import time
|
| 9 |
import json
|
| 10 |
import requests
|
|
@@ -554,8 +584,8 @@ PLANT_DATABASE = {"aloe_vera": {"care_tips": ["שמש חלקית עד מלאה",
|
|
| 554 |
"tomato_amish_paste": {"care_tips": ["שמש מלאה", "השקיה סדירה"], "common_diseases": ["כליה מוקדמת"], "img_url": "https://www.google.com/searchq=https://placehold.co/600x400/000000/FFFFFF%3Ftext%3Damish_paste_tomato", "plant_id": "tomato_amish_paste"},
|
| 555 |
"tulip_triumph": {"care_tips": ["שמש מלאה", "השקיה מועטה"], "common_diseases": ["ריקבון בצל פוסריום"], "img_url": "https://www.google.com/searchq=https://placehold.co/600x400/000000/FFFFFF%3Ftext%3Dtriumph_tulip", "plant_id": "tulip_triumph"},
|
| 556 |
"vanilla_planifolia": {"care_tips": ["צל חלקי", "לחות גבוהה"], "common_diseases": ["ריקבון גזע"], "img_url": "https://www.google.com/searchq=https://placehold.co/600x400/000000/FFFFFF%3Ftext%3Dvanilla_planifolia", "plant_id": "vanilla_planifolia"},
|
| 557 |
-
"verbena_perennial": {"care_tips": ["שמש מלאה", "השקיה מתונה"], "common_diseases": ["קימחון"], "img_url": "https://www.google.com/searchq=https://placehold.co/600x400/000000/FFFFFF%3Ftext%3Dperennial_verbena", "plant_id": "verbena_perennial"}
|
| 558 |
-
}
|
| 559 |
|
| 560 |
MODEL_WEIGHTS = {}
|
| 561 |
last_analysis_details: Optional[Dict] = None
|
|
@@ -640,10 +670,9 @@ PLANT_NAMES_TO_FILTER = [
|
|
| 640 |
'cyclamen', 'pothos', 'fern', 'ivy', 'succulent', 'cactus'
|
| 641 |
]
|
| 642 |
# ========================================================
|
| 643 |
-
#
|
| 644 |
# ========================================================
|
| 645 |
-
PLANT_AI_MODELS = {
|
| 646 |
-
#// ============ TIER 1: Core Species & Taxonomy Experts ============
|
| 647 |
"PlantNet-Species-Expert": {
|
| 648 |
"model_id": "google/vit-large-patch16-224-in21k",
|
| 649 |
"specialty": "Species|Taxonomy",
|
|
@@ -1021,10 +1050,8 @@ PLANT_AI_MODELS = {
|
|
| 1021 |
"reliability": 0.65,
|
| 1022 |
"priority": 51,
|
| 1023 |
"description": "External PlantNet API for community validation"
|
| 1024 |
-
}
|
| 1025 |
-
# ... (keeping the same model definitions from v19.9)
|
| 1026 |
}
|
| 1027 |
-
|
| 1028 |
# ========================================================
|
| 1029 |
# UTILITY FUNCTIONS
|
| 1030 |
# ========================================================
|
|
@@ -1161,34 +1188,35 @@ class DataIntegrator:
|
|
| 1161 |
self.max_retries = 3
|
| 1162 |
self.retry_delay = 2
|
| 1163 |
|
|
|
|
| 1164 |
if ADAFRUIT_AVAILABLE and ADAFRUIT_IO_USERNAME and ADAFRUIT_IO_KEY:
|
| 1165 |
-
# Try multiple times to initialize Adafruit
|
| 1166 |
for attempt in range(self.max_retries):
|
| 1167 |
try:
|
| 1168 |
self.aio = AdafruitClient(ADAFRUIT_IO_USERNAME, ADAFRUIT_IO_KEY)
|
| 1169 |
-
# Test connection
|
| 1170 |
self.aio.feeds()
|
| 1171 |
-
print("✅ Adafruit IO client initialized
|
| 1172 |
break
|
| 1173 |
except Exception as e:
|
| 1174 |
-
print(f"⚠️ Adafruit init attempt {attempt + 1} failed: {str(e)[:50]}")
|
| 1175 |
if attempt < self.max_retries - 1:
|
| 1176 |
time.sleep(self.retry_delay)
|
| 1177 |
else:
|
| 1178 |
-
print("
|
| 1179 |
self.aio = None
|
| 1180 |
else:
|
| 1181 |
-
print("⚠️ Adafruit IO
|
| 1182 |
|
|
|
|
| 1183 |
if GEOPY_AVAILABLE:
|
| 1184 |
try:
|
| 1185 |
self.geolocator = Nominatim(user_agent="plantscope_app")
|
| 1186 |
print("✅ Geopy initialized")
|
| 1187 |
except Exception as e:
|
| 1188 |
-
print(f"
|
|
|
|
|
|
|
| 1189 |
|
|
|
|
| 1190 |
if CLOUDINARY_AVAILABLE and CLOUDINARY_CLOUD_NAME:
|
| 1191 |
-
# Try multiple configuration methods
|
| 1192 |
for attempt in range(self.max_retries):
|
| 1193 |
try:
|
| 1194 |
cloudinary.config(
|
|
@@ -1197,19 +1225,20 @@ class DataIntegrator:
|
|
| 1197 |
api_secret=CLOUDINARY_API_SECRET,
|
| 1198 |
secure=True
|
| 1199 |
)
|
| 1200 |
-
# Test connection
|
| 1201 |
cloudinary.api.ping()
|
| 1202 |
-
print("✅ Cloudinary configured
|
| 1203 |
break
|
| 1204 |
except Exception as e:
|
| 1205 |
-
print(f"⚠️ Cloudinary config attempt {attempt + 1} failed: {str(e)[:50]}")
|
| 1206 |
if attempt < self.max_retries - 1:
|
| 1207 |
time.sleep(self.retry_delay)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1208 |
|
| 1209 |
def get_adafruit_data(self, feed_name: str, limit: int = 100) -> Optional[List[Dict]]:
|
| 1210 |
"""
|
| 1211 |
Fetch data from Adafruit IO with multiple retry strategies.
|
| 1212 |
-
Tries: direct fetch, feed creation, alternative API endpoints.
|
| 1213 |
"""
|
| 1214 |
if not self.aio:
|
| 1215 |
print(f"⚠️ Adafruit IO not initialized for feed: {feed_name}")
|
|
@@ -1225,33 +1254,27 @@ class DataIntegrator:
|
|
| 1225 |
print(f"✅ Retrieved {len(data)} records from {feed_name}")
|
| 1226 |
return data
|
| 1227 |
else:
|
| 1228 |
-
print(f"⚠️ Feed {feed_name}
|
| 1229 |
return None
|
| 1230 |
|
| 1231 |
except APIError as e:
|
| 1232 |
if "404" in str(e) and attempt == 0:
|
| 1233 |
-
# Strategy 2: Try to create feed if it doesn't exist
|
| 1234 |
-
print(f"⚠️ Feed '{feed_name}' not found, attempting creation...")
|
| 1235 |
try:
|
| 1236 |
feed = self.aio.create_feed({"name": feed_name, "key": feed_name})
|
| 1237 |
print(f"✅ Created feed: {feed_name}")
|
| 1238 |
-
return []
|
| 1239 |
except Exception as create_error:
|
| 1240 |
print(f"❌ Could not create feed: {str(create_error)[:50]}")
|
| 1241 |
-
else:
|
| 1242 |
-
print(f"❌ Attempt {attempt + 1} - API Error: {str(e)[:50]}")
|
| 1243 |
|
| 1244 |
if attempt < self.max_retries - 1:
|
| 1245 |
time.sleep(self.retry_delay * (attempt + 1))
|
| 1246 |
|
| 1247 |
except Exception as e:
|
| 1248 |
-
print(f"❌ Attempt {attempt + 1} - Unexpected error: {str(e)[:50]}")
|
| 1249 |
if attempt < self.max_retries - 1:
|
| 1250 |
time.sleep(self.retry_delay * (attempt + 1))
|
| 1251 |
|
| 1252 |
-
# Strategy 3: Try REST API
|
| 1253 |
try:
|
| 1254 |
-
print(f"⚠️ Trying direct REST API for {feed_name}...")
|
| 1255 |
url = f"https://io.adafruit.com/api/v2/{ADAFRUIT_IO_USERNAME}/feeds/{feed_name}/data"
|
| 1256 |
headers = {"X-AIO-Key": ADAFRUIT_IO_KEY}
|
| 1257 |
response = requests.get(url, headers=headers, params={"limit": limit}, timeout=10)
|
|
@@ -1260,11 +1283,9 @@ class DataIntegrator:
|
|
| 1260 |
data = response.json()
|
| 1261 |
print(f"✅ Retrieved {len(data)} records via REST API")
|
| 1262 |
return data
|
| 1263 |
-
else:
|
| 1264 |
-
print(f"❌ REST API returned: {response.status_code}")
|
| 1265 |
|
| 1266 |
except Exception as e:
|
| 1267 |
-
print(f"❌
|
| 1268 |
|
| 1269 |
return None
|
| 1270 |
|
|
@@ -1310,14 +1331,13 @@ class DataIntegrator:
|
|
| 1310 |
def get_cloudinary_images(self, count: int = 20) -> List[Dict]:
|
| 1311 |
"""
|
| 1312 |
Fetch images from Cloudinary with multiple retry strategies.
|
| 1313 |
-
Tries: standard API, different resource types, pagination.
|
| 1314 |
"""
|
| 1315 |
if not CLOUDINARY_AVAILABLE:
|
| 1316 |
-
print("⚠️ Cloudinary
|
| 1317 |
return []
|
| 1318 |
|
| 1319 |
if not CLOUDINARY_CLOUD_NAME:
|
| 1320 |
-
print("⚠️ Cloudinary
|
| 1321 |
return []
|
| 1322 |
|
| 1323 |
# Strategy 1: Try standard fetch
|
|
@@ -1338,15 +1358,14 @@ class DataIntegrator:
|
|
| 1338 |
return resources
|
| 1339 |
else:
|
| 1340 |
print(f"⚠️ No images in folder: {CLOUDINARY_FOLDER}")
|
|
|
|
| 1341 |
|
| 1342 |
except Exception as e:
|
| 1343 |
-
print(f"❌ Attempt {attempt + 1} failed: {str(e)[:50]}")
|
| 1344 |
if attempt < self.max_retries - 1:
|
| 1345 |
time.sleep(self.retry_delay * (attempt + 1))
|
| 1346 |
|
| 1347 |
-
# Strategy 2: Try without prefix
|
| 1348 |
try:
|
| 1349 |
-
print("⚠️ Trying to fetch all images (no folder filter)...")
|
| 1350 |
results = cloudinary.api.resources(
|
| 1351 |
type="upload",
|
| 1352 |
max_results=count,
|
|
@@ -1355,7 +1374,6 @@ class DataIntegrator:
|
|
| 1355 |
)
|
| 1356 |
|
| 1357 |
resources = results.get('resources', [])
|
| 1358 |
-
# Filter by folder manually
|
| 1359 |
filtered = [r for r in resources if CLOUDINARY_FOLDER in r.get('public_id', '')]
|
| 1360 |
|
| 1361 |
if filtered:
|
|
@@ -1363,11 +1381,10 @@ class DataIntegrator:
|
|
| 1363 |
return filtered
|
| 1364 |
|
| 1365 |
except Exception as e:
|
| 1366 |
-
print(f"
|
| 1367 |
|
| 1368 |
-
# Strategy 3: Try REST API
|
| 1369 |
try:
|
| 1370 |
-
print("⚠️ Trying Cloudinary REST API...")
|
| 1371 |
import base64
|
| 1372 |
auth_string = f"{CLOUDINARY_API_KEY}:{CLOUDINARY_API_SECRET}"
|
| 1373 |
auth_header = base64.b64encode(auth_string.encode()).decode()
|
|
@@ -1385,7 +1402,7 @@ class DataIntegrator:
|
|
| 1385 |
return resources
|
| 1386 |
|
| 1387 |
except Exception as e:
|
| 1388 |
-
print(f"❌ REST API
|
| 1389 |
|
| 1390 |
return []
|
| 1391 |
|
|
@@ -2333,21 +2350,42 @@ if __name__ == "__main__":
|
|
| 2333 |
print(f"\n⏰ Startup: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
|
| 2334 |
|
| 2335 |
print("📊 System Status:")
|
| 2336 |
-
print(f" • AI
|
| 2337 |
print(f" • Device: {device.upper()}")
|
| 2338 |
-
print(f" • Adafruit IO: {'✅' if data_integrator.aio else '
|
| 2339 |
-
print(f" • Cloudinary: {'✅' if CLOUDINARY_AVAILABLE and CLOUDINARY_CLOUD_NAME else '
|
|
|
|
|
|
|
| 2340 |
print(f" • Max Retries: {data_integrator.max_retries}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2341 |
|
| 2342 |
print("\n📊 Loading model weights...")
|
| 2343 |
MODEL_WEIGHTS = load_weights()
|
| 2344 |
|
| 2345 |
if AI_AVAILABLE:
|
|
|
|
| 2346 |
preload_all_models()
|
| 2347 |
else:
|
| 2348 |
-
print("\n
|
| 2349 |
-
|
| 2350 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2351 |
print("=" * 80 + "\n")
|
| 2352 |
|
| 2353 |
app = create_gradio_app()
|
|
|
|
| 1 |
#!/usr/bin/env python3
|
| 2 |
+
# PLANETYOYO AI Ultimate v19.10 - Auto-Install Dependencies
|
| 3 |
+
# Description: Plant analysis system with automatic dependency installation
|
| 4 |
|
| 5 |
import subprocess
|
| 6 |
import sys
|
| 7 |
import os
|
| 8 |
+
|
| 9 |
+
# ========================================================
|
| 10 |
+
# AUTO-INSTALL MISSING DEPENDENCIES
|
| 11 |
+
# ========================================================
|
| 12 |
+
def install_package(package_name: str, import_name: str = None):
|
| 13 |
+
"""Install package if not available."""
|
| 14 |
+
if import_name is None:
|
| 15 |
+
import_name = package_name
|
| 16 |
+
|
| 17 |
+
try:
|
| 18 |
+
__import__(import_name)
|
| 19 |
+
return True
|
| 20 |
+
except ImportError:
|
| 21 |
+
print(f"📦 Installing {package_name}...")
|
| 22 |
+
try:
|
| 23 |
+
subprocess.check_call([sys.executable, "-m", "pip", "install", package_name, "-q"])
|
| 24 |
+
print(f"✅ {package_name} installed successfully")
|
| 25 |
+
return True
|
| 26 |
+
except subprocess.CalledProcessError:
|
| 27 |
+
print(f"❌ Failed to install {package_name}")
|
| 28 |
+
return False
|
| 29 |
+
|
| 30 |
+
# Install core dependencies
|
| 31 |
+
print("\n🔧 Checking dependencies...")
|
| 32 |
+
install_package("adafruit-io", "adafruit_io")
|
| 33 |
+
install_package("geopy")
|
| 34 |
+
install_package("cloudinary")
|
| 35 |
+
install_package("prophet")
|
| 36 |
+
install_package("requests")
|
| 37 |
+
|
| 38 |
import time
|
| 39 |
import json
|
| 40 |
import requests
|
|
|
|
| 584 |
"tomato_amish_paste": {"care_tips": ["שמש מלאה", "השקיה סדירה"], "common_diseases": ["כליה מוקדמת"], "img_url": "https://www.google.com/searchq=https://placehold.co/600x400/000000/FFFFFF%3Ftext%3Damish_paste_tomato", "plant_id": "tomato_amish_paste"},
|
| 585 |
"tulip_triumph": {"care_tips": ["שמש מלאה", "השקיה מועטה"], "common_diseases": ["ריקבון בצל פוסריום"], "img_url": "https://www.google.com/searchq=https://placehold.co/600x400/000000/FFFFFF%3Ftext%3Dtriumph_tulip", "plant_id": "tulip_triumph"},
|
| 586 |
"vanilla_planifolia": {"care_tips": ["צל חלקי", "לחות גבוהה"], "common_diseases": ["ריקבון גזע"], "img_url": "https://www.google.com/searchq=https://placehold.co/600x400/000000/FFFFFF%3Ftext%3Dvanilla_planifolia", "plant_id": "vanilla_planifolia"},
|
| 587 |
+
"verbena_perennial": {"care_tips": ["שמש מלאה", "השקיה מתונה"], "common_diseases": ["קימחון"], "img_url": "https://www.google.com/searchq=https://placehold.co/600x400/000000/FFFFFF%3Ftext%3Dperennial_verbena", "plant_id": "verbena_perennial"}
|
| 588 |
+
}
|
| 589 |
|
| 590 |
MODEL_WEIGHTS = {}
|
| 591 |
last_analysis_details: Optional[Dict] = None
|
|
|
|
| 670 |
'cyclamen', 'pothos', 'fern', 'ivy', 'succulent', 'cactus'
|
| 671 |
]
|
| 672 |
# ========================================================
|
| 673 |
+
# CURATED AI MODELS - USER WILL INSERT THEIR MODELS
|
| 674 |
# ========================================================
|
| 675 |
+
PLANT_AI_MODELS = { #// ============ TIER 1: Core Species & Taxonomy Experts ============
|
|
|
|
| 676 |
"PlantNet-Species-Expert": {
|
| 677 |
"model_id": "google/vit-large-patch16-224-in21k",
|
| 678 |
"specialty": "Species|Taxonomy",
|
|
|
|
| 1050 |
"reliability": 0.65,
|
| 1051 |
"priority": 51,
|
| 1052 |
"description": "External PlantNet API for community validation"
|
| 1053 |
+
} # Insert your models here
|
|
|
|
| 1054 |
}
|
|
|
|
| 1055 |
# ========================================================
|
| 1056 |
# UTILITY FUNCTIONS
|
| 1057 |
# ========================================================
|
|
|
|
| 1188 |
self.max_retries = 3
|
| 1189 |
self.retry_delay = 2
|
| 1190 |
|
| 1191 |
+
# Try Adafruit IO initialization with fallback
|
| 1192 |
if ADAFRUIT_AVAILABLE and ADAFRUIT_IO_USERNAME and ADAFRUIT_IO_KEY:
|
|
|
|
| 1193 |
for attempt in range(self.max_retries):
|
| 1194 |
try:
|
| 1195 |
self.aio = AdafruitClient(ADAFRUIT_IO_USERNAME, ADAFRUIT_IO_KEY)
|
|
|
|
| 1196 |
self.aio.feeds()
|
| 1197 |
+
print("✅ Adafruit IO client initialized")
|
| 1198 |
break
|
| 1199 |
except Exception as e:
|
|
|
|
| 1200 |
if attempt < self.max_retries - 1:
|
| 1201 |
time.sleep(self.retry_delay)
|
| 1202 |
else:
|
| 1203 |
+
print(f"⚠️ Adafruit IO unavailable (will use mock data): {str(e)[:50]}")
|
| 1204 |
self.aio = None
|
| 1205 |
else:
|
| 1206 |
+
print("⚠️ Adafruit IO not configured (will use mock data)")
|
| 1207 |
|
| 1208 |
+
# Try Geopy initialization
|
| 1209 |
if GEOPY_AVAILABLE:
|
| 1210 |
try:
|
| 1211 |
self.geolocator = Nominatim(user_agent="plantscope_app")
|
| 1212 |
print("✅ Geopy initialized")
|
| 1213 |
except Exception as e:
|
| 1214 |
+
print(f"⚠️ Geopy unavailable: {str(e)[:50]}")
|
| 1215 |
+
else:
|
| 1216 |
+
print("⚠️ Geopy not installed (location features limited)")
|
| 1217 |
|
| 1218 |
+
# Try Cloudinary configuration with fallback
|
| 1219 |
if CLOUDINARY_AVAILABLE and CLOUDINARY_CLOUD_NAME:
|
|
|
|
| 1220 |
for attempt in range(self.max_retries):
|
| 1221 |
try:
|
| 1222 |
cloudinary.config(
|
|
|
|
| 1225 |
api_secret=CLOUDINARY_API_SECRET,
|
| 1226 |
secure=True
|
| 1227 |
)
|
|
|
|
| 1228 |
cloudinary.api.ping()
|
| 1229 |
+
print("✅ Cloudinary configured")
|
| 1230 |
break
|
| 1231 |
except Exception as e:
|
|
|
|
| 1232 |
if attempt < self.max_retries - 1:
|
| 1233 |
time.sleep(self.retry_delay)
|
| 1234 |
+
else:
|
| 1235 |
+
print(f"⚠️ Cloudinary unavailable (will use mock data): {str(e)[:50]}")
|
| 1236 |
+
else:
|
| 1237 |
+
print("⚠️ Cloudinary not configured (gallery features limited)")
|
| 1238 |
|
| 1239 |
def get_adafruit_data(self, feed_name: str, limit: int = 100) -> Optional[List[Dict]]:
|
| 1240 |
"""
|
| 1241 |
Fetch data from Adafruit IO with multiple retry strategies.
|
|
|
|
| 1242 |
"""
|
| 1243 |
if not self.aio:
|
| 1244 |
print(f"⚠️ Adafruit IO not initialized for feed: {feed_name}")
|
|
|
|
| 1254 |
print(f"✅ Retrieved {len(data)} records from {feed_name}")
|
| 1255 |
return data
|
| 1256 |
else:
|
| 1257 |
+
print(f"⚠️ Feed {feed_name} is empty")
|
| 1258 |
return None
|
| 1259 |
|
| 1260 |
except APIError as e:
|
| 1261 |
if "404" in str(e) and attempt == 0:
|
|
|
|
|
|
|
| 1262 |
try:
|
| 1263 |
feed = self.aio.create_feed({"name": feed_name, "key": feed_name})
|
| 1264 |
print(f"✅ Created feed: {feed_name}")
|
| 1265 |
+
return []
|
| 1266 |
except Exception as create_error:
|
| 1267 |
print(f"❌ Could not create feed: {str(create_error)[:50]}")
|
|
|
|
|
|
|
| 1268 |
|
| 1269 |
if attempt < self.max_retries - 1:
|
| 1270 |
time.sleep(self.retry_delay * (attempt + 1))
|
| 1271 |
|
| 1272 |
except Exception as e:
|
|
|
|
| 1273 |
if attempt < self.max_retries - 1:
|
| 1274 |
time.sleep(self.retry_delay * (attempt + 1))
|
| 1275 |
|
| 1276 |
+
# Strategy 3: Try REST API
|
| 1277 |
try:
|
|
|
|
| 1278 |
url = f"https://io.adafruit.com/api/v2/{ADAFRUIT_IO_USERNAME}/feeds/{feed_name}/data"
|
| 1279 |
headers = {"X-AIO-Key": ADAFRUIT_IO_KEY}
|
| 1280 |
response = requests.get(url, headers=headers, params={"limit": limit}, timeout=10)
|
|
|
|
| 1283 |
data = response.json()
|
| 1284 |
print(f"✅ Retrieved {len(data)} records via REST API")
|
| 1285 |
return data
|
|
|
|
|
|
|
| 1286 |
|
| 1287 |
except Exception as e:
|
| 1288 |
+
print(f"❌ All methods failed: {str(e)[:50]}")
|
| 1289 |
|
| 1290 |
return None
|
| 1291 |
|
|
|
|
| 1331 |
def get_cloudinary_images(self, count: int = 20) -> List[Dict]:
|
| 1332 |
"""
|
| 1333 |
Fetch images from Cloudinary with multiple retry strategies.
|
|
|
|
| 1334 |
"""
|
| 1335 |
if not CLOUDINARY_AVAILABLE:
|
| 1336 |
+
print("⚠️ Cloudinary not installed")
|
| 1337 |
return []
|
| 1338 |
|
| 1339 |
if not CLOUDINARY_CLOUD_NAME:
|
| 1340 |
+
print("⚠️ Cloudinary not configured")
|
| 1341 |
return []
|
| 1342 |
|
| 1343 |
# Strategy 1: Try standard fetch
|
|
|
|
| 1358 |
return resources
|
| 1359 |
else:
|
| 1360 |
print(f"⚠️ No images in folder: {CLOUDINARY_FOLDER}")
|
| 1361 |
+
return []
|
| 1362 |
|
| 1363 |
except Exception as e:
|
|
|
|
| 1364 |
if attempt < self.max_retries - 1:
|
| 1365 |
time.sleep(self.retry_delay * (attempt + 1))
|
| 1366 |
|
| 1367 |
+
# Strategy 2: Try without prefix
|
| 1368 |
try:
|
|
|
|
| 1369 |
results = cloudinary.api.resources(
|
| 1370 |
type="upload",
|
| 1371 |
max_results=count,
|
|
|
|
| 1374 |
)
|
| 1375 |
|
| 1376 |
resources = results.get('resources', [])
|
|
|
|
| 1377 |
filtered = [r for r in resources if CLOUDINARY_FOLDER in r.get('public_id', '')]
|
| 1378 |
|
| 1379 |
if filtered:
|
|
|
|
| 1381 |
return filtered
|
| 1382 |
|
| 1383 |
except Exception as e:
|
| 1384 |
+
print(f"⚠️ Fallback fetch failed: {str(e)[:50]}")
|
| 1385 |
|
| 1386 |
+
# Strategy 3: Try REST API
|
| 1387 |
try:
|
|
|
|
| 1388 |
import base64
|
| 1389 |
auth_string = f"{CLOUDINARY_API_KEY}:{CLOUDINARY_API_SECRET}"
|
| 1390 |
auth_header = base64.b64encode(auth_string.encode()).decode()
|
|
|
|
| 1402 |
return resources
|
| 1403 |
|
| 1404 |
except Exception as e:
|
| 1405 |
+
print(f"❌ REST API failed: {str(e)[:50]}")
|
| 1406 |
|
| 1407 |
return []
|
| 1408 |
|
|
|
|
| 2350 |
print(f"\n⏰ Startup: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
|
| 2351 |
|
| 2352 |
print("📊 System Status:")
|
| 2353 |
+
print(f" • AI Engine: {'✅ Active' if AI_AVAILABLE else '❌ Install: pip install torch transformers'}")
|
| 2354 |
print(f" • Device: {device.upper()}")
|
| 2355 |
+
print(f" • Adafruit IO: {'✅ Connected' if data_integrator.aio else '⚠️ Mock Data Mode'}")
|
| 2356 |
+
print(f" • Cloudinary: {'✅ Connected' if CLOUDINARY_AVAILABLE and CLOUDINARY_CLOUD_NAME else '⚠️ Placeholder Mode'}")
|
| 2357 |
+
print(f" • Prophet: {'✅ Available' if PROPHET_AVAILABLE else '⚠️ Install: pip install prophet'}")
|
| 2358 |
+
print(f" • Geopy: {'✅ Available' if GEOPY_AVAILABLE else '⚠️ Install: pip install geopy'}")
|
| 2359 |
print(f" • Max Retries: {data_integrator.max_retries}")
|
| 2360 |
+
print(f" • Plant Models: {len(PLANT_AI_MODELS)}")
|
| 2361 |
+
|
| 2362 |
+
# Feature availability
|
| 2363 |
+
print("\n🔧 Feature Availability:")
|
| 2364 |
+
if not data_integrator.aio:
|
| 2365 |
+
print(" ⚠️ Sensor data: Using mock/simulated data")
|
| 2366 |
+
if not CLOUDINARY_AVAILABLE or not CLOUDINARY_CLOUD_NAME:
|
| 2367 |
+
print(" ⚠️ Image gallery: Using placeholder images")
|
| 2368 |
+
if not PROPHET_AVAILABLE:
|
| 2369 |
+
print(" ⚠️ Forecasting: Disabled (install prophet)")
|
| 2370 |
+
if AI_AVAILABLE:
|
| 2371 |
+
print(" ✅ Plant Analysis: Fully functional")
|
| 2372 |
|
| 2373 |
print("\n📊 Loading model weights...")
|
| 2374 |
MODEL_WEIGHTS = load_weights()
|
| 2375 |
|
| 2376 |
if AI_AVAILABLE:
|
| 2377 |
+
print("\n💡 TIP: Model preload may take 5-10 minutes on first run...")
|
| 2378 |
preload_all_models()
|
| 2379 |
else:
|
| 2380 |
+
print("\n❌ AI Disabled - Install dependencies:")
|
| 2381 |
+
print(" pip install torch transformers")
|
| 2382 |
+
print("\n⚠️ System will run in limited mode (no plant analysis)")
|
| 2383 |
+
|
| 2384 |
+
print("\n🚀 Launching Gradio Interface...")
|
| 2385 |
+
print("\n💡 TIPS:")
|
| 2386 |
+
print(" • Missing dependencies? System uses mock data automatically")
|
| 2387 |
+
print(" • Optional features gracefully degrade")
|
| 2388 |
+
print(" • Core AI analysis works even without IoT integrations")
|
| 2389 |
print("=" * 80 + "\n")
|
| 2390 |
|
| 2391 |
app = create_gradio_app()
|