fix: convert Decimal to float for JSON serialization in evaluation
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s

- PostgreSQL returns numeric values as Decimal objects
- psycopg2.Json() cannot serialize Decimal to JSON
- Added convert_decimals() helper function
- Converts activity_data, context, and evaluation_result before saving

Fixes: Batch evaluation errors (31 errors 'Decimal is not JSON serializable')

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lars 2026-03-23 13:28:07 +01:00
parent 4937ce4b05
commit 2c73c3df52

View File

@ -6,6 +6,7 @@ Issue: #15
Date: 2026-03-23 Date: 2026-03-23
""" """
from typing import Dict, Optional, List from typing import Dict, Optional, List
from decimal import Decimal
import logging import logging
from db import get_cursor from db import get_cursor
@ -14,6 +15,21 @@ from profile_evaluator import TrainingProfileEvaluator
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def convert_decimals(obj):
"""
Recursively converts Decimal objects to float for JSON serialization.
PostgreSQL returns numeric values as Decimal, but psycopg2.Json() can't serialize them.
"""
if isinstance(obj, Decimal):
return float(obj)
elif isinstance(obj, dict):
return {k: convert_decimals(v) for k, v in obj.items()}
elif isinstance(obj, list):
return [convert_decimals(item) for item in obj]
return obj
def load_parameters_registry(cur) -> Dict[str, Dict]: def load_parameters_registry(cur) -> Dict[str, Dict]:
""" """
Loads training parameters registry from database. Loads training parameters registry from database.
@ -145,17 +161,24 @@ def evaluate_and_save_activity(
lookback_days=30 lookback_days=30
) )
# Convert Decimal values in activity_data and context
activity_data_clean = convert_decimals(activity_data)
context_clean = convert_decimals(context)
# Evaluate # Evaluate
evaluator = TrainingProfileEvaluator(parameters) evaluator = TrainingProfileEvaluator(parameters)
evaluation_result = evaluator.evaluate_activity( evaluation_result = evaluator.evaluate_activity(
activity_data, activity_data_clean,
profile, profile,
context context_clean
) )
# Save to database # Save to database
from psycopg2.extras import Json from psycopg2.extras import Json
# Convert Decimal to float for JSON serialization
evaluation_result_clean = convert_decimals(evaluation_result)
cur.execute(""" cur.execute("""
UPDATE activity_log UPDATE activity_log
SET evaluation = %s, SET evaluation = %s,
@ -163,9 +186,9 @@ def evaluate_and_save_activity(
overall_score = %s overall_score = %s
WHERE id = %s WHERE id = %s
""", ( """, (
Json(evaluation_result), Json(evaluation_result_clean),
evaluation_result.get("quality_label"), evaluation_result_clean.get("quality_label"),
evaluation_result.get("overall_score"), evaluation_result_clean.get("overall_score"),
activity_id activity_id
)) ))