Spaces:
Sleeping
Sleeping
Update api_utils.py
Browse files- api_utils.py +37 -7
api_utils.py
CHANGED
|
@@ -3,40 +3,70 @@ import pandas as pd
|
|
| 3 |
import pytz
|
| 4 |
import plotly.graph_objects as go
|
| 5 |
from plotly.subplots import make_subplots
|
|
|
|
| 6 |
from supabase_utils import get_supabase_client
|
| 7 |
from config import STATION_NAMES
|
| 8 |
|
|
|
|
|
|
|
|
|
|
| 9 |
def fetch_tide_data(station_id, start_utc, end_utc, table='historical_tide'):
|
| 10 |
-
"""
|
| 11 |
supabase = get_supabase_client()
|
| 12 |
if not supabase:
|
|
|
|
| 13 |
raise ValueError("Supabase 클라이언트를 생성할 수 없습니다.")
|
| 14 |
|
| 15 |
try:
|
|
|
|
|
|
|
|
|
|
| 16 |
result = supabase.table(table) \
|
| 17 |
-
.select(
|
| 18 |
.eq('station_id', station_id) \
|
| 19 |
-
.gte(
|
| 20 |
-
.lte(
|
| 21 |
-
.order(
|
| 22 |
.execute()
|
|
|
|
| 23 |
if not result.data:
|
| 24 |
-
|
|
|
|
|
|
|
| 25 |
return pd.DataFrame(result.data)
|
| 26 |
except Exception as e:
|
|
|
|
| 27 |
raise ValueError(f"데이터 조회 오류: {e}")
|
| 28 |
|
| 29 |
def get_tide_data(station_id, start_date=None, end_date=None, include_extremes=False, return_plot=False):
|
| 30 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
start_date = start_date or datetime.now(pytz.timezone('Asia/Seoul')).strftime('%Y-%m-%d')
|
| 32 |
start_time = pytz.timezone('Asia/Seoul').localize(datetime.strptime(start_date, '%Y-%m-%d'))
|
|
|
|
|
|
|
|
|
|
| 33 |
end_time = start_time + timedelta(hours=24) if not end_date else \
|
| 34 |
pytz.timezone('Asia/Seoul').localize(datetime.strptime(end_date, '%Y-%m-%d')) + timedelta(hours=24)
|
| 35 |
|
|
|
|
| 36 |
start_utc = start_time.astimezone(pytz.UTC).isoformat()
|
| 37 |
end_utc = end_time.astimezone(pytz.UTC).isoformat()
|
| 38 |
|
| 39 |
df = fetch_tide_data(station_id, start_utc, end_utc)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
df['observed_at'] = pd.to_datetime(df['observed_at']).dt.tz_convert('Asia/Seoul')
|
| 41 |
df['tide_level'] = pd.to_numeric(df['tide_level'])
|
| 42 |
|
|
|
|
| 3 |
import pytz
|
| 4 |
import plotly.graph_objects as go
|
| 5 |
from plotly.subplots import make_subplots
|
| 6 |
+
import logging
|
| 7 |
from supabase_utils import get_supabase_client
|
| 8 |
from config import STATION_NAMES
|
| 9 |
|
| 10 |
+
# Basic logging configuration
|
| 11 |
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
| 12 |
+
|
| 13 |
def fetch_tide_data(station_id, start_utc, end_utc, table='historical_tide'):
|
| 14 |
+
"""Fetches data from a specified Supabase table within a date range."""
|
| 15 |
supabase = get_supabase_client()
|
| 16 |
if not supabase:
|
| 17 |
+
logging.error("Failed to create a Supabase client.")
|
| 18 |
raise ValueError("Supabase 클라이언트를 생성할 수 없습니다.")
|
| 19 |
|
| 20 |
try:
|
| 21 |
+
query_column = 'observed_at' if table == 'historical_tide' else 'predicted_at'
|
| 22 |
+
select_columns = 'observed_at, tide_level' if table == 'historical_tide' else 'predicted_at, final_tide_level'
|
| 23 |
+
|
| 24 |
result = supabase.table(table) \
|
| 25 |
+
.select(select_columns) \
|
| 26 |
.eq('station_id', station_id) \
|
| 27 |
+
.gte(query_column, start_utc) \
|
| 28 |
+
.lte(query_column, end_utc) \
|
| 29 |
+
.order(query_column) \
|
| 30 |
.execute()
|
| 31 |
+
|
| 32 |
if not result.data:
|
| 33 |
+
logging.warning(f"No data found for station {station_id} from {start_utc} to {end_utc} in table '{table}'.")
|
| 34 |
+
return pd.DataFrame() # Return empty DataFrame for robustness
|
| 35 |
+
|
| 36 |
return pd.DataFrame(result.data)
|
| 37 |
except Exception as e:
|
| 38 |
+
logging.error(f"Error fetching data for station {station_id}: {e}", exc_info=True)
|
| 39 |
raise ValueError(f"데이터 조회 오류: {e}")
|
| 40 |
|
| 41 |
def get_tide_data(station_id, start_date=None, end_date=None, include_extremes=False, return_plot=False):
|
| 42 |
+
"""
|
| 43 |
+
Retrieves and processes tide data, optionally including tide extremes and a plot.
|
| 44 |
+
|
| 45 |
+
:param station_id: The station identifier.
|
| 46 |
+
:param start_date: Start date in 'YYYY-MM-DD' format. Defaults to today.
|
| 47 |
+
:param end_date: End date in 'YYYY-MM-DD' format. Defaults to the start date.
|
| 48 |
+
:param include_extremes: Whether to calculate and include tidal extremes (high/low tides).
|
| 49 |
+
:param return_plot: Whether to generate and return a Plotly figure.
|
| 50 |
+
:return: A dictionary containing the data, and optionally extremes and a plot.
|
| 51 |
+
"""
|
| 52 |
+
# Default to today (in Seoul timezone) if start_date is not provided.
|
| 53 |
start_date = start_date or datetime.now(pytz.timezone('Asia/Seoul')).strftime('%Y-%m-%d')
|
| 54 |
start_time = pytz.timezone('Asia/Seoul').localize(datetime.strptime(start_date, '%Y-%m-%d'))
|
| 55 |
+
|
| 56 |
+
# The query period ends 24 hours after the start of the end_date.
|
| 57 |
+
# If no end_date is given, the period is 24 hours from the start_time.
|
| 58 |
end_time = start_time + timedelta(hours=24) if not end_date else \
|
| 59 |
pytz.timezone('Asia/Seoul').localize(datetime.strptime(end_date, '%Y-%m-%d')) + timedelta(hours=24)
|
| 60 |
|
| 61 |
+
# Convert local time to UTC for the database query.
|
| 62 |
start_utc = start_time.astimezone(pytz.UTC).isoformat()
|
| 63 |
end_utc = end_time.astimezone(pytz.UTC).isoformat()
|
| 64 |
|
| 65 |
df = fetch_tide_data(station_id, start_utc, end_utc)
|
| 66 |
+
if df.empty:
|
| 67 |
+
logging.warning(f"No tide data available for station {station_id} for the selected period.")
|
| 68 |
+
return {"data": pd.DataFrame(), "extremes": pd.DataFrame(), "plot": go.Figure()}
|
| 69 |
+
|
| 70 |
df['observed_at'] = pd.to_datetime(df['observed_at']).dt.tz_convert('Asia/Seoul')
|
| 71 |
df['tide_level'] = pd.to_numeric(df['tide_level'])
|
| 72 |
|