diff --git a/prediction/db/kcgdb.py b/prediction/db/kcgdb.py index 05d463d..7a18cae 100644 --- a/prediction/db/kcgdb.py +++ b/prediction/db/kcgdb.py @@ -72,7 +72,7 @@ def upsert_results(results: list['AnalysisResult']) -> int: insert_sql = """ INSERT INTO vessel_analysis_results ( mmsi, analyzed_at, vessel_type, confidence, fishing_pct, - cluster_id, season, zone_code, dist_to_baseline_nm, activity_state, + cluster_id, season, lat, lon, zone_code, dist_to_baseline_nm, activity_state, ucaf_score, ucft_score, is_dark, gap_duration_min, spoofing_score, bd09_offset_m, speed_jump_count, fleet_cluster_id, fleet_is_leader, fleet_role, @@ -88,6 +88,8 @@ def upsert_results(results: list['AnalysisResult']) -> int: fishing_pct = EXCLUDED.fishing_pct, cluster_id = EXCLUDED.cluster_id, season = EXCLUDED.season, + lat = EXCLUDED.lat, + lon = EXCLUDED.lon, zone_code = EXCLUDED.zone_code, dist_to_baseline_nm = EXCLUDED.dist_to_baseline_nm, activity_state = EXCLUDED.activity_state, diff --git a/prediction/models/result.py b/prediction/models/result.py index 91a22cb..833d1c2 100644 --- a/prediction/models/result.py +++ b/prediction/models/result.py @@ -20,6 +20,8 @@ class AnalysisResult: # ALGO 01: 위치 zone: str = 'EEZ_OR_BEYOND' dist_to_baseline_nm: float = 999.0 + lat: Optional[float] = None + lon: Optional[float] = None # ALGO 02: 활동 상태 activity_state: str = 'UNKNOWN' @@ -95,6 +97,10 @@ class AnalysisResult: safe_features = _sanitize(self.features) if self.features else {} + def _opt_f(v: object) -> Optional[float]: + """Optional float (None 유지).""" + return float(v) if v is not None else None + return ( str(self.mmsi), self.analyzed_at, # analyzed_at (PK 파티션키) @@ -103,6 +109,8 @@ class AnalysisResult: _f(self.fishing_pct), _i(self.cluster_id), str(self.season), + _opt_f(self.lat), + _opt_f(self.lon), str(self.zone), # → zone_code _f(self.dist_to_baseline_nm), str(self.activity_state), diff --git a/prediction/scheduler.py b/prediction/scheduler.py index b8906e5..91a786b 100644 --- a/prediction/scheduler.py +++ b/prediction/scheduler.py @@ -466,6 +466,9 @@ def run_analysis_cycle(): 'registered_fishery_code': registered_fishery_code or '', } + # 분석 시점의 선박 위치 — 특이운항 판별 근거 좌표로 DB에 저장 + lat_val = last_row.get('lat') + lon_val = last_row.get('lon') results.append(AnalysisResult( mmsi=mmsi, timestamp=ts, @@ -474,6 +477,8 @@ def run_analysis_cycle(): fishing_pct=c['fishing_pct'], cluster_id=fleet_info.get('cluster_id', -1), season=c['season'], + lat=float(lat_val) if lat_val is not None else None, + lon=float(lon_val) if lon_val is not None else None, zone=zone_info.get('zone', 'EEZ_OR_BEYOND'), dist_to_baseline_nm=zone_info.get('dist_from_baseline_nm', 999.0), activity_state=activity, @@ -615,6 +620,8 @@ def run_analysis_cycle(): vessel_type='UNKNOWN', confidence=0.0, fishing_pct=0.0, + lat=float(lat) if lat is not None else None, + lon=float(lon) if lon is not None else None, zone=zone_info.get('zone', 'EEZ_OR_BEYOND'), dist_to_baseline_nm=zone_info.get('dist_from_baseline_nm', 999.0), activity_state=state,