Update main.py and history.html; add new templates

This commit is contained in:
root
2025-07-07 14:51:10 +02:00
parent 137f8c1c93
commit 9fe99f0cde
8 changed files with 942 additions and 9 deletions

370
main.py
View File

@ -6,6 +6,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from db import get_session, engine, Base from db import get_session, engine, Base
from models import WeatherRecord from models import WeatherRecord
from datetime import datetime from datetime import datetime
from fastapi.responses import HTMLResponse, JSONResponse
app = FastAPI() app = FastAPI()
templates = Jinja2Templates(directory="templates") templates = Jinja2Templates(directory="templates")
@ -14,8 +15,74 @@ CITIES = {
"warszawa": (52.23, 21.01), "warszawa": (52.23, 21.01),
"krakow": (50.06, 19.94), "krakow": (50.06, 19.94),
"gdansk": (54.35, 18.65), "gdansk": (54.35, 18.65),
"wroclaw": (51.11, 17.03),
"poznan": (52.41, 16.93),
"szczecin": (53.43, 14.55),
"bydgoszcz": (53.12, 18.01),
"lublin": (51.25, 22.57),
"bialystok": (53.13, 23.15),
"katowice": (50.26, 19.02),
"lodz": (51.77, 19.46),
"torun": (53.01, 18.60),
"kielce": (50.87, 20.63),
"rzeszow": (50.04, 22.00),
"opole": (50.67, 17.93),
"zielona_gora": (51.94, 15.50),
"gorzow_wlkp": (52.73, 15.24),
"olsztyn": (53.78, 20.48),
"radom": (51.40, 21.15),
"plock": (52.55, 19.70),
"elblag": (54.16, 19.40),
"tarnow": (50.01, 20.99),
"chorzow": (50.30, 18.95),
"gliwice": (50.30, 18.67),
"zabrze": (50.30, 18.78),
"rybnik": (50.10, 18.55),
"walbrzych": (50.77, 16.28),
"legnica": (51.21, 16.16),
"pila": (53.15, 16.74),
"suwalki": (54.10, 22.93),
"siedlce": (52.17, 22.29),
"piotrkow_tryb": (51.40, 19.70),
"nowy_sacz": (49.62, 20.69),
"przemysl": (49.78, 22.77),
"zamosc": (50.72, 23.25),
"chelm": (51.14, 23.47),
"koszalin": (54.19, 16.18),
"slupsk": (54.46, 17.03),
"grudziadz": (53.48, 18.75),
"jaworzno": (50.20, 19.27),
"tarnobrzeg": (50.58, 21.68),
"ostrow_wlkp": (51.65, 17.81),
"konin": (52.22, 18.26),
"leszno": (51.84, 16.57),
"stargard": (53.34, 15.05),
"lubin": (51.40, 16.20),
"mielec": (50.28, 21.42),
"pabianice": (51.66, 19.35),
"glogow": (51.66, 16.08),
"ostroleka": (53.09, 21.56),
"siemianowice_sl": (50.31, 19.03),
"swidnica": (50.84, 16.49),
"skierniewice": (51.97, 20.15),
"bedzin": (50.33, 19.13),
"pulawy": (51.42, 21.97),
"starachowice": (51.05, 21.08),
"nowy_targ": (49.48, 20.03),
"radomsko": (51.07, 19.45),
"wloclawek": (52.65, 19.07),
"lubartow": (51.46, 22.61),
"lomza": (53.18, 22.07),
"klodzko": (50.43, 16.65),
"biala_podlaska": (52.03, 23.13),
"pruszkow": (52.17, 20.80),
"jaslo": (49.75, 21.47),
"dzierzoniow": (50.73, 16.65),
"bielsk_podlaski": (52.77, 23.19),
} }
@app.on_event("startup") @app.on_event("startup")
async def startup(): async def startup():
async with engine.begin() as conn: async with engine.begin() as conn:
@ -34,6 +101,7 @@ async def get_weather(city: str = Query("warszawa"), session: AsyncSession = Dep
data = res.json() data = res.json()
current = data.get("current_weather", {}) current = data.get("current_weather", {})
record = WeatherRecord( record = WeatherRecord(
city=city.capitalize(), city=city.capitalize(),
temperature=current.get("temperature"), temperature=current.get("temperature"),
@ -50,6 +118,7 @@ async def get_weather(city: str = Query("warszawa"), session: AsyncSession = Dep
"time": record.time "time": record.time
} }
@app.get("/history") @app.get("/history")
async def get_history(city: str = Query("warszawa"), session: AsyncSession = Depends(get_session)): 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) stmt = select(WeatherRecord).where(WeatherRecord.city.ilike(city)).order_by(WeatherRecord.time.desc()).limit(10)
@ -78,9 +147,10 @@ async def view_history(request: Request, city: str = "warszawa", session: AsyncS
@app.get("/ping") @app.get("/ping")
async def ping(): async def ping(request: Request):
return {"status": "ok"} if "text/html" in request.headers.get("accept", ""):
return templates.TemplateResponse("ping.html", {"request": request})
return JSONResponse({"status": "ok"})
@app.get("/weather/geo") @app.get("/weather/geo")
async def get_weather_by_coords( async def get_weather_by_coords(
@ -121,3 +191,297 @@ async def get_weather_by_coords(
"windspeed": record.windspeed, "windspeed": record.windspeed,
"time": record.time "time": record.time
} }
@app.get("/forecast", response_class=HTMLResponse)
async def get_forecast(
request: Request,
city: str = Query("warszawa"),
days: int = Query(3, ge=1, le=16)
):
coords = CITIES.get(city.lower())
if not coords:
return templates.TemplateResponse(
"forecast.html",
{
"request": request,
"city": city.capitalize(),
"forecast": None
}
)
url = (
f"https://api.open-meteo.com/v1/forecast?"
f"latitude={coords[0]}&longitude={coords[1]}"
f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum"
f"&timezone=Europe/Warsaw"
f"&forecast_days={days}"
)
async with httpx.AsyncClient() as client:
res = await client.get(url)
data = res.json()
daily = data.get("daily", {})
accept = request.headers.get("accept", "")
if "text/html" in accept:
return templates.TemplateResponse(
"forecast.html",
{
"request": request,
"city": city.capitalize(),
"forecast": daily,
"error": None,
}
)
else:
return JSONResponse(content={
"city": city.capitalize(),
"forecast": daily,
})
@app.get("/forecast/geo", response_class=HTMLResponse)
async def get_forecast_geo(
request: Request,
latitude: float = Query(..., ge=-90, le=90),
longitude: float = Query(..., ge=-180, le=180),
days: int = Query(3, ge=1, le=16)
):
url = (
f"https://api.open-meteo.com/v1/forecast?"
f"latitude={latitude}&longitude={longitude}"
f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum"
f"&timezone=Europe/Warsaw"
f"&forecast_days={days}"
)
async with httpx.AsyncClient() as client:
res = await client.get(url)
data = res.json()
daily = data.get("daily", {})
accept = request.headers.get("accept", "")
if "text/html" in accept:
return templates.TemplateResponse(
"forecast.html",
{
"request": request,
"city": f"Lat: {latitude}, Lon: {longitude}",
"forecast": daily,
"error": None,
}
)
else:
return JSONResponse(content={
"latitude": latitude,
"longitude": longitude,
"forecast": daily
})
@app.get("/forecast/hourly/geo", response_class=HTMLResponse)
async def get_hourly_forecast_geo(
request: Request,
latitude: float = Query(..., ge=-90, le=90),
longitude: float = Query(..., ge=-180, le=180),
hours: int = Query(12, ge=1, le=48)
):
url = (
f"https://api.open-meteo.com/v1/forecast?"
f"latitude={latitude}&longitude={longitude}"
f"&hourly=temperature_2m,windspeed_10m,precipitation"
f"&timezone=Europe/Warsaw"
)
async with httpx.AsyncClient() as client:
res = await client.get(url)
data = res.json()
hourly_data = {}
for key, values in data.get("hourly", {}).items():
hourly_data[key] = values[:hours]
accept = request.headers.get("accept", "")
if "text/html" in accept:
return templates.TemplateResponse(
"hourly_forecast.html",
{
"request": request,
"city": f"Lat: {latitude}, Lon: {longitude}",
"hourly_forecast": hourly_data,
"error": None,
}
)
else:
return JSONResponse(content={
"latitude": latitude,
"longitude": longitude,
"hourly_forecast": hourly_data
})
@app.get("/forecast/hourly")
async def get_hourly_forecast_city(
request: Request,
city: str = Query(...),
hours: int = Query(12, ge=1, le=48)
):
coords = CITIES.get(city.lower())
if not coords:
error_data = {"error": "Miasto nieobsługiwane"}
accept = request.headers.get("accept", "")
if "text/html" in accept:
return templates.TemplateResponse(
"hourly_forecast.html",
{
"request": request,
"city": city.capitalize(),
"hourly_forecast": None,
"error": error_data["error"],
}
)
else:
raise HTTPException(status_code=404, detail=error_data["error"])
latitude, longitude = coords
url = (
f"https://api.open-meteo.com/v1/forecast?"
f"latitude={latitude}&longitude={longitude}"
f"&hourly=temperature_2m,windspeed_10m,precipitation"
f"&timezone=Europe/Warsaw"
)
async with httpx.AsyncClient() as client:
res = await client.get(url)
data = res.json()
hourly_data = {}
for key, values in data.get("hourly", {}).items():
hourly_data[key] = values[:hours]
accept = request.headers.get("accept", "")
if "text/html" in accept:
return templates.TemplateResponse(
"hourly_forecast.html",
{
"request": request,
"city": city.capitalize(),
"hourly_forecast": hourly_data,
"error": None,
}
)
else:
return JSONResponse(content={
"city": city.capitalize(),
"hourly_forecast": hourly_data
})
@app.get("/history-range")
async def get_weather_history_range(
request: Request,
city: str = Query(..., description="Nazwa miasta, np. warszawa"),
start_date: str = Query(..., description="Początkowa data w formacie YYYY-MM-DD"),
end_date: str = Query(..., description="Końcowa data w formacie YYYY-MM-DD")
):
coords = CITIES.get(city.lower())
if not coords:
error_data = {"error": "Miasto nieobsługiwane"}
accept = request.headers.get("accept", "")
if "text/html" in accept:
return templates.TemplateResponse(
"history_range.html",
{
"request": request,
"city": city.capitalize(),
"start_date": start_date,
"end_date": end_date,
"history": None,
"error": error_data["error"]
}
)
else:
raise HTTPException(status_code=404, detail=error_data["error"])
latitude, longitude = coords
url = (
f"https://archive-api.open-meteo.com/v1/archive?"
f"latitude={latitude}&longitude={longitude}"
f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum"
f"&start_date={start_date}&end_date={end_date}"
f"&timezone=Europe/Warsaw"
)
async with httpx.AsyncClient() as client:
res = await client.get(url)
data = res.json()
daily = data.get("daily", {})
accept = request.headers.get("accept", "")
if "text/html" in accept:
return templates.TemplateResponse(
"history_range.html",
{
"request": request,
"city": city.capitalize(),
"start_date": start_date,
"end_date": end_date,
"history": daily,
"error": None
}
)
else:
return JSONResponse(content={
"city": city.capitalize(),
"start_date": start_date,
"end_date": end_date,
"history": daily
})
@app.get("/history-range/geo")
async def get_weather_history_range_geo(
request: Request,
latitude: float = Query(..., ge=-90, le=90, description="Szerokość geograficzna"),
longitude: float = Query(..., ge=-180, le=180, description="Długość geograficzna"),
start_date: str = Query(..., description="Początkowa data w formacie YYYY-MM-DD"),
end_date: str = Query(..., description="Końcowa data w formacie YYYY-MM-DD")
):
url = (
f"https://archive-api.open-meteo.com/v1/archive?"
f"latitude={latitude}&longitude={longitude}"
f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum"
f"&start_date={start_date}&end_date={end_date}"
f"&timezone=Europe/Warsaw"
)
async with httpx.AsyncClient() as client:
res = await client.get(url)
data = res.json()
daily = data.get("daily", {})
accept = request.headers.get("accept", "")
if "text/html" in accept:
city_name = f"({latitude}, {longitude})"
return templates.TemplateResponse(
"history_range.html",
{
"request": request,
"city": city_name,
"start_date": start_date,
"end_date": end_date,
"history": daily,
"error": None
}
)
else:
return JSONResponse(content={
"latitude": latitude,
"longitude": longitude,
"start_date": start_date,
"end_date": end_date,
"history": daily
})

298
main_copy.py Normal file
View File

@ -0,0 +1,298 @@
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]}&current_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}&current_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
}
@app.get("/forecast")
async def get_forecast(
city: str = Query("warszawa"),
days: int = Query(3, ge=1, le=16)
):
coords = CITIES.get(city.lower())
if not coords:
return {"error": "Miasto nieobsługiwane"}
url = (
f"https://api.open-meteo.com/v1/forecast?"
f"latitude={coords[0]}&longitude={coords[1]}"
f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum"
f"&timezone=Europe/Warsaw"
f"&forecast_days={days}"
)
async with httpx.AsyncClient() as client:
res = await client.get(url)
data = res.json()
daily = data.get("daily", {})
return {
"city": city.capitalize(),
"forecast": daily
}
@app.get("/forecast/geo")
async def get_forecast_geo(
latitude: float = Query(..., ge=-90, le=90),
longitude: float = Query(..., ge=-180, le=180),
days: int = Query(3, ge=1, le=16)
):
url = (
f"https://api.open-meteo.com/v1/forecast?"
f"latitude={latitude}&longitude={longitude}"
f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum"
f"&timezone=Europe/Warsaw"
f"&forecast_days={days}"
)
async with httpx.AsyncClient() as client:
res = await client.get(url)
data = res.json()
daily = data.get("daily", {})
return {
"latitude": latitude,
"longitude": longitude,
"forecast": daily
}
@app.get("/forecast/hourly/geo")
async def get_hourly_forecast_geo(
latitude: float = Query(..., ge=-90, le=90),
longitude: float = Query(..., ge=-180, le=180),
hours: int = Query(12, ge=1, le=48)
):
url = (
f"https://api.open-meteo.com/v1/forecast?"
f"latitude={latitude}&longitude={longitude}"
f"&hourly=temperature_2m,windspeed_10m,precipitation"
f"&timezone=Europe/Warsaw"
)
async with httpx.AsyncClient() as client:
res = await client.get(url)
data = res.json()
hourly_data = {}
for key, values in data.get("hourly", {}).items():
hourly_data[key] = values[:hours]
return {
"latitude": latitude,
"longitude": longitude,
"hourly_forecast": hourly_data
}
@app.get("/forecast/hourly")
async def get_hourly_forecast_city(
city: str = Query(...),
hours: int = Query(12, ge=1, le=48)
):
coords = CITIES.get(city.lower())
if not coords:
raise HTTPException(status_code=404, detail="Miasto nieobsługiwane")
latitude, longitude = coords
url = (
f"https://api.open-meteo.com/v1/forecast?"
f"latitude={latitude}&longitude={longitude}"
f"&hourly=temperature_2m,windspeed_10m,precipitation"
f"&timezone=Europe/Warsaw"
)
async with httpx.AsyncClient() as client:
res = await client.get(url)
data = res.json()
hourly_data = {}
for key, values in data.get("hourly", {}).items():
hourly_data[key] = values[:hours]
return {
"city": city.capitalize(),
"hourly_forecast": hourly_data
}
@app.get("/history-range")
async def get_weather_history_range(
city: str = Query(..., description="Nazwa miasta, np. warszawa"),
start_date: str = Query(..., description="Początkowa data w formacie YYYY-MM-DD"),
end_date: str = Query(..., description="Końcowa data w formacie YYYY-MM-DD")
):
coords = CITIES.get(city.lower())
if not coords:
raise HTTPException(status_code=404, detail="Miasto nieobsługiwane")
latitude, longitude = coords
url = (
f"https://archive-api.open-meteo.com/v1/archive?"
f"latitude={latitude}&longitude={longitude}"
f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum"
f"&start_date={start_date}&end_date={end_date}"
f"&timezone=Europe/Warsaw"
)
async with httpx.AsyncClient() as client:
res = await client.get(url)
data = res.json()
daily = data.get("daily", {})
return {
"city": city.capitalize(),
"start_date": start_date,
"end_date": end_date,
"history": daily
}
@app.get("/history-range/geo")
async def get_weather_history_range_geo(
latitude: float = Query(..., ge=-90, le=90, description="Szerokość geograficzna"),
longitude: float = Query(..., ge=-180, le=180, description="Długość geograficzna"),
start_date: str = Query(..., description="Początkowa data w formacie YYYY-MM-DD"),
end_date: str = Query(..., description="Końcowa data w formacie YYYY-MM-DD")
):
url = (
f"https://archive-api.open-meteo.com/v1/archive?"
f"latitude={latitude}&longitude={longitude}"
f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum"
f"&start_date={start_date}&end_date={end_date}"
f"&timezone=Europe/Warsaw"
)
async with httpx.AsyncClient() as client:
res = await client.get(url)
data = res.json()
daily = data.get("daily", {})
return {
"latitude": latitude,
"longitude": longitude,
"start_date": start_date,
"end_date": end_date,
"history": daily
}

