payi 0.1.0a77__tar.gz → 0.1.0a78__tar.gz
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-0.1.0a78/.release-please-manifest.json +3 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/CHANGELOG.md +8 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/PKG-INFO +1 -1
- {payi-0.1.0a77 → payi-0.1.0a78}/pyproject.toml +1 -1
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_version.py +1 -1
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/lib/AnthropicInstrumentor.py +43 -9
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/lib/BedrockInstrumentor.py +6 -2
- payi-0.1.0a78/src/payi/lib/GoogleGenAiInstrumentor.py +370 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/lib/OpenAIInstrumentor.py +6 -2
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/lib/VertexInstrumentor.py +8 -5
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/lib/instrument.py +109 -41
- payi-0.1.0a77/.release-please-manifest.json +0 -3
- {payi-0.1.0a77 → payi-0.1.0a78}/.gitignore +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/CONTRIBUTING.md +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/LICENSE +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/README.md +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/SECURITY.md +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/api.md +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/bin/check-release-environment +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/bin/publish-pypi +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/examples/.keep +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/mypy.ini +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/noxfile.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/release-please-config.json +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/requirements-dev.lock +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/requirements.lock +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_base_client.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_client.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_compat.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_constants.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_exceptions.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_files.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_models.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_qs.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_resource.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_streaming.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_types.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_utils/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_utils/_logs.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_utils/_proxy.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_utils/_reflection.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_utils/_resources_proxy.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_utils/_streams.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_utils/_sync.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_utils/_transform.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_utils/_typing.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/_utils/_utils.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/lib/.keep +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/lib/Stopwatch.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/lib/helpers.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/pagination.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/py.typed +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/categories/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/categories/categories.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/categories/resources.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/experiences/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/experiences/experiences.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/experiences/properties.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/experiences/types/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/experiences/types/limit_config.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/experiences/types/types.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/ingest.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/limits/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/limits/limits.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/limits/tags.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/requests/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/requests/properties.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/requests/requests.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/requests/result.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/use_cases/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/use_cases/definitions/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/use_cases/definitions/definitions.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/use_cases/definitions/kpis.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/use_cases/definitions/limit_config.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/use_cases/definitions/version.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/use_cases/kpis.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/use_cases/properties.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/resources/use_cases/use_cases.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/bulk_ingest_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/categories/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/categories/resource_create_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/categories/resource_list_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/category_delete_resource_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/category_delete_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/category_list_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/category_list_resources_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/category_resource_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/category_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/cost_data.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/cost_details.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/default_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/experience_instance_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/experiences/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/experiences/experience_type.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/experiences/property_create_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/experiences/type_create_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/experiences/type_list_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/experiences/type_update_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/experiences/types/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/experiences/types/limit_config_create_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/ingest_bulk_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/ingest_event_param.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/ingest_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/ingest_units_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/limit_create_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/limit_history_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/limit_list_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/limit_list_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/limit_reset_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/limit_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/limit_update_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/limits/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/limits/limit_tags.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/limits/tag_create_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/limits/tag_create_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/limits/tag_delete_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/limits/tag_list_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/limits/tag_remove_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/limits/tag_remove_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/limits/tag_update_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/limits/tag_update_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/pay_i_common_models_api_router_header_info_param.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/requests/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/requests/property_create_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/requests/request_result.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/requests_data.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/shared/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/shared/evaluation_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/shared/ingest_units.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/shared/pay_i_common_models_budget_management_cost_details_base.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/shared/pay_i_common_models_budget_management_create_limit_base.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/shared/properties_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/shared/xproxy_error.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/shared/xproxy_result.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/shared_params/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/shared_params/ingest_units.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/shared_params/pay_i_common_models_budget_management_create_limit_base.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/total_cost_data.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_case_instance_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/definition_create_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/definition_list_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/definition_update_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/kpi_create_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/kpi_create_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/kpi_delete_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/kpi_list_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/kpi_list_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/kpi_retrieve_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/kpi_update_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/kpi_update_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/limit_config_create_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/kpi_create_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/kpi_list_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/kpi_list_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/kpi_update_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/property_create_params.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/src/payi/types/use_cases/use_case_definition.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/categories/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/categories/test_resources.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/experiences/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/experiences/test_properties.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/experiences/test_types.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/experiences/types/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/experiences/types/test_limit_config.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/limits/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/limits/test_tags.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/requests/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/requests/test_properties.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/requests/test_result.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/test_categories.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/test_experiences.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/test_ingest.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/test_limits.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/test_use_cases.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/use_cases/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/use_cases/definitions/__init__.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/use_cases/definitions/test_kpis.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/use_cases/definitions/test_limit_config.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/use_cases/definitions/test_version.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/use_cases/test_definitions.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/use_cases/test_kpis.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/api_resources/use_cases/test_properties.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/conftest.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/sample_file.txt +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/test_client.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/test_deepcopy.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/test_extract_files.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/test_files.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/test_models.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/test_qs.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/test_required_args.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/test_response.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/test_streaming.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/test_transform.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/test_utils/test_proxy.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/test_utils/test_typing.py +0 -0
- {payi-0.1.0a77 → payi-0.1.0a78}/tests/utils.py +0 -0
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.0-alpha.78 (2025-06-03)
|
|
4
|
+
|
|
5
|
+
Full Changelog: [v0.1.0-alpha.77...v0.1.0-alpha.78](https://github.com/Pay-i/pay-i-python/compare/v0.1.0-alpha.77...v0.1.0-alpha.78)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
* **api:** google genai, anthropic stream() ([#306](https://github.com/Pay-i/pay-i-python/issues/306)) ([341da40](https://github.com/Pay-i/pay-i-python/commit/341da40fb228cb83994bec12e7cda457f5452692))
|
|
10
|
+
|
|
3
11
|
## 0.1.0-alpha.77 (2025-06-03)
|
|
4
12
|
|
|
5
13
|
Full Changelog: [v0.1.0-alpha.76...v0.1.0-alpha.77](https://github.com/Pay-i/pay-i-python/compare/v0.1.0-alpha.76...v0.1.0-alpha.77)
|
|
@@ -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
|
|
@@ -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)
|
|
@@ -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
|
|
@@ -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
|