alaselababatunde commited on
Commit
dab8605
·
1 Parent(s): 41b31c2
Files changed (1) hide show
  1. app.py +80 -85
app.py CHANGED
@@ -1,44 +1,33 @@
1
  import os
2
  import logging
3
- from fastapi import FastAPI, Request, Header, HTTPException
4
- from fastapi.responses import JSONResponse
5
  from fastapi.middleware.cors import CORSMiddleware
6
- from huggingface_hub.utils import HfHubHTTPError
7
  from langchain.prompts import PromptTemplate
8
  from langchain_huggingface import HuggingFaceEndpoint
 
 
9
  from vector import query_vector
10
 
11
- # ==============================
12
- # Setup Logging
13
- # ==============================
14
  logging.basicConfig(level=logging.INFO)
15
  logger = logging.getLogger("AgriCopilot")
16
 
17
- # ==============================
18
- # Config
19
- # ==============================
20
- PROJECT_API_KEY = os.getenv("PROJECT_API_KEY", "super-secret-123") # 🔑 Change in prod
21
 
22
- # ==============================
23
- # App Init
24
- # ==============================
25
  app = FastAPI(title="AgriCopilot")
26
 
27
- @app.get("/")
28
- async def root():
29
- return {"status": "AgriCopilot AI Backend is working perfectly"}
30
-
31
- # ==============================
32
- # Global Exception Handler
33
- # ==============================
34
- @app.exception_handler(Exception)
35
- async def global_exception_handler(request: Request, exc: Exception):
36
- logger.error(f"Unhandled error: {exc}")
37
- return JSONResponse(status_code=500, content={"error": str(exc)})
38
-
39
- # ==============================
40
- # Auth Helper
41
- # ==============================
42
  def check_auth(authorization: str | None):
43
  if not PROJECT_API_KEY:
44
  return
@@ -48,102 +37,108 @@ def check_auth(authorization: str | None):
48
  if token != PROJECT_API_KEY:
49
  raise HTTPException(status_code=403, detail="Invalid token")
50
 
51
- # ==============================
52
- # HuggingFace Model Config
53
- # ==============================
54
- default_model = dict(
55
- temperature=0.3,
56
- top_p=0.9,
57
- do_sample=True,
58
- repetition_penalty=1.1,
59
- max_new_tokens=1024
60
- )
61
 
62
- # ==============================
63
- # CHAINS
64
- # ==============================
65
 
66
- # 1. Crop Doctor
 
 
 
 
 
 
 
 
 
67
  crop_template = PromptTemplate(
68
  input_variables=["symptoms"],
69
- template="You are AgriCopilot, a multilingual AI assistant for farmers. "
70
- "A farmer reports: {symptoms}. Diagnose the likely disease and suggest "
71
- "clear, farmer-friendly treatments."
72
  )
73
- crop_llm = HuggingFaceEndpoint(repo_id="meta-llama/Llama-3.2-11B-Vision-Instruct", **default_model)
74
- crop_chain = crop_template | crop_llm
75
 
76
- # 2. Multilingual Chat
77
  chat_template = PromptTemplate(
78
  input_variables=["query"],
79
- template="You are AgriCopilot, a supportive multilingual AI guide. "
80
- "Respond in the SAME language as the user. Farmer says: {query}"
81
  )
82
- chat_llm = HuggingFaceEndpoint(repo_id="meta-llama/Llama-3.1-8B-Instruct", **default_model)
83
- chat_chain = chat_template | chat_llm
84
 
85
- # 3. Disaster Summarizer
86
  disaster_template = PromptTemplate(
87
  input_variables=["report"],
88
- template="You are AgriCopilot, an AI disaster assistant. "
89
- "Summarize the following report into 3–5 short, actionable steps farmers can follow: {report}"
90
  )
91
- disaster_llm = HuggingFaceEndpoint(repo_id="meta-llama/Llama-3.1-8B-Instruct", **default_model)
92
- disaster_chain = disaster_template | disaster_llm
93
 
94
- # 4. Marketplace Recommender
95
  market_template = PromptTemplate(
96
  input_variables=["product"],
97
- template="You are AgriCopilot, an agricultural marketplace advisor. "
98
- "Farmer wants to sell or buy: {product}. Suggest options, advice, and safe trade tips."
99
  )
100
- market_llm = HuggingFaceEndpoint(repo_id="meta-llama/Llama-3.1-8B-Instruct", **default_model)
101
- market_chain = market_template | market_llm
102
 
