Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions packages/gen/codegen/.openapi-generator-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
README.md
git_push.sh
setup.py
setup.cfg
pyproject.toml
requirements.txt
test-requirements.txt
tox.ini
.gitignore
.gitlab-ci.yml
.travis.yml
docs/
test/
.github/
.openapi-generator/
19 changes: 19 additions & 0 deletions packages/gen/codegen/rpt_1_5_generate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
# Regenerates rpt_1_5/generated/ from the vendored OpenAPI spec.
# Run from packages/gen/ directory.
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PKG_DIR="$(dirname "$SCRIPT_DIR")"
OUT_DIR="${PKG_DIR}/gen_ai_hub/proxy/native/rpt_1_5/generated"

mkdir -p "${OUT_DIR}"
cp "${SCRIPT_DIR}/.openapi-generator-ignore" "${OUT_DIR}/.openapi-generator-ignore"

docker run --rm \
-v "${PKG_DIR}:/local" \
openapitools/openapi-generator-cli generate \
-i /local/openapi_specs/sap-rpt-1.5_openapi.json \
-g python \
--additional-properties=library=httpx,packageName=generated \
-o /local/gen_ai_hub/proxy/native/rpt_1_5/generated
130 changes: 130 additions & 0 deletions packages/gen/gen_ai_hub/proxy/native/rpt_1_5/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# RPT 1.5 Native Client

Async Python client for the SAP RPT 1.5 prediction service. Models are auto-generated from
the OpenAPI spec; a thin hand-written wrapper wires SAP proxy authentication and deployment
URL resolution on top.

## File Structure

```
packages/gen/
├── openapi_specs/
│ └── sap-rpt-1.5_openapi.json # vendored spec snapshot
├── codegen/
│ ├── rpt_1_5_generate.sh # Docker regeneration command
│ └── .openapi-generator-ignore # excludes docs/tests from generator output
└── gen_ai_hub/proxy/native/
├── utils.py # shared proxy/auth utilities
└── rpt_1_5/
├── __init__.py # public surface re-exports
├── client.py # RPT15Client
├── models.py # readable aliases + factory functions
└── generated/ # openapi-generator output — DO NOT EDIT
├── api/
│ └── default_api.py
├── models/
├── api_client.py
├── configuration.py
└── rest.py
```

## Usage

```python
from gen_ai_hub.proxy.native.rpt_1_5 import (
RPT15Client,
PredictionConfig,
PredictionPlaceholder,
TargetColumnConfig,
rows_request,
columns_request,
)

# Build a row-oriented request
request = rows_request(
prediction_config=PredictionConfig(
target_columns=[
TargetColumnConfig(
name="SALESGROUP",
prediction_placeholder=PredictionPlaceholder("[PREDICT]"),
)
]
),
index_column="__row_idx__",
rows=[
{
"PRODUCT": "Laptop",
"PRICE": 999.99,
"SALESGROUP": "[PREDICT]",
"__row_idx__": "1",
},
],
)

# Predict — deployment URL and auth are resolved automatically
async with RPT15Client(model_name="sap-rpt-1.5") as client:
response = await client.predict(request)
predictions = response["predictions"]
```

## Request formats

### Row-oriented (`rows_request`)

Each row is a plain `dict`. Columns with `"[PREDICT]"` as the value are prediction targets.

```python
rows_request(
prediction_config=PredictionConfig(...),
rows=[{"COL_A": "value", "COL_B": 1.0}],
index_column="__row_idx__", # optional
parse_data_types=True, # optional, default True
)
```

### Column-oriented (`columns_request`)

Each column is a list of values, one per row.

```python
columns_request(
prediction_config=PredictionConfig(...),
columns={
"PRODUCT": ["Laptop", "Chair"],
"PRICE": [999.99, 142.99],
},
)
```

## Client

```python
RPT15Client(
model_name: str,
model_version: str | None = None, # None → server default (latest)
proxy_client: GenAIHubProxyClient | None = None, # None → process default
timeout: float | None = None,
)
```

