surfiniaburger commited on
Commit
f733284
Β·
1 Parent(s): a61c2dd
Files changed (5) hide show
  1. Procfile +1 -0
  2. README.md +3 -5
  3. api_server.py +131 -0
  4. app.py +2 -2
  5. requirements.txt +4 -1
Procfile ADDED
@@ -0,0 +1 @@
 
 
1
+ web: uvicorn api_server:app --host 0.0.0.0 --port 7860
README.md CHANGED
@@ -1,11 +1,9 @@
1
  ---
2
  title: Aura Mind Glow
3
- emoji: πŸ“‰
4
  colorFrom: green
5
- colorTo: purple
6
- sdk: gradio
7
- sdk_version: 5.42.0
8
- app_file: app.py
9
  pinned: false
10
  ---
11
 
 
1
  ---
2
  title: Aura Mind Glow
3
+ emoji: 🌻
4
  colorFrom: green
5
+ colorTo: blue
6
+ sdk: docker
 
 
7
  pinned: false
8
  ---
9
 
api_server.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ==============================================================================
2
+ # Aura Mind Glow - Main Server (FastAPI + Gradio)
3
+ # ==============================================================================
4
+ """
5
+ This script is the main entry point for the application. It launches a FastAPI
6
+ server that provides the diagnosis API and also serves the entire Gradio UI.
7
+
8
+ To run this server for development:
9
+ 1. Make sure you have installed all packages from requirements.txt.
10
+ 2. Run the command: uvicorn api_server:app --host 127.0.0.1 --port 7860
11
+
12
+ When deployed to Hugging Face Spaces, the Procfile will handle this command.
13
+ """
14
+
15
+ # --- Essential Imports ---
16
+ from fastapi import FastAPI, UploadFile, File, HTTPException
17
+ from fastapi.responses import JSONResponse
18
+ from PIL import Image
19
+ import os
20
+ import warnings
21
+ import tempfile
22
+ import re
23
+ import io
24
+ import gradio as gr
25
+
26
+ # --- Import Core Components from Modules ---
27
+ # This setup is now shared between the API and the Gradio App
28
+ from vision_model import load_vision_model
29
+ from knowledge_base import KnowledgeBase
30
+ from agent_setup import initialize_adk
31
+ from bigquery_search import search_bigquery_for_remedy
32
+ from vector_store import embed_and_store_documents
33
+
34
+ # --- Import the Gradio UI from app.py ---
35
+ # We import the 'demo' object directly. The app.py script should not call demo.launch()
36
+ try:
37
+ from app import demo as gradio_app
38
+ print("βœ… Gradio UI imported successfully from app.py.")
39
+ except ImportError as e:
40
+ gradio_app = None
41
+ print(f"❌ CRITICAL: Could not import Gradio UI from app.py: {e}")
42
+ print("Ensure app.py defines a Gradio Blocks object named 'demo' and does not call .launch().")
43
+
44
+
45
+ print("βœ… All server libraries imported successfully.")
46
+
47
+ # --- Global Initialization ---
48
+ warnings.filterwarnings("ignore")
49
+ os.environ["TORCH_COMPILE_DISABLE"] = "1"
50
+
51
+ print("Performing initial setup for server (this may take a moment)...")
52
+ VISION_MODEL, PROCESSOR = load_vision_model()
53
+ KB = KnowledgeBase()
54
+ RETRIEVER = KB
55
+ embed_and_store_documents()
56
+
57
+ adk_components = initialize_adk(VISION_MODEL, PROCESSOR, RETRIEVER)
58
+ DIAGNOSIS_TOOL = adk_components["diagnosis_tool"] if adk_components else None
59
+
60
+ if not DIAGNOSIS_TOOL:
61
+ print("❌ CRITICAL: Diagnosis tool could not be initialized. The API will not work.")
62
+
63
+ print("βœ… Server setup complete.")
64
+
65
+ # --- FastAPI App and Endpoint Logic ---
66
+ app = FastAPI(
67
+ title="Aura Mind Glow API",
68
+ description="Provides access to the plant diagnosis model and serves the Gradio UI.",
69
+ version="1.0.0",
70
+ )
71
+
72
+ def run_diagnosis_logic(image: Image.Image):
73
+ """
74
+ Core logic for running diagnosis and getting remedies.
75
+ """
76
+ temp_file_path = None
77
+ try:
78
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as temp_file:
79
+ image.save(temp_file.name)
80
+ temp_file_path = temp_file.name
81
+
82
+ diagnosis = DIAGNOSIS_TOOL(temp_file_path)
83
+ if "Could not parse" in diagnosis:
84
+ return {"error": f"Could not identify condition: {diagnosis}"}
85
+
86
+ cleaned_diagnosis = re.sub(r'[^\w\s.\\-,\"]', '', diagnosis)
87
+ cleaned_diagnosis = re.sub(r'\s+', ' ', cleaned_diagnosis).strip()
88
+
89
+ local_remedy_list = search_documents(cleaned_diagnosis)
90
+ local_remedy = local_remedy_list[0] if local_remedy_list else "No remedy found in local knowledge base."
91
+
92
+ search_query = "healthy maize" if "healthy" in cleaned_diagnosis.lower() else "phosphorus" if "phosphorus" in cleaned_diagnosis.lower() else "general"
93
+ cloud_remedy = search_bigquery_for_remedy(search_query)
94
+
95
+ return {
96
+ "diagnosis": diagnosis,
97
+ "remedy_local": local_remedy,
98
+ "remedy_cloud": cloud_remedy
99
+ }
100
+ finally:
101
+ if temp_file_path:
102
+ os.remove(temp_file_path)
103
+
104
+ @app.post("/diagnose/", tags=["Diagnosis"])
105
+ async def diagnose_endpoint(file: UploadFile = File(...)):
106
+ """
107
+ Receives an image file, performs diagnosis, and returns the result as JSON.
108
+ """
109
+ if not file.content_type.startswith('image/'):
110
+ raise HTTPException(status_code=400, detail="File provided is not an image.")
111
+
112
+ try:
113
+ image_bytes = await file.read()
114
+ image = Image.open(io.BytesIO(image_bytes))
115
+ result = run_diagnosis_logic(image)
116
+
117
+ if "error" in result:
118
+ raise HTTPException(status_code=500, detail=result["error"])
119
+
120
+ return JSONResponse(content=result)
121
+ except Exception as e:
122
+ print(f"❌ API Error: {e}")
123
+ raise HTTPException(status_code=500, detail=f"An internal server error occurred: {e}")
124
+
125
+ # --- Mount the Gradio App ---
126
+ if gradio_app:
127
+ app = gr.mount_gradio_app(app, gradio_app, path="/")
128
+ print("βœ… Gradio UI has been mounted on the FastAPI server at the root path '/'.")
129
+
130
+ # Note: The 'if __name__ == "__main__":' block with uvicorn.run() is removed.
131
+ # The Procfile will be used by Hugging Face to run the server.
app.py CHANGED
@@ -134,7 +134,7 @@ def create_field_mode_ui(user_state):
134
  """Creates the Gradio UI for the offline Field Mode."""