103
- # ==============================
104
- # ENDPOINTS (with auth)
105
- # ==============================
 
 
 
 
 
 
 
 
 
106
  @app.post("/crop-doctor")
107
- async def crop_doctor(symptoms: str, authorization: str | None = Header(None)):
108
  check_auth(authorization)
109
  try:
110
- response = crop_chain.invoke({"symptoms": symptoms})
111
- return {"diagnosis": str(response)}
 
112
  except HfHubHTTPError as e:
113
- return {"error": f"HuggingFace error: {str(e)}"}
 
 
114
 
115
  @app.post("/multilingual-chat")
116
- async def multilingual_chat(query: str, authorization: str | None = Header(None)):
117
  check_auth(authorization)
118
  try:
119
- response = chat_chain.invoke({"query": query})
120
- return {"reply": str(response)}
 
121
  except HfHubHTTPError as e:
122
- return {"error": f"HuggingFace error: {str(e)}"}
 
 
123
 
124
  @app.post("/disaster-summarizer")
125
- async def disaster_summarizer(report: str, authorization: str | None = Header(None)):
126
  check_auth(authorization)
127
  try:
128
- response = disaster_chain.invoke({"report": report})
129
- return {"summary": str(response)}
 
130
  except HfHubHTTPError as e:
131
- return {"error": f"HuggingFace error: {str(e)}"}
 
 
132
 
133
  @app.post("/marketplace")
134
- async def marketplace(product: str, authorization: str | None = Header(None)):
135
  check_auth(authorization)
136
  try:
137
- response = market_chain.invoke({"product": product})
138
- return {"recommendation": str(response)}
 
139
  except HfHubHTTPError as e:
140
- return {"error": f"HuggingFace error: {str(e)}"}
 
 
141
 
142
  @app.post("/vector-search")
143
- async def vector_search(query: str, authorization: str | None = Header(None)):
144
  check_auth(authorization)
145
  try:
146
- results = query_vector(query)
147
- return {"results": results}
148
  except Exception as e:
149
- return {"error": f"Vector search error: {str(e)}"}
 
1
  import os
2
  import logging
3
+ from fastapi import FastAPI, Header, HTTPException
 
4
  from fastapi.middleware.cors import CORSMiddleware
5
+ from pydantic import BaseModel
6
  from langchain.prompts import PromptTemplate
7
  from langchain_huggingface import HuggingFaceEndpoint
8
+ from huggingface_hub.utils import HfHubHTTPError
9
+ from langchain.schema import HumanMessage
10
  from vector import query_vector
11
 
12
+ # ----------------- CONFIG -----------------
 
 
13
  logging.basicConfig(level=logging.INFO)
14
  logger = logging.getLogger("AgriCopilot")
15
 
16
+ PROJECT_API_KEY = os.getenv("PROJECT_API_KEY", "super-secret-123")
 
 
 
17
 
18
+ # FastAPI app
 
 
19
  app = FastAPI(title="AgriCopilot")
20
 
21
+ # CORS
22
+ app.add_middleware(
23
+ CORSMiddleware,
24
+ allow_origins=["*"], # Change to frontend URL in prod
25
+ allow_credentials=True,
26
+ allow_methods=["*"],
27
+ allow_headers=["*"],
28
+ )
29
+
30
+ # ----------------- AUTH -----------------
 
 
 
 
 
31
  def check_auth(authorization: str | None):
32
  if not PROJECT_API_KEY:
33
  return
 
37
  if token != PROJECT_API_KEY:
38
  raise HTTPException(status_code=403, detail="Invalid token")
39
 
40
+ # ----------------- REQUEST MODELS -----------------
41
+ class CropDoctorRequest(BaseModel):
42
+ symptoms: str
 
 
 
 
 
 
 
43
 
44
+ class ChatRequest(BaseModel):
45
+ query: str
 
46
 
47
+ class DisasterRequest(BaseModel):
48
+ report: str
49
+
50
+ class MarketplaceRequest(BaseModel):
51
+ product: str
52
+
53
+ class VectorRequest(BaseModel):
54
+ query: str
55
+
56
+ # ----------------- PROMPT TEMPLATES -----------------
57
  crop_template = PromptTemplate(
58
  input_variables=["symptoms"],
59
+ template="You are AgriCopilot, a multilingual AI crop doctor. Farmer reports: {symptoms}. Diagnose the disease and suggest treatments in simple farmer-friendly language."
 
 
60
  )
 
 
