payi 0.1.0a76__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.0a76 → payi-0.1.0a78}/CHANGELOG.md +22 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/CONTRIBUTING.md +1 -2
- {payi-0.1.0a76 → payi-0.1.0a78}/PKG-INFO +2 -7
- {payi-0.1.0a76 → payi-0.1.0a78}/README.md +1 -6
- {payi-0.1.0a76 → payi-0.1.0a78}/pyproject.toml +1 -1
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_base_client.py +6 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_models.py +2 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_types.py +2 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_version.py +1 -1
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/lib/AnthropicInstrumentor.py +43 -9
- {payi-0.1.0a76 → 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.0a76 → payi-0.1.0a78}/src/payi/lib/OpenAIInstrumentor.py +6 -2
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/lib/VertexInstrumentor.py +8 -5
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/lib/instrument.py +109 -41
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/test_client.py +54 -0
- payi-0.1.0a76/.release-please-manifest.json +0 -3
- {payi-0.1.0a76 → payi-0.1.0a78}/.gitignore +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/LICENSE +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/SECURITY.md +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/api.md +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/bin/check-release-environment +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/bin/publish-pypi +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/examples/.keep +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/mypy.ini +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/noxfile.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/release-please-config.json +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/requirements-dev.lock +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/requirements.lock +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_client.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_compat.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_constants.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_exceptions.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_files.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_qs.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_resource.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_streaming.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_utils/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_utils/_logs.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_utils/_proxy.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_utils/_reflection.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_utils/_resources_proxy.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_utils/_streams.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_utils/_sync.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_utils/_transform.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_utils/_typing.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/_utils/_utils.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/lib/.keep +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/lib/Stopwatch.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/lib/helpers.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/pagination.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/py.typed +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/categories/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/categories/categories.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/categories/resources.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/experiences/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/experiences/experiences.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/experiences/properties.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/experiences/types/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/experiences/types/limit_config.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/experiences/types/types.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/ingest.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/limits/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/limits/limits.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/limits/tags.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/requests/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/requests/properties.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/requests/requests.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/requests/result.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/use_cases/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/use_cases/definitions/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/use_cases/definitions/definitions.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/use_cases/definitions/kpis.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/use_cases/definitions/limit_config.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/use_cases/definitions/version.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/use_cases/kpis.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/use_cases/properties.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/resources/use_cases/use_cases.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/bulk_ingest_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/categories/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/categories/resource_create_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/categories/resource_list_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/category_delete_resource_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/category_delete_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/category_list_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/category_list_resources_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/category_resource_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/category_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/cost_data.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/cost_details.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/default_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/experience_instance_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/experiences/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/experiences/experience_type.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/experiences/property_create_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/experiences/type_create_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/experiences/type_list_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/experiences/type_update_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/experiences/types/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/experiences/types/limit_config_create_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/ingest_bulk_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/ingest_event_param.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/ingest_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/ingest_units_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/limit_create_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/limit_history_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/limit_list_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/limit_list_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/limit_reset_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/limit_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/limit_update_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/limits/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/limits/limit_tags.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/limits/tag_create_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/limits/tag_create_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/limits/tag_delete_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/limits/tag_list_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/limits/tag_remove_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/limits/tag_remove_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/limits/tag_update_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/limits/tag_update_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/pay_i_common_models_api_router_header_info_param.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/requests/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/requests/property_create_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/requests/request_result.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/requests_data.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/shared/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/shared/evaluation_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/shared/ingest_units.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/shared/pay_i_common_models_budget_management_cost_details_base.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/shared/pay_i_common_models_budget_management_create_limit_base.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/shared/properties_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/shared/xproxy_error.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/shared/xproxy_result.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/shared_params/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/shared_params/ingest_units.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/shared_params/pay_i_common_models_budget_management_create_limit_base.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/total_cost_data.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_case_instance_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/definition_create_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/definition_list_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/definition_update_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/kpi_create_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/kpi_create_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/kpi_delete_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/kpi_list_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/kpi_list_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/kpi_retrieve_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/kpi_update_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/kpi_update_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/definitions/limit_config_create_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/kpi_create_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/kpi_list_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/kpi_list_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/kpi_update_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/property_create_params.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/src/payi/types/use_cases/use_case_definition.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/categories/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/categories/test_resources.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/experiences/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/experiences/test_properties.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/experiences/test_types.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/experiences/types/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/experiences/types/test_limit_config.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/limits/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/limits/test_tags.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/requests/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/requests/test_properties.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/requests/test_result.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/test_categories.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/test_experiences.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/test_ingest.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/test_limits.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/test_use_cases.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/use_cases/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/use_cases/definitions/__init__.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/use_cases/definitions/test_kpis.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/use_cases/definitions/test_limit_config.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/use_cases/definitions/test_version.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/use_cases/test_definitions.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/use_cases/test_kpis.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/api_resources/use_cases/test_properties.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/conftest.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/sample_file.txt +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/test_deepcopy.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/test_extract_files.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/test_files.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/test_models.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/test_qs.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/test_required_args.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/test_response.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/test_streaming.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/test_transform.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/test_utils/test_proxy.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/test_utils/test_typing.py +0 -0
- {payi-0.1.0a76 → payi-0.1.0a78}/tests/utils.py +0 -0
|
@@ -1,5 +1,27 @@
|
|
|
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
|
+
|
|
11
|
+
## 0.1.0-alpha.77 (2025-06-03)
|
|
12
|
+
|
|
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)
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* **client:** add follow_redirects request option ([3308085](https://github.com/Pay-i/pay-i-python/commit/3308085121c320d80931d6749f36ecee049be669))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Chores
|
|
21
|
+
|
|
22
|
+
* **docs:** remove reference to rye shell ([eb25599](https://github.com/Pay-i/pay-i-python/commit/eb255999808df39a9eaaf5b91825c8fe150dbf55))
|
|
23
|
+
* **docs:** remove unnecessary param examples ([4d34a34](https://github.com/Pay-i/pay-i-python/commit/4d34a343cd19fc091fb836d411034d9ad62bf564))
|
|
24
|
+
|
|
3
25
|
## 0.1.0-alpha.76 (2025-05-31)
|
|
4
26
|
|
|
5
27
|
Full Changelog: [v0.1.0-alpha.75...v0.1.0-alpha.76](https://github.com/Pay-i/pay-i-python/compare/v0.1.0-alpha.75...v0.1.0-alpha.76)
|
|
@@ -17,8 +17,7 @@ $ rye sync --all-features
|
|
|
17
17
|
You can then run scripts using `rye run python script.py` or by activating the virtual environment:
|
|
18
18
|
|
|
19
19
|
```sh
|
|
20
|
-
|
|
21
|
-
# or manually activate - https://docs.python.org/3/library/venv.html#how-venvs-work
|
|
20
|
+
# Activate the virtual environment - https://docs.python.org/3/library/venv.html#how-venvs-work
|
|
22
21
|
$ source .venv/bin/activate
|
|
23
22
|
|
|
24
23
|
# now you can omit the `rye run` prefix
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: payi
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.0a78
|
|
4
4
|
Summary: The official Python library for the payi API
|
|
5
5
|
Project-URL: Homepage, https://github.com/Pay-i/pay-i-python
|
|
6
6
|
Project-URL: Repository, https://github.com/Pay-i/pay-i-python
|
|
@@ -188,12 +188,7 @@ client = Payi()
|
|
|
188
188
|
use_case_definition = client.use_cases.definitions.create(
|
|
189
189
|
description="x",
|
|
190
190
|
name="x",
|
|
191
|
-
limit_config={
|
|
192
|
-
"max": 0,
|
|
193
|
-
"limit_tags": ["tag1", "tag2"],
|
|
194
|
-
"limit_type": "block",
|
|
195
|
-
"threshold": 0,
|
|
196
|
-
},
|
|
191
|
+
limit_config={"max": 0},
|
|
197
192
|
)
|
|
198
193
|
print(use_case_definition.limit_config)
|
|
199
194
|
```
|
|
@@ -154,12 +154,7 @@ client = Payi()
|
|
|
154
154
|
use_case_definition = client.use_cases.definitions.create(
|
|
155
155
|
description="x",
|
|
156
156
|
name="x",
|
|
157
|
-
limit_config={
|
|
158
|
-
"max": 0,
|
|
159
|
-
"limit_tags": ["tag1", "tag2"],
|
|
160
|
-
"limit_type": "block",
|
|
161
|
-
"threshold": 0,
|
|
162
|
-
},
|
|
157
|
+
limit_config={"max": 0},
|
|
163
158
|
)
|
|
164
159
|
print(use_case_definition.limit_config)
|
|
165
160
|
```
|
|
@@ -960,6 +960,9 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
|
|
|
960
960
|
if self.custom_auth is not None:
|
|
961
961
|
kwargs["auth"] = self.custom_auth
|
|
962
962
|
|
|
963
|
+
if options.follow_redirects is not None:
|
|
964
|
+
kwargs["follow_redirects"] = options.follow_redirects
|
|
965
|
+
|
|
963
966
|
log.debug("Sending HTTP Request: %s %s", request.method, request.url)
|
|
964
967
|
|
|
965
968
|
response = None
|
|
@@ -1460,6 +1463,9 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
|
|
|
1460
1463
|
if self.custom_auth is not None:
|
|
1461
1464
|
kwargs["auth"] = self.custom_auth
|
|
1462
1465
|
|
|
1466
|
+
if options.follow_redirects is not None:
|
|
1467
|
+
kwargs["follow_redirects"] = options.follow_redirects
|
|
1468
|
+
|
|
1463
1469
|
log.debug("Sending HTTP Request: %s %s", request.method, request.url)
|
|
1464
1470
|
|
|
1465
1471
|
response = None
|
|
@@ -737,6 +737,7 @@ class FinalRequestOptionsInput(TypedDict, total=False):
|
|
|
737
737
|
idempotency_key: str
|
|
738
738
|
json_data: Body
|
|
739
739
|
extra_json: AnyMapping
|
|
740
|
+
follow_redirects: bool
|
|
740
741
|
|
|
741
742
|
|
|
742
743
|
@final
|
|
@@ -750,6 +751,7 @@ class FinalRequestOptions(pydantic.BaseModel):
|
|
|
750
751
|
files: Union[HttpxRequestFiles, None] = None
|
|
751
752
|
idempotency_key: Union[str, None] = None
|
|
752
753
|
post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven()
|
|
754
|
+
follow_redirects: Union[bool, None] = None
|
|
753
755
|
|
|
754
756
|
# It should be noted that we cannot use `json` here as that would override
|
|
755
757
|
# a BaseModel method in an incompatible fashion.
|
|
@@ -100,6 +100,7 @@ class RequestOptions(TypedDict, total=False):
|
|
|
100
100
|
params: Query
|
|
101
101
|
extra_json: AnyMapping
|
|
102
102
|
idempotency_key: str
|
|
103
|
+
follow_redirects: bool
|
|
103
104
|
|
|
104
105
|
|
|
105
106
|
# Sentinel class used until PEP 0661 is accepted
|
|
@@ -215,3 +216,4 @@ class _GenericAlias(Protocol):
|
|
|
215
216
|
|
|
216
217
|
class HttpxSendArgs(TypedDict, total=False):
|
|
217
218
|
auth: httpx.Auth
|
|
219
|
+
follow_redirects: bool
|
|
@@ -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
|