Methods:

| Method | Description |
|---|---|
| `await client.predict(request)` | Run predictions; returns raw response dict |
| `await client.health()` | Check deployment health |
| `await client.close()` | Release the underlying HTTP connection pool |

Supports use as an async context manager (`async with`).

## Regenerating the generated code

```bash
cd packages/gen
bash codegen/rpt_1_5_generate.sh
```

The script runs `openapi-generator` via Docker — no local Java installation required.
The source spec is at `openapi_specs/sap-rpt-1.5_openapi.json`.

> **Do not edit files under `generated/` by hand.** Run the generator and commit the result.
34 changes: 34 additions & 0 deletions packages/gen/gen_ai_hub/proxy/native/rpt_1_5/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""RPT 1.5 native client — spec-generated with SAP auth wiring."""
from gen_ai_hub.proxy.native.rpt_1_5.client import RPT15Client
from gen_ai_hub.proxy.native.rpt_1_5.models import (
ColumnsRequest,
PredictionConfig,
PredictionPlaceholder,
PredictionResult,
PredictResponseMetadata,
PredictResponsePayload,
PredictResponseStatus,
RowsInnerValue,
RowsRequest,
SchemaFieldConfig,
TargetColumnConfig,
columns_request,
rows_request,
)

__all__ = [
"ColumnsRequest",
"PredictResponseMetadata",
"PredictResponsePayload",
"PredictResponseStatus",
"PredictionConfig",
"PredictionPlaceholder",
"PredictionResult",
"RPT15Client",
"RowsInnerValue",
"RowsRequest",
"SchemaFieldConfig",
"TargetColumnConfig",
"columns_request",
"rows_request",
]
98 changes: 98 additions & 0 deletions packages/gen/gen_ai_hub/proxy/native/rpt_1_5/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"""RPT 1.5 typed client with SAP proxy authentication."""
from __future__ import annotations

from typing import Self

from generated.api.default_api import DefaultApi
from generated.api_client import ApiClient
from generated.configuration import Configuration
from generated.models.predict_request_payload import PredictRequestPayload
from generated.models.predict_request_payload_one_of import (
PredictRequestPayloadOneOf as RowsRequest,
)
from generated.models.predict_request_payload_one_of1 import (
PredictRequestPayloadOneOf1 as ColumnsRequest,
)
from generated.rest import RESTClientObject

from gen_ai_hub import GenAIHubProxyClient
from gen_ai_hub.proxy.native.utils import (
build_sap_api_client,
get_proxy_client_instance,
resolve_deployment_url,
)


class RPT15Client:
"""Async client for the RPT 1.5 prediction service.

Resolves the deployment URL from the proxy client credentials using
model_name and optional model_version. All requests are authenticated
automatically via the SAP proxy client.

Usage::

async with RPT15Client(model_name="sap-rpt-1.5") as client:
response = await client.predict(request)

# or without context manager
client = RPT15Client(model_name="sap-rpt-1.5")
response = await client.predict(request)
await client.close()
"""

def __init__(
self,
model_name: str,
model_version: str | None = None,
proxy_client: GenAIHubProxyClient | None = None,
timeout: float | None = None,
) -> None:
self._proxy = get_proxy_client_instance(proxy_client)
base_url = resolve_deployment_url(self._proxy, model_name, model_version)
self._api_client = build_sap_api_client(
base_url=base_url,
proxy_client=self._proxy,
api_client_class=ApiClient,
configuration_class=Configuration,
rest_client_class=RESTClientObject,
timeout=timeout,
)
self._api = DefaultApi(self._api_client)

async def close(self) -> None:
"""Close the underlying HTTP client."""
await self._api_client.close()

async def __aenter__(self) -> Self:
return self

async def __aexit__(self, *_: object) -> None:
await self.close()

async def predict(self, request: RowsRequest | ColumnsRequest) -> object:
"""Make predictions from JSON data.