135
 
136
  def clean_diagnosis_text(diagnosis: str) -> str:
137
- cleaned_text = re.sub(r'[^\w\s.\-,\"]', '', diagnosis)
138
  cleaned_text = re.sub(r'\s+', ' ', cleaned_text).strip()
139
  return cleaned_text
140
 
@@ -577,4 +577,4 @@ if __name__ == "__main__":
577
  outputs=[user_state, login_view, main_view, logged_in_user_display]
578
  )
579
 
580
- demo.launch(share=True, debug=True)
 
134
  """Creates the Gradio UI for the offline Field Mode."""
135
 
136
  def clean_diagnosis_text(diagnosis: str) -> str:
137
+ cleaned_text = re.sub(r'[^\w\s.\-,"]', '', diagnosis)
138
  cleaned_text = re.sub(r'\s+', ' ', cleaned_text).strip()
139
  return cleaned_text
140
 
 
577
  outputs=[user_state, login_view, main_view, logged_in_user_display]
578
  )
579
 
580
+ # demo.launch() is removed because the app is now launched by api_server.py
requirements.txt CHANGED
@@ -20,4 +20,7 @@ google-genai
20
  google-adk
21
  google-cloud-bigquery
22
  requests
23
- faiss-cpu
 
 
 
 
20
  google-adk
21
  google-cloud-bigquery
22
  requests
23
+ faiss-cpu
24
+ fastapi
25
+ python-multipart
26
+ uvicorn