payi 0.1.0a70__tar.gz → 0.1.0a72__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.0a72/.release-please-manifest.json +3 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/CHANGELOG.md +27 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/PKG-INFO +1 -1
- {payi-0.1.0a70 → payi-0.1.0a72}/api.md +3 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/pyproject.toml +1 -1
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/__init__.py +5 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_utils/_proxy.py +4 -1
- payi-0.1.0a72/src/payi/_utils/_resources_proxy.py +24 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_version.py +1 -1
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/lib/AnthropicInstrumentor.py +8 -6
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/lib/BedrockInstrumentor.py +8 -8
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/lib/OpenAIInstrumentor.py +11 -10
- payi-0.1.0a72/src/payi/lib/VertexInstrumentor.py +313 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/lib/helpers.py +1 -1
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/lib/instrument.py +190 -47
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/ingest.py +55 -24
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/limits/limits.py +0 -8
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/__init__.py +3 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/bulk_ingest_response.py +3 -8
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/category_resource_response.py +2 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/ingest_event_param.py +7 -10
- payi-0.1.0a72/src/payi/types/ingest_response.py +18 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/ingest_units_params.py +5 -2
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/limit_create_params.py +2 -2
- payi-0.1.0a72/src/payi/types/requests/request_result.py +10 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/shared/__init__.py +3 -0
- payi-0.1.0a72/src/payi/types/shared/ingest_units.py +13 -0
- payi-0.1.0a72/src/payi/types/shared/xproxy_error.py +13 -0
- payi-0.1.0a70/src/payi/types/requests/request_result.py → payi-0.1.0a72/src/payi/types/shared/xproxy_result.py +11 -12
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/shared_params/__init__.py +1 -0
- payi-0.1.0a72/src/payi/types/shared_params/ingest_units.py +13 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/test_ingest.py +4 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/test_limits.py +0 -4
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/test_utils/test_proxy.py +11 -0
- payi-0.1.0a70/.release-please-manifest.json +0 -3
- payi-0.1.0a70/src/payi/types/ingest_response.py +0 -57
- {payi-0.1.0a70 → payi-0.1.0a72}/.gitignore +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/CONTRIBUTING.md +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/LICENSE +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/README.md +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/SECURITY.md +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/bin/check-release-environment +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/bin/publish-pypi +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/examples/.keep +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/mypy.ini +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/noxfile.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/release-please-config.json +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/requirements-dev.lock +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/requirements.lock +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_base_client.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_client.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_compat.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_constants.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_exceptions.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_files.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_models.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_qs.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_resource.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_streaming.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_types.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_utils/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_utils/_logs.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_utils/_reflection.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_utils/_streams.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_utils/_sync.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_utils/_transform.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_utils/_typing.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/_utils/_utils.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/lib/.keep +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/lib/Stopwatch.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/pagination.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/py.typed +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/categories/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/categories/categories.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/categories/resources.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/experiences/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/experiences/experiences.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/experiences/properties.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/experiences/types/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/experiences/types/limit_config.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/experiences/types/types.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/limits/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/limits/tags.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/requests/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/requests/properties.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/requests/requests.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/requests/result.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/use_cases/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/use_cases/definitions/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/use_cases/definitions/definitions.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/use_cases/definitions/kpis.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/use_cases/definitions/limit_config.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/use_cases/definitions/version.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/use_cases/kpis.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/use_cases/properties.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/resources/use_cases/use_cases.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/categories/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/categories/resource_create_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/categories/resource_list_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/category_delete_resource_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/category_delete_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/category_list_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/category_list_resources_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/category_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/cost_data.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/cost_details.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/default_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/experience_instance_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/experiences/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/experiences/experience_type.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/experiences/property_create_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/experiences/type_create_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/experiences/type_list_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/experiences/type_update_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/experiences/types/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/experiences/types/limit_config_create_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/ingest_bulk_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/limit_history_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/limit_list_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/limit_list_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/limit_reset_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/limit_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/limit_update_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/limits/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/limits/limit_tags.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/limits/tag_create_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/limits/tag_create_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/limits/tag_delete_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/limits/tag_list_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/limits/tag_remove_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/limits/tag_remove_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/limits/tag_update_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/limits/tag_update_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/pay_i_common_models_api_router_header_info_param.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/requests/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/requests/property_create_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/requests_data.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/shared/evaluation_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/shared/pay_i_common_models_budget_management_cost_details_base.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/shared/pay_i_common_models_budget_management_create_limit_base.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/shared/properties_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/shared_params/pay_i_common_models_budget_management_create_limit_base.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/total_cost_data.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_case_instance_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/definition_create_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/definition_list_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/definition_update_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/definitions/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/definitions/kpi_create_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/definitions/kpi_create_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/definitions/kpi_delete_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/definitions/kpi_list_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/definitions/kpi_list_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/definitions/kpi_retrieve_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/definitions/kpi_update_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/definitions/kpi_update_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/definitions/limit_config_create_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/kpi_create_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/kpi_list_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/kpi_list_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/kpi_update_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/property_create_params.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/src/payi/types/use_cases/use_case_definition.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/categories/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/categories/test_resources.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/experiences/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/experiences/test_properties.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/experiences/test_types.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/experiences/types/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/experiences/types/test_limit_config.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/limits/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/limits/test_tags.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/requests/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/requests/test_properties.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/requests/test_result.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/test_categories.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/test_experiences.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/test_use_cases.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/use_cases/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/use_cases/definitions/__init__.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/use_cases/definitions/test_kpis.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/use_cases/definitions/test_limit_config.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/use_cases/definitions/test_version.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/use_cases/test_definitions.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/use_cases/test_kpis.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/api_resources/use_cases/test_properties.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/conftest.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/sample_file.txt +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/test_client.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/test_deepcopy.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/test_extract_files.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/test_files.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/test_models.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/test_qs.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/test_required_args.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/test_response.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/test_streaming.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/test_transform.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/test_utils/test_typing.py +0 -0
- {payi-0.1.0a70 → payi-0.1.0a72}/tests/utils.py +0 -0
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.0-alpha.72 (2025-05-10)
|
|
4
|
+
|
|
5
|
+
Full Changelog: [v0.1.0-alpha.71...v0.1.0-alpha.72](https://github.com/Pay-i/pay-i-python/compare/v0.1.0-alpha.71...v0.1.0-alpha.72)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
* **package:** support direct resource imports ([314f86c](https://github.com/Pay-i/pay-i-python/commit/314f86cb0d46aa35628c9d059c1b1ca25d24d911))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Chores
|
|
13
|
+
|
|
14
|
+
* **internal:** avoid errors for isinstance checks on proxies ([b935f82](https://github.com/Pay-i/pay-i-python/commit/b935f82c9de01353ec83b9c12c4ed6749e984c7d))
|
|
15
|
+
|
|
16
|
+
## 0.1.0-alpha.71 (2025-05-03)
|
|
17
|
+
|
|
18
|
+
Full Changelog: [v0.1.0-alpha.70...v0.1.0-alpha.71](https://github.com/Pay-i/pay-i-python/compare/v0.1.0-alpha.70...v0.1.0-alpha.71)
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* **api:** google vertex ([#294](https://github.com/Pay-i/pay-i-python/issues/294)) ([6d9e39b](https://github.com/Pay-i/pay-i-python/commit/6d9e39b2ee522589d4962c73f697f9cce76fdf6a))
|
|
23
|
+
* **api:** manual updates ([7d11112](https://github.com/Pay-i/pay-i-python/commit/7d1111205f30fe78c9e2e833d3f99a62f95419e8))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Bug Fixes
|
|
27
|
+
|
|
28
|
+
* lint ([e7d5a21](https://github.com/Pay-i/pay-i-python/commit/e7d5a210db38448629511b470a4d1b426368577f))
|
|
29
|
+
|
|
3
30
|
## 0.1.0-alpha.70 (2025-04-24)
|
|
4
31
|
|
|
5
32
|
Full Changelog: [v0.1.0-alpha.69...v0.1.0-alpha.70](https://github.com/Pay-i/pay-i-python/compare/v0.1.0-alpha.69...v0.1.0-alpha.70)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
2
|
|
|
3
|
+
import typing as _t
|
|
4
|
+
|
|
3
5
|
from . import types
|
|
4
6
|
from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes
|
|
5
7
|
from ._utils import file_from_path
|
|
@@ -68,6 +70,9 @@ __all__ = [
|
|
|
68
70
|
"DefaultAsyncHttpxClient",
|
|
69
71
|
]
|
|
70
72
|
|
|
73
|
+
if not _t.TYPE_CHECKING:
|
|
74
|
+
from ._utils._resources_proxy import resources as resources
|
|
75
|
+
|
|
71
76
|
_setup_logging()
|
|
72
77
|
|
|
73
78
|
# Update the __module__ attribute for exported symbols so that
|
|
@@ -46,7 +46,10 @@ class LazyProxy(Generic[T], ABC):
|
|
|
46
46
|
@property # type: ignore
|
|
47
47
|
@override
|
|
48
48
|
def __class__(self) -> type: # pyright: ignore
|
|
49
|
-
|
|
49
|
+
try:
|
|
50
|
+
proxied = self.__get_proxied__()
|
|
51
|
+
except Exception:
|
|
52
|
+
return type(self)
|
|
50
53
|
if issubclass(type(proxied), LazyProxy):
|
|
51
54
|
return type(proxied)
|
|
52
55
|
return proxied.__class__
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
from typing_extensions import override
|
|
5
|
+
|
|
6
|
+
from ._proxy import LazyProxy
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ResourcesProxy(LazyProxy[Any]):
|
|
10
|
+
"""A proxy for the `payi.resources` module.
|
|
11
|
+
|
|
12
|
+
This is used so that we can lazily import `payi.resources` only when
|
|
13
|
+
needed *and* so that users can just import `payi` and reference `payi.resources`
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
@override
|
|
17
|
+
def __load__(self) -> Any:
|
|
18
|
+
import importlib
|
|
19
|
+
|
|
20
|
+
mod = importlib.import_module("payi.resources")
|
|
21
|
+
return mod
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
resources = ResourcesProxy().__as_proxied__()
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import Any, Union, Optional
|
|
2
|
+
from typing import Any, Union, Optional, Sequence
|
|
3
3
|
from typing_extensions import override
|
|
4
4
|
|
|
5
5
|
import tiktoken
|
|
6
6
|
from wrapt import wrap_function_wrapper # type: ignore
|
|
7
7
|
|
|
8
|
+
from payi.lib.helpers import PayiCategories
|
|
8
9
|
from payi.types.ingest_units_params import Units
|
|
9
10
|
|
|
10
11
|
from .instrument import _IsStreaming, _ProviderRequest, _PayiInstrumentor
|
|
@@ -53,7 +54,7 @@ def chat_wrapper(
|
|
|
53
54
|
*args: Any,
|
|
54
55
|
**kwargs: Any,
|
|
55
56
|
) -> Any:
|
|
56
|
-
return instrumentor.
|
|
57
|
+
return instrumentor.invoke_wrapper(
|
|
57
58
|
_AnthropicProviderRequest(instrumentor),
|
|
58
59
|
_IsStreaming.kwargs,
|
|
59
60
|
wrapped,
|
|
@@ -70,7 +71,7 @@ async def achat_wrapper(
|
|
|
70
71
|
*args: Any,
|
|
71
72
|
**kwargs: Any,
|
|
72
73
|
) -> Any:
|
|
73
|
-
return await instrumentor.
|
|
74
|
+
return await instrumentor.async_invoke_wrapper(
|
|
74
75
|
_AnthropicProviderRequest(instrumentor),
|
|
75
76
|
_IsStreaming.kwargs,
|
|
76
77
|
wrapped,
|
|
@@ -81,7 +82,7 @@ async def achat_wrapper(
|
|
|
81
82
|
|
|
82
83
|
class _AnthropicProviderRequest(_ProviderRequest):
|
|
83
84
|
def __init__(self, instrumentor: _PayiInstrumentor):
|
|
84
|
-
super().__init__(instrumentor=instrumentor, category=
|
|
85
|
+
super().__init__(instrumentor=instrumentor, category=PayiCategories.anthropic)
|
|
85
86
|
|
|
86
87
|
@override
|
|
87
88
|
def process_chunk(self, chunk: Any) -> bool:
|
|
@@ -136,7 +137,7 @@ class _AnthropicProviderRequest(_ProviderRequest):
|
|
|
136
137
|
return None
|
|
137
138
|
|
|
138
139
|
@override
|
|
139
|
-
def process_request(self, instance: Any, extra_headers: 'dict[str, str]', kwargs: Any) -> bool:
|
|
140
|
+
def process_request(self, instance: Any, extra_headers: 'dict[str, str]', args: Sequence[Any], kwargs: Any) -> bool:
|
|
140
141
|
self._ingest["resource"] = kwargs.get("model", "")
|
|
141
142
|
messages = kwargs.get("messages")
|
|
142
143
|
if messages:
|
|
@@ -166,7 +167,8 @@ class _AnthropicProviderRequest(_ProviderRequest):
|
|
|
166
167
|
self._ingest["http_status_code"] = status_code
|
|
167
168
|
|
|
168
169
|
if not status_code:
|
|
169
|
-
|
|
170
|
+
self.exception_to_semantic_failure(exception,)
|
|
171
|
+
return True
|
|
170
172
|
|
|
171
173
|
if hasattr(exception, "request_id"):
|
|
172
174
|
request_id = getattr(exception, "request_id", None)
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import json
|
|
3
3
|
import logging
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any, Sequence
|
|
5
5
|
from functools import wraps
|
|
6
6
|
from typing_extensions import override
|
|
7
7
|
|
|
8
8
|
from wrapt import ObjectProxy, wrap_function_wrapper # type: ignore
|
|
9
9
|
|
|
10
|
-
from payi.lib.helpers import PayiHeaderNames, payi_aws_bedrock_url
|
|
10
|
+
from payi.lib.helpers import PayiCategories, PayiHeaderNames, payi_aws_bedrock_url
|
|
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
|
|
|
@@ -148,7 +148,7 @@ def wrap_invoke(instrumentor: _PayiInstrumentor, wrapped: Any) -> Any:
|
|
|
148
148
|
modelId:str = kwargs.get("modelId", "") # type: ignore
|
|
149
149
|
|
|
150
150
|
if _is_supported_model(modelId):
|
|
151
|
-
return instrumentor.
|
|
151
|
+
return instrumentor.invoke_wrapper(
|
|
152
152
|
_BedrockInvokeSynchronousProviderRequest(instrumentor=instrumentor),
|
|
153
153
|
_IsStreaming.false,
|
|
154
154
|
wrapped,
|
|
@@ -166,7 +166,7 @@ def wrap_invoke_stream(instrumentor: _PayiInstrumentor, wrapped: Any) -> Any:
|
|
|
166
166
|
modelId: str = kwargs.get("modelId", "") # type: ignore
|
|
167
167
|
|
|
168
168
|
if _is_supported_model(modelId):
|
|
169
|
-
return instrumentor.
|
|
169
|
+
return instrumentor.invoke_wrapper(
|
|
170
170
|
_BedrockInvokeStreamingProviderRequest(instrumentor=instrumentor, model_id=modelId),
|
|
171
171
|
_IsStreaming.true,
|
|
172
172
|
wrapped,
|
|
@@ -184,7 +184,7 @@ def wrap_converse(instrumentor: _PayiInstrumentor, wrapped: Any) -> Any:
|
|
|
184
184
|
modelId:str = kwargs.get("modelId", "") # type: ignore
|
|
185
185
|
|
|
186
186
|
if _is_supported_model(modelId):
|
|
187
|
-
return instrumentor.
|
|
187
|
+
return instrumentor.invoke_wrapper(
|
|
188
188
|
_BedrockConverseSynchronousProviderRequest(instrumentor=instrumentor),
|
|
189
189
|
_IsStreaming.false,
|
|
190
190
|
wrapped,
|
|
@@ -202,7 +202,7 @@ def wrap_converse_stream(instrumentor: _PayiInstrumentor, wrapped: Any) -> Any:
|
|
|
202
202
|
modelId: str = kwargs.get("modelId", "") # type: ignore
|
|
203
203
|
|
|
204
204
|
if _is_supported_model(modelId):
|
|
205
|
-
return instrumentor.
|
|
205
|
+
return instrumentor.invoke_wrapper(
|
|
206
206
|
_BedrockConverseStreamingProviderRequest(instrumentor=instrumentor),
|
|
207
207
|
_IsStreaming.true,
|
|
208
208
|
wrapped,
|
|
@@ -216,10 +216,10 @@ 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__(instrumentor=instrumentor, category=
|
|
219
|
+
super().__init__(instrumentor=instrumentor, category=PayiCategories.aws_bedrock)
|
|
220
220
|
|
|
221
221
|
@override
|
|
222
|
-
def process_request(self, instance: Any, extra_headers: 'dict[str, str]', kwargs: Any) -> bool:
|
|
222
|
+
def process_request(self, instance: Any, extra_headers: 'dict[str, str]', args: Sequence[Any], kwargs: Any) -> bool:
|
|
223
223
|
# boto3 doesn't allow extra_headers
|
|
224
224
|
kwargs.pop("extra_headers", None)
|
|
225
225
|
self._ingest["resource"] = kwargs.get("modelId", "")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
|
-
from typing import Any, Union, Optional
|
|
3
|
+
from typing import Any, Union, Optional, Sequence
|
|
4
4
|
from typing_extensions import override
|
|
5
5
|
from importlib.metadata import version
|
|
6
6
|
|
|
@@ -63,7 +63,7 @@ def embeddings_wrapper(
|
|
|
63
63
|
*args: Any,
|
|
64
64
|
**kwargs: Any,
|
|
65
65
|
) -> Any:
|
|
66
|
-
return instrumentor.
|
|
66
|
+
return instrumentor.invoke_wrapper(
|
|
67
67
|
_OpenAiEmbeddingsProviderRequest(instrumentor),
|
|
68
68
|
_IsStreaming.false,
|
|
69
69
|
wrapped,
|
|
@@ -80,7 +80,7 @@ async def aembeddings_wrapper(
|
|
|
80
80
|
*args: Any,
|
|
81
81
|
**kwargs: Any,
|
|
82
82
|
) -> Any:
|
|
83
|
-
return await instrumentor.
|
|
83
|
+
return await instrumentor.async_invoke_wrapper(
|
|
84
84
|
_OpenAiEmbeddingsProviderRequest(instrumentor),
|
|
85
85
|
_IsStreaming.false,
|
|
86
86
|
wrapped,
|
|
@@ -97,7 +97,7 @@ def chat_wrapper(
|
|
|
97
97
|
*args: Any,
|
|
98
98
|
**kwargs: Any,
|
|
99
99
|
) -> Any:
|
|
100
|
-
return instrumentor.
|
|
100
|
+
return instrumentor.invoke_wrapper(
|
|
101
101
|
_OpenAiChatProviderRequest(instrumentor),
|
|
102
102
|
_IsStreaming.kwargs,
|
|
103
103
|
wrapped,
|
|
@@ -114,7 +114,7 @@ async def achat_wrapper(
|
|
|
114
114
|
*args: Any,
|
|
115
115
|
**kwargs: Any,
|
|
116
116
|
) -> Any:
|
|
117
|
-
return await instrumentor.
|
|
117
|
+
return await instrumentor.async_invoke_wrapper(
|
|
118
118
|
_OpenAiChatProviderRequest(instrumentor),
|
|
119
119
|
_IsStreaming.kwargs,
|
|
120
120
|
wrapped,
|
|
@@ -125,10 +125,10 @@ async def achat_wrapper(
|
|
|
125
125
|
|
|
126
126
|
class _OpenAiProviderRequest(_ProviderRequest):
|
|
127
127
|
def __init__(self, instrumentor: _PayiInstrumentor):
|
|
128
|
-
super().__init__(instrumentor=instrumentor, category=
|
|
128
|
+
super().__init__(instrumentor=instrumentor, category=PayiCategories.openai)
|
|
129
129
|
|
|
130
130
|
@override
|
|
131
|
-
def process_request(self, instance: Any, extra_headers: 'dict[str, str]', kwargs: Any) -> bool:
|
|
131
|
+
def process_request(self, instance: Any, extra_headers: 'dict[str, str]', args: Sequence[Any], kwargs: Any) -> bool: # type: ignore
|
|
132
132
|
self._ingest["resource"] = kwargs.get("model", "")
|
|
133
133
|
|
|
134
134
|
if not (instance and hasattr(instance, "_client")) or OpenAiInstrumentor.is_azure(instance) is False:
|
|
@@ -172,7 +172,8 @@ class _OpenAiProviderRequest(_ProviderRequest):
|
|
|
172
172
|
self._ingest["http_status_code"] = status_code
|
|
173
173
|
|
|
174
174
|
if not status_code:
|
|
175
|
-
|
|
175
|
+
self.exception_to_semantic_failure(exception,)
|
|
176
|
+
return True
|
|
176
177
|
|
|
177
178
|
if hasattr(exception, "request_id"):
|
|
178
179
|
request_id = getattr(exception, "request_id", None)
|
|
@@ -232,8 +233,8 @@ class _OpenAiChatProviderRequest(_OpenAiProviderRequest):
|
|
|
232
233
|
return send_chunk_to_client
|
|
233
234
|
|
|
234
235
|
@override
|
|
235
|
-
def process_request(self, instance: Any, extra_headers: 'dict[str, str]', kwargs: Any) -> bool:
|
|
236
|
-
result = super().process_request(instance, extra_headers, kwargs)
|
|
236
|
+
def process_request(self, instance: Any, extra_headers: 'dict[str, str]', args: Sequence[Any], kwargs: Any) -> bool:
|
|
237
|
+
result = super().process_request(instance, extra_headers, args, kwargs)
|
|
237
238
|
if result is False:
|
|
238
239
|
return result
|
|
239
240
|
|
|
@@ -0,0 +1,313 @@
|
|
|
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, _ProviderRequest, _PayiInstrumentor
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class VertexInstrumentor:
|
|
16
|
+
@staticmethod
|
|
17
|
+
def instrument(instrumentor: _PayiInstrumentor) -> None:
|
|
18
|
+
try:
|
|
19
|
+
import vertexai # type: ignore # noqa: F401 I001
|
|
20
|
+
|
|
21
|
+
wrap_function_wrapper(
|
|
22
|
+
"vertexai.generative_models",
|
|
23
|
+
"GenerativeModel.generate_content",
|
|
24
|
+
generate_wrapper(instrumentor),
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
wrap_function_wrapper(
|
|
28
|
+
"vertexai.preview.generative_models",
|
|
29
|
+
"GenerativeModel.generate_content",
|
|
30
|
+
generate_wrapper(instrumentor),
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
wrap_function_wrapper(
|
|
34
|
+
"vertexai.generative_models",
|
|
35
|
+
"GenerativeModel.generate_content_async",
|
|
36
|
+
agenerate_wrapper(instrumentor),
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
wrap_function_wrapper(
|
|
40
|
+
"vertexai.preview.generative_models",
|
|
41
|
+
"GenerativeModel.generate_content_async",
|
|
42
|
+
agenerate_wrapper(instrumentor),
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
except Exception as e:
|
|
46
|
+
logging.debug(f"Error instrumenting vertex: {e}")
|
|
47
|
+
return
|
|
48
|
+
|
|
49
|
+
@_PayiInstrumentor.payi_wrapper
|
|
50
|
+
def generate_wrapper(
|
|
51
|
+
instrumentor: _PayiInstrumentor,
|
|
52
|
+
wrapped: Any,
|
|
53
|
+
instance: Any,
|
|
54
|
+
*args: Any,
|
|
55
|
+
**kwargs: Any,
|
|
56
|
+
) -> Any:
|
|
57
|
+
return instrumentor.invoke_wrapper(
|
|
58
|
+
_GoogleVertexRequest(instrumentor),
|
|
59
|
+
_IsStreaming.kwargs,
|
|
60
|
+
wrapped,
|
|
61
|
+
instance,
|
|
62
|
+
args,
|
|
63
|
+
kwargs,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
@_PayiInstrumentor.payi_awrapper
|
|
67
|
+
async def agenerate_wrapper(
|
|
68
|
+
instrumentor: _PayiInstrumentor,
|
|
69
|
+
wrapped: Any,
|
|
70
|
+
instance: Any,
|
|
71
|
+
*args: Any,
|
|
72
|
+
**kwargs: Any,
|
|
73
|
+
) -> Any:
|
|
74
|
+
return await instrumentor.async_invoke_wrapper(
|
|
75
|
+
_GoogleVertexRequest(instrumentor),
|
|
76
|
+
_IsStreaming.kwargs,
|
|
77
|
+
wrapped,
|
|
78
|
+
instance,
|
|
79
|
+
args,
|
|
80
|
+
kwargs,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
def count_chars_skip_spaces(text: str) -> int:
|
|
84
|
+
return sum(1 for c in text if not c.isspace())
|
|
85
|
+
|
|
86
|
+
class _GoogleVertexRequest(_ProviderRequest):
|
|
87
|
+
def __init__(self, instrumentor: _PayiInstrumentor):
|
|
88
|
+
super().__init__(instrumentor=instrumentor, category=PayiCategories.google_vertex)
|
|
89
|
+
self._prompt_character_count = 0
|
|
90
|
+
self._candiates_character_count = 0
|
|
91
|
+
|
|
92
|
+
@override
|
|
93
|
+
def process_request(self, instance: Any, extra_headers: 'dict[str, str]', args: Sequence[Any], kwargs: Any) -> bool:
|
|
94
|
+
from vertexai.generative_models import Content, Image, Part # type: ignore # noqa: F401 I001
|
|
95
|
+
|
|
96
|
+
if not args:
|
|
97
|
+
return True
|
|
98
|
+
|
|
99
|
+
value: Union[ # type: ignore
|
|
100
|
+
Content,
|
|
101
|
+
str,
|
|
102
|
+
Image,
|
|
103
|
+
Part,
|
|
104
|
+
List[Union[str, Image, Part]],
|
|
105
|
+
] = args[0] # type: ignore
|
|
106
|
+
|
|
107
|
+
items: List[Union[str, Image, Part]] = [] # type: ignore # noqa: F401 I001
|
|
108
|
+
|
|
109
|
+
if not value:
|
|
110
|
+
raise TypeError("value must not be empty")
|
|
111
|
+
|
|
112
|
+
if isinstance(value, Content):
|
|
113
|
+
return value.parts # type: ignore
|
|
114
|
+
if isinstance(value, (str, Image, Part)):
|
|
115
|
+
items = [value] # type: ignore
|
|
116
|
+
|
|
117
|
+
elif isinstance(value, list):
|
|
118
|
+
items = value # type: ignore
|
|
119
|
+
|
|
120
|
+
for item in items: # type: ignore
|
|
121
|
+
text = ""
|
|
122
|
+
if isinstance(item, Part):
|
|
123
|
+
d = item.to_dict() # type: ignore
|
|
124
|
+
if "text" in d:
|
|
125
|
+
text = d["text"] # type: ignore
|
|
126
|
+
elif isinstance(item, str):
|
|
127
|
+
text = item
|
|
128
|
+
|
|
129
|
+
if text != "":
|
|
130
|
+
self._prompt_character_count += count_chars_skip_spaces(text) # type: ignore
|
|
131
|
+
|
|
132
|
+
return True
|
|
133
|
+
|
|
134
|
+
@override
|
|
135
|
+
def process_request_prompt(self, prompt: 'dict[str, Any]', args: Sequence[Any], kwargs: 'dict[str, Any]') -> None:
|
|
136
|
+
from vertexai.generative_models import Content, Image, Part, Tool # type: ignore # noqa: F401 I001
|
|
137
|
+
|
|
138
|
+
key = "contents"
|
|
139
|
+
|
|
140
|
+
if not args:
|
|
141
|
+
return
|
|
142
|
+
|
|
143
|
+
value: Union[ # type: ignore
|
|
144
|
+
Content,
|
|
145
|
+
str,
|
|
146
|
+
Image,
|
|
147
|
+
Part,
|
|
148
|
+
List[Union[str, Image, Part]],
|
|
149
|
+
] = args[0] # type: ignore
|
|
150
|
+
|
|
151
|
+
items: List[Union[str, Image, Part]] = [] # type: ignore # noqa: F401 I001
|
|
152
|
+
|
|
153
|
+
if not value:
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
if isinstance(value, str):
|
|
157
|
+
prompt[key] = Content(parts=[Part.from_text(value)]).to_dict() # type: ignore
|
|
158
|
+
elif isinstance(value, (Image, Part)):
|
|
159
|
+
prompt[key] = Content(parts=[value]).to_dict() # type: ignore
|
|
160
|
+
elif isinstance(value, Content):
|
|
161
|
+
prompt[key] = value.to_dict() # type: ignore
|
|
162
|
+
elif isinstance(value, list):
|
|
163
|
+
items = value # type: ignore
|
|
164
|
+
parts = []
|
|
165
|
+
|
|
166
|
+
for item in items: # type: ignore
|
|
167
|
+
if isinstance(item, str):
|
|
168
|
+
parts.append(Part.from_text(item)) # type: ignore
|
|
169
|
+
elif isinstance(item, Part):
|
|
170
|
+
parts.append(item) # type: ignore
|
|
171
|
+
elif isinstance(item, Image):
|
|
172
|
+
parts.append(Part.from_image(item)) # type: ignore
|
|
173
|
+
|
|
174
|
+
prompt[key] = Content(parts=parts).to_dict() # type: ignore
|
|
175
|
+
|
|
176
|
+
tools: Optional[list[Tool]] = kwargs.get("tools", None) # type: ignore
|
|
177
|
+
if tools:
|
|
178
|
+
t: list[dict[Any, Any]] = []
|
|
179
|
+
for tool in tools: # type: ignore
|
|
180
|
+
if isinstance(tool, Tool):
|
|
181
|
+
t.append(tool.to_dict()) # type: ignore
|
|
182
|
+
if t:
|
|
183
|
+
prompt["tools"] = t
|
|
184
|
+
|
|
185
|
+
tool_config = kwargs.get("tool_config", None) # type: ignore
|
|
186
|
+
if tool_config:
|
|
187
|
+
# tool_config does not have to_dict or any other serializable object
|
|
188
|
+
prompt["tool_config"] = str(tool_config) # type: ignore
|
|
189
|
+
|
|
190
|
+
@override
|
|
191
|
+
def process_chunk(self, chunk: Any) -> bool:
|
|
192
|
+
response_dict: dict[str, Any] = chunk.to_dict()
|
|
193
|
+
if "provider_response_id" not in self._ingest:
|
|
194
|
+
id = response_dict.get("response_id", None)
|
|
195
|
+
if id:
|
|
196
|
+
self._ingest["provider_response_id"] = id
|
|
197
|
+
|
|
198
|
+
model: str = response_dict.get("model_version", "")
|
|
199
|
+
|
|
200
|
+
self._ingest["resource"] = "google." + model
|
|
201
|
+
|
|
202
|
+
for candidate in response_dict.get("candidates", []):
|
|
203
|
+
parts = candidate.get("content", {}).get("parts", [])
|
|
204
|
+
for part in parts:
|
|
205
|
+
self._candiates_character_count += count_chars_skip_spaces(part.get("text", ""))
|
|
206
|
+
|
|
207
|
+
usage = response_dict.get("usage_metadata", {})
|
|
208
|
+
if usage and "prompt_token_count" in usage and "candidates_token_count" in usage:
|
|
209
|
+
self._compute_usage(response_dict, streaming_candidates_characters=self._candiates_character_count)
|
|
210
|
+
|
|
211
|
+
return True
|
|
212
|
+
|
|
213
|
+
@staticmethod
|
|
214
|
+
def _is_character_billing_model(model: str) -> bool:
|
|
215
|
+
return model.startswith("gemini-1.")
|
|
216
|
+
|
|
217
|
+
@override
|
|
218
|
+
def process_synchronous_response(
|
|
219
|
+
self,
|
|
220
|
+
response: Any,
|
|
221
|
+
log_prompt_and_response: bool,
|
|
222
|
+
kwargs: Any) -> Any:
|
|
223
|
+
response_dict = response.to_dict()
|
|
224
|
+
|
|
225
|
+
self._ingest["provider_response_id"] = response_dict["response_id"]
|
|
226
|
+
self._ingest["resource"] = "google." + response_dict["model_version"]
|
|
227
|
+
|
|
228
|
+
self._compute_usage(response_dict)
|
|
229
|
+
|
|
230
|
+
if log_prompt_and_response:
|
|
231
|
+
self._ingest["provider_response_json"] = [json.dumps(response_dict)]
|
|
232
|
+
|
|
233
|
+
return None
|
|
234
|
+
|
|
235
|
+
def add_units(self, key: str, input: Optional[int] = None, output: Optional[int] = None) -> None:
|
|
236
|
+
if key not in self._ingest["units"]:
|
|
237
|
+
self._ingest["units"][key] = {}
|
|
238
|
+
if input is not None:
|
|
239
|
+
self._ingest["units"][key]["input"] = input
|
|
240
|
+
if output is not None:
|
|
241
|
+
self._ingest["units"][key]["output"] = output
|
|
242
|
+
|
|
243
|
+
def _compute_usage(self, response_dict: 'dict[str, Any]', streaming_candidates_characters: Optional[int] = None) -> None:
|
|
244
|
+
usage = response_dict.get("usage_metadata", {})
|
|
245
|
+
input = usage.get("prompt_token_count", 0)
|
|
246
|
+
|
|
247
|
+
prompt_tokens_details: list[dict[str, Any]] = usage.get("prompt_tokens_details")
|
|
248
|
+
candidates_tokens_details: list[dict[str, Any]] = usage.get("candidates_tokens_details")
|
|
249
|
+
|
|
250
|
+
model: str = response_dict.get("model_version", "")
|
|
251
|
+
|
|
252
|
+
if self._is_character_billing_model(model):
|
|
253
|
+
# gemini 1.0 and 1.5 units are reported in characters, per second, per image, etc...
|
|
254
|
+
large_context = "" if input < 128000 else "_large_context"
|
|
255
|
+
|
|
256
|
+
for details in prompt_tokens_details:
|
|
257
|
+
modality = details.get("modality", "")
|
|
258
|
+
if not modality:
|
|
259
|
+
continue
|
|
260
|
+
|
|
261
|
+
modality_token_count = details.get("token_count", 0)
|
|
262
|
+
if modality == "TEXT":
|
|
263
|
+
input = self._prompt_character_count
|
|
264
|
+
if input == 0:
|
|
265
|
+
# back up calc if nothing was calculated from the prompt
|
|
266
|
+
input = response_dict["usage_metadata"]["prompt_token_count"] * 4
|
|
267
|
+
|
|
268
|
+
output = 0
|
|
269
|
+
if streaming_candidates_characters is None:
|
|
270
|
+
for candidate in response_dict.get("candidates", []):
|
|
271
|
+
parts = candidate.get("content", {}).get("parts", [])
|
|
272
|
+
for part in parts:
|
|
273
|
+
output += count_chars_skip_spaces(part.get("text", ""))
|
|
274
|
+
|
|
275
|
+
if output == 0:
|
|
276
|
+
# back up calc if no parts
|
|
277
|
+
output = response_dict["usage_metadata"]["candidates_token_count"] * 4
|
|
278
|
+
else:
|
|
279
|
+
output = streaming_candidates_characters
|
|
280
|
+
|
|
281
|
+
self._ingest["units"]["text"+large_context] = Units(input=input, output=output)
|
|
282
|
+
|
|
283
|
+
elif modality == "IMAGE":
|
|
284
|
+
num_images = math.ceil(modality_token_count / 258)
|
|
285
|
+
self.add_units("vision"+large_context, input=num_images)
|
|
286
|
+
|
|
287
|
+
elif modality == "VIDEO":
|
|
288
|
+
video_seconds = math.ceil(modality_token_count / 285)
|
|
289
|
+
self.add_units("video"+large_context, input=video_seconds)
|
|
290
|
+
|
|
291
|
+
elif modality == "AUDIO":
|
|
292
|
+
audio_seconds = math.ceil(modality_token_count / 25)
|
|
293
|
+
self.add_units("audio"+large_context, input=audio_seconds)
|
|
294
|
+
|
|
295
|
+
elif model.startswith("gemini-2.0"):
|
|
296
|
+
for details in prompt_tokens_details:
|
|
297
|
+
modality = details.get("modality", "")
|
|
298
|
+
if not modality:
|
|
299
|
+
continue
|
|
300
|
+
|
|
301
|
+
modality_token_count = details.get("token_count", 0)
|
|
302
|
+
if modality == "IMAGE":
|
|
303
|
+
self.add_units("vision", input=modality_token_count)
|
|
304
|
+
elif modality in ("VIDEO", "AUDIO", "TEXT"):
|
|
305
|
+
self.add_units(modality.lower(), input=modality_token_count)
|
|
306
|
+
for details in candidates_tokens_details:
|
|
307
|
+
modality = details.get("modality", "")
|
|
308
|
+
if not modality:
|
|
309
|
+
continue
|
|
310
|
+
|
|
311
|
+
modality_token_count = details.get("token_count", 0)
|
|
312
|
+
if modality in ("VIDEO", "AUDIO", "TEXT", "IMAGE"):
|
|
313
|
+
self.add_units(modality.lower(), output=modality_token_count)
|
|
@@ -22,6 +22,7 @@ class PayiCategories:
|
|
|
22
22
|
openai:str = "system.openai"
|
|
23
23
|
azure_openai:str = "system.azureopenai"
|
|
24
24
|
aws_bedrock:str = "system.aws.bedrock"
|
|
25
|
+
google_vertex:str = "system.google.vertex"
|
|
25
26
|
|
|
26
27
|
def create_limit_header_from_ids(limit_ids: List[str]) -> Dict[str, str]:
|
|
27
28
|
if not isinstance(limit_ids, list): # type: ignore
|
|
@@ -40,7 +41,6 @@ def create_request_header_from_tags(request_tags: List[str]) -> Dict[str, str]:
|
|
|
40
41
|
|
|
41
42
|
return { PayiHeaderNames.request_tags: ",".join(valid_tags) } if valid_tags else {}
|
|
42
43
|
|
|
43
|
-
|
|
44
44
|
def create_headers(
|
|
45
45
|
limit_ids: Union[List[str], None] = None,
|
|
46
46
|
request_tags: Union[List[str], None] = None,
|