AbdullahMohzar commited on
Commit
5862ee1
·
1 Parent(s): 83a664b

Add auto-admin script and route DB/Media to persistent storage

Browse files
0a055266cd32ddd1222176d9cd02fd44.jpg ADDED
Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM python:3.12-slim
2
 
3
  # Install system dependencies for OpenCV/YOLO
4
  RUN apt-get update && apt-get install -y \
@@ -46,5 +46,7 @@ CMD cd plant_core && \
46
  python manage.py collectstatic --no-input && \
47
  echo "Running migrations..." && \
48
  python manage.py migrate && \
 
 
49
  echo "Starting Gunicorn..." && \
50
  gunicorn plant_core.wsgi:application --bind 0.0.0.0:7860 --timeout 300 --log-level info
 
1
+ FROM python:3.12-slim
2
 
3
  # Install system dependencies for OpenCV/YOLO
4
  RUN apt-get update && apt-get install -y \
 
46
  python manage.py collectstatic --no-input && \
47
  echo "Running migrations..." && \
48
  python manage.py migrate && \
49
+ echo "Setting up admin user..." && \
50
+ python manage.py setup_admin && \
51
  echo "Starting Gunicorn..." && \
52
  gunicorn plant_core.wsgi:application --bind 0.0.0.0:7860 --timeout 300 --log-level info
check_classes.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import django
3
+
4
+ sys.path.append('d:/Plant_App/plant_core')
5
+ import os
6
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'plant_core.settings')
7
+ django.setup()
8
+
9
+ from diseases.ml_logic import CLASS_NAMES
10
+ print("Mango classes:")
11
+ for c in CLASS_NAMES:
12
+ if "mango" in c.lower():
13
+ print(c)
images.jpg ADDED
mango1_538x.jpg ADDED
plant_core/diseases/management/commands/setup_admin.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from django.core.management.base import BaseCommand
2
+ from django.contrib.auth import get_user_model
3
+ import os
4
+
5
+ class Command(BaseCommand):
6
+ help = 'Automatically creates a superuser from ADMIN_USERNAME and ADMIN_PASSWORD environment variables'
7
+
8
+ def handle(self, *args, **options):
9
+ User = get_user_model()
10
+
11
+ username = os.environ.get('ADMIN_USERNAME', 'admin')
12
+ password = os.environ.get('ADMIN_PASSWORD', 'admin')
13
+ email = os.environ.get('ADMIN_EMAIL', 'admin@example.com')
14
+
15
+ if not User.objects.filter(username=username).exists():
16
+ self.stdout.write(f"Creating superuser '{username}'...")
17
+ User.objects.create_superuser(username=username, email=email, password=password)
18
+ self.stdout.write(self.style.SUCCESS(f"Successfully created superuser '{username}'"))
19
+ else:
20
+ self.stdout.write(f"Superuser '{username}' already exists. Skipping creation.")
plant_core/plant_core/settings.py CHANGED
@@ -32,9 +32,15 @@ BASE_DIR = Path(__file__).resolve().parent.parent
32
 
33
  import dj_database_url
34
 
 
 
 
 
 
 
