commit 137f8c1c931a4281e1c6246401b3fd707a320324 Author: root Date: Sun Jul 6 23:48:33 2025 +0200 Initial commit diff --git a/client.py b/client.py new file mode 100644 index 0000000..931e0c4 --- /dev/null +++ b/client.py @@ -0,0 +1,54 @@ +import requests + +def get_weather_by_city(city): + url = "http://127.0.0.1:8000/weather" + params = {"city": city} + response = requests.get(url, params=params) + response.raise_for_status() + return response.json() + +def get_weather_by_geo(latitude, longitude): + url = "http://127.0.0.1:8000/weather/geo" + params = {"latitude": latitude, "longitude": longitude} + response = requests.get(url, params=params) + response.raise_for_status() + return response.json() + +def main(): + print("=== POBIERANIE POGODY Z SERWERA ===") + choice = input("Wybierz sposób pobierania pogody (1 - miasto, 2 - współrzędne): ").strip() + + try: + if choice == "1": + city = input("Podaj miasto (np. warszawa, krakow, gdansk): ").strip().lower() + data = get_weather_by_city(city) + + if "error" in data: + print("Błąd:", data["error"]) + return + + print("\n=== AKTUALNA POGODA DLA MIASTA ===") + print(f"Miasto: {data.get('city')}") + print(f"Temperatura: {data.get('temperature')} °C") + print(f"Wiatr: {data.get('windspeed')} km/h") + print(f"Czas pomiaru: {data.get('time')}") + + elif choice == "2": + latitude = input("Podaj szerokość geograficzną (latitude): ").strip() + longitude = input("Podaj długość geograficzną (longitude): ").strip() + data = get_weather_by_geo(latitude, longitude) + + print("\n=== AKTUALNA POGODA WG WSPÓŁRZĘDNYCH ===") + print(f"Miasto: {data.get('city')}") + print(f"Szerokość: {data.get('latitude')}") + print(f"Długość: {data.get('longitude')}") + print(f"Temperatura: {data.get('temperature')} °C") + print(f"Wiatr: {data.get('windspeed')} km/h") + print(f"Czas pomiaru: {data.get('time')}") + else: + print("Nieprawidłowy wybór. Wybierz 1 lub 2.") + except requests.RequestException as e: + print("Błąd połączenia z serwerem lub serwer zwrócił błąd:", e) + +if __name__ == "__main__": + main() diff --git a/db.py b/db.py new file mode 100644 index 0000000..9821db3 --- /dev/null +++ b/db.py @@ -0,0 +1,13 @@ +from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession +from sqlalchemy.orm import sessionmaker, declarative_base + +DATABASE_URL = "postgresql+asyncpg://weather_user:weather_pass@localhost:5432/weather" + +engine = create_async_engine(DATABASE_URL, echo=False) +AsyncSessionLocal = sessionmaker(bind=engine, class_=AsyncSession, expire_on_commit=False) + +Base = declarative_base() + +async def get_session(): + async with AsyncSessionLocal() as session: + yield session diff --git a/main.py b/main.py new file mode 100644 index 0000000..14b869c --- /dev/null +++ b/main.py @@ -0,0 +1,123 @@ +from fastapi import FastAPI, Depends, Query, Request +from fastapi.templating import Jinja2Templates +import httpx +from sqlalchemy.future import select +from sqlalchemy.ext.asyncio import AsyncSession +from db import get_session, engine, Base +from models import WeatherRecord +from datetime import datetime + +app = FastAPI() +templates = Jinja2Templates(directory="templates") + +CITIES = { + "warszawa": (52.23, 21.01), + "krakow": (50.06, 19.94), + "gdansk": (54.35, 18.65), +} + +@app.on_event("startup") +async def startup(): + async with engine.begin() as conn: + await conn.run_sync(Base.metadata.create_all) + +@app.get("/weather") +async def get_weather(city: str = Query("warszawa"), session: AsyncSession = Depends(get_session)): + coords = CITIES.get(city.lower()) + if not coords: + return {"error": "Miasto nieobsługiwane"} + + url = f"https://api.open-meteo.com/v1/forecast?latitude={coords[0]}&longitude={coords[1]}¤t_weather=true" + + async with httpx.AsyncClient() as client: + res = await client.get(url) + data = res.json() + + current = data.get("current_weather", {}) + record = WeatherRecord( + city=city.capitalize(), + temperature=current.get("temperature"), + windspeed=current.get("windspeed"), + time=datetime.fromisoformat(current.get("time")), + ) + session.add(record) + await session.commit() + + return { + "city": record.city, + "temperature": record.temperature, + "windspeed": record.windspeed, + "time": record.time + } + +@app.get("/history") +async def get_history(city: str = Query("warszawa"), session: AsyncSession = Depends(get_session)): + stmt = select(WeatherRecord).where(WeatherRecord.city.ilike(city)).order_by(WeatherRecord.time.desc()).limit(10) + result = await session.execute(stmt) + records = result.scalars().all() + return [ + { + "city": r.city, + "temperature": r.temperature, + "windspeed": r.windspeed, + "time": r.time.isoformat() + } + for r in records + ] + +@app.get("/view") +async def view_history(request: Request, city: str = "warszawa", session: AsyncSession = Depends(get_session)): + stmt = select(WeatherRecord).where(WeatherRecord.city.ilike(city)).order_by(WeatherRecord.time.desc()).limit(10) + result = await session.execute(stmt) + records = result.scalars().all() + return templates.TemplateResponse("history.html", { + "request": request, + "city": city.capitalize(), + "records": records + }) + + +@app.get("/ping") +async def ping(): + return {"status": "ok"} + + +@app.get("/weather/geo") +async def get_weather_by_coords( + latitude: float = Query(..., ge=-90, le=90), + longitude: float = Query(..., ge=-180, le=180), + session: AsyncSession = Depends(get_session) +): + url = ( + f"https://api.open-meteo.com/v1/forecast?" + f"latitude={latitude}&longitude={longitude}¤t_weather=true" + ) + + async with httpx.AsyncClient() as client: + try: + res = await client.get(url, timeout=10.0) + res.raise_for_status() + data = res.json() + except httpx.RequestError as e: + raise HTTPException(status_code=502, detail=f"Błąd połączenia: {e}") + except httpx.HTTPStatusError as e: + raise HTTPException(status_code=502, detail=f"Błąd API pogodowego: {e}") + + current = data.get("current_weather", {}) + record = WeatherRecord( + city="Custom Location", + temperature=current.get("temperature"), + windspeed=current.get("windspeed"), + time=datetime.fromisoformat(current.get("time")), + ) + session.add(record) + await session.commit() + + return { + "city": record.city, + "latitude": latitude, + "longitude": longitude, + "temperature": record.temperature, + "windspeed": record.windspeed, + "time": record.time + } diff --git a/models.py b/models.py new file mode 100644 index 0000000..e23a577 --- /dev/null +++ b/models.py @@ -0,0 +1,12 @@ +from sqlalchemy import Column, Integer, String, Float, DateTime +from db import Base +from datetime import datetime + +class WeatherRecord(Base): + __tablename__ = "weather" + + id = Column(Integer, primary_key=True, index=True) + city = Column(String, index=True) + temperature = Column(Float) + windspeed = Column(Float) + time = Column(DateTime, default=datetime.utcnow) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f037d93 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +fastapi +httpx +sqlalchemy +asyncpg +jinja2 +uvicorn diff --git a/templates/history.html b/templates/history.html new file mode 100644 index 0000000..99643a7 --- /dev/null +++ b/templates/history.html @@ -0,0 +1,28 @@ + + + + Historia pogody - {{ city }} + + + +

Historia pogody – {{ city }}

+ + + + + + + {% for r in records %} + + + + + + {% endfor %} +
DataTemperatura (°C)Wiatr (m/s)
{{ r.time.strftime('%Y-%m-%d %H:%M') }}{{ r.temperature }}{{ r.windspeed }}
+ +