demeter
Autonomous Hydroponic Intelligencegit clone https://github.com/maydayv7/demeter
agent/sub_agents/Explainer.py (2331B)
1import json
2import os
3from openai import AzureOpenAI
4from dotenv import load_dotenv
5
6load_dotenv()
7
8class ExplainerAgent:
9 def __init__(self):
10 self.llm = AzureOpenAI(
11 api_key=os.getenv("AZURE_OPENAI_API_KEY"),
12 api_version=os.getenv("AZURE_OPENAI_API_VERSION", "2024-12-01-preview"),
13 azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT")
14 )
15 self.deployment_name = os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME", "gpt-4.1")
16
17 def explain(self, current_fmu, similar_fmus, sub_agent_reports, final_decision):
18 """
19 Generates a detailed, human-readable log of the decision process.
20 """
21
22 # Construct the context for the LLM
23 context = f"""
24 CONTEXT DATA:
25 - Current Sensors: {json.dumps(current_fmu['payload']['sensors'])}
26 - Visual Context: {current_fmu['metadata'].get('stage')} {current_fmu['metadata'].get('crop')}
27 - Expert Reports: {json.dumps(sub_agent_reports)}
28 - Historical Precedents: Found {len(similar_fmus)} similar past cases.
29
30 FINAL DECISION TAKEN:
31 {json.dumps(final_decision)}
32 """
33
34 system_prompt = """
35 You are the "Explainer" for an AI Hydroponic System.
36 Your goal is to write a "Chain of Thought" log that explains WHY a specific decision was made.
37
38 STRUCTURE YOUR RESPONSE AS A CLEAN LIST OF STEPS:
39 1. **Observation**: What did the sensors and vision see? (Cite specific numbers).
40 2. **Precedent**: Did we see this before? (Reference the similar cases).
41 3. **Logic**: Connect the dots. (e.g., "High pH + Yellow Leaves usually means X").
42 4. **Conclusion**: Why is the recommended action the safest bet?
43
44 Keep the tone professional, transparent, and educational.
45 """
46
47 try:
48 response = self.llm.chat.completions.create(
49 model=self.deployment_name,
50 messages=[
51 {"role": "system", "content": system_prompt},
52 {"role": "user", "content": context}
53 ],
54 temperature=0.3 # Keep it factual
55 )
56 return response.choices[0].message.content
57 except Exception as e:
58 return f"Explanation unavailable: {str(e)}"