From dac4a3bda2b2f1a66e06b3d5a5f351fb79ac4215 Mon Sep 17 00:00:00 2001 From: htlee Date: Thu, 9 Apr 2026 07:56:04 +0900 Subject: [PATCH] =?UTF-8?q?fix(prediction):=20features=20JSONB=20=EC=A4=91?= =?UTF-8?q?=EC=B2=A9=20=EA=B5=AC=EC=A1=B0=20sanitize?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AnalysisResult.to_db_tuple이 기존에 features dict 값을 모두 float로 변환했는데, dark_suspicion 구조를 넣으면서 dark_patterns(list) 등 비스칼라 타입이 포함되어 upsert 실패 (float argument not a list). _sanitize 재귀 함수로 JSON 호환 타입(str/int/float/bool/list/dict/None)을 그대로 보존하도록 변경. --- prediction/models/result.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/prediction/models/result.py b/prediction/models/result.py index bb7a69c..ae439e7 100644 --- a/prediction/models/result.py +++ b/prediction/models/result.py @@ -70,8 +70,24 @@ class AnalysisResult: """numpy int → Python int 변환.""" return int(v) if v is not None else 0 - # features dict 내부 numpy 값도 변환 - safe_features = {k: float(v) for k, v in self.features.items()} if self.features else {} + # features dict 내부 numpy 값도 변환 (재귀적 처리) + # int/float/bool/str/None/list/dict 모두 허용 (JSON 호환 타입만 유지) + def _sanitize(v): + if v is None or isinstance(v, (str, bool)): + return v + if isinstance(v, (int, float)): + return float(v) if isinstance(v, float) else int(v) + if isinstance(v, dict): + return {str(k): _sanitize(val) for k, val in v.items()} + if isinstance(v, (list, tuple)): + return [_sanitize(x) for x in v] + # numpy 스칼라 등은 float 변환 시도, 실패 시 str + try: + return float(v) + except (TypeError, ValueError): + return str(v) + + safe_features = _sanitize(self.features) if self.features else {} return ( str(self.mmsi),