Skip to content

Commit cf9ec3e

Browse files
authored
feat(cost-tracking): trace all usage keys (#1021)
1 parent 4945318 commit cf9ec3e

20 files changed

+349
-66
lines changed

langfuse/api/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
ObservationsView,
8888
ObservationsViews,
8989
OpenAiUsage,
90+
OpenAiUsageSchema,
9091
OptionalObservationBody,
9192
PaginatedDatasetItems,
9293
PaginatedDatasetRuns,
@@ -133,6 +134,7 @@
133134
UpdateSpanEvent,
134135
Usage,
135136
UsageByModel,
137+
UsageDetails,
136138
comments,
137139
commons,
138140
dataset_items,
@@ -240,6 +242,7 @@
240242
"ObservationsView",
241243
"ObservationsViews",
242244
"OpenAiUsage",
245+
"OpenAiUsageSchema",
243246
"OptionalObservationBody",
244247
"PaginatedDatasetItems",
245248
"PaginatedDatasetRuns",
@@ -286,6 +289,7 @@
286289
"UpdateSpanEvent",
287290
"Usage",
288291
"UsageByModel",
292+
"UsageDetails",
289293
"comments",
290294
"commons",
291295
"dataset_items",

langfuse/api/resources/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
ObservationBody,
9393
ObservationType,
9494
OpenAiUsage,
95+
OpenAiUsageSchema,
9596
OptionalObservationBody,
9697
ScoreBody,
9798
ScoreEvent,
@@ -105,6 +106,7 @@
105106
UpdateObservationEvent,
106107
UpdateSpanBody,
107108
UpdateSpanEvent,
109+
UsageDetails,
108110
)
109111
from .media import (
110112
GetMediaResponse,
@@ -237,6 +239,7 @@
237239
"ObservationsView",
238240
"ObservationsViews",
239241
"OpenAiUsage",
242+
"OpenAiUsageSchema",
240243
"OptionalObservationBody",
241244
"PaginatedDatasetItems",
242245
"PaginatedDatasetRuns",
@@ -283,6 +286,7 @@
283286
"UpdateSpanEvent",
284287
"Usage",
285288
"UsageByModel",
289+
"UsageDetails",
286290
"comments",
287291
"commons",
288292
"dataset_items",

langfuse/api/resources/comments/types/create_comment_request.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class CreateCommentRequest(pydantic_v1.BaseModel):
2525

2626
content: str = pydantic_v1.Field()
2727
"""
28-
The content of the comment. May include markdown. Currently limited to 500 characters.
28+
The content of the comment. May include markdown. Currently limited to 3000 characters.
2929
"""
3030

3131
author_user_id: typing.Optional[str] = pydantic_v1.Field(

langfuse/api/resources/commons/types/observation.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class Observation(pydantic_v1.BaseModel):
8484

8585
usage: typing.Optional[Usage] = pydantic_v1.Field(default=None)
8686
"""
87-
The usage data of the observation
87+
(Deprecated. Use usageDetails and costDetails instead.) The usage data of the observation
8888
"""
8989

9090
level: ObservationLevel = pydantic_v1.Field()
@@ -111,6 +111,20 @@ class Observation(pydantic_v1.BaseModel):
111111
The prompt ID associated with the observation
112112
"""
113113

114+
usage_details: typing.Optional[typing.Dict[str, int]] = pydantic_v1.Field(
115+
alias="usageDetails", default=None
116+
)
117+
"""
118+
The usage details of the observation. Key is the name of the usage metric, value is the number of units consumed. The total key is the sum of all (non-total) usage metrics or the total value ingested.
119+
"""
120+
121+
cost_details: typing.Optional[typing.Dict[str, float]] = pydantic_v1.Field(
122+
alias="costDetails", default=None
123+
)
124+
"""
125+
The cost details of the observation. Key is the name of the cost metric, value is the cost in USD. The total key is the sum of all (non-total) cost metrics or the total value ingested.
126+
"""
127+
114128
def json(self, **kwargs: typing.Any) -> str:
115129
kwargs_with_defaults: typing.Any = {
116130
"by_alias": True,

langfuse/api/resources/commons/types/observations_view.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -53,21 +53,21 @@ class ObservationsView(Observation):
5353
alias="calculatedInputCost", default=None
5454
)
5555
"""
56-
The calculated cost of the input in USD
56+
(Deprecated. Use usageDetails and costDetails instead.) The calculated cost of the input in USD
5757
"""
5858

5959
calculated_output_cost: typing.Optional[float] = pydantic_v1.Field(
6060
alias="calculatedOutputCost", default=None
6161
)
6262
"""
63-
The calculated cost of the output in USD
63+
(Deprecated. Use usageDetails and costDetails instead.) The calculated cost of the output in USD
6464
"""
6565

6666
calculated_total_cost: typing.Optional[float] = pydantic_v1.Field(
6767
alias="calculatedTotalCost", default=None
6868
)
6969
"""
70-
The calculated total cost in USD
70+
(Deprecated. Use usageDetails and costDetails instead.) The calculated total cost in USD
7171
"""
7272

7373
latency: typing.Optional[float] = pydantic_v1.Field(default=None)

langfuse/api/resources/commons/types/usage.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
class Usage(pydantic_v1.BaseModel):
1212
"""
13-
Standard interface for usage and cost
13+
(Deprecated. Use usageDetails and costDetails instead.) Standard interface for usage and cost
1414
"""
1515

1616
input: typing.Optional[int] = pydantic_v1.Field(default=None)

langfuse/api/resources/ingestion/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
ObservationBody,
2828
ObservationType,
2929
OpenAiUsage,
30+
OpenAiUsageSchema,
3031
OptionalObservationBody,
3132
ScoreBody,
3233
ScoreEvent,
@@ -40,6 +41,7 @@
4041
UpdateObservationEvent,
4142
UpdateSpanBody,
4243
UpdateSpanEvent,
44+
UsageDetails,
4345
)
4446

4547
__all__ = [
@@ -69,6 +71,7 @@
6971
"ObservationBody",
7072
"ObservationType",
7173
"OpenAiUsage",
74+
"OpenAiUsageSchema",
7275
"OptionalObservationBody",
7376
"ScoreBody",
7477
"ScoreEvent",
@@ -82,4 +85,5 @@
8285
"UpdateObservationEvent",
8386
"UpdateSpanBody",
8487
"UpdateSpanEvent",
88+
"UsageDetails",
8589
]

langfuse/api/resources/ingestion/types/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from .observation_body import ObservationBody
2929
from .observation_type import ObservationType
3030
from .open_ai_usage import OpenAiUsage
31+
from .open_ai_usage_schema import OpenAiUsageSchema
3132
from .optional_observation_body import OptionalObservationBody
3233
from .score_body import ScoreBody
3334
from .score_event import ScoreEvent
@@ -41,6 +42,7 @@
4142
from .update_observation_event import UpdateObservationEvent
4243
from .update_span_body import UpdateSpanBody
4344
from .update_span_event import UpdateSpanEvent
45+
from .usage_details import UsageDetails
4446

4547
__all__ = [
4648
"BaseEvent",
@@ -69,6 +71,7 @@
6971
"ObservationBody",
7072
"ObservationType",
7173
"OpenAiUsage",
74+
"OpenAiUsageSchema",
7275
"OptionalObservationBody",
7376
"ScoreBody",
7477
"ScoreEvent",
@@ -82,4 +85,5 @@
8285
"UpdateObservationEvent",
8386
"UpdateSpanBody",
8487
"UpdateSpanEvent",
88+
"UsageDetails",
8589
]

langfuse/api/resources/ingestion/types/create_generation_body.py

+7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from ...commons.types.map_value import MapValue
99
from .create_span_body import CreateSpanBody
1010
from .ingestion_usage import IngestionUsage
11+
from .usage_details import UsageDetails
1112

1213

1314
class CreateGenerationBody(CreateSpanBody):
@@ -19,6 +20,12 @@ class CreateGenerationBody(CreateSpanBody):
1920
alias="modelParameters", default=None
2021
)
2122
usage: typing.Optional[IngestionUsage] = None
23+
usage_details: typing.Optional[UsageDetails] = pydantic_v1.Field(
24+
alias="usageDetails", default=None
25+
)
26+
cost_details: typing.Optional[typing.Dict[str, float]] = pydantic_v1.Field(
27+
alias="costDetails", default=None
28+
)
2229
prompt_name: typing.Optional[str] = pydantic_v1.Field(
2330
alias="promptName", default=None
2431
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# This file was auto-generated by Fern from our API Definition.
2+
3+
import datetime as dt
4+
import typing
5+
6+
from ....core.datetime_utils import serialize_datetime
7+
from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
8+
9+
10+
class OpenAiUsageSchema(pydantic_v1.BaseModel):
11+
prompt_tokens: int
12+
completion_tokens: int
13+
total_tokens: int
14+
prompt_tokens_details: typing.Optional[typing.Dict[str, int]] = None
15+
completion_tokens_details: typing.Optional[typing.Dict[str, int]] = None
16+
17+
def json(self, **kwargs: typing.Any) -> str:
18+
kwargs_with_defaults: typing.Any = {
19+
"by_alias": True,
20+
"exclude_unset": True,
21+
**kwargs,
22+
}
23+
return super().json(**kwargs_with_defaults)
24+
25+
def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
26+
kwargs_with_defaults_exclude_unset: typing.Any = {
27+
"by_alias": True,
28+
"exclude_unset": True,
29+
**kwargs,
30+
}
31+
kwargs_with_defaults_exclude_none: typing.Any = {
32+
"by_alias": True,
33+
"exclude_none": True,
34+
**kwargs,
35+
}
36+
37+
return deep_union_pydantic_dicts(
38+
super().dict(**kwargs_with_defaults_exclude_unset),
39+
super().dict(**kwargs_with_defaults_exclude_none),
40+
)
41+
42+
class Config:
43+
frozen = True
44+
smart_union = True
45+
extra = pydantic_v1.Extra.allow
46+
json_encoders = {dt.datetime: serialize_datetime}

langfuse/api/resources/ingestion/types/update_generation_body.py

+7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from ...commons.types.map_value import MapValue
99
from .ingestion_usage import IngestionUsage
1010
from .update_span_body import UpdateSpanBody
11+
from .usage_details import UsageDetails
1112

1213

1314
class UpdateGenerationBody(UpdateSpanBody):
@@ -22,6 +23,12 @@ class UpdateGenerationBody(UpdateSpanBody):
2223
prompt_name: typing.Optional[str] = pydantic_v1.Field(
2324
alias="promptName", default=None
2425
)
26+
usage_details: typing.Optional[UsageDetails] = pydantic_v1.Field(
27+
alias="usageDetails", default=None
28+
)
29+
cost_details: typing.Optional[typing.Dict[str, float]] = pydantic_v1.Field(
30+
alias="costDetails", default=None
31+
)
2532
prompt_version: typing.Optional[int] = pydantic_v1.Field(
2633
alias="promptVersion", default=None
2734
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# This file was auto-generated by Fern from our API Definition.
2+
3+
import typing
4+
5+
from .open_ai_usage_schema import OpenAiUsageSchema
6+
7+
UsageDetails = typing.Union[typing.Dict[str, int], OpenAiUsageSchema]

langfuse/api/resources/media/client.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ def get_upload_url(
197197
198198
Examples
199199
--------
200-
from langfuse.api import GetMediaUploadUrlRequest
200+
from langfuse.api import GetMediaUploadUrlRequest, MediaContentType
201201
from langfuse.api.client import FernLangfuse
202202
203203
client = FernLangfuse(
@@ -212,6 +212,7 @@ def get_upload_url(
212212
request=GetMediaUploadUrlRequest(
213213
trace_id="string",
214214
observation_id="string",
215+
content_type=MediaContentType.IMAGE_PNG,
215216
content_length=1,
216217
sha_256_hash="string",
217218
field="string",
@@ -446,7 +447,7 @@ async def get_upload_url(
446447
--------
447448
import asyncio
448449
449-
from langfuse.api import GetMediaUploadUrlRequest
450+
from langfuse.api import GetMediaUploadUrlRequest, MediaContentType
450451
from langfuse.api.client import AsyncFernLangfuse
451452
452453
client = AsyncFernLangfuse(
@@ -464,6 +465,7 @@ async def main() -> None:
464465
request=GetMediaUploadUrlRequest(
465466
trace_id="string",
466467
observation_id="string",
468+
content_type=MediaContentType.IMAGE_PNG,
467469
content_length=1,
468470
sha_256_hash="string",
469471
field="string",

0 commit comments

Comments
 (0)