payi 0.1.0a77__py3-none-any.whl → 0.1.0a78__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of payi might be problematic. Click here for more details.
- payi/_version.py +1 -1
- payi/lib/AnthropicInstrumentor.py +43 -9
- payi/lib/BedrockInstrumentor.py +6 -2
- payi/lib/GoogleGenAiInstrumentor.py +370 -0
- payi/lib/OpenAIInstrumentor.py +6 -2
- payi/lib/VertexInstrumentor.py +8 -5
- payi/lib/instrument.py +109 -41
- {payi-0.1.0a77.dist-info → payi-0.1.0a78.dist-info}/METADATA +1 -1
- {payi-0.1.0a77.dist-info → payi-0.1.0a78.dist-info}/RECORD +11 -10
- {payi-0.1.0a77.dist-info → payi-0.1.0a78.dist-info}/WHEEL +0 -0
- {payi-0.1.0a77.dist-info → payi-0.1.0a78.dist-info}/licenses/LICENSE +0 -0
payi/_version.py
CHANGED
|
@@ -8,7 +8,7 @@ from wrapt import wrap_function_wrapper # type: ignore
|
|
|
8
8
|
from payi.lib.helpers import PayiCategories
|
|
9
9
|
from payi.types.ingest_units_params import Units
|
|
10
10
|
|
|
11
|
-
from .instrument import _IsStreaming, _ProviderRequest, _PayiInstrumentor
|
|
11
|
+
from .instrument import _IsStreaming, _StreamingType, _ProviderRequest, _PayiInstrumentor
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class AnthropicInstrumentor:
|
|
@@ -32,7 +32,7 @@ class AnthropicInstrumentor:
|
|
|
32
32
|
wrap_function_wrapper(
|
|
33
33
|
"anthropic.resources.messages",
|
|
34
34
|
"Messages.stream",
|
|
35
|
-
|
|
35
|
+
stream_messages_wrapper(instrumentor),
|
|
36
36
|
)
|
|
37
37
|
|
|
38
38
|
wrap_function_wrapper(
|
|
@@ -44,7 +44,7 @@ class AnthropicInstrumentor:
|
|
|
44
44
|
wrap_function_wrapper(
|
|
45
45
|
"anthropic.resources.messages",
|
|
46
46
|
"AsyncMessages.stream",
|
|
47
|
-
|
|
47
|
+
astream_messages_wrapper(instrumentor),
|
|
48
48
|
)
|
|
49
49
|
|
|
50
50
|
except Exception as e:
|
|
@@ -61,7 +61,7 @@ def messages_wrapper(
|
|
|
61
61
|
**kwargs: Any,
|
|
62
62
|
) -> Any:
|
|
63
63
|
return instrumentor.invoke_wrapper(
|
|
64
|
-
_AnthropicProviderRequest(instrumentor, instance),
|
|
64
|
+
_AnthropicProviderRequest(instrumentor=instrumentor, streaming_type=_StreamingType.iterator, instance=instance),
|
|
65
65
|
_IsStreaming.kwargs,
|
|
66
66
|
wrapped,
|
|
67
67
|
instance,
|
|
@@ -69,6 +69,23 @@ def messages_wrapper(
|
|
|
69
69
|
kwargs,
|
|
70
70
|
)
|
|
71
71
|
|
|
72
|
+
@_PayiInstrumentor.payi_wrapper
|
|
73
|
+
def stream_messages_wrapper(
|
|
74
|
+
instrumentor: _PayiInstrumentor,
|
|
75
|
+
wrapped: Any,
|
|
76
|
+
instance: Any,
|
|
77
|
+
*args: Any,
|
|
78
|
+
**kwargs: Any,
|
|
79
|
+
) -> Any:
|
|
80
|
+
return instrumentor.invoke_wrapper(
|
|
81
|
+
_AnthropicProviderRequest(instrumentor=instrumentor, streaming_type=_StreamingType.stream_manager, instance=instance),
|
|
82
|
+
_IsStreaming.true,
|
|
83
|
+
wrapped,
|
|
84
|
+
instance,
|
|
85
|
+
args,
|
|
86
|
+
kwargs,
|
|
87
|
+
)
|
|
88
|
+
|
|
72
89
|
@_PayiInstrumentor.payi_awrapper
|
|
73
90
|
async def amessages_wrapper(
|
|
74
91
|
instrumentor: _PayiInstrumentor,
|
|
@@ -78,7 +95,7 @@ async def amessages_wrapper(
|
|
|
78
95
|
**kwargs: Any,
|
|
79
96
|
) -> Any:
|
|
80
97
|
return await instrumentor.async_invoke_wrapper(
|
|
81
|
-
_AnthropicProviderRequest(instrumentor, instance),
|
|
98
|
+
_AnthropicProviderRequest(instrumentor=instrumentor, streaming_type=_StreamingType.iterator, instance=instance),
|
|
82
99
|
_IsStreaming.kwargs,
|
|
83
100
|
wrapped,
|
|
84
101
|
instance,
|
|
@@ -86,12 +103,30 @@ async def amessages_wrapper(
|
|
|
86
103
|
kwargs,
|
|
87
104
|
)
|
|
88
105
|
|
|
106
|
+
@_PayiInstrumentor.payi_awrapper
|
|
107
|
+
async def astream_messages_wrapper(
|
|
108
|
+
instrumentor: _PayiInstrumentor,
|
|
109
|
+
wrapped: Any,
|
|
110
|
+
instance: Any,
|
|
111
|
+
*args: Any,
|
|
112
|
+
**kwargs: Any,
|
|
113
|
+
) -> Any:
|
|
114
|
+
return await instrumentor.async_invoke_wrapper(
|
|
115
|
+
_AnthropicProviderRequest(instrumentor=instrumentor, streaming_type=_StreamingType.stream_manager, instance=instance),
|
|
116
|
+
_IsStreaming.true,
|
|
117
|
+
wrapped,
|
|
118
|
+
instance,
|
|
119
|
+
args,
|
|
120
|
+
kwargs,
|
|
121
|
+
)
|
|
122
|
+
|
|
89
123
|
class _AnthropicProviderRequest(_ProviderRequest):
|
|
90
|
-
def __init__(self, instrumentor: _PayiInstrumentor, instance: Any = None) -> None:
|
|
124
|
+
def __init__(self, instrumentor: _PayiInstrumentor, streaming_type: _StreamingType, instance: Any = None) -> None:
|
|
91
125
|
self._vertex: bool = AnthropicInstrumentor.is_vertex(instance)
|
|
92
126
|
super().__init__(
|
|
93
127
|
instrumentor=instrumentor,
|
|
94
|
-
category=PayiCategories.google_vertex if self._vertex else PayiCategories.anthropic
|
|
128
|
+
category=PayiCategories.google_vertex if self._vertex else PayiCategories.anthropic,
|
|
129
|
+
streaming_type=streaming_type,
|
|
95
130
|
)
|
|
96
131
|
|
|
97
132
|
@override
|
|
@@ -209,5 +244,4 @@ def has_image_and_get_texts(encoding: tiktoken.Encoding, content: Union[str, 'li
|
|
|
209
244
|
token_count = sum(len(encoding.encode(item.get("text", ""))) for item in content if item.get("type") == "text")
|
|
210
245
|
return has_image, token_count
|
|
211
246
|
|
|
212
|
-
return False, 0
|
|
213
|
-
|
|
247
|
+
return False, 0
|
payi/lib/BedrockInstrumentor.py
CHANGED
|
@@ -11,7 +11,7 @@ from payi.lib.helpers import PayiCategories, PayiHeaderNames, payi_aws_bedrock_u
|
|
|
11
11
|
from payi.types.ingest_units_params import Units, IngestUnitsParams
|
|
12
12
|
from payi.types.pay_i_common_models_api_router_header_info_param import PayICommonModelsAPIRouterHeaderInfoParam
|
|
13
13
|
|
|
14
|
-
from .instrument import _IsStreaming, _ProviderRequest, _PayiInstrumentor
|
|
14
|
+
from .instrument import _IsStreaming, _StreamingType, _ProviderRequest, _PayiInstrumentor
|
|
15
15
|
|
|
16
16
|
_supported_model_prefixes = ["meta.llama3", "anthropic.", "amazon.nova-pro", "amazon.nova-lite", "amazon.nova-micro"]
|
|
17
17
|
|
|
@@ -216,7 +216,11 @@ def wrap_converse_stream(instrumentor: _PayiInstrumentor, wrapped: Any) -> Any:
|
|
|
216
216
|
|
|
217
217
|
class _BedrockProviderRequest(_ProviderRequest):
|
|
218
218
|
def __init__(self, instrumentor: _PayiInstrumentor):
|
|
219
|
-
super().__init__(
|
|
219
|
+
super().__init__(
|
|
220
|
+
instrumentor=instrumentor,
|
|
221
|
+
category=PayiCategories.aws_bedrock,
|
|
222
|
+
streaming_type=_StreamingType.iterator,
|
|
223
|
+
)
|
|
220
224
|
|
|
221
225
|
@override
|
|
222
226
|
def process_request(self, instance: Any, extra_headers: 'dict[str, str]', args: Sequence[Any], kwargs: Any) -> bool:
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import math
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Any, List, Union, Optional, Sequence
|
|
5
|
+
from typing_extensions import override
|
|
6
|
+
|
|
7
|
+
from wrapt import wrap_function_wrapper # type: ignore
|
|
8
|
+
|
|
9
|
+
from payi.lib.helpers import PayiCategories
|
|
10
|
+
from payi.types.ingest_units_params import Units
|
|
11
|
+
|
|
12
|
+
from .instrument import _IsStreaming, _StreamingType, _ProviderRequest, _PayiInstrumentor
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class GoogleGenAiInstrumentor:
|
|
16
|
+
@staticmethod
|
|
17
|
+
def instrument(instrumentor: _PayiInstrumentor) -> None:
|
|
18
|
+
try:
|
|
19
|
+
wrap_function_wrapper(
|
|
20
|
+
"google.genai.models",
|
|
21
|
+
"Models.generate_content",
|
|
22
|
+
generate_wrapper(instrumentor),
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
wrap_function_wrapper(
|
|
26
|
+
"google.genai.models",
|
|
27
|
+
"Models.generate_content_stream",
|
|
28
|
+
generate_stream_wrapper(instrumentor),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
wrap_function_wrapper(
|
|
32
|
+
"google.genai.models",
|
|
33
|
+
"AsyncModels.generate_content",
|
|
34
|
+
agenerate_wrapper(instrumentor),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
wrap_function_wrapper(
|
|
38
|
+
"google.genai.models",
|
|
39
|
+
"AsyncModels.generate_content_stream",
|
|
40
|
+
agenerate_stream_wrapper(instrumentor),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
except Exception as e:
|
|
44
|
+
logging.debug(f"Error instrumenting vertex: {e}")
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
@_PayiInstrumentor.payi_wrapper
|
|
48
|
+
def generate_wrapper(
|
|
49
|
+
instrumentor: _PayiInstrumentor,
|
|
50
|
+
wrapped: Any,
|
|
51
|
+
instance: Any,
|
|
52
|
+
*args: Any,
|
|
53
|
+
**kwargs: Any,
|
|
54
|
+
) -> Any:
|
|
55
|
+
return instrumentor.invoke_wrapper(
|
|
56
|
+
_GoogleGenAiRequest(instrumentor),
|
|
57
|
+
_IsStreaming.false,
|
|
58
|
+
wrapped,
|
|
59
|
+
instance,
|
|
60
|
+
args,
|
|
61
|
+
kwargs,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
@_PayiInstrumentor.payi_wrapper
|
|
65
|
+
def generate_stream_wrapper(
|
|
66
|
+
instrumentor: _PayiInstrumentor,
|
|
67
|
+
wrapped: Any,
|
|
68
|
+
instance: Any,
|
|
69
|
+
*args: Any,
|
|
70
|
+
**kwargs: Any,
|
|
71
|
+
) -> Any:
|
|
72
|
+
return instrumentor.invoke_wrapper(
|
|
73
|
+
_GoogleGenAiRequest(instrumentor),
|
|
74
|
+
_IsStreaming.true,
|
|
75
|
+
wrapped,
|
|
76
|
+
instance,
|
|
77
|
+
args,
|
|
78
|
+
kwargs,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
@_PayiInstrumentor.payi_awrapper
|
|
82
|
+
async def agenerate_wrapper(
|
|
83
|
+
instrumentor: _PayiInstrumentor,
|
|
84
|
+
wrapped: Any,
|
|
85
|
+
instance: Any,
|
|
86
|
+
*args: Any,
|
|
87
|
+
**kwargs: Any,
|
|
88
|
+
) -> Any:
|
|
89
|
+
return await instrumentor.async_invoke_wrapper(
|
|
90
|
+
_GoogleGenAiRequest(instrumentor),
|
|
91
|
+
_IsStreaming.false,
|
|
92
|
+
wrapped,
|
|
93
|
+
instance,
|
|
94
|
+
args,
|
|
95
|
+
kwargs,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
@_PayiInstrumentor.payi_wrapper
|
|
99
|
+
async def agenerate_stream_wrapper(
|
|
100
|
+
instrumentor: _PayiInstrumentor,
|
|
101
|
+
wrapped: Any,
|
|
102
|
+
instance: Any,
|
|
103
|
+
*args: Any,
|
|
104
|
+
**kwargs: Any,
|
|
105
|
+
) -> Any:
|
|
106
|
+
return await instrumentor.async_invoke_wrapper(
|
|
107
|
+
_GoogleGenAiRequest(instrumentor),
|
|
108
|
+
_IsStreaming.true,
|
|
109
|
+
wrapped,
|
|
110
|
+
instance,
|
|
111
|
+
args,
|
|
112
|
+
kwargs,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
def count_chars_skip_spaces(text: str) -> int:
|
|
116
|
+
return sum(1 for c in text if not c.isspace())
|
|
117
|
+
|
|
118
|
+
class _GoogleGenAiRequest(_ProviderRequest):
|
|
119
|
+
def __init__(self, instrumentor: _PayiInstrumentor):
|
|
120
|
+
super().__init__(
|
|
121
|
+
instrumentor=instrumentor,
|
|
122
|
+
category=PayiCategories.google_vertex,
|
|
123
|
+
streaming_type=_StreamingType.generator,
|
|
124
|
+
)
|
|
125
|
+
self._prompt_character_count = 0
|
|
126
|
+
self._candiates_character_count = 0
|
|
127
|
+
|
|
128
|
+
@override
|
|
129
|
+
def process_request(self, instance: Any, extra_headers: 'dict[str, str]', args: Sequence[Any], kwargs: Any) -> bool:
|
|
130
|
+
from google.genai.types import Content, PIL_Image, Part # type: ignore # noqa: F401 I001
|
|
131
|
+
|
|
132
|
+
if not kwargs:
|
|
133
|
+
return True
|
|
134
|
+
|
|
135
|
+
model: str = kwargs.get("model", "")
|
|
136
|
+
self._ingest["resource"] = "google." + model
|
|
137
|
+
|
|
138
|
+
value: Union[ # type: ignore
|
|
139
|
+
Content,
|
|
140
|
+
str,
|
|
141
|
+
PIL_Image,
|
|
142
|
+
Part,
|
|
143
|
+
List[Union[str, PIL_Image, Part]],
|
|
144
|
+
] = kwargs.get("contents", None) # type: ignore
|
|
145
|
+
|
|
146
|
+
items: List[Union[str, Image, Part]] = [] # type: ignore # noqa: F401 I001
|
|
147
|
+
|
|
148
|
+
if not value:
|
|
149
|
+
raise TypeError("value must not be empty")
|
|
150
|
+
|
|
151
|
+
if isinstance(value, Content):
|
|
152
|
+
items = value.parts # type: ignore
|
|
153
|
+
if isinstance(value, (str, PIL_Image, Part)):
|
|
154
|
+
items = [value] # type: ignore
|
|
155
|
+
if isinstance(value, list):
|
|
156
|
+
items = value # type: ignore
|
|
157
|
+
|
|
158
|
+
for item in items: # type: ignore
|
|
159
|
+
text = ""
|
|
160
|
+
if isinstance(item, Part):
|
|
161
|
+
d = item.to_json_dict() # type: ignore
|
|
162
|
+
if "text" in d:
|
|
163
|
+
text = d["text"] # type: ignore
|
|
164
|
+
elif isinstance(item, str):
|
|
165
|
+
text = item
|
|
166
|
+
|
|
167
|
+
if text != "":
|
|
168
|
+
self._prompt_character_count += count_chars_skip_spaces(text) # type: ignore
|
|
169
|
+
|
|
170
|
+
return True
|
|
171
|
+
|
|
172
|
+
@override
|
|
173
|
+
def process_request_prompt(self, prompt: 'dict[str, Any]', args: Sequence[Any], kwargs: 'dict[str, Any]') -> None:
|
|
174
|
+
from google.genai.types import Content, PIL_Image, Part, Tool, GenerateContentConfig, GenerateContentConfigDict, ToolConfig # type: ignore # noqa: F401 I001
|
|
175
|
+
|
|
176
|
+
key = "contents"
|
|
177
|
+
|
|
178
|
+
if not kwargs:
|
|
179
|
+
return
|
|
180
|
+
|
|
181
|
+
value: Union[ # type: ignore
|
|
182
|
+
Content,
|
|
183
|
+
str,
|
|
184
|
+
PIL_Image,
|
|
185
|
+
Part,
|
|
186
|
+
List[Union[str, PIL_Image, Part]],
|
|
187
|
+
] = kwargs.get("contents", None) # type: ignore
|
|
188
|
+
|
|
189
|
+
items: List[Union[str, Image, Part]] = [] # type: ignore # noqa: F401 I001
|
|
190
|
+
|
|
191
|
+
if not value:
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
if isinstance(value, str):
|
|
195
|
+
prompt[key] = Content(parts=[Part.from_text(text=value)]).to_json_dict() # type: ignore
|
|
196
|
+
elif isinstance(value, (PIL_Image, Part)):
|
|
197
|
+
prompt[key] = Content(parts=[value]).to_json_dict() # type: ignore
|
|
198
|
+
elif isinstance(value, Content):
|
|
199
|
+
prompt[key] = value.to_json_dict() # type: ignore
|
|
200
|
+
elif isinstance(value, list):
|
|
201
|
+
items = value # type: ignore
|
|
202
|
+
parts = []
|
|
203
|
+
|
|
204
|
+
for item in items: # type: ignore
|
|
205
|
+
if isinstance(item, str):
|
|
206
|
+
parts.append(Part.from_text(text=item)) # type: ignore
|
|
207
|
+
elif isinstance(item, Part):
|
|
208
|
+
parts.append(item) # type: ignore
|
|
209
|
+
# elif isinstance(item, PIL_Image): TODO
|
|
210
|
+
# parts.append(Part.from_image(item)) # type: ignore
|
|
211
|
+
|
|
212
|
+
prompt[key] = Content(parts=parts).to_json_dict() # type: ignore
|
|
213
|
+
|
|
214
|
+
# tools: Optional[list[Tool]] = kwargs.get("tools", None) # type: ignore
|
|
215
|
+
# if tools:
|
|
216
|
+
# t: list[dict[Any, Any]] = []
|
|
217
|
+
# for tool in tools: # type: ignore
|
|
218
|
+
# if isinstance(tool, Tool):
|
|
219
|
+
# t.append(tool.text=()) # type: ignore
|
|
220
|
+
# if t:
|
|
221
|
+
# prompt["tools"] = t
|
|
222
|
+
config_kwarg = kwargs.get("config", None) # type: ignore
|
|
223
|
+
if config_kwarg is None:
|
|
224
|
+
return
|
|
225
|
+
|
|
226
|
+
config: GenerateContentConfigDict = {}
|
|
227
|
+
if isinstance(config_kwarg, GenerateContentConfig):
|
|
228
|
+
config = config_kwarg.to_json_dict() # type: ignore
|
|
229
|
+
else:
|
|
230
|
+
config = config_kwarg
|
|
231
|
+
|
|
232
|
+
tools = config.get("tools", None) # type: ignore
|
|
233
|
+
if isinstance(tools, list):
|
|
234
|
+
t: list[dict[str, object]] = []
|
|
235
|
+
for tool in tools: # type: ignore
|
|
236
|
+
if isinstance(tool, Tool):
|
|
237
|
+
t.append(tool.to_json_dict()) # type: ignore
|
|
238
|
+
if t:
|
|
239
|
+
prompt["tools"] = t
|
|
240
|
+
|
|
241
|
+
tool_config = config.get("tool_config", None) # type: ignore
|
|
242
|
+
if isinstance(tool_config, ToolConfig):
|
|
243
|
+
prompt["tool_config"] = tool_config.to_json_dict() # type: ignore
|
|
244
|
+
elif isinstance(tool_config, dict):
|
|
245
|
+
prompt["tool_config"] = tool_config
|
|
246
|
+
|
|
247
|
+
@override
|
|
248
|
+
def process_chunk(self, chunk: Any) -> bool:
|
|
249
|
+
response_dict: dict[str, Any] = chunk.to_json_dict()
|
|
250
|
+
if "provider_response_id" not in self._ingest:
|
|
251
|
+
id = response_dict.get("response_id", None)
|
|
252
|
+
if id:
|
|
253
|
+
self._ingest["provider_response_id"] = id
|
|
254
|
+
|
|
255
|
+
model: str = response_dict.get("model_version", "")
|
|
256
|
+
|
|
257
|
+
self._ingest["resource"] = "google." + model
|
|
258
|
+
|
|
259
|
+
for candidate in response_dict.get("candidates", []):
|
|
260
|
+
parts = candidate.get("content", {}).get("parts", [])
|
|
261
|
+
for part in parts:
|
|
262
|
+
self._candiates_character_count += count_chars_skip_spaces(part.get("text", ""))
|
|
263
|
+
|
|
264
|
+
usage = response_dict.get("usage_metadata", {})
|
|
265
|
+
if usage and "prompt_token_count" in usage and "candidates_token_count" in usage:
|
|
266
|
+
self._compute_usage(response_dict, streaming_candidates_characters=self._candiates_character_count)
|
|
267
|
+
|
|
268
|
+
return True
|
|
269
|
+
|
|
270
|
+
@staticmethod
|
|
271
|
+
def _is_character_billing_model(model: str) -> bool:
|
|
272
|
+
return model.startswith("gemini-1.")
|
|
273
|
+
|
|
274
|
+
@override
|
|
275
|
+
def process_synchronous_response(
|
|
276
|
+
self,
|
|
277
|
+
response: Any,
|
|
278
|
+
log_prompt_and_response: bool,
|
|
279
|
+
kwargs: Any) -> Any:
|
|
280
|
+
response_dict = response.to_json_dict()
|
|
281
|
+
|
|
282
|
+
self._ingest["provider_response_id"] = response_dict["response_id"]
|
|
283
|
+
self._ingest["resource"] = "google." + response_dict["model_version"]
|
|
284
|
+
|
|
285
|
+
self._compute_usage(response_dict)
|
|
286
|
+
|
|
287
|
+
if log_prompt_and_response:
|
|
288
|
+
self._ingest["provider_response_json"] = [json.dumps(response_dict)]
|
|
289
|
+
|
|
290
|
+
return None
|
|
291
|
+
|
|
292
|
+
def add_units(self, key: str, input: Optional[int] = None, output: Optional[int] = None) -> None:
|
|
293
|
+
if key not in self._ingest["units"]:
|
|
294
|
+
self._ingest["units"][key] = {}
|
|
295
|
+
if input is not None:
|
|
296
|
+
self._ingest["units"][key]["input"] = input
|
|
297
|
+
if output is not None:
|
|
298
|
+
self._ingest["units"][key]["output"] = output
|
|
299
|
+
|
|
300
|
+
def _compute_usage(self, response_dict: 'dict[str, Any]', streaming_candidates_characters: Optional[int] = None) -> None:
|
|
301
|
+
usage = response_dict.get("usage_metadata", {})
|
|
302
|
+
input = usage.get("prompt_token_count", 0)
|
|
303
|
+
|
|
304
|
+
prompt_tokens_details: list[dict[str, Any]] = usage.get("prompt_tokens_details")
|
|
305
|
+
candidates_tokens_details: list[dict[str, Any]] = usage.get("candidates_tokens_details")
|
|
306
|
+
|
|
307
|
+
model: str = response_dict.get("model_version", "")
|
|
308
|
+
|
|
309
|
+
if self._is_character_billing_model(model):
|
|
310
|
+
# gemini 1.0 and 1.5 units are reported in characters, per second, per image, etc...
|
|
311
|
+
large_context = "" if input < 128000 else "_large_context"
|
|
312
|
+
|
|
313
|
+
for details in prompt_tokens_details:
|
|
314
|
+
modality = details.get("modality", "")
|
|
315
|
+
if not modality:
|
|
316
|
+
continue
|
|
317
|
+
|
|
318
|
+
modality_token_count = details.get("token_count", 0)
|
|
319
|
+
if modality == "TEXT":
|
|
320
|
+
input = self._prompt_character_count
|
|
321
|
+
if input == 0:
|
|
322
|
+
# back up calc if nothing was calculated from the prompt
|
|
323
|
+
input = response_dict["usage_metadata"]["prompt_token_count"] * 4
|
|
324
|
+
|
|
325
|
+
output = 0
|
|
326
|
+
if streaming_candidates_characters is None:
|
|
327
|
+
for candidate in response_dict.get("candidates", []):
|
|
328
|
+
parts = candidate.get("content", {}).get("parts", [])
|
|
329
|
+
for part in parts:
|
|
330
|
+
output += count_chars_skip_spaces(part.get("text", ""))
|
|
331
|
+
|
|
332
|
+
if output == 0:
|
|
333
|
+
# back up calc if no parts
|
|
334
|
+
output = response_dict["usage_metadata"]["candidates_token_count"] * 4
|
|
335
|
+
else:
|
|
336
|
+
output = streaming_candidates_characters
|
|
337
|
+
|
|
338
|
+
self._ingest["units"]["text"+large_context] = Units(input=input, output=output)
|
|
339
|
+
|
|
340
|
+
elif modality == "IMAGE":
|
|
341
|
+
num_images = math.ceil(modality_token_count / 258)
|
|
342
|
+
self.add_units("vision"+large_context, input=num_images)
|
|
343
|
+
|
|
344
|
+
elif modality == "VIDEO":
|
|
345
|
+
video_seconds = math.ceil(modality_token_count / 285)
|
|
346
|
+
self.add_units("video"+large_context, input=video_seconds)
|
|
347
|
+
|
|
348
|
+
elif modality == "AUDIO":
|
|
349
|
+
audio_seconds = math.ceil(modality_token_count / 25)
|
|
350
|
+
self.add_units("audio"+large_context, input=audio_seconds)
|
|
351
|
+
|
|
352
|
+
elif model.startswith("gemini-2.0"):
|
|
353
|
+
for details in prompt_tokens_details:
|
|
354
|
+
modality = details.get("modality", "")
|
|
355
|
+
if not modality:
|
|
356
|
+
continue
|
|
357
|
+
|
|
358
|
+
modality_token_count = details.get("token_count", 0)
|
|
359
|
+
if modality == "IMAGE":
|
|
360
|
+
self.add_units("vision", input=modality_token_count)
|
|
361
|
+
elif modality in ("VIDEO", "AUDIO", "TEXT"):
|
|
362
|
+
self.add_units(modality.lower(), input=modality_token_count)
|
|
363
|
+
for details in candidates_tokens_details:
|
|
364
|
+
modality = details.get("modality", "")
|
|
365
|
+
if not modality:
|
|
366
|
+
continue
|
|
367
|
+
|
|
368
|
+
modality_token_count = details.get("token_count", 0)
|
|
369
|
+
if modality in ("VIDEO", "AUDIO", "TEXT", "IMAGE"):
|
|
370
|
+
self.add_units(modality.lower(), output=modality_token_count)
|
payi/lib/OpenAIInstrumentor.py
CHANGED
|
@@ -10,7 +10,7 @@ from wrapt import wrap_function_wrapper # type: ignore
|
|
|
10
10
|
from payi.lib.helpers import PayiCategories, PayiHeaderNames
|
|
11
11
|
from payi.types.ingest_units_params import Units
|
|
12
12
|
|
|
13
|
-
from .instrument import _IsStreaming, _ProviderRequest, _PayiInstrumentor
|
|
13
|
+
from .instrument import _IsStreaming, _StreamingType, _ProviderRequest, _PayiInstrumentor
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class OpenAiInstrumentor:
|
|
@@ -178,7 +178,11 @@ class _OpenAiProviderRequest(_ProviderRequest):
|
|
|
178
178
|
responses_input_tokens_details_key: str = "input_tokens_details"
|
|
179
179
|
|
|
180
180
|
def __init__(self, instrumentor: _PayiInstrumentor, input_tokens_key: str, output_tokens_key: str, input_tokens_details_key: str) -> None:
|
|
181
|
-
super().__init__(
|
|
181
|
+
super().__init__(
|
|
182
|
+
instrumentor=instrumentor,
|
|
183
|
+
category=PayiCategories.openai,
|
|
184
|
+
streaming_type=_StreamingType.iterator,
|
|
185
|
+
)
|
|
182
186
|
self._input_tokens_key = input_tokens_key
|
|
183
187
|
self._output_tokens_key = output_tokens_key
|
|
184
188
|
self._input_tokens_details_key = input_tokens_details_key
|
payi/lib/VertexInstrumentor.py
CHANGED
|
@@ -9,7 +9,7 @@ from wrapt import wrap_function_wrapper # type: ignore
|
|
|
9
9
|
from payi.lib.helpers import PayiCategories
|
|
10
10
|
from payi.types.ingest_units_params import Units
|
|
11
11
|
|
|
12
|
-
from .instrument import _IsStreaming, _ProviderRequest, _PayiInstrumentor
|
|
12
|
+
from .instrument import _IsStreaming, _StreamingType, _ProviderRequest, _PayiInstrumentor
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class VertexInstrumentor:
|
|
@@ -85,7 +85,11 @@ def count_chars_skip_spaces(text: str) -> int:
|
|
|
85
85
|
|
|
86
86
|
class _GoogleVertexRequest(_ProviderRequest):
|
|
87
87
|
def __init__(self, instrumentor: _PayiInstrumentor):
|
|
88
|
-
super().__init__(
|
|
88
|
+
super().__init__(
|
|
89
|
+
instrumentor=instrumentor,
|
|
90
|
+
category=PayiCategories.google_vertex,
|
|
91
|
+
streaming_type=_StreamingType.generator,
|
|
92
|
+
)
|
|
89
93
|
self._prompt_character_count = 0
|
|
90
94
|
self._candiates_character_count = 0
|
|
91
95
|
|
|
@@ -110,11 +114,10 @@ class _GoogleVertexRequest(_ProviderRequest):
|
|
|
110
114
|
raise TypeError("value must not be empty")
|
|
111
115
|
|
|
112
116
|
if isinstance(value, Content):
|
|
113
|
-
|
|
117
|
+
items = value.parts # type: ignore
|
|
114
118
|
if isinstance(value, (str, Image, Part)):
|
|
115
119
|
items = [value] # type: ignore
|
|
116
|
-
|
|
117
|
-
elif isinstance(value, list):
|
|
120
|
+
if isinstance(value, list):
|
|
118
121
|
items = value # type: ignore
|
|
119
122
|
|
|
120
123
|
for item in items: # type: ignore
|
payi/lib/instrument.py
CHANGED
|
@@ -27,11 +27,12 @@ from .Stopwatch import Stopwatch
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
class _ProviderRequest:
|
|
30
|
-
def __init__(self, instrumentor: '_PayiInstrumentor', category: str):
|
|
30
|
+
def __init__(self, instrumentor: '_PayiInstrumentor', category: str, streaming_type: '_StreamingType'):
|
|
31
31
|
self._instrumentor: '_PayiInstrumentor' = instrumentor
|
|
32
32
|
self._estimated_prompt_tokens: Optional[int] = None
|
|
33
33
|
self._category: str = category
|
|
34
34
|
self._ingest: IngestUnitsParams = { "category": category, "units": {} } # type: ignore
|
|
35
|
+
self._streaming_type: '_StreamingType' = streaming_type
|
|
35
36
|
|
|
36
37
|
def process_chunk(self, _chunk: Any) -> bool:
|
|
37
38
|
return True
|
|
@@ -55,6 +56,10 @@ class _ProviderRequest:
|
|
|
55
56
|
def process_exception(self, exception: Exception, kwargs: Any, ) -> bool: # noqa: ARG002
|
|
56
57
|
self.exception_to_semantic_failure(exception)
|
|
57
58
|
return True
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def streaming_type(self) -> '_StreamingType':
|
|
62
|
+
return self._streaming_type
|
|
58
63
|
|
|
59
64
|
def exception_to_semantic_failure(self, e: Exception) -> None:
|
|
60
65
|
exception_str = f"{type(e).__name__}"
|
|
@@ -111,6 +116,11 @@ class _IsStreaming(Enum):
|
|
|
111
116
|
true = 1
|
|
112
117
|
kwargs = 2
|
|
113
118
|
|
|
119
|
+
class _StreamingType(Enum):
|
|
120
|
+
generator = 0
|
|
121
|
+
iterator = 1
|
|
122
|
+
stream_manager = 2
|
|
123
|
+
|
|
114
124
|
class _TrackContext:
|
|
115
125
|
def __init__(
|
|
116
126
|
self,
|
|
@@ -192,6 +202,7 @@ class _PayiInstrumentor:
|
|
|
192
202
|
self._instrument_anthropic()
|
|
193
203
|
self._instrument_aws_bedrock()
|
|
194
204
|
self._instrument_google_vertex()
|
|
205
|
+
self._instrument_google_genai()
|
|
195
206
|
|
|
196
207
|
def _instrument_specific(self, instruments: Set[str]) -> None:
|
|
197
208
|
if PayiCategories.openai in instruments or PayiCategories.azure_openai in instruments:
|
|
@@ -202,6 +213,7 @@ class _PayiInstrumentor:
|
|
|
202
213
|
self._instrument_aws_bedrock()
|
|
203
214
|
if PayiCategories.google_vertex in instruments:
|
|
204
215
|
self._instrument_google_vertex()
|
|
216
|
+
self._instrument_google_genai()
|
|
205
217
|
|
|
206
218
|
def _instrument_openai(self) -> None:
|
|
207
219
|
from .OpenAIInstrumentor import OpenAiInstrumentor
|
|
@@ -239,6 +251,14 @@ class _PayiInstrumentor:
|
|
|
239
251
|
except Exception as e:
|
|
240
252
|
logging.error(f"Error instrumenting Google Vertex: {e}")
|
|
241
253
|
|
|
254
|
+
def _instrument_google_genai(self) -> None:
|
|
255
|
+
from .GoogleGenAiInstrumentor import GoogleGenAiInstrumentor
|
|
256
|
+
|
|
257
|
+
try:
|
|
258
|
+
GoogleGenAiInstrumentor.instrument(self)
|
|
259
|
+
|
|
260
|
+
except Exception as e:
|
|
261
|
+
logging.error(f"Error instrumenting Google GenAi: {e}")
|
|
242
262
|
|
|
243
263
|
def _process_ingest_units(self, ingest_units: IngestUnitsParams, log_data: 'dict[str, str]') -> bool:
|
|
244
264
|
if int(ingest_units.get("http_status_code") or 0) < 400:
|
|
@@ -690,25 +710,30 @@ class _PayiInstrumentor:
|
|
|
690
710
|
raise e
|
|
691
711
|
|
|
692
712
|
if stream:
|
|
693
|
-
if request.
|
|
713
|
+
if request.streaming_type == _StreamingType.generator:
|
|
694
714
|
return _GeneratorWrapper(
|
|
695
715
|
generator=response,
|
|
696
716
|
instance=instance,
|
|
697
717
|
instrumentor=self,
|
|
698
718
|
stopwatch=sw,
|
|
699
719
|
request=request,
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
720
|
+
)
|
|
721
|
+
elif request.streaming_type == _StreamingType.stream_manager:
|
|
722
|
+
return _StreamManagerWrapper(
|
|
723
|
+
stream_manager=response,
|
|
724
|
+
instance=instance,
|
|
725
|
+
instrumentor=self,
|
|
726
|
+
stopwatch=sw,
|
|
727
|
+
request=request,
|
|
728
|
+
)
|
|
729
|
+
else:
|
|
730
|
+
return _StreamIteratorWrapper(
|
|
731
|
+
response=response,
|
|
732
|
+
instance=instance,
|
|
733
|
+
instrumentor=self,
|
|
734
|
+
stopwatch=sw,
|
|
735
|
+
request=request,
|
|
736
|
+
)
|
|
712
737
|
|
|
713
738
|
sw.stop()
|
|
714
739
|
duration = sw.elapsed_ms_int()
|
|
@@ -797,32 +822,40 @@ class _PayiInstrumentor:
|
|
|
797
822
|
raise e
|
|
798
823
|
|
|
799
824
|
if stream:
|
|
800
|
-
if request.
|
|
825
|
+
if request.streaming_type == _StreamingType.generator:
|
|
801
826
|
return _GeneratorWrapper(
|
|
802
827
|
generator=response,
|
|
803
828
|
instance=instance,
|
|
804
829
|
instrumentor=self,
|
|
805
830
|
stopwatch=sw,
|
|
806
831
|
request=request,
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
832
|
+
)
|
|
833
|
+
elif request.streaming_type == _StreamingType.stream_manager:
|
|
834
|
+
return _StreamManagerWrapper(
|
|
835
|
+
stream_manager=response,
|
|
836
|
+
instance=instance,
|
|
837
|
+
instrumentor=self,
|
|
838
|
+
stopwatch=sw,
|
|
839
|
+
request=request,
|
|
840
|
+
)
|
|
841
|
+
else:
|
|
842
|
+
# request.streaming_type == _StreamingType.iterator
|
|
843
|
+
stream_result = _StreamIteratorWrapper(
|
|
844
|
+
response=response,
|
|
845
|
+
instance=instance,
|
|
846
|
+
instrumentor=self,
|
|
847
|
+
stopwatch=sw,
|
|
848
|
+
request=request,
|
|
849
|
+
)
|
|
817
850
|
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
851
|
+
if request.is_bedrock():
|
|
852
|
+
if "body" in response:
|
|
853
|
+
response["body"] = stream_result
|
|
854
|
+
else:
|
|
855
|
+
response["stream"] = stream_result
|
|
856
|
+
return response
|
|
857
|
+
|
|
858
|
+
return stream_result
|
|
826
859
|
|
|
827
860
|
sw.stop()
|
|
828
861
|
duration = sw.elapsed_ms_int()
|
|
@@ -986,7 +1019,7 @@ class _PayiInstrumentor:
|
|
|
986
1019
|
|
|
987
1020
|
return _payi_awrapper
|
|
988
1021
|
|
|
989
|
-
class
|
|
1022
|
+
class _StreamIteratorWrapper(ObjectProxy): # type: ignore
|
|
990
1023
|
def __init__(
|
|
991
1024
|
self,
|
|
992
1025
|
response: Any,
|
|
@@ -994,7 +1027,6 @@ class ChatStreamWrapper(ObjectProxy): # type: ignore
|
|
|
994
1027
|
instrumentor: _PayiInstrumentor,
|
|
995
1028
|
stopwatch: Stopwatch,
|
|
996
1029
|
request: _ProviderRequest,
|
|
997
|
-
log_prompt_and_response: bool = True,
|
|
998
1030
|
) -> None:
|
|
999
1031
|
|
|
1000
1032
|
bedrock_from_stream: bool = False
|
|
@@ -1016,7 +1048,6 @@ class ChatStreamWrapper(ObjectProxy): # type: ignore
|
|
|
1016
1048
|
|
|
1017
1049
|
self._instrumentor = instrumentor
|
|
1018
1050
|
self._stopwatch: Stopwatch = stopwatch
|
|
1019
|
-
self._log_prompt_and_response: bool = log_prompt_and_response
|
|
1020
1051
|
self._responses: list[str] = []
|
|
1021
1052
|
|
|
1022
1053
|
self._request: _ProviderRequest = request
|
|
@@ -1091,7 +1122,7 @@ class ChatStreamWrapper(ObjectProxy): # type: ignore
|
|
|
1091
1122
|
self._request._ingest["time_to_first_token_ms"] = self._stopwatch.elapsed_ms_int()
|
|
1092
1123
|
self._first_token = False
|
|
1093
1124
|
|
|
1094
|
-
if self._log_prompt_and_response:
|
|
1125
|
+
if self._instrumentor._log_prompt_and_response:
|
|
1095
1126
|
self._responses.append(self.chunk_to_json(chunk))
|
|
1096
1127
|
|
|
1097
1128
|
return self._request.process_chunk(chunk)
|
|
@@ -1101,7 +1132,7 @@ class ChatStreamWrapper(ObjectProxy): # type: ignore
|
|
|
1101
1132
|
self._request._ingest["end_to_end_latency_ms"] = self._stopwatch.elapsed_ms_int()
|
|
1102
1133
|
self._request._ingest["http_status_code"] = 200
|
|
1103
1134
|
|
|
1104
|
-
if self._log_prompt_and_response:
|
|
1135
|
+
if self._instrumentor._log_prompt_and_response:
|
|
1105
1136
|
self._request._ingest["provider_response_json"] = self._responses
|
|
1106
1137
|
|
|
1107
1138
|
async def _astop_iteration(self) -> None:
|
|
@@ -1124,6 +1155,35 @@ class ChatStreamWrapper(ObjectProxy): # type: ignore
|
|
|
1124
1155
|
# assume dict
|
|
1125
1156
|
return json.dumps(chunk)
|
|
1126
1157
|
|
|
1158
|
+
class _StreamManagerWrapper(ObjectProxy): # type: ignore
|
|
1159
|
+
def __init__(
|
|
1160
|
+
self,
|
|
1161
|
+
stream_manager: Any, # type: ignore
|
|
1162
|
+
instance: Any,
|
|
1163
|
+
instrumentor: _PayiInstrumentor,
|
|
1164
|
+
stopwatch: Stopwatch,
|
|
1165
|
+
request: _ProviderRequest,
|
|
1166
|
+
) -> None:
|
|
1167
|
+
super().__init__(stream_manager) # type: ignore
|
|
1168
|
+
|
|
1169
|
+
self._stream_manager = stream_manager
|
|
1170
|
+
self._instance = instance
|
|
1171
|
+
self._instrumentor = instrumentor
|
|
1172
|
+
self._stopwatch: Stopwatch = stopwatch
|
|
1173
|
+
self._responses: list[str] = []
|
|
1174
|
+
self._request: _ProviderRequest = request
|
|
1175
|
+
self._first_token: bool = True
|
|
1176
|
+
self._done: bool = False
|
|
1177
|
+
|
|
1178
|
+
def __enter__(self) -> _StreamIteratorWrapper:
|
|
1179
|
+
return _StreamIteratorWrapper(
|
|
1180
|
+
response=self.__wrapped__.__enter__(), # type: ignore
|
|
1181
|
+
instance=self._instance,
|
|
1182
|
+
instrumentor=self._instrumentor,
|
|
1183
|
+
stopwatch=self._stopwatch,
|
|
1184
|
+
request=self._request,
|
|
1185
|
+
)
|
|
1186
|
+
|
|
1127
1187
|
class _GeneratorWrapper: # type: ignore
|
|
1128
1188
|
def __init__(
|
|
1129
1189
|
self,
|
|
@@ -1132,7 +1192,6 @@ class _GeneratorWrapper: # type: ignore
|
|
|
1132
1192
|
instrumentor: _PayiInstrumentor,
|
|
1133
1193
|
stopwatch: Stopwatch,
|
|
1134
1194
|
request: _ProviderRequest,
|
|
1135
|
-
log_prompt_and_response: bool = True,
|
|
1136
1195
|
) -> None:
|
|
1137
1196
|
super().__init__() # type: ignore
|
|
1138
1197
|
|
|
@@ -1140,7 +1199,7 @@ class _GeneratorWrapper: # type: ignore
|
|
|
1140
1199
|
self._instance = instance
|
|
1141
1200
|
self._instrumentor = instrumentor
|
|
1142
1201
|
self._stopwatch: Stopwatch = stopwatch
|
|
1143
|
-
self._log_prompt_and_response: bool =
|
|
1202
|
+
self._log_prompt_and_response: bool = instrumentor._log_prompt_and_response
|
|
1144
1203
|
self._responses: list[str] = []
|
|
1145
1204
|
self._request: _ProviderRequest = request
|
|
1146
1205
|
self._first_token: bool = True
|
|
@@ -1176,13 +1235,22 @@ class _GeneratorWrapper: # type: ignore
|
|
|
1176
1235
|
await self._process_async_stop_iteration()
|
|
1177
1236
|
raise stop_exception
|
|
1178
1237
|
|
|
1238
|
+
@staticmethod
|
|
1239
|
+
def _chunk_to_dict(chunk: Any) -> 'dict[str, object]':
|
|
1240
|
+
if hasattr(chunk, "to_json"):
|
|
1241
|
+
return chunk.to_json() # type: ignore
|
|
1242
|
+
elif hasattr(chunk, "to_json_dict"):
|
|
1243
|
+
return chunk.to_json_dict() # type: ignore
|
|
1244
|
+
else:
|
|
1245
|
+
return {}
|
|
1246
|
+
|
|
1179
1247
|
def _process_chunk(self, chunk: Any) -> Any:
|
|
1180
1248
|
if self._first_token:
|
|
1181
1249
|
self._request._ingest["time_to_first_token_ms"] = self._stopwatch.elapsed_ms_int()
|
|
1182
1250
|
self._first_token = False
|
|
1183
1251
|
|
|
1184
1252
|
if self._log_prompt_and_response:
|
|
1185
|
-
dict =
|
|
1253
|
+
dict = self._chunk_to_dict(chunk)
|
|
1186
1254
|
self._responses.append(json.dumps(dict))
|
|
1187
1255
|
|
|
1188
1256
|
self._request.process_chunk(chunk)
|
|
@@ -11,7 +11,7 @@ payi/_resource.py,sha256=j2jIkTr8OIC8sU6-05nxSaCyj4MaFlbZrwlyg4_xJos,1088
|
|
|
11
11
|
payi/_response.py,sha256=rh9oJAvCKcPwQFm4iqH_iVrmK8bNx--YP_A2a4kN1OU,28776
|
|
12
12
|
payi/_streaming.py,sha256=Z_wIyo206T6Jqh2rolFg2VXZgX24PahLmpURp0-NssU,10092
|
|
13
13
|
payi/_types.py,sha256=7jE5MoQQFVoVxw5vVzvZ2Ao0kcjfNOGsBgyJfLBEnMo,6195
|
|
14
|
-
payi/_version.py,sha256=
|
|
14
|
+
payi/_version.py,sha256=562XNlpNWouu5fR8P9024ptW4UWs2S750PSKhFzqfdY,165
|
|
15
15
|
payi/pagination.py,sha256=k2356QGPOUSjRF2vHpwLBdF6P-2vnQzFfRIJQAHGQ7A,1258
|
|
16
16
|
payi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
payi/_utils/__init__.py,sha256=PNZ_QJuzZEgyYXqkO1HVhGkj5IU9bglVUcw7H-Knjzw,2062
|
|
@@ -25,13 +25,14 @@ payi/_utils/_transform.py,sha256=n7kskEWz6o__aoNvhFoGVyDoalNe6mJwp-g7BWkdj88,156
|
|
|
25
25
|
payi/_utils/_typing.py,sha256=D0DbbNu8GnYQTSICnTSHDGsYXj8TcAKyhejb0XcnjtY,4602
|
|
26
26
|
payi/_utils/_utils.py,sha256=ts4CiiuNpFiGB6YMdkQRh2SZvYvsl7mAF-JWHCcLDf4,12312
|
|
27
27
|
payi/lib/.keep,sha256=wuNrz-5SXo3jJaJOJgz4vFHM41YH_g20F5cRQo0vLes,224
|
|
28
|
-
payi/lib/AnthropicInstrumentor.py,sha256=
|
|
29
|
-
payi/lib/BedrockInstrumentor.py,sha256=
|
|
30
|
-
payi/lib/
|
|
28
|
+
payi/lib/AnthropicInstrumentor.py,sha256=q1Iq2NG06OHUwcwTgYjHa1_kwhbSxE3vrGk_fm5IGSM,8749
|
|
29
|
+
payi/lib/BedrockInstrumentor.py,sha256=cIjHlPQmVEAixabUoT3mV8h50lfzdc1u8iLj0gQNukE,14076
|
|
30
|
+
payi/lib/GoogleGenAiInstrumentor.py,sha256=y9FuEtuITaIac_N-WhmypAr-UF1lzRCc9YBRVwwwydQ,13411
|
|
31
|
+
payi/lib/OpenAIInstrumentor.py,sha256=iMOriAm-2zcRNjQDkEAG-NfZhBJUnkBDrNNbO920ajc,17468
|
|
31
32
|
payi/lib/Stopwatch.py,sha256=7OJlxvr2Jyb6Zr1LYCYKczRB7rDVKkIR7gc4YoleNdE,764
|
|
32
|
-
payi/lib/VertexInstrumentor.py,sha256=
|
|
33
|
+
payi/lib/VertexInstrumentor.py,sha256=Xmp5kRI8G0u2OieGmlNxIduwnqp8cAXO-fROpkdXbgs,11748
|
|
33
34
|
payi/lib/helpers.py,sha256=K1KAfWrpPT1UUGNxspLe1lHzQjP3XV5Pkh9IU4pKMok,4624
|
|
34
|
-
payi/lib/instrument.py,sha256=
|
|
35
|
+
payi/lib/instrument.py,sha256=UpZ6SGg3YI9lSxmwH5ziwe1xt_ca6FS35CcNJpG9ONM,58214
|
|
35
36
|
payi/resources/__init__.py,sha256=1rtrPLWbNt8oJGOp6nwPumKLJ-ftez0B6qwLFyfcoP4,2972
|
|
36
37
|
payi/resources/ingest.py,sha256=8HNHEyfgIyJNqCh0rOhO9msoc61-8IyifJ6AbxjCrDg,22612
|
|
37
38
|
payi/resources/categories/__init__.py,sha256=w5gMiPdBSzJA_qfoVtFBElaoe8wGf_O63R7R1Spr6Gk,1093
|
|
@@ -141,7 +142,7 @@ payi/types/use_cases/definitions/kpi_retrieve_response.py,sha256=uQXliSvS3k-yDYw
|
|
|
141
142
|
payi/types/use_cases/definitions/kpi_update_params.py,sha256=jbawdWAdMnsTWVH0qfQGb8W7_TXe3lq4zjSRu44d8p8,373
|
|
142
143
|
payi/types/use_cases/definitions/kpi_update_response.py,sha256=zLyEoT0S8d7XHsnXZYT8tM7yDw0Aze0Mk-_Z6QeMtc8,459
|
|
143
144
|
payi/types/use_cases/definitions/limit_config_create_params.py,sha256=pzQza_16N3z8cFNEKr6gPbFvuGFrwNuGxAYb--Kbo2M,449
|
|
144
|
-
payi-0.1.
|
|
145
|
-
payi-0.1.
|
|
146
|
-
payi-0.1.
|
|
147
|
-
payi-0.1.
|
|
145
|
+
payi-0.1.0a78.dist-info/METADATA,sha256=kKY9frrRc7_WbcIUIphMDmRBHQVZgdSGH1eLkF26Pzk,15180
|
|
146
|
+
payi-0.1.0a78.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
|
147
|
+
payi-0.1.0a78.dist-info/licenses/LICENSE,sha256=CQt03aM-P4a3Yg5qBg3JSLVoQS3smMyvx7tYg_6V7Gk,11334
|
|
148
|
+
payi-0.1.0a78.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|