Returns the raw response dict. The generated PredictResponsePayload
deserializer cannot handle the spec's nested anyOf response structure,
so response_types_map is set to "object" to bypass it.
"""
payload = PredictRequestPayload(request)
_param = self._api._predict_serialize( # type: ignore[attr-defined] # pylint: disable=protected-access
predict_request_payload=payload,
content_encoding=None,
_request_auth=None,
_content_type=None,
_headers=None,
_host_index=0,
)
response_data = await self._api_client.call_api(*_param) # type: ignore[arg-type]
await response_data.read() # type: ignore[misc]
return self._api_client.response_deserialize( # type: ignore[no-any-return]
response_data=response_data,
response_types_map={"200": "object"},
).data

async def health(self) -> object:
"""Check the health of the RPT deployment."""
return await self._api.health() # type: ignore[no-any-return]
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# coding: utf-8

# flake8: noqa

"""
SAP RPT

A REST API for in-context learning with SAP RPT models.

The version of the OpenAPI document: 1.5.0
Generated by OpenAPI Generator (https://openapi-generator.tech)

Do not edit the class manually.
""" # noqa: E501


__version__ = "1.0.0"

# Define package exports
__all__ = [
"DefaultApi",
"ApiResponse",
"ApiClient",
"Configuration",
"OpenApiException",
"ApiTypeError",
"ApiValueError",
"ApiKeyError",
"ApiAttributeError",
"ApiException",
"ColumnType",
"ExplanationConfig",
"ExplanationResult",
"PredictRequestPayload",
"PredictRequestPayloadOneOf",
"PredictRequestPayloadOneOf1",
"PredictResponseMetadata",
"PredictResponsePayload",
"PredictResponseStatus",
"Prediction",
"PredictionConfig",
"PredictionPlaceholder",
"PredictionResult",
"PredictionsInnerValue",
"RowsInnerValue",
"SchemaFieldConfig",
"TargetColumnConfig",
]

# import apis into sdk package
from generated.api.default_api import DefaultApi as DefaultApi

# import ApiClient
from generated.api_response import ApiResponse as ApiResponse
from generated.api_client import ApiClient as ApiClient
from generated.configuration import Configuration as Configuration
from generated.exceptions import OpenApiException as OpenApiException
from generated.exceptions import ApiTypeError as ApiTypeError
from generated.exceptions import ApiValueError as ApiValueError
from generated.exceptions import ApiKeyError as ApiKeyError
from generated.exceptions import ApiAttributeError as ApiAttributeError
from generated.exceptions import ApiException as ApiException

# import models into sdk package
from generated.models.column_type import ColumnType as ColumnType
from generated.models.explanation_config import ExplanationConfig as ExplanationConfig
from generated.models.explanation_result import ExplanationResult as ExplanationResult
from generated.models.predict_request_payload import PredictRequestPayload as PredictRequestPayload
from generated.models.predict_request_payload_one_of import PredictRequestPayloadOneOf as PredictRequestPayloadOneOf
from generated.models.predict_request_payload_one_of1 import PredictRequestPayloadOneOf1 as PredictRequestPayloadOneOf1
from generated.models.predict_response_metadata import PredictResponseMetadata as PredictResponseMetadata
from generated.models.predict_response_payload import PredictResponsePayload as PredictResponsePayload
from generated.models.predict_response_status import PredictResponseStatus as PredictResponseStatus
from generated.models.prediction import Prediction as Prediction
from generated.models.prediction_config import PredictionConfig as PredictionConfig
from generated.models.prediction_placeholder import PredictionPlaceholder as PredictionPlaceholder
from generated.models.prediction_result import PredictionResult as PredictionResult
from generated.models.predictions_inner_value import PredictionsInnerValue as PredictionsInnerValue
from generated.models.rows_inner_value import RowsInnerValue as RowsInnerValue
from generated.models.schema_field_config import SchemaFieldConfig as SchemaFieldConfig
from generated.models.target_column_config import TargetColumnConfig as TargetColumnConfig

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# flake8: noqa

# import apis into api package
from generated.api.default_api import DefaultApi

Loading
Loading