Crocolil commited on
Commit
a3ee5be
·
1 Parent(s): 5ac2dd2

Revert health check to share the advisor's LLM client

Browse files

No HF Inference Providers vision-language model under 0.5B parameters
is available; the next-smallest options (Llama-4-Scout, Qwen3-VL-8B)
were rejected as too large. Back to sharing ADVISOR_MODEL_ID/PROVIDER,
even though the text-only model can't process the uploaded image.

Files changed (2) hide show
  1. TECHNICAL_DOCUMENT.md +4 -7
  2. modules/advisor.py +1 -14
TECHNICAL_DOCUMENT.md CHANGED
@@ -230,11 +230,9 @@ yellow?", "Can I plant this next to my tomatoes?").
230
  **Task**: given a *new* photo of the selected plant, assess its health
231
  (leaves, stems, soil) and store the verdict on the plant record.
232
 
233
- - Model: `HEALTH_MODEL_ID` (default `meta-llama/Llama-4-Scout-17B-16E-Instruct`),
234
- on the same `HEALTH_PROVIDER` (defaults to `ADVISOR_PROVIDER`, i.e. `nscale`)
235
- a vision-capable model, since the text-only advisor model (§4.4) cannot
236
- process images. Called via `InferenceClient.chat_completion` with a
237
- **multimodal** message: the uploaded `PIL.Image` is re-encoded as JPEG,
238
  base64-encoded, and sent as an OpenAI-style content array
239
  (`{"type": "text", ...}` + `{"type": "image_url", "image_url": {"url":
240
  "data:image/jpeg;base64,..."}}`).
@@ -315,8 +313,7 @@ defaults baked in so the app runs locally without any secrets:
315
  |---|---|---|
316
  | `WEATHER_CITY` | `"Marseille"` | Initial forecast location before the user sets one |
317
  | `CLASSIFIER_MODEL_ID` | `"your-username/plant-genus-classifier"` | HF Hub repo of the fine-tuned SigLIP genus classifier |
318
- | `ADVISOR_MODEL_ID` / `ADVISOR_PROVIDER` | `Qwen/Qwen2.5-Coder-3B-Instruct` / `nscale` | Chat advisor model + HF Inference provider |
319
- | `HEALTH_MODEL_ID` / `HEALTH_PROVIDER` | `meta-llama/Llama-4-Scout-17B-16E-Instruct` / `nscale` | Vision-language health-diagnostic model + provider (defaults to `ADVISOR_PROVIDER`) |
320
  | `HF_TOKEN` | — | Hugging Face token for Inference Providers (advisor + health check) |
321
 
322
  `app.launch(allowed_paths=[...])` whitelists `user_data/`, `static/` and
 
230
  **Task**: given a *new* photo of the selected plant, assess its health
231
  (leaves, stems, soil) and store the verdict on the plant record.
232
 
233
+ - Model: the same `ADVISOR_MODEL_ID` / `ADVISOR_PROVIDER` client as the chat
234
+ advisor (§4.4), again via `InferenceClient.chat_completion` but this time
235
+ with a **multimodal** message: the uploaded `PIL.Image` is re-encoded as JPEG,
 
 
236
  base64-encoded, and sent as an OpenAI-style content array
237
  (`{"type": "text", ...}` + `{"type": "image_url", "image_url": {"url":
238
  "data:image/jpeg;base64,..."}}`).
 
313
  |---|---|---|
314
  | `WEATHER_CITY` | `"Marseille"` | Initial forecast location before the user sets one |
315
  | `CLASSIFIER_MODEL_ID` | `"your-username/plant-genus-classifier"` | HF Hub repo of the fine-tuned SigLIP genus classifier |
316
+ | `ADVISOR_MODEL_ID` / `ADVISOR_PROVIDER` | `Qwen/Qwen2.5-Coder-3B-Instruct` / `nscale` | Chat advisor + health-diagnostic model and HF Inference provider (shared) |
 
317
  | `HF_TOKEN` | — | Hugging Face token for Inference Providers (advisor + health check) |
318
 
319
  `app.launch(allowed_paths=[...])` whitelists `user_data/`, `static/` and
modules/advisor.py CHANGED
@@ -9,13 +9,7 @@ from PIL import Image
9
  ADVISOR_MODEL_ID = os.getenv("ADVISOR_MODEL_ID", "Qwen/Qwen2.5-Coder-3B-Instruct")
10
  ADVISOR_PROVIDER = os.getenv("ADVISOR_PROVIDER", "nscale")
11
 
12
- # Qwen2.5-Coder is text-only, so the health check (which sends a photo) needs
13
- # a vision-capable model. Use the same provider, on a model that supports images.
14
- HEALTH_MODEL_ID = os.getenv("HEALTH_MODEL_ID", "meta-llama/Llama-4-Scout-17B-16E-Instruct")
15
- HEALTH_PROVIDER = os.getenv("HEALTH_PROVIDER", ADVISOR_PROVIDER)
16
-
17
  _client = None
18
- _health_client = None
19
 
20
 
21
  def _get_client() -> InferenceClient:
@@ -25,13 +19,6 @@ def _get_client() -> InferenceClient:
25
  return _client
26
 
27
 
28
- def _get_health_client() -> InferenceClient:
29
- global _health_client
30
- if _health_client is None:
31
- _health_client = InferenceClient(model=HEALTH_MODEL_ID, provider=HEALTH_PROVIDER, token=os.getenv("HF_TOKEN"))
32
- return _health_client
33
-
34
-
35
  def _watering_status(last_watered: str | None) -> str:
36
  if not last_watered:
37
  return "Never watered yet (no record)."
@@ -127,7 +114,7 @@ def diagnose_plant_health(
127
  )
128
 
129
  try:
130
- completion = _get_health_client().chat_completion(
131
  messages=[{
132
  "role": "user",
133
  "content": [
 
9
  ADVISOR_MODEL_ID = os.getenv("ADVISOR_MODEL_ID", "Qwen/Qwen2.5-Coder-3B-Instruct")
10
  ADVISOR_PROVIDER = os.getenv("ADVISOR_PROVIDER", "nscale")
11
 
 
 
 
 
 
12
  _client = None
 
13
 
14
 
15
  def _get_client() -> InferenceClient:
 
19
  return _client
20
 
21
 
 
 
 
 
 
 
 
22
  def _watering_status(last_watered: str | None) -> str:
23
  if not last_watered:
24
  return "Never watered yet (no record)."
 
114
  )
115
 
116
  try:
117
+ completion = _get_client().chat_completion(
118
  messages=[{
119
  "role": "user",
120
  "content": [