ParthivM1 commited on
Commit
00457fc
·
1 Parent(s): 58d7125

Added validation table endpoint

Browse files
Files changed (1) hide show
  1. app.py +77 -50
app.py CHANGED
@@ -32,6 +32,7 @@ if not SUPABASE_URL or not SUPABASE_KEY:
32
  raise ValueError("Supabase credentials not found.")
33
  supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
34
 
 
35
  def convert_to_decimal(coord):
36
  if coord and len(coord.values) >= 3:
37
  deg = float(coord.values[0])
@@ -88,10 +89,6 @@ def process_video_in_background(video_data: bytes, video_guid: str, filename: st
88
  os.remove(temp_path)
89
  supabase.table("videos").update({"status": "complete"}).eq("guid", video_guid).execute()
90
 
91
- @app.get("/")
92
- async def root():
93
- return {"message": "API is running"}
94
-
95
  def safe_date_converter(date_string):
96
  if not date_string:
97
  return datetime.min.replace(tzinfo=timezone.utc)
@@ -103,6 +100,34 @@ def safe_date_converter(date_string):
103
  except (ValueError, TypeError):
104
  return datetime.min.replace(tzinfo=timezone.utc)
105
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  @app.get("/latest_reports")
107
  async def get_latest_reports():
108
  try:
@@ -112,19 +137,65 @@ async def get_latest_reports():
112
  video['type'] = 'video'
113
  first_frame_response = supabase.table("detected_frames").select("frame_image_url").eq("video_guid", video["guid"]).order("frame_number").limit(1).execute()
114
  video["thumbnail_url"] = first_frame_response.data[0]["frame_image_url"] if first_frame_response.data else None
115
-
116
  images_response = supabase.table("potholes").select("guid, image_name, image_url, created_at, status, category").order("created_at", desc=True).limit(30).execute()
117
  images = images_response.data
118
  for image in images:
119
  image['type'] = 'image'
120
  image['thumbnail_url'] = image.get('image_url')
121
-
122
  all_reports = videos + images
123
  combined_reports = sorted(all_reports, key=lambda x: safe_date_converter(x.get('created_at')), reverse=True)
124
  return combined_reports[:30]
125
  except Exception as e:
126
  raise HTTPException(status_code=500, detail=f"A severe database error occurred: {str(e)}")
127
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  @app.patch("/report/{guid}/status")
129
  async def update_report_status(guid: str, payload: dict = Body(...)):
130
  new_status = payload.get("status")
@@ -205,49 +276,5 @@ async def get_report(guid: str):
205
  return response.data
206
  except Exception as e: raise HTTPException(status_code=500, detail=f"Database Error: {str(e)}")
207
 
208
- @app.post("/upload")
209
- async def upload_image(
210
- file: UploadFile = File(...),
211
- location: str = Form(None),
212
- category: str = Form(...)
213
- ):
214
- image_data = await file.read()
215
- with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp_image_file:
216
- temp_image_file.write(image_data)
217
- temp_path = temp_image_file.name
218
- results = model(temp_path, device='cpu')
219
- annotated_image_array = results[0].plot()
220
- os.remove(temp_path)
221
- is_success, buffer = cv2.imencode(".jpg", annotated_image_array)
222
- if not is_success: raise HTTPException(status_code=500, detail="Failed to encode annotated image.")
223
- annotated_image_bytes = buffer.tobytes()
224
- bucket_name = 'pothole-images'
225
- uuid_path = f"annotated_{uuid.uuid4()}.jpg"
226
- try:
227
- supabase.storage.from_(bucket_name).upload(path=uuid_path, file=annotated_image_bytes, file_options={"content-type": "image/jpeg"})
228
- url = supabase.storage.from_(bucket_name).get_public_url(uuid_path)
229
- except Exception as e: raise HTTPException(status_code=500, detail=f"Storage Error: {str(e)}")
230
-
231
- await file.seek(0)
232
- lat, lon = get_gps_location(file.file)
233
- location_point = f"Point({lon:.6f} {lat:.6f})" if lat and lon else None
234
- guid = str(uuid.uuid4())
235
-
236
- try:
237
- insert_data = {
238
- "guid": guid,
239
- "image_name": file.filename,
240
- "image_url": url,
241
- "location": location_point,
242
- "location_text": location if not location_point and location else None,
243
- "status": "In Progress",
244
- "category": category
245
- }
246
- response = supabase.table("potholes").insert(insert_data).execute()
247
- except Exception as e:
248
- raise HTTPException(status_code=500, detail=f"Database Error: {str(e)}")
249
-
250
- return {"message": "Upload successful", "guid": guid, "image_url": url, "db_response": response.data}
251
-
252
  if __name__ == "__main__":
253
  uvicorn.run(app, port=8000, host="127.0.0.1")
 
32
  raise ValueError("Supabase credentials not found.")
33
  supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
34
 
35
+ # --- Helper Functions ---
36
  def convert_to_decimal(coord):
37
  if coord and len(coord.values) >= 3:
38
  deg = float(coord.values[0])
 
89
  os.remove(temp_path)
90
  supabase.table("videos").update({"status": "complete"}).eq("guid", video_guid).execute()
91
 
 
 
 
 
92
  def safe_date_converter(date_string):
93
  if not date_string:
94
  return datetime.min.replace(tzinfo=timezone.utc)
 
100
  except (ValueError, TypeError):
101
  return datetime.min.replace(tzinfo=timezone.utc)
102
 
103
+ # --- API Endpoints ---
104
+ @app.get("/")
105
+ async def root():
106
+ return {"message": "API is running"}
107
+
108
+ @app.get("/report_summary")
109
+ async def get_report_summary():
110
+ try:
111
+ reports_response = supabase.table("potholes").select("category, approved").execute()
112
+ all_reports = reports_response.data
113
+ summary = {
114
+ "billboard": {"total": 0, "approved": 0, "unapproved": 0, "damage": 0},
115
+ "guardrails": {"total": 0, "missing": 0, "damaged": 0},
116
+ "construction": {"total": 0},
117
+ "potholes": {"total": 0}
118
+ }
119
+ for report in all_reports:
120
+ category = report.get("category")
121
+ is_approved = report.get("approved")
122
+ if category in summary:
123
+ summary[category]["total"] += 1
124
+ if is_approved == 1:
125
+ summary[category]["approved"] += 1
126
+ summary[category]["unapproved"] = summary[category]["total"] - summary[category]["approved"]
127
+ return summary
128
+ except Exception as e:
129
+ raise HTTPException(status_code=500, detail=f"Database error: {str(e)}")
130
+
131
  @app.get("/latest_reports")
132
  async def get_latest_reports():
133
  try:
 
137
  video['type'] = 'video'
138
  first_frame_response = supabase.table("detected_frames").select("frame_image_url").eq("video_guid", video["guid"]).order("frame_number").limit(1).execute()
139
  video["thumbnail_url"] = first_frame_response.data[0]["frame_image_url"] if first_frame_response.data else None
 
140
  images_response = supabase.table("potholes").select("guid, image_name, image_url, created_at, status, category").order("created_at", desc=True).limit(30).execute()
141
  images = images_response.data
142
  for image in images:
143
  image['type'] = 'image'
144
  image['thumbnail_url'] = image.get('image_url')
 
145
  all_reports = videos + images
146
  combined_reports = sorted(all_reports, key=lambda x: safe_date_converter(x.get('created_at')), reverse=True)
147
  return combined_reports[:30]
148
  except Exception as e:
149
  raise HTTPException(status_code=500, detail=f"A severe database error occurred: {str(e)}")
150
 
151
+ @app.post("/upload")
152
+ async def upload_image(
153
+ file: UploadFile = File(...),
154
+ location: str = Form(None),
155
+ category: str = Form(...)
156
+ ):
157
+ image_data = await file.read()
158
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp_image_file:
159
+ temp_image_file.write(image_data)
160
+ temp_path = temp_image_file.name
161
+ results = model(temp_path, device='cpu')
162
+ annotated_image_array = results[0].plot()
163
+ os.remove(temp_path)
164
+ is_success, buffer = cv2.imencode(".jpg", annotated_image_array)
165
+ if not is_success: raise HTTPException(status_code=500, detail="Failed to encode annotated image.")
166
+ annotated_image_bytes = buffer.tobytes()
167
+ bucket_name = 'pothole-images'
168
+ uuid_path = f"annotated_{uuid.uuid4()}.jpg"
169
+ try:
170
+ supabase.storage.from_(bucket_name).upload(path=uuid_path, file=annotated_image_bytes, file_options={"content-type": "image/jpeg"})
171
+ url = supabase.storage.from_(bucket_name).get_public_url(uuid_path)
172
+ except Exception as e: raise HTTPException(status_code=500, detail=f"Storage Error: {str(e)}")
173
+
174
+ await file.seek(0)
175
+ lat, lon = get_gps_location(file.file)
176
+ location_point = f"Point({lon:.6f} {lat:.6f})" if lat and lon else None
177
+ guid = str(uuid.uuid4())
178
+
179
+ try:
180
+ validation_response = supabase.table("validation").select("location_text").execute()
181
+ approved_locations = {item['location_text'] for item in validation_response.data}
182
+ is_approved = 1 if location in approved_locations else 0
183
+ insert_data = {
184
+ "guid": guid,
185
+ "image_name": file.filename,
186
+ "image_url": url,
187
+ "location": location_point,
188
+ "location_text": location if not location_point and location else None,
189
+ "status": "In Progress",
190
+ "category": category,
191
+ "approved": is_approved
192
+ }
193
+ response = supabase.table("potholes").insert(insert_data).execute()
194
+ except Exception as e:
195
+ raise HTTPException(status_code=500, detail=f"Database Error: {str(e)}")
196
+
197
+ return {"message": "Upload successful", "guid": guid, "image_url": url, "db_response": response.data}
198
+
199
  @app.patch("/report/{guid}/status")
200
  async def update_report_status(guid: str, payload: dict = Body(...)):
201
  new_status = payload.get("status")
 
276
  return response.data
277
  except Exception as e: raise HTTPException(status_code=500, detail=f"Database Error: {str(e)}")
278
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279
  if __name__ == "__main__":
280
  uvicorn.run(app, port=8000, host="127.0.0.1")