Ayatullah-hanif commited on
Commit
cf380e1
·
1 Parent(s): 5eda14f

fix huggingface config

Browse files
Files changed (1) hide show
  1. app_fastapi.py +89 -90
app_fastapi.py CHANGED
@@ -4,25 +4,26 @@ AgriCare – Disease Detection API
4
 
5
  Production-grade AI backend for cassava disease detection.
6
 
 
7
  ✓ ONNX EfficientNet-B3 inference
8
- Deterministic English advice (dict-based)
9
- N-ATLaS translation + audio generation
 
10
  ✓ Human-in-the-loop escalation
11
- ✓ Hugging Face Spaces ready
 
12
  """
13
 
14
  import os
15
  import io
16
  import logging
17
- import base64
18
  import numpy as np
19
  import onnxruntime as ort
20
  import requests
21
- import uvicorn
22
  from PIL import Image
23
  from fastapi import FastAPI, UploadFile, File, Form
24
  from fastapi.middleware.cors import CORSMiddleware
25
- from fastapi.responses import HTMLResponse
26
 
27
  # -------------------------------------------------------
28
  # App Setup
@@ -61,54 +62,72 @@ IMG_SIZE = 300
61
  LOW_CONF_THRESHOLD = 0.60
62
 
63
  # -------------------------------------------------------
64
- # English Advice Dictionary (SOURCE OF TRUTH)
65
- # -------------------------------------------------------
66
- ENGLISH_ADVICE = {
67
- "Cassava Bacterial Blight": (
68
- "Cassava bacterial blight causes leaf wilting and stem rot. "
69
- "Remove infected plants, avoid overhead watering, and use resistant varieties."
70
- ),
71
- "Cassava Brown Streak Disease": (
72
- "Cassava brown streak disease damages roots and reduces yield. "
73
- "Use certified disease-free cuttings and control whiteflies."
74
- ),
75
- "Cassava Green Mottle": (
76
- "Cassava green mottle causes leaf discoloration. "
77
- "Remove affected plants early and maintain good farm hygiene."
78
- ),
79
- "Cassava Mosaic Disease": (
80
- "Cassava mosaic disease leads to distorted leaves and stunted growth. "
81
- "Plant resistant varieties and control whitefly populations."
82
- ),
83
- "Healthy Leaf": (
84
- "Your cassava plant appears healthy. "
85
- "Continue good farming practices and monitor regularly."
86
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  }
88
 
89
  # -------------------------------------------------------
90
- # Hugging Face – N-ATLaS
91
  # -------------------------------------------------------
92
  HF_TOKEN = os.getenv("HF_TOKEN")
93
- if not HF_TOKEN:
94
- raise RuntimeError("HF_TOKEN is required and must be set in Hugging Face Secrets.")
95
 
96
  HF_BASE = "https://router.huggingface.co/hf-inference/models"
97
  NATLAS_TEXT_URL = f"{HF_BASE}/NCAIR1/N-ATLaS"
98
- NATLAS_TTS_URL = f"{HF_BASE}/NCAIR1/N-ATLaS-TTS"
99
 
100
  HEADERS = {
101
  "Authorization": f"Bearer {HF_TOKEN}",
102
  "Content-Type": "application/json"
103
  }
104
 
105
- LANG_CODE_MAP = {
106
- "english": "en",
107
- "hausa": "ha",
108
- "igbo": "ig",
109
- "yoruba": "yo"
110
- }
111
-
112
  # -------------------------------------------------------
113
  # Utilities
114
  # -------------------------------------------------------
@@ -126,59 +145,42 @@ def preprocess(image_bytes):
126
  return arr[np.newaxis, :].astype(MODEL_DTYPE)
127
 
128
  # -------------------------------------------------------
129
- # N-ATLaS Translation
130
  # -------------------------------------------------------
131
- def translate_text(text: str, target_language: str) -> str:
132
- if target_language == "english":
133
  return text
134
 
135
  prompt = f"""
136
- Translate the following agricultural advice into {target_language}.
137
- Keep it clear and farmer-friendly.
138
 
139
  Text:
140
  {text}
