Spaces:
Running
Running
File size: 5,458 Bytes
beddf30 14d5092 63959ee beddf30 63959ee beddf30 63959ee bdd923c 63959ee bdd923c 63959ee 14d5092 3fa67e8 14d5092 63959ee 3fa67e8 63959ee 14d5092 3fa67e8 14d5092 63959ee 3fa67e8 14d5092 63959ee 14d5092 3fa67e8 14d5092 63959ee 3fa67e8 63959ee 62644f1 63959ee beddf30 a3ee5be beddf30 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | import base64
import datetime
import os
from io import BytesIO
from huggingface_hub import InferenceClient
from PIL import Image
ADVISOR_MODEL_ID = os.getenv("ADVISOR_MODEL_ID", "Qwen/Qwen2.5-Coder-3B-Instruct")
ADVISOR_PROVIDER = os.getenv("ADVISOR_PROVIDER", "nscale")
_client = None
def _get_client() -> InferenceClient:
global _client
if _client is None:
_client = InferenceClient(model=ADVISOR_MODEL_ID, provider=ADVISOR_PROVIDER, token=os.getenv("HF_TOKEN"))
return _client
def _watering_status(last_watered: str | None) -> str:
if not last_watered:
return "Never watered yet (no record)."
days_since = (datetime.date.today() - datetime.date.fromisoformat(last_watered)).days
if days_since <= 0:
return f"Watered today ({last_watered})."
if days_since == 1:
return f"Last watered yesterday ({last_watered})."
return f"Last watered {days_since} days ago (on {last_watered})."
def _build_system_prompt(
plant_info: dict,
plant_name: str | None = None,
genus: str | None = None,
last_watered: str | None = None,
neighbors: list[dict] | None = None,
) -> str:
name = plant_name or genus or "this plant"
neighbor_line = ""
if neighbors:
names = ", ".join(f"{n['name']} ({n['genus']})" for n in neighbors)
neighbor_line = f"- Plants growing right next to it in the garden: {names}\n"
return (
"You are an expert gardening assistant with deep knowledge of houseplant "
"and garden plant care. Be practical, encouraging, and specific.\n\n"
f"The user is asking about their plant: {name} (genus: {genus}). "
"Known care profile for this plant:\n"
f"- Sunlight: {plant_info.get('sunlight')}\n"
f"- Soil: {plant_info.get('soil')}\n"
f"- Watering frequency: every {plant_info.get('watering_frequency_days')} days\n"
f"- Fertilization: {plant_info.get('fertilization_type')}\n"
f"- Watering status: {_watering_status(last_watered)}\n"
f"{neighbor_line}\n"
"Always factor the watering status into your answer: if it is overdue "
"compared to the recommended frequency, say so and recommend watering; "
"if it was watered recently, take that into account (don't tell the "
"user to water again right away) and consider overwatering as a "
"possible cause if the question describes a problem.\n\n"
"Use this profile as context, but also draw on your general gardening "
"knowledge for issues it doesn't cover (pests, diseases, yellowing "
"leaves, repotting, etc.). If nearby plants are listed, factor in "
"companion-planting effects (competition for light, water or nutrients, "
"shared pests/diseases, or beneficial pairings) when relevant to the "
"question. Give a precise, actionable, gardening-advice "
"focused answer and never recommend dangerous or toxic substances. "
"Answer in 2-4 sentences, in the same language as the question."
)
def ask_about_plant(
question: str,
plant_info: dict,
plant_name: str | None = None,
genus: str | None = None,
last_watered: str | None = None,
neighbors: list[dict] | None = None,
) -> str:
"""Ask the advisor a question about a specific plant, grounded in its care data."""
try:
completion = _get_client().chat_completion(
messages=[
{"role": "system", "content": _build_system_prompt(plant_info, plant_name, genus, last_watered, neighbors)},
{"role": "user", "content": question},
],
max_tokens=300,
)
return completion.choices[0].message.content
except Exception as e:
# TEMP debug: surface the real HF Inference error in the Space logs
print(f"[advisor] HF Inference error: {e!r}")
return "Sorry, the assistant is unavailable right now — please try again later."
def diagnose_plant_health(
image: Image.Image,
plant_name: str | None = None,
genus: str | None = None,
) -> str:
"""Ask a vision-language model to assess a plant's health from a photo."""
name = plant_name or genus or "this plant"
buf = BytesIO()
image.convert("RGB").save(buf, format="JPEG")
b64 = base64.b64encode(buf.getvalue()).decode()
prompt = (
f"This is a photo of a houseplant named '{name}' (genus: {genus}). "
"Look closely at its leaves, stems and soil for signs of trouble: "
"yellowing or browning leaves, wilting, spots, pests, mold, or "
"dry/overwatered soil. Start your reply with exactly one status word "
"on its own — 'Healthy', 'Needs attention', or 'Sick' — then a short "
"explanation (1-3 sentences) of what you see and what to do about it."
)
try:
completion = _get_client().chat_completion(
messages=[{
"role": "user",
"content": [
{"type": "text", "text": prompt},
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{b64}"}},
],
}],
max_tokens=250,
)
return completion.choices[0].message.content.strip()
except Exception as e:
print(f"[advisor] HF Inference health-check error: {e!r}")
return "Sorry, the health check is unavailable right now — please try again later."
|