r3hab commited on
Commit
ddfbfda
·
verified ·
1 Parent(s): 26623e4

Upload 3 files

Browse files
Files changed (3) hide show
  1. Dockerfile +16 -0
  2. app.py +101 -0
  3. requirements.txt +5 -0
Dockerfile ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
2
+ # you will also find guides on how best to write your Dockerfile
3
+
4
+ FROM python:3.9
5
+
6
+ RUN useradd -m -u 1000 user
7
+ USER user
8
+ ENV PATH="/home/user/.local/bin:$PATH"
9
+
10
+ WORKDIR /app
11
+
12
+ COPY --chown=user ./requirements.txt requirements.txt
13
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
14
+
15
+ COPY --chown=user . /app
16
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Optional
2
+
3
+ from fastapi import FastAPI, HTTPException, Query
4
+ from pydantic import BaseModel
5
+ import httpx
6
+ import os
7
+ from dotenv import load_dotenv
8
+
9
+ load_dotenv()
10
+
11
+ app = FastAPI(title="Keyless Weather API",
12
+ description="Fetches real-time weather and temperature data using Open-Meteo (no API key required).",
13
+ version="1.0.0")
14
+
15
+ # --- Configuration ---
16
+ OPEN_METEO_BASE_URL = "https://api.open-meteo.com/v1/forecast"
17
+
18
+ # --- Data Models ---
19
+ class Coordinates(BaseModel):
20
+ latitude: float = Query(..., description="Latitude of the location")
21
+ longitude: float = Query(..., description="Longitude of the location")
22
+
23
+ class WeatherData(BaseModel):
24
+ temperature: float
25
+ # feels_like: Optional[float] = None # Not directly available in Open-Meteo free tier
26
+ # humidity: Optional[int] = None # Not directly available in Open-Meteo free tier
27
+ wind_speed: float
28
+ wind_direction: int
29
+ # description: Optional[str] = None # Not directly available in Open-Meteo free tier
30
+ # icon: Optional[str] = None # Not directly available in Open-Meteo free tier
31
+ unit_temperature: str = "°C"
32
+ unit_wind_speed: str = "m/s"
33
+
34
+ class ApiResponse(BaseModel):
35
+ weather: WeatherData
36
+
37
+ # --- Helper Functions ---
38
+ async def fetch_weather_data_open_meteo(latitude: float, longitude: float) -> WeatherData:
39
+ """Fetches weather data from Open-Meteo (no API key required)."""
40
+ url = OPEN_METEO_BASE_URL
41
+ params = {
42
+ "latitude": latitude,
43
+ "longitude": longitude,
44
+ "current_weather": True,
45
+ "temperature_unit": "celsius",
46
+ "windspeed_unit": "ms",
47
+ "timezone": "auto" # Automatically detect timezone
48
+ }
49
+ async with httpx.AsyncClient() as client:
50
+ try:
51
+ response = await client.get(url, params=params)
52
+ response.raise_for_status()
53
+ data = response.json()["current_weather"]
54
+ return WeatherData(
55
+ temperature=data["temperature"],
56
+ wind_speed=data["windspeed"],
57
+ wind_direction=data["winddirection"],
58
+ )
59
+ except httpx.HTTPStatusError as e:
60
+ raise HTTPException(status_code=e.response.status_code, detail=f"Error fetching weather data: {e}")
61
+ except httpx.RequestError as e:
62
+ raise HTTPException(status_code=500, detail=f"Error connecting to weather service: {e}")
63
+ except KeyError:
64
+ raise HTTPException(status_code=500, detail="Error parsing weather data from Open-Meteo.")
65
+
66
+ # --- API Endpoints ---
67
+ @app.get("/weather", response_model=WeatherData, summary="Get Weather (Open-Meteo)",
68
+ description="Fetches real-time weather and temperature data using Open-Meteo (no API key required).")
69
+ async def get_weather(coords: Coordinates):
70
+ """
71
+ Retrieves weather data for a specific location using Open-Meteo.
72
+ """
73
+ return await fetch_weather_data_open_meteo(coords.latitude, coords.longitude)
74
+
75
+ @app.get("/current_conditions", response_model=ApiResponse, summary="Get Current Conditions (Open-Meteo)",
76
+ description="Fetches current weather conditions using Open-Meteo (no API key required).")
77
+ async def get_current_conditions(coords: Coordinates):
78
+ """
79
+ Retrieves current weather conditions (temperature, wind) for a specific location using Open-Meteo.
80
+ """
81
+ weather_data = await fetch_weather_data_open_meteo(coords.latitude, coords.longitude)
82
+ return ApiResponse(weather=weather_data)
83
+
84
+ # --- Note on Air Quality ---
85
+ # Finding a reliable, completely keyless air quality API can be challenging.
86
+ # Many free services either require registration (and thus an API key) or have
87
+ # very limited coverage/data quality.
88
+ #
89
+ # If you absolutely need air quality without a key, you might explore:
90
+ # 1. OpenAQ (mentioned earlier): While their API has a key, they have public datasets.
91
+ # You could potentially download and process these datasets, but this is more complex
92
+ # than a direct API call.
93
+ # 2. Government Environmental Agencies: As discussed, some provide public data, but
94
+ # finding a consistent API without any registration can be difficult.
95
+ #
96
+ # For this example, we will focus on the keyless weather data from Open-Meteo.
97
+
98
+ # --- Running the App ---
99
+ if __name__ == "__main__":
100
+ import uvicorn
101
+ uvicorn.run(app, host="0.0.0.0", port=8000)
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn[standard]
3
+ httpx
4
+ pydantic
5
+ requests