mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-16 23:41:43 +00:00
fix(mavvrik_focus): carry prompt/completion token counts in FOCUS Tags
FOCUS v1.2 has no standard column for LLM token counts, and the shared FocusTransformer used by every destination (Mavvrik, Vantage, CloudZero) drops prompt_tokens/completion_tokens even though the source query already selects them. Merge the two counts into the existing Tags JSON column, which is the spec's own escape hatch for non-standard fields, inside the Mavvrik-only export path so no shared transformer changes.
This commit is contained in:
parent
6375923f65
commit
a58ab8b19a
1 changed files with 37 additions and 0 deletions
|
|
@ -19,10 +19,13 @@ overwrite each other within the same day, producing incomplete data.
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import TYPE_CHECKING, Any, List, Optional
|
||||
|
||||
import polars as pl
|
||||
|
||||
import litellm
|
||||
from litellm._logging import verbose_proxy_logger
|
||||
from litellm.constants import MAVVRIK_FOCUS_EXPORT_JOB_NAME
|
||||
|
|
@ -34,6 +37,39 @@ if TYPE_CHECKING:
|
|||
else:
|
||||
AsyncIOScheduler = Any
|
||||
|
||||
# FOCUS v1.2 has no standard column for token counts; core's transformer
|
||||
# drops prompt_tokens/completion_tokens even though the source query selects
|
||||
# them. Mavvrik carries them through as extra keys in the existing Tags JSON
|
||||
# column (the spec's own escape hatch for non-standard fields), rather than
|
||||
# changing the shared transformer used by every FOCUS destination.
|
||||
_TOKEN_TAG_KEYS = ("prompt_tokens", "completion_tokens")
|
||||
|
||||
|
||||
def _with_token_tags(data: pl.DataFrame, normalized: pl.DataFrame) -> pl.DataFrame:
|
||||
"""Merge prompt/completion token counts from the pre-transform frame into
|
||||
``normalized``'s Tags column. Rows correspond 1:1 and in the same order
|
||||
across both frames -- transform() only adds/renames columns, it never
|
||||
filters or reorders rows.
|
||||
"""
|
||||
available = [k for k in _TOKEN_TAG_KEYS if k in data.columns]
|
||||
if not available or len(data) != len(normalized):
|
||||
return normalized
|
||||
|
||||
token_rows = data.select(available).to_dicts()
|
||||
|
||||
def _merge(tags_json: str, row: dict) -> str:
|
||||
tags = json.loads(tags_json) if tags_json else {}
|
||||
for key in available:
|
||||
value = row.get(key)
|
||||
if value is not None:
|
||||
tags[key] = str(value)
|
||||
return json.dumps(tags)
|
||||
|
||||
merged_tags = pl.Series(
|
||||
[_merge(tags_json, row) for tags_json, row in zip(normalized["Tags"].to_list(), token_rows)]
|
||||
)
|
||||
return normalized.with_columns(merged_tags.alias("Tags"))
|
||||
|
||||
|
||||
def _parse_metrics_marker(
|
||||
marker: Optional[object],
|
||||
|
|
@ -136,6 +172,7 @@ class MavvrikFocusLogger(FocusLogger):
|
|||
else:
|
||||
normalized = engine._transformer.transform(data)
|
||||
if not normalized.is_empty():
|
||||
normalized = _with_token_tags(data, normalized)
|
||||
payload = engine._serializer.serialize(normalized)
|
||||
await engine._destination.deliver(
|
||||
content=payload or b"",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue