Yoyo-9877 commited on
Commit
f92d242
·
verified ·
1 Parent(s): 060a16c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +89 -51
app.py CHANGED
@@ -1,10 +1,40 @@
1
  #!/usr/bin/env python3
2
- # PLANETYOYO AI Ultimate v19.10 - Enhanced with Retry Logic & Disease Filtering
3
- # Description: Plant analysis system with robust error handling and filtering
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
- # [INSERT YOUR PLANT_AI_MODELS HERE - same as before]
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 and tested")
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(" Adafruit IO initialization failed after all retries")
1179
  self.aio = None
1180
  else:
1181
- print("⚠️ Adafruit IO credentials missing")
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" Geopy init failed: {e}")
 
 
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 and tested")
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} exists but is empty")
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 [] # Return empty list for new feed
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 directly as last resort
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"❌ REST API fallback failed: {str(e)[:50]}")
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 library not installed")
1317
  return []
1318
 
1319
  if not CLOUDINARY_CLOUD_NAME:
1320
- print("⚠️ Cloudinary credentials not configured")
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 (get all images)
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" Fallback fetch failed: {str(e)[:50]}")
1367
 
1368
- # Strategy 3: Try REST API directly
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 fallback failed: {str(e)[:50]}")
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 Available: {AI_AVAILABLE}")
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⚠️ AI disabled. Install: pip install torch transformers")
2349
-
2350
- print("\n🚀 Launching Gradio...")
 
 
 
 
 
 
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()