69
templates/forecast.html Normal file
View File

@ -0,0 +1,69 @@
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Prognoza pogody - {{ city }}</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #eef2f3;
color: #333;
margin: 20px;
}
h1 {
color: #2a6ebb;
}
.error {
color: red;
font-weight: bold;
}
table {
border-collapse: collapse;
width: 60%;
margin-top: 20px;
}
th, td {
border: 1px solid #aaa;
padding: 8px 12px;
text-align: center;
}
th {
background-color: #2a6ebb;
color: #fff;
}
tr:nth-child(even) {
background-color: #d9e1ec;
}
</style>
</head>
<body>
<h1>Prognoza pogody dla {{ city }}</h1>
{% if error %}
<p class="error">{{ error }}</p>
{% elif forecast and forecast.time %}
<table>
<thead>
<tr>
<th>Data</th>
<th>Temperatura maks. (°C)</th>
<th>Temperatura min. (°C)</th>
<th>Opady (mm)</th>
</tr>
</thead>
<tbody>
{% for i in range(forecast.time|length) %}
<tr>
<td>{{ forecast.time[i] }}</td>
<td>{{ forecast.temperature_2m_max[i] }}</td>
<td>{{ forecast.temperature_2m_min[i] }}</td>
<td>{{ forecast.precipitation_sum[i] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>Brak danych pogodowych.</p>
{% endif %}
</body>
</html>

View File

@ -1,15 +1,44 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="pl">
<head> <head>
<title>Historia pogody - {{ city }}</title> <meta charset="UTF-8">
<title>Historia zapytan o {{ city }}</title>
<style> <style>
body { font-family: Arial; padding: 20px; } body {
table { border-collapse: collapse; width: 100%; } font-family: Arial, sans-serif;
th, td { padding: 10px; border: 1px solid #ddd; text-align: left; } background-color: #eef2f3;
color: #333;
margin: 20px;
}
h1 {
color: #2a6ebb;
}
.error {
color: red;
font-weight: bold;
}
table {
border-collapse: collapse;
width: 60%;
margin-top: 20px;
}
th, td {
border: 1px solid #aaa;
padding: 8px 12px;
text-align: center;
}
th {
background-color: #2a6ebb;
color: #fff;
}
tr:nth-child(even) {
background-color: #d9e1ec;
}
</style> </style>
</head> </head>
<body> <body>
<h2>Historia pogody {{ city }}</h2> <h1>Historia zapytan o {{ city }}</h1>
<table> <table>
<tr> <tr>
<th>Data</th> <th>Data</th>

View File

@ -0,0 +1,67 @@
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Historia pogody - {{ city }}</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #eef2f3;
color: #333;
margin: 20px;
}
h1 {
color: #2a6ebb;
}
.error {
color: red;
font-weight: bold;
}
table {
border-collapse: collapse;
width: 80%;
margin-top: 20px;
}
th, td {
border: 1px solid #aaa;
padding: 6px 10px;
text-align: center;
}
th {
background-color: #2a6ebb;
color: #fff;
}
tr:nth-child(even) {
background-color: #d9e1ec;
}
</style>
</head>
<body>
<h1>Historia pogody dla {{ city }} <br> od {{ start_date }} do {{ end_date }}</h1>
{% if error %}
<p class="error">{{ error }}</p>
{% elif history %}
<table>
<thead>
<tr>
<th>Data</th>
<th>Temp. maks. (°C)</th>
<th>Temp. min. (°C)</th>
<th>Opady (mm)</th>
</tr>
</thead>
<tbody>
{% for i in range(history["time"]|length) %}
<tr>
<td>{{ history["time"][i] }}</td>
<td>{{ history["temperature_2m_max"][i] }}</td>
<td>{{ history["temperature_2m_min"][i] }}</td>
<td>{{ history["precipitation_sum"][i] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</body>
</html>

View File

@ -0,0 +1,67 @@
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Prognoza godzinowa - {{ city }}</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #eef2f3;
color: #333;
margin: 20px;
}
h1 {
color: #2a6ebb;
}
.error {
color: red;
font-weight: bold;
}
table {
border-collapse: collapse;
width: 80%;
margin-top: 20px;
}
th, td {
border: 1px solid #aaa;
padding: 6px 10px;
text-align: center;
}
th {
background-color: #2a6ebb;
color: #fff;
}
tr:nth-child(even) {
background-color: #d9e1ec;
}
</style>
</head>
<body>
<h1>Prognoza godzinowa dla {{ city }}</h1>
{% if error %}
<p class="error">{{ error }}</p>
{% elif hourly_forecast %}
<table>
<thead>
<tr>
<th>Godzina</th>
<th>Temp. (°C)</th>
<th>Wiatr (km/h)</th>
<th>Opady (mm)</th>
</tr>
</thead>
<tbody>
{% for i in range(hourly_forecast["time"]|length) %}
<tr>
<td>{{ hourly_forecast["time"][i] }}</td>
<td>{{ hourly_forecast["temperature_2m"][i] }}</td>
<td>{{ hourly_forecast["windspeed_10m"][i] }}</td>
<td>{{ hourly_forecast["precipitation"][i] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</body>
</html>

11
templates/ping.html Normal file
View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8" />
<title>Ping status</title>
</head>
<body>
<h1>Status: OK</h1>
<p>Serwer działa poprawnie.</p>
</body>
</html>

28
templates/test.html Normal file
View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title>Historia pogody - {{ city }}</title>
<style>
body { font-family: Arial; padding: 20px; }
table { border-collapse: collapse; width: 100%; }
th, td { padding: 10px; border: 1px solid #ddd; text-align: left; }
</style>
</head>
<body>
<h2>Historia pogody {{ city }}</h2>
<table>
<tr>
<th>Data</th>
<th>Temperatura (°C)</th>
<th>Wiatr (m/s)</th>
</tr>
{% for r in records %}
<tr>
<td>{{ r.time.strftime('%Y-%m-%d %H:%M') }}</td>
<td>{{ r.temperature }}</td>
<td>{{ r.windspeed }}</td>
</tr>
{% endfor %}
</table>
</body>
</html>