Spaces:
Sleeping
Sleeping
Update api_utils.py
Browse files- api_utils.py +53 -11
api_utils.py
CHANGED
|
@@ -83,22 +83,49 @@ def api_get_tide_level(
|
|
| 83 |
|
| 84 |
try:
|
| 85 |
# 대상 시간 파싱
|
|
|
|
| 86 |
if target_time:
|
| 87 |
query_time = datetime.fromisoformat(target_time.replace('Z', '+00:00'))
|
|
|
|
|
|
|
| 88 |
else:
|
| 89 |
-
query_time = datetime.now(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
-
|
|
|
|
|
|
|
| 94 |
result = supabase.table('tide_predictions')\
|
| 95 |
.select('*')\
|
| 96 |
.eq('station_id', station_id)\
|
| 97 |
-
.
|
| 98 |
-
.order('predicted_at')\
|
| 99 |
-
.limit(1)\
|
| 100 |
.execute()
|
| 101 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
if result.data:
|
| 103 |
# 최종 예측 데이터가 있는 경우
|
| 104 |
data = result.data[0]
|
|
@@ -121,15 +148,28 @@ def api_get_tide_level(
|
|
| 121 |
)
|
| 122 |
|
| 123 |
# 2차: 조화 예측 (harmonic_predictions) 폴백
|
| 124 |
-
if use_harmonic_fallback:
|
|
|
|
| 125 |
result = supabase.table('harmonic_predictions')\
|
| 126 |
.select('*')\
|
| 127 |
.eq('station_id', station_id)\
|
| 128 |
-
.
|
| 129 |
-
.order('predicted_at')\
|
| 130 |
-
.limit(1)\
|
| 131 |
.execute()
|
| 132 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 133 |
if result.data:
|
| 134 |
data = result.data[0]
|
| 135 |
# UTC를 KST로 변환
|
|
@@ -146,7 +186,9 @@ def api_get_tide_level(
|
|
| 146 |
"harmonic_value": round(data.get('harmonic_level', 0), 1),
|
| 147 |
"data_source": "harmonic_only",
|
| 148 |
"confidence": "medium",
|
| 149 |
-
"note": "잔차 예측이 없어 조화 예측만 제공됩니다"
|
|
|
|
|
|
|
| 150 |
},
|
| 151 |
meta=get_station_meta(station_id)
|
| 152 |
)
|
|
|
|
| 83 |
|
| 84 |
try:
|
| 85 |
# 대상 시간 파싱
|
| 86 |
+
kst = pytz.timezone('Asia/Seoul')
|
| 87 |
if target_time:
|
| 88 |
query_time = datetime.fromisoformat(target_time.replace('Z', '+00:00'))
|
| 89 |
+
if query_time.tzinfo is None:
|
| 90 |
+
query_time = kst.localize(query_time)
|
| 91 |
else:
|
| 92 |
+
query_time = datetime.now(kst)
|
| 93 |
+
|
| 94 |
+
# UTC로 변환하여 쿼리 (중요!)
|
| 95 |
+
query_time_utc = query_time.astimezone(pytz.UTC)
|
| 96 |
+
query_str = query_time_utc.strftime('%Y-%m-%dT%H:%M:%S')
|
| 97 |
|
| 98 |
+
# 가장 가까운 5분 단위로 반올림
|
| 99 |
+
minutes = query_time.minute
|
| 100 |
+
rounded_minutes = round(minutes / 5) * 5
|
| 101 |
+
if rounded_minutes == 60:
|
| 102 |
+
query_time_rounded = query_time.replace(minute=0, second=0, microsecond=0) + timedelta(hours=1)
|
| 103 |
+
else:
|
| 104 |
+
query_time_rounded = query_time.replace(minute=rounded_minutes, second=0, microsecond=0)
|
| 105 |
|
| 106 |
+
query_time_rounded_utc = query_time_rounded.astimezone(pytz.UTC)
|
| 107 |
+
|
| 108 |
+
# 1차: 정확한 시간 매칭 시도
|
| 109 |
result = supabase.table('tide_predictions')\
|
| 110 |
.select('*')\
|
| 111 |
.eq('station_id', station_id)\
|
| 112 |
+
.eq('predicted_at', query_time_rounded_utc.strftime('%Y-%m-%dT%H:%M:%S'))\
|
|
|
|
|
|
|
| 113 |
.execute()
|
| 114 |
|
| 115 |
+
# 2차: 정확한 매칭이 없으면 전후 5분 범위에서 가장 가까운 것
|
| 116 |
+
if not result.data:
|
| 117 |
+
start_time = (query_time_rounded_utc - timedelta(minutes=5)).strftime('%Y-%m-%dT%H:%M:%S')
|
| 118 |
+
end_time = (query_time_rounded_utc + timedelta(minutes=5)).strftime('%Y-%m-%dT%H:%M:%S')
|
| 119 |
+
|
| 120 |
+
result = supabase.table('tide_predictions')\
|
| 121 |
+
.select('*')\
|
| 122 |
+
.eq('station_id', station_id)\
|
| 123 |
+
.gte('predicted_at', start_time)\
|
| 124 |
+
.lte('predicted_at', end_time)\
|
| 125 |
+
.order('predicted_at')\
|
| 126 |
+
.limit(1)\
|
| 127 |
+
.execute()
|
| 128 |
+
|
| 129 |
if result.data:
|
| 130 |
# 최종 예측 데이터가 있는 경우
|
| 131 |
data = result.data[0]
|
|
|
|
| 148 |
)
|
| 149 |
|
| 150 |
# 2차: 조화 예측 (harmonic_predictions) 폴백
|
| 151 |
+
if use_harmonic_fallback and not result.data:
|
| 152 |
+
# 1차: 정확한 시간 매칭 시도
|
| 153 |
result = supabase.table('harmonic_predictions')\
|
| 154 |
.select('*')\
|
| 155 |
.eq('station_id', station_id)\
|
| 156 |
+
.eq('predicted_at', query_time_rounded_utc.strftime('%Y-%m-%dT%H:%M:%S'))\
|
|
|
|
|
|
|
| 157 |
.execute()
|
| 158 |
|
| 159 |
+
# 2차: 정확한 매칭이 없으면 전후 5분 범위
|
| 160 |
+
if not result.data:
|
| 161 |
+
start_time = (query_time_rounded_utc - timedelta(minutes=5)).strftime('%Y-%m-%dT%H:%M:%S')
|
| 162 |
+
end_time = (query_time_rounded_utc + timedelta(minutes=5)).strftime('%Y-%m-%dT%H:%M:%S')
|
| 163 |
+
|
| 164 |
+
result = supabase.table('harmonic_predictions')\
|
| 165 |
+
.select('*')\
|
| 166 |
+
.eq('station_id', station_id)\
|
| 167 |
+
.gte('predicted_at', start_time)\
|
| 168 |
+
.lte('predicted_at', end_time)\
|
| 169 |
+
.order('predicted_at')\
|
| 170 |
+
.limit(1)\
|
| 171 |
+
.execute()
|
| 172 |
+
|
| 173 |
if result.data:
|
| 174 |
data = result.data[0]
|
| 175 |
# UTC를 KST로 변환
|
|
|
|
| 186 |
"harmonic_value": round(data.get('harmonic_level', 0), 1),
|
| 187 |
"data_source": "harmonic_only",
|
| 188 |
"confidence": "medium",
|
| 189 |
+
"note": "잔차 예측이 없어 조화 예측만 제공됩니다",
|
| 190 |
+
"query_time": query_time.strftime('%Y-%m-%d %H:%M:%S KST'),
|
| 191 |
+
"matched_time_diff_seconds": abs((time_utc - query_time_utc).total_seconds())
|
| 192 |
},
|
| 193 |
meta=get_station_meta(station_id)
|
| 194 |
)
|