Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI, UploadFile, File, HTTPException | |
| from fastapi import Form | |
| from PIL import Image | |
| import base64 | |
| from io import BytesIO | |
| import os | |
| import time | |
| from src.image_desc import ImageAnalyzer | |
| from src.agent import ReportGenerator | |
| from src.envllm_service import env_llm_service, get_current_outdoor_values | |
| import asyncio | |
| import logging | |
| import requests | |
| import re | |
| from fastapi.middleware.cors import CORSMiddleware | |
| channel_id = "2916848" | |
| read_api_key = "4TSSCTPIYPXFZW9H" | |
| app = FastAPI() | |
| # Configure CORS for frontend access | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| def get_tds_value(): | |
| try: | |
| url = f'https://api.thingspeak.com/channels/{channel_id}/feeds.json?api_key={read_api_key}&results=2' | |
| response = requests.get(url) | |
| data = response.json() | |
| feed = data['feeds'][0]['field1'] | |
| print("FFF", feed) | |
| return f"The TDS value is {feed}" | |
| except Exception as e: | |
| print(f"Error fetching TDS value: {e}") | |
| return "The TDS value is 300" | |
| # MULTI SUPPORT MODELS FOR FALLBACK IF ONE FAILS | |
| VLM_MODEL_NAMES = [ | |
| "meta-llama/llama-4-maverick-17b-128e-instruct", | |
| "meta-llama/llama-4-scout-17b-16e-instruct", | |
| ] | |
| LLM_MODEL_NAMES = [ | |
| "llama-3.3-70b-versatile", | |
| "llama3-70b-8192", | |
| "mistral-saba-24b", | |
| "qwen-qwq-32b", | |
| "gemma2-9b-it", | |
| "llama-3.1-8b-instant" | |
| ] | |
| # Initialize analyzers with multiple models | |
| analyzer = ImageAnalyzer(VLM_MODEL_NAMES) | |
| report_gen = ReportGenerator(LLM_MODEL_NAMES) | |
| # Format model names for report naming (using first model in each list) | |
| VLM_MODEL_NAME = "_".join(VLM_MODEL_NAMES[0].split("-")[:2]) | |
| LLM_MODEL_NAME = "_".join(LLM_MODEL_NAMES[0].split("-")[:2]) | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| # def get_tds_value(): | |
| async def process_image(image: UploadFile, additional_info=None): | |
| """Processes image and generates water quality report.""" | |
| try: | |
| image_data = await image.read() | |
| img = Image.open(BytesIO(image_data)) | |
| if img.mode != 'RGB': | |
| img = img.convert('RGB') | |
| buffered = BytesIO() | |
| img.save(buffered, format="JPEG") | |
| image_base64 = base64.b64encode(buffered.getvalue()).decode('utf-8') | |
| start_time = time.time() | |
| report_message = await asyncio.to_thread(analyzer.generate_water_quality_report, image_base64, additional_info) | |
| end_time = time.time() | |
| logger.info(f"Time taken for water quality report generation: {end_time - start_time:.5f} seconds") | |
| return report_message | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=f"Error processing the image: {e}") | |
| async def analyze_water_quality(image: UploadFile = File(...), additional_info: str = Form(None)): | |
| """Endpoint to analyze water quality based on an uploaded image.""" | |
| try: | |
| report_message = await process_image(image, additional_info) | |
| if additional_info == "": | |
| additional_info = get_tds_value() | |
| print("additional_info", additional_info) | |
| start_time = time.time() | |
| combined_report = await asyncio.to_thread(report_gen.forward, report_message, additional_info) | |
| end_time = time.time() | |
| logger.info(f"Time taken for combined VLM and LLM report generation: {end_time - start_time:.5f} seconds") | |
| if isinstance(combined_report, str): | |
| combined_report = combined_report.replace("Corrected Report:", "").replace("Report:", "").replace("Water Quality Analysis Report", "") | |
| else: | |
| combined_report = combined_report.corrected_report.replace("Corrected Report:", "").replace("Report:", "").replace("Water Quality Analysis Report", "") | |
| print(type(combined_report)) | |
| return {"status": "success", "report": combined_report} | |
| except HTTPException as http_exc: | |
| raise http_exc | |
| except Exception as e: | |
| logger.error(f"Unhandled exception in /analyze: {e}", exc_info=True) | |
| raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {e}") | |
| async def get_environment_values(location: str = None): | |
| """Endpoint to fetch the current environmental values for a location without generating a report. | |
| Parameters: | |
| - location: Location name to get values for (city, country, etc.) | |
| """ | |
| try: | |
| if not location: | |
| raise HTTPException(status_code=400, detail="Location parameter is required") | |
| # Get values from API | |
| api_values = get_current_outdoor_values(location) | |
| # Check if we got valid values | |
| if api_values.get('error') or None in [api_values.get('temp'), api_values.get('humid'), api_values.get('air')]: | |
| # If API failed, return the error | |
| logger.warning(f"API returned incomplete data for location '{location}': {api_values}") | |
| raise HTTPException(status_code=404, detail=f"Could not retrieve environmental data for location: {location}") | |
| # Return the parameters without generating a report | |
| return { | |
| "status": "success", | |
| "parameters": { | |
| "temperature": api_values['temp'], | |
| "humidity": api_values['humid'], | |
| "air_quality_index": api_values['air'], | |
| "location": api_values['location'], | |
| "lat": api_values['lat'], | |
| "lon": api_values['lon'] | |
| } | |
| } | |
| except HTTPException as http_exc: | |
| raise http_exc | |
| except Exception as e: | |
| logger.error(f"Error fetching environment values: {e}", exc_info=True) | |
| raise HTTPException(status_code=500, detail=f"An error occurred: {str(e)}") | |
| async def get_environment_report( | |
| use_api: bool = True, | |
| temperature: int = None, | |
| humidity: int = None, | |
| air_quality: int = None, | |
| location: str = None, | |
| latitude: float = None, | |
| longitude: float = None | |
| ): | |
| """Endpoint to generate environmental reports based on weather parameters. | |
| Parameters: | |
| - use_api: Whether to use the OpenWeatherMap API for real-time data (default: True) | |
| - temperature: Optional temperature in Celsius if not using API | |
| - humidity: Optional humidity percentage if not using API | |
| - air_quality: Optional air quality index if not using API (1-5) | |
| - location: Optional location name (city, country, etc.) | |
| - latitude: Optional latitude coordinate | |
| - longitude: Optional longitude coordinate | |
| """ | |
| try: | |
| start_time = time.time() | |
| # We use asyncio.to_thread to move the model inference to a separate thread | |
| # to avoid blocking the FastAPI event loop | |
| result = await asyncio.to_thread( | |
| env_llm_service.generate_environment_report, | |
| location=location, | |
| temp=temperature, | |
| humid=humidity, | |
| air=air_quality, | |
| use_api=use_api, | |
| lat=latitude, | |
| lon=longitude | |
| ) | |
| end_time = time.time() | |
| logger.info(f"Time taken for environment report generation: {end_time - start_time:.5f} seconds") | |
| return result | |
| except Exception as e: | |
| logger.error(f"Error generating environment report: {e}", exc_info=True) | |
| raise HTTPException(status_code=500, detail=f"An error occurred: {str(e)}") | |
| async def get_environment_stats(location: str = None, limit: int = 10, format: str = "table"): | |
| """Endpoint to retrieve historical environmental data. | |
| Parameters: | |
| - location: Optional location name to filter data | |
| - limit: Number of records to return (default: 10) | |
| - format: Return format - "table" for HTML table or "json" for raw data (default: table) | |
| """ | |
| try: | |
| if format.lower() == "table": | |
| result = env_llm_service.get_realtime_values_table(location, limit) | |
| return {"status": "success", "data": result} | |
| else: | |
| result = env_llm_service.get_historical_data(location, format="json") | |
| return {"status": "success", "data": result} | |
| except Exception as e: | |
| logger.error(f"Error retrieving environmental stats: {e}", exc_info=True) | |
| raise HTTPException(status_code=500, detail=f"An error occurred: {str(e)}") | |