61
 
 
62
  chat_template = PromptTemplate(
63
  input_variables=["query"],
64
+ template="You are AgriCopilot, a supportive multilingual AI guide built for farmers. Farmer says: {query}"
 
65
  )
 
 
66
 
 
67
  disaster_template = PromptTemplate(
68
  input_variables=["report"],
69
+ template="You are AgriCopilot, an AI disaster assistant. Summarize the following report for farmers in simple steps: {report}"
 
70
  )
 
 
71
 
 
72
  market_template = PromptTemplate(
73
  input_variables=["product"],
74
+ template="You are AgriCopilot, an agricultural marketplace recommender. Farmer wants: {product}. Suggest buyers/sellers and short advice."
 
75
  )
 
 
76
 
77
+ # ----------------- LLM MODELS -----------------
78
+ crop_llm = HuggingFaceEndpoint(repo_id="meta-llama/Llama-3.2-11B-Vision-Instruct")
79
+ chat_llm = HuggingFaceEndpoint(repo_id="meta-llama/Llama-3.1-8B-Instruct")
80
+ disaster_llm = HuggingFaceEndpoint(repo_id="meta-llama/Llama-3.1-8B-Instruct")
81
+ market_llm = HuggingFaceEndpoint(repo_id="meta-llama/Llama-3.1-8B-Instruct")
82
+
83
+ # ----------------- ROOT -----------------
84
+ @app.get("/")
85
+ async def root():
86
+ return {"status": "✅ AgriCopilot AI Backend running"}
87
+
88
+ # ----------------- ENDPOINTS -----------------
89
  @app.post("/crop-doctor")
90
+ async def crop_doctor(req: CropDoctorRequest, authorization: str | None = Header(None)):
91
  check_auth(authorization)
92
  try:
93
+ prompt = crop_template.format(symptoms=req.symptoms)
94
+ response = crop_llm.invoke([HumanMessage(content=prompt)])
95
+ return {"success": True, "diagnosis": str(response)}
96
  except HfHubHTTPError as e:
97
+ if "quota" in str(e).lower():
98
+ return {"success": False, "error": "⚠️ Model quota exceeded. Try again later."}
99
+ raise e
100
 
101
  @app.post("/multilingual-chat")
102
+ async def multilingual_chat(req: ChatRequest, authorization: str | None = Header(None)):
103
  check_auth(authorization)
104
  try:
105
+ prompt = chat_template.format(query=req.query)
106
+ response = chat_llm.invoke([HumanMessage(content=prompt)])
107
+ return {"success": True, "reply": str(response)}
108
  except HfHubHTTPError as e:
109
+ if "quota" in str(e).lower():
110
+ return {"success": False, "error": "⚠️ Model quota exceeded. Try again later."}
111
+ raise e
112
 
113
  @app.post("/disaster-summarizer")
114
+ async def disaster_summarizer(req: DisasterRequest, authorization: str | None = Header(None)):
115
  check_auth(authorization)
116
  try:
117
+ prompt = disaster_template.format(report=req.report)
118
+ response = disaster_llm.invoke([HumanMessage(content=prompt)])
119
+ return {"success": True, "summary": str(response)}
120
  except HfHubHTTPError as e:
121
+ if "quota" in str(e).lower():
122
+ return {"success": False, "error": "⚠️ Model quota exceeded. Try again later."}
123
+ raise e
124
 
125
  @app.post("/marketplace")
126
+ async def marketplace(req: MarketplaceRequest, authorization: str | None = Header(None)):
127
  check_auth(authorization)
128
  try:
129
+ prompt = market_template.format(product=req.product)
130
+ response = market_llm.invoke([HumanMessage(content=prompt)])
131
+ return {"success": True, "recommendation": str(response)}
132
  except HfHubHTTPError as e:
133
+ if "quota" in str(e).lower():
134
+ return {"success": False, "error": "⚠️ Model quota exceeded. Try again later."}
135
+ raise e
136
 
137
  @app.post("/vector-search")
138
+ async def vector_search(req: VectorRequest, authorization: str | None = Header(None)):
139
  check_auth(authorization)
140
  try:
141
+ results = query_vector(req.query)
142
+ return {"success": True, "results": results}
143
  except Exception as e:
144
+ return {"success": False, "error": str(e)}