-
Notifications
You must be signed in to change notification settings - Fork 37
Add Air Quality, Noise Pollution, and Graffiti Verification Features #408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
fd5dbae
f50b145
7f28348
f1c4c61
67c50bd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -456,3 +456,49 @@ async def detect_abandoned_vehicle_clip(image: Union[Image.Image, bytes], client | |
| labels = ["abandoned car", "rusted vehicle", "car with flat tires", "wrecked car", "normal parked car"] | ||
| targets = ["abandoned car", "rusted vehicle", "car with flat tires", "wrecked car"] | ||
| return await _detect_clip_generic(image, labels, targets, client) | ||
|
|
||
| async def detect_air_quality_clip(image: Union[Image.Image, bytes], client: httpx.AsyncClient = None): | ||
| """ | ||
| Detects air quality/smog levels using CLIP. | ||
| """ | ||
| labels = ["clean air", "mild smog", "dense smog", "hazardous air pollution", "fog", "clear sky", "blue sky", "polluted city"] | ||
| targets = ["mild smog", "dense smog", "hazardous air pollution", "fog", "polluted city"] | ||
| return await _detect_clip_generic(image, labels, targets, client) | ||
|
|
||
| async def detect_cleanliness_clip(image: Union[Image.Image, bytes], client: httpx.AsyncClient = None): | ||
| """ | ||
| Verifies if a wall/area is clean (for graffiti removal verification). | ||
| """ | ||
| labels = ["clean wall", "graffiti", "vandalism", "freshly painted wall", "dirty wall"] | ||
| # We want to know if it is CLEAN | ||
| targets = ["clean wall", "freshly painted wall"] | ||
| return await _detect_clip_generic(image, labels, targets, client) | ||
|
Comment on lines
+468
to
+475
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cleanliness detector only returns positive matches — dirty walls produce empty results, breaking frontend UX.
In Consider returning the top result regardless of target membership, or include negative labels in targets so the frontend can distinguish clean from dirty. Proposed fix: return all results and let the frontend decide async def detect_cleanliness_clip(image: Union[Image.Image, bytes], client: httpx.AsyncClient = None):
"""
Verifies if a wall/area is clean (for graffiti removal verification).
"""
labels = ["clean wall", "graffiti", "vandalism", "freshly painted wall", "dirty wall"]
- # We want to know if it is CLEAN
- targets = ["clean wall", "freshly painted wall"]
- return await _detect_clip_generic(image, labels, targets, client)
+ try:
+ img_bytes = _prepare_image_bytes(image)
+ results = await query_hf_api(img_bytes, labels, client=client)
+ if not isinstance(results, list) or len(results) == 0:
+ return []
+ top = results[0]
+ return [{
+ "label": top.get('label', 'unknown'),
+ "confidence": top.get('score', 0),
+ "box": []
+ }]
+ except Exception as e:
+ logger.error(f"Cleanliness Detection Error: {e}")
+ return []🤖 Prompt for AI Agents |
||
|
|
||
| async def detect_noise_pollution_event(audio_bytes: bytes, client: httpx.AsyncClient = None): | ||
| """ | ||
| Wraps detect_audio_event to flag noise pollution. | ||
| """ | ||
| events = await detect_audio_event(audio_bytes, client) | ||
|
|
||
| noise_pollution_labels = [ | ||
| "traffic", "horn", "siren", "jackhammer", "construction", "drill", | ||
| "engine", "explosion", "gunshot", "scream", "shout", "bark", "chainsaw", | ||
| "aircraft", "helicopter", "train" | ||
| ] | ||
|
|
||
| detected_noise = [] | ||
| for event in events: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Missing type validation on Prompt for AI agents |
||
| # MIT/AST labels might be specific, e.g. "Car alarm" | ||
| label = event.get('label', '').lower() | ||
| score = event.get('score', 0) | ||
|
|
||
| is_noise = any(nl in label for nl in noise_pollution_labels) | ||
|
|
||
| if is_noise and score > 0.3: | ||
|
||
| detected_noise.append({ | ||
| "type": event.get('label'), | ||
| "confidence": score, | ||
| "is_pollution": True | ||
| }) | ||
|
|
||
| return detected_noise | ||
|
Comment on lines
+477
to
+504
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -13,5 +13,7 @@ Pillow | |||||||
| firebase-functions | ||||||||
| firebase-admin | ||||||||
| a2wsgi | ||||||||
| python-jose[cryptography] | ||||||||
| passlib[bcrypt] | ||||||||
| python-jose | ||||||||
| cryptography | ||||||||
|
Comment on lines
+16
to
+17
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Prefer Prompt for AI agents
Suggested change
|
||||||||
| passlib | ||||||||
| bcrypt | ||||||||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -35,7 +35,10 @@ | |||||||||
| detect_civic_eye_clip, | ||||||||||
| detect_graffiti_art_clip, | ||||||||||
| detect_traffic_sign_clip, | ||||||||||
| detect_abandoned_vehicle_clip | ||||||||||
| detect_abandoned_vehicle_clip, | ||||||||||
| detect_air_quality_clip, | ||||||||||
| detect_cleanliness_clip, | ||||||||||
| detect_noise_pollution_event | ||||||||||
| ) | ||||||||||
| from backend.dependencies import get_http_client | ||||||||||
| import backend.dependencies | ||||||||||
|
|
@@ -436,3 +439,49 @@ async def detect_abandoned_vehicle_endpoint(request: Request, image: UploadFile | |||||||||
| except Exception as e: | ||||||||||
| logger.error(f"Abandoned vehicle detection error: {e}", exc_info=True) | ||||||||||
| raise HTTPException(status_code=500, detail="Internal server error") | ||||||||||
|
|
||||||||||
| @router.post("/api/detect-air-quality") | ||||||||||
| async def detect_air_quality_endpoint(request: Request, image: UploadFile = File(...)): | ||||||||||
| # Optimized Image Processing: Validation + Optimization | ||||||||||
| _, image_bytes = await process_uploaded_image(image) | ||||||||||
|
|
||||||||||
| try: | ||||||||||
| client = get_http_client(request) | ||||||||||
| detections = await detect_air_quality_clip(image_bytes, client=client) | ||||||||||
| return {"detections": detections} | ||||||||||
| except Exception as e: | ||||||||||
| logger.error(f"Air quality detection error: {e}", exc_info=True) | ||||||||||
| raise HTTPException(status_code=500, detail="Internal server error") | ||||||||||
|
|
||||||||||
| @router.post("/api/detect-cleanliness") | ||||||||||
| async def detect_cleanliness_endpoint(request: Request, image: UploadFile = File(...)): | ||||||||||
| # Optimized Image Processing: Validation + Optimization | ||||||||||
| _, image_bytes = await process_uploaded_image(image) | ||||||||||
|
|
||||||||||
| try: | ||||||||||
| client = get_http_client(request) | ||||||||||
| detections = await detect_cleanliness_clip(image_bytes, client=client) | ||||||||||
| return {"detections": detections} | ||||||||||
| except Exception as e: | ||||||||||
| logger.error(f"Cleanliness detection error: {e}", exc_info=True) | ||||||||||
| raise HTTPException(status_code=500, detail="Internal server error") | ||||||||||
|
|
||||||||||
| @router.post("/api/detect-noise-pollution") | ||||||||||
| async def detect_noise_pollution_endpoint(request: Request, file: UploadFile = File(...)): | ||||||||||
| # Audio validation | ||||||||||
| if hasattr(file, 'size') and file.size and file.size > 10 * 1024 * 1024: | ||||||||||
| raise HTTPException(status_code=413, detail="Audio file too large") | ||||||||||
|
|
||||||||||
| try: | ||||||||||
| audio_bytes = await file.read() | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: Missing post-read file size validation. Unlike the existing Prompt for AI agents
Suggested change
|
||||||||||
| except Exception as e: | ||||||||||
| logger.error(f"Invalid audio file: {e}", exc_info=True) | ||||||||||
| raise HTTPException(status_code=400, detail="Invalid audio file") | ||||||||||
|
Comment on lines
+471
to
+479
|
||||||||||
|
|
||||||||||
| try: | ||||||||||
| client = get_http_client(request) | ||||||||||
| detections = await detect_noise_pollution_event(audio_bytes, client=client) | ||||||||||
| return {"detections": detections} | ||||||||||
| except Exception as e: | ||||||||||
| logger.error(f"Noise pollution detection error: {e}", exc_info=True) | ||||||||||
| raise HTTPException(status_code=500, detail="Internal server error") | ||||||||||
|
Comment on lines
+443
to
+487
|
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"fog" classified as pollution may produce false positives.
The
targetslist includes"fog", which is a natural weather phenomenon and not necessarily an indicator of air pollution. This could cause clean-air scenes with natural fog to be flagged as polluted. Consider removing"fog"from targets or adding a separate neutral category.🤖 Prompt for AI Agents