141
  """
142
 
143
- r = requests.post(
144
- NATLAS_TEXT_URL,
145
- headers=HEADERS,
146
- json={"inputs": prompt},
147
- timeout=25
148
- )
149
-
150
- r.raise_for_status()
151
- data = r.json()
152
- return data[0]["generated_text"]
153
 
154
- # -------------------------------------------------------
155
- # N-ATLaS Audio
156
- # -------------------------------------------------------
157
- def generate_audio(text: str, language: str):
158
- lang_code = LANG_CODE_MAP.get(language, "en")
159
 
160
- r = requests.post(
161
- NATLAS_TTS_URL,
162
- headers=HEADERS,
163
- json={
164
- "inputs": text,
165
- "parameters": {"language": lang_code}
166
- },
167
- timeout=25
168
- )
169
 
170
- r.raise_for_status()
171
- return r.json().get("audio") # base64 WAV
172
 
173
- # -------------------------------------------------------
174
- # Root (HF requirement)
175
- # -------------------------------------------------------
176
- @app.get("/", response_class=HTMLResponse)
177
- def root():
178
- return "<h2>AgriCare API is running</h2><p>Visit <a href='/docs'>/docs</a></p>"
179
 
180
  # -------------------------------------------------------
181
- # Prediction Endpoint
182
  # -------------------------------------------------------
183
  @app.post("/predict")
184
  async def predict(
@@ -193,30 +195,27 @@ async def predict(
193
 
194
  idx = int(np.argmax(probs))
195
  confidence = float(probs[idx])
196
- disease = CLASS_NAMES[idx]
197
 
198
  # English source text
199
- english_text = ENGLISH_ADVICE[disease]
200
-
201
- # Translation
202
- final_text = translate_text(english_text, language.lower())
203
 
204
- # Audio
205
- audio = generate_audio(final_text, language.lower())
206
 
207
  return {
208
  "status": "low_confidence" if confidence < LOW_CONF_THRESHOLD else "ok",
209
- "predicted_class": disease,
210
  "confidence": round(confidence, 4),
211
  "route_to_expert": confidence < LOW_CONF_THRESHOLD,
212
  "language": language,
213
- "text": final_text,
214
- "audio_base64": audio,
215
  "probabilities": probs.tolist()
216
  }
217
 
218
  # -------------------------------------------------------
219
- # Run (Local)
220
  # -------------------------------------------------------
221
  if __name__ == "__main__":
222
- uvicorn.run("app_fastapi:app", host="0.0.0.0", port=8000, reload=True)
 
4
 
5
  Production-grade AI backend for cassava disease detection.
6
 
7
+ Features:
8
  ✓ ONNX EfficientNet-B3 inference
9
+ Proper softmax probabilities
10
+ English-first agricultural guidance
11
+ ✓ Multilingual translation via N-ATLaS
12
  ✓ Human-in-the-loop escalation
13
+
14
+ Designed for real-world Nigerian agriculture.
15
  """
16
 
17
  import os
18
  import io
19
  import logging
 
20
  import numpy as np
21
  import onnxruntime as ort
22
  import requests
 
23
  from PIL import Image
24
  from fastapi import FastAPI, UploadFile, File, Form
25
  from fastapi.middleware.cors import CORSMiddleware
26
+ import uvicorn
27
 
28
  # -------------------------------------------------------
29
  # App Setup
 
62
  LOW_CONF_THRESHOLD = 0.60
63
 
64
  # -------------------------------------------------------
