From cd206076288a36743afb94d4b03ffd6c3fa9cd93 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Thu, 23 Jul 2026 16:58:41 +0530 Subject: [PATCH] fix: cast usage run filter JSON values to Float instead of Integer (#574) The duration and tokenUsage numberRange filters cast the JSON text value to INTEGER, but some rows store call_duration_seconds as a JSON float (0.0, written by get_call_duration when the pipeline never recorded a start time). Postgres cannot cast the text '0.0' to integer, so any duration filter on /organizations/usage/runs failed with InvalidTextRepresentationError. Cast to FLOAT instead, matching the duration sort clause, and make get_call_duration return an int so new rows are written as integers. Co-authored-by: Claude Fable 5 --- api/db/filters.py | 17 ++++++++--------- .../pipecat/pipeline_metrics_aggregator.py | 4 ++-- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/api/db/filters.py b/api/db/filters.py index cd30b144..8e3458e5 100644 --- a/api/db/filters.py +++ b/api/db/filters.py @@ -3,7 +3,7 @@ from datetime import datetime from typing import Any, Dict, List, Optional -from sqlalchemy import Float, Integer, Text, and_, cast, func +from sqlalchemy import Float, Text, and_, cast, func from sqlalchemy.dialects.postgresql import JSONB from api.db.models import WorkflowRunModel @@ -211,17 +211,16 @@ def apply_workflow_run_filters( if field == "usage_info.call_duration_seconds": # Use ->> operator for compatibility with all PostgreSQL versions # (subscript [] only works in PostgreSQL 14+) + # Cast to Float, not Integer: some rows store the value as + # a JSON float (e.g. 0.0), and Postgres can't cast the text + # '0.0' to integer. duration_text = cast(WorkflowRunModel.usage_info, JSONB).op("->>")( "call_duration_seconds" ) if min_val is not None: - filter_conditions.append( - cast(duration_text, Integer) >= min_val - ) + filter_conditions.append(cast(duration_text, Float) >= min_val) if max_val is not None: - filter_conditions.append( - cast(duration_text, Integer) <= max_val - ) + filter_conditions.append(cast(duration_text, Float) <= max_val) elif field == "cost_info.total_cost_usd": # Use ->> operator for compatibility with all PostgreSQL versions @@ -229,9 +228,9 @@ def apply_workflow_run_filters( "total_cost_usd" ) if min_val is not None: - filter_conditions.append(cast(cost_text, Integer) >= min_val) + filter_conditions.append(cast(cost_text, Float) >= min_val) if max_val is not None: - filter_conditions.append(cast(cost_text, Integer) <= max_val) + filter_conditions.append(cast(cost_text, Float) <= max_val) if filter_conditions: base_query = base_query.where(and_(*filter_conditions)) diff --git a/api/services/pipecat/pipeline_metrics_aggregator.py b/api/services/pipecat/pipeline_metrics_aggregator.py index 361f4b90..4861f92d 100644 --- a/api/services/pipecat/pipeline_metrics_aggregator.py +++ b/api/services/pipecat/pipeline_metrics_aggregator.py @@ -113,10 +113,10 @@ class PipelineMetricsAggregator(FrameProcessor): """Get the aggregated STT usage metrics grouped by processor|||model.""" return self._stt_usage_metrics - def get_call_duration(self) -> float: + def get_call_duration(self) -> int: """Get call duration""" if self._start_time is None: - return 0.0 + return 0 if self._stop_time is None: call_duration = time.time() - self._start_time