35
  DATABASES = {
36
  'default': dj_database_url.config(
37
- default=f"sqlite:///{BASE_DIR / 'db.sqlite3'}",
38
  conn_max_age=600,
39
  conn_health_checks=True,
40
  )
@@ -174,7 +180,10 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
174
 
175
 
176
  MEDIA_URL = '/media/'
177
- MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
 
 
 
178
 
179
  DATA_UPLOAD_MAX_MEMORY_SIZE = 10_485_760 # 10MB — allow phone camera uploads
180
 
 
32
 
33
  import dj_database_url
34
 
35
+ # Check if running on Hugging Face Spaces with persistent storage
36
+ if os.path.exists('/data'):
37
+ DB_PATH = '/data/db.sqlite3'
38
+ else:
39
+ DB_PATH = BASE_DIR / 'db.sqlite3'
40
+
41
  DATABASES = {
42
  'default': dj_database_url.config(
43
+ default=f"sqlite:///{DB_PATH}",
44
  conn_max_age=600,
45
  conn_health_checks=True,
46
  )
 
180
 
181
 
182
  MEDIA_URL = '/media/'
183
+ if os.path.exists('/data'):
184
+ MEDIA_ROOT = '/data/media'
185
+ else:
186
+ MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
187
 
188
  DATA_UPLOAD_MAX_MEMORY_SIZE = 10_485_760 # 10MB — allow phone camera uploads
189
 
update_prompt.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+
3
+ with open('plant_core/diseases/ml_logic.py', 'r') as f:
4
+ content = f.read()
5
+
6
+ replacement = '''
7
+ if species_hint:
8
+ prompt = (
9
+ "You are a plant pathologist analyzing a single leaf image.\\n\\n"
10
+ f"CONTEXT: An upstream object-detection model tagged this leaf as species '{species_hint}'. "
11
+ "That model is NOT trained on all crop types and frequently mislabels out-of-distribution leaves. "
12
+ "Treat the hint as a weak prior only — never as evidence.\\n\\n"
13
+ "ANALYSIS STEPS (do this reasoning internally, do not output it):\\n"
14
+ "1. Confirm this is actually a leaf. If it's not a leaf (or not identifiable as one), set is_plant_leaf to false and every other field to null.\\n"
15
+ f"2. Identify the species independently from leaf shape, margin, venation pattern, and texture. Only agree with '{species_hint}' if your own visual evidence supports it. If you're not confident in the species, say so via a lower confidence score rather than defaulting to the hint.\\n"
16
+ "3. Inspect the leaf surface for visible symptoms: discoloration, lesions, spots, mold, wilting, curling, chlorosis, necrosis, pest damage, etc.\\n"
17
+ "4. Decide health status:\\n"
18
+ " - No visible symptoms -> disease_name MUST be \\"healthy\\".\\n"
19
+ " - Visible symptoms -> name the disease based on the specific visual pattern you observe (e.g. \\"early blight\\", \\"powdery mildew\\", \\"leaf rust\\"), not a generic guess. If symptoms are visible but you can't confidently name a specific disease, use \\"unidentified leaf disease\\" rather than inventing a specific name.\\n"
20
+ "5. Only fill organic_cure, chemical_cure, and prevention_tips if disease_name is a real (non-null, non-\\"healthy\\") diagnosis you are reasonably confident in. If disease_name is \\"healthy\\" or \\"unidentified leaf disease\\", set these three fields to null instead of fabricating treatment advice.\\n\\n"
21
+ "CONFIDENCE CALIBRATION:\\n"
22
+ "- confidence reflects your certainty in the (species + disease) call jointly.\\n"
23
+ "- Use <0.5 when the image is blurry, ambiguous, or symptoms are non-specific.\\n"
24
+ "- Do not inflate confidence just because a specific hint was provided.\\n\\n"
25
+ "Respond with ONLY valid JSON, no markdown, no explanation, no reasoning text.\\n"
26
+ "Schema:\\n"
27
+ '{"is_plant_leaf": bool, "plant_species": str or null, "disease_name": str or null, "confidence": float 0-1, "severity": "mild"|"moderate"|"severe"|null, "organic_cure": str or null, "chemical_cure": str or null, "prevention_tips": str or null}'
28
+ )
29
+ else:
30
+ prompt = (
31
+ "You are a plant pathologist analyzing a single leaf image.\\n\\n"
32
+ "ANALYSIS STEPS (do this reasoning internally, do not output it):\\n"
33
+ "1. Confirm this is actually a leaf. If it's not a leaf (or not identifiable as one), set is_plant_leaf to false and every other field to null.\\n"
34
+ "2. Identify the species independently from leaf shape, margin, venation pattern, and texture. If you're not confident in the species, say so via a lower confidence score.\\n"
35
+ "3. Inspect the leaf surface for visible symptoms: discoloration, lesions, spots, mold, wilting, curling, chlorosis, necrosis, pest damage, etc.\\n"
36
+ "4. Decide health status:\\n"
37
+ " - No visible symptoms -> disease_name MUST be \\"healthy\\".\\n"
38
+ " - Visible symptoms -> name the disease based on the specific visual pattern you observe (e.g. \\"early blight\\", \\"powdery mildew\\", \\"leaf rust\\"), not a generic guess. If symptoms are visible but you can't confidently name a specific disease, use \\"unidentified leaf disease\\" rather than inventing a specific name.\\n"
39
+ "5. Only fill organic_cure, chemical_cure, and prevention_tips if disease_name is a real (non-null, non-\\"healthy\\") diagnosis you are reasonably confident in. If disease_name is \\"healthy\\" or \\"unidentified leaf disease\\", set these three fields to null instead of fabricating treatment advice.\\n\\n"
40
+ "CONFIDENCE CALIBRATION:\\n"
41
+ "- confidence reflects your certainty in the (species + disease) call jointly.\\n"
42
+ "- Use <0.5 when the image is blurry, ambiguous, or symptoms are non-specific.\\n\\n"
43
+ "Respond with ONLY valid JSON, no markdown, no explanation, no reasoning text.\\n"
44
+ "Schema:\\n"
45
+ '{"is_plant_leaf": bool, "plant_species": str or null, "disease_name": str or null, "confidence": float 0-1, "severity": "mild"|"moderate"|"severe"|null, "organic_cure": str or null, "chemical_cure": str or null, "prevention_tips": str or null}'
46
+ )'''
47
+
48
+ pattern = r'if species_hint:\s+prompt = \(.*?\)\s+else:\s+prompt = \(.*?\)'
49
+ new_content = re.sub(pattern, replacement.strip(), content, flags=re.DOTALL)
50
+
51
+ with open('plant_core/diseases/ml_logic.py', 'w') as f:
52
+ f.write(new_content)