65
+ # Disease Recommendations (ENGLISH SOURCE OF TRUTH)
66
+ # -------------------------------------------------------
67
+ DISEASE_RECOMMENDATIONS = {
68
+ "Cassava Bacterial Blight": {
69
+ "english": (
70
+ "Cassava Bacterial Blight was detected.\n"
71
+ "• Remove and destroy infected plants.\n"
72
+ " Use clean, disease-free planting materials.\n"
73
+ " Apply copper-based bactericides such as Copper Oxychloride.\n"
74
+ " Avoid overhead irrigation to reduce disease spread."
75
+ )
76
+ },
77
+
78
+ "Cassava Brown Streak Disease": {
79
+ "english": (
80
+ "Cassava Brown Streak Disease was detected.\n"
81
+ " There is no chemical cure for this disease.\n"
82
+ " Control whiteflies using insecticides like Imidacloprid or Thiamethoxam.\n"
83
+ "• Plant resistant cassava varieties.\n"
84
+ " Remove and destroy infected plants early."
85
+ )
86
+ },
87
+
88
+ "Cassava Green Mottle": {
89
+ "english": (
90
+ "Cassava Green Mottle was detected.\n"
91
+ "• Control insect vectors such as aphids and whiteflies.\n"
92
+ "• Use insecticides like Lambda-cyhalothrin or Cypermethrin.\n"
93
+ "• Maintain field hygiene.\n"
94
+ "• Use certified disease-free planting materials."
95
+ )
96
+ },
97
+
98
+ "Cassava Mosaic Disease": {
99
+ "english": (
100
+ "Cassava Mosaic Disease was detected.\n"
101
+ "• No direct chemical cure exists.\n"
102
+ "• Control whiteflies using Imidacloprid or Acetamiprid.\n"
103
+ "• Uproot and destroy infected plants immediately.\n"
104
+ "• Plant resistant cassava varieties."
105
+ )
106
+ },
107
+
108
+ "Healthy Leaf": {
109
+ "english": (
110
+ "The cassava leaf is healthy.\n"
111
+ "• No treatment is required.\n"
112
+ "• Continue monitoring your farm.\n"
113
+ "• Maintain good agricultural practices."
114
+ )
115
+ }
116
  }
117
 
118
  # -------------------------------------------------------
119
+ # Hugging Face – N-ATLaS (TEXT TRANSLATION ONLY)
120
  # -------------------------------------------------------
121
  HF_TOKEN = os.getenv("HF_TOKEN")
 
 
122
 
123
  HF_BASE = "https://router.huggingface.co/hf-inference/models"
124
  NATLAS_TEXT_URL = f"{HF_BASE}/NCAIR1/N-ATLaS"
 
125
 
126
  HEADERS = {
127
  "Authorization": f"Bearer {HF_TOKEN}",
128
  "Content-Type": "application/json"
129
  }
130
 
 
 
 
 
 
 
 
131
  # -------------------------------------------------------
132
  # Utilities
133
  # -------------------------------------------------------
 
145
  return arr[np.newaxis, :].astype(MODEL_DTYPE)
146
 
147
  # -------------------------------------------------------
148
+ # Translation via N-ATLaS
149
  # -------------------------------------------------------
150
+ def translate_text(text: str, language: str) -> str:
151
+ if language.lower() == "english":
152
  return text
153
 
154
  prompt = f"""
155
+ Translate the following agricultural advice into {language}.
156
+ Keep it simple and farmer-friendly.
157
 
158
  Text:
159
  {text}
160
  """
161
 
162
+ try:
163
+ r = requests.post(
164
+ NATLAS_TEXT_URL,
165
+ headers=HEADERS,
166
+ json={"inputs": prompt},
167
+ timeout=20
168
+ )
 
 
 
169
 
170
+ r.raise_for_status()
 
 
 
 
171
 
172
+ data = r.json()
173
+ if isinstance(data, list) and data:
174
+ return data[0].get("generated_text", text)
 
 
 
 
 
 
175
 
176
+ return text
 
177
 
178
+ except Exception as e:
179
+ logger.error(f"N-ATLaS translation failed: {e}")
180
+ return text
 
 
 
181
 
182
  # -------------------------------------------------------
183
+ # API Endpoint
184
  # -------------------------------------------------------
185
  @app.post("/predict")
186
  async def predict(
 
195
 
196
  idx = int(np.argmax(probs))
197
  confidence = float(probs[idx])
198
+ predicted = CLASS_NAMES[idx]
199
 
200
  # English source text
201
+ base_text = DISEASE_RECOMMENDATIONS[predicted]["english"]
 
 
 
202
 
203
+ # Translate if needed
204
+ final_text = translate_text(base_text, language)
205
 
206
  return {
207
  "status": "low_confidence" if confidence < LOW_CONF_THRESHOLD else "ok",
208
+ "predicted_class": predicted,
209
  "confidence": round(confidence, 4),
210
  "route_to_expert": confidence < LOW_CONF_THRESHOLD,
211
  "language": language,
212
+ "recommendation_text": final_text,
213
+ "audio_available": False,
214
  "probabilities": probs.tolist()
215
  }
216
 
217
  # -------------------------------------------------------
218
+ # Run (HF-compatible)
219
  # -------------------------------------------------------
220
  if __name__ == "__main__":
221
+ uvicorn.run("app_fastapi:app", host="0.0.0.0", port=7860)