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
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ sap-ai-sdk-core = { workspace = true }
sap-ai-sdk-gen = { workspace = true }

[tool.uv.workspace]
members = ["packages/*"]
members = [
"packages/*",
"sample-code",
]

[tool.pip-licenses]
# Blue Oak Council Bronze+ permissive licenses (https://blueoakcouncil.org/list)
Expand Down
2 changes: 2 additions & 0 deletions sample-code/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
server:
uv run uvicorn sample_code.server:app --app-dir src --env-file .env --reload
41 changes: 41 additions & 0 deletions sample-code/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Sample Code - Work in Progress

Sample code to demonstrate the usage of the SAP Cloud SDK for AI.

## Prerequisites

Before running the application, ensure the following prerequisites are met:

- Python installation (3.10 or higher)
- uv installation (0.12)
- Credentials for [SAP AI Core](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/what-is-sap-ai-core) service configured.
- Deployments of the orchestration service as well as the following models in the resource group specified in the `.env` file below:
- `gpt-5.4-nano`
- `text-embedding-3-small`
- `anthropic--claude-4.6-sonnet`
- `gemini-3.5-flash`

## Local Deployment

Create a `.env` file in the sample-code directory with the complete content of your AI core service key by adding the following lines:

```bash
AICORE_CLIENT_ID="..."
AICORE_CLIENT_SECRET="..."
AICORE_AUTH_URL="..."
AICORE_BASE_URL="..."
```

Optionally, you can add the `AICORE_RESOURCE_GROUP` environment variable to specify a resource group different from the `default` one.

The server can be started with

```bash
uv run uvicorn sample_code.server:app --app-dir src --env-file .env --reload
```

or by running ```make```.

## Usage

When the server is running, head to `http://localhost:8000/docs` to see all available endpoints.
18 changes: 18 additions & 0 deletions sample-code/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[project]
name = "sample-code"
version = "0.1.0"
description = "Sample code for using the AI Core Python SDK"
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
"fastapi>=0.141.1",
"sap-ai-sdk-gen",
"uvicorn>=0.52.1",
]

[build-system]
requires = ["uv_build>=0.12.1,<0.13.0"]
build-backend = "uv_build"

[tool.uv.sources]
sap-ai-sdk-gen = { workspace = true, editable = true }
9 changes: 9 additions & 0 deletions sample-code/pyrightconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"venvPath": "..",
"venv": ".venv",
"extraPaths": [
"../packages/base",
"../packages/core",
"../packages/gen"
]
}
Empty file.
25 changes: 25 additions & 0 deletions sample-code/src/sample_code/amazon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from gen_ai_hub.proxy.native.amazon import Session


def converse():
"""
Run chat example for Claude 4.6 Sonnet.

Returns:
JSON object containing the model response as result.
"""
bedrock = Session().client(model_name="anthropic--claude-4.6-sonnet")
conversation = [
{
"role": "user",
"content": [
{
"text": "Describe the purpose of a 'Hello World' program in one sentence."
}
],
}
]
response = bedrock.converse(
messages=conversation,
)
return {"result": response["output"]["message"]["content"][0]["text"]}
80 changes: 80 additions & 0 deletions sample-code/src/sample_code/core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
from typing import Annotated

from ai_api_client_sdk.models.parameter_binding import ParameterBinding
from ai_core_sdk.ai_core_v2_client import AICoreV2Client
from fastapi import Body


def get_configurations():
"""
Get all configurations for the resource group specified in the .env file.

Returns:
A dict containing the configurations in a ConfigurationQueryResponse object.
"""
client = AICoreV2Client.from_env()
return client.configuration.query()


def create_configuration():
"""
Create configuration for GPT-5.4-nano.

The configuration is created for the resource group specified in the .env file.
"""
client = AICoreV2Client.from_env()
# for illustrative purposes the example config is hardcoded
parameter_bindings = [
ParameterBinding.from_dict({"key": "modelName", "value": "gpt-5.4-nano"}),
ParameterBinding.from_dict({"key": "modelVersion", "value": "latest"}),
]
return client.configuration.create(
name="my-gpt-5.4-nano-config",
scenario_id="foundation-models",
executable_id="azure-openai",
parameter_bindings=parameter_bindings,
input_artifact_bindings=[],
)


def get_deployments():
"""
Get all deployments for the resource group specified in the .env file.

Returns:
A dict containing the deployments in a DeploymentQueryResponse object.
"""
client = AICoreV2Client.from_env()
return client.deployment.query()


def create_deployment(configuration_id: Annotated[str, Body(embed=True)]):
"""
Create deployment for the configuration_id in the request body.

The deployment is created for the resource group specified in the .env file.
"""
client = AICoreV2Client.from_env()
return client.deployment.create(configuration_id=configuration_id)


def get_scenarios():
"""
Get all scenarios.

Returns:
A dict containing the scenarios in a ScenarioQueryResponse object.
"""
client = AICoreV2Client.from_env()
return client.scenario.query()


def get_models():
"""
Get all available models.

Returns:
A dict containing the models in a ModelQueryResponse object.
"""
client = AICoreV2Client.from_env()
return client.model.query()
69 changes: 69 additions & 0 deletions sample-code/src/sample_code/google.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from fastapi.responses import StreamingResponse
from gen_ai_hub.proxy import get_proxy_client
from gen_ai_hub.proxy.native.google_genai import Client
from google.genai import types


def generate():
"""
Run chat example for Gemini 3.5 Flash.

Returns:
JSON object containing the model response as result.
"""
proxy_client = get_proxy_client("gen-ai-hub")
client = Client(proxy_client=proxy_client)
response = client.models.generate_content(
model="gemini-3.5-flash", contents="How many paws are there for a dog?"
)
return {"result": response.candidates[0].content.parts[0].text}


def generate_stream():
"""
Run chat example with streaming response for Gemini 3.5 Flash.

Returns:
Streaming response emitting the produced text.
"""
proxy_client = get_proxy_client("gen-ai-hub")

client = Client(
proxy_client=proxy_client,
)

def stream():
stream = client.models.generate_content_stream(
model="gemini-3.5-flash", contents="Explain singularity in short terms."
)
for chunk in stream:
if chunk.text:
yield chunk.text

return StreamingResponse(stream(), media_type="text/plain")


def tool_call():
"""
Run chat example including a tool call for Gemini 3.5 Flash.

Returns:
JSON object containing the model response as result.
"""

# addition tool to call
def add(a: int, b: int) -> int:
"""Add two numbers."""
return a + b

proxy_client = get_proxy_client("gen-ai-hub")

client = Client(
proxy_client=proxy_client,
)
response = client.models.generate_content(
model="gemini-3.5-flash",
contents="What is 769 + 348?",
config=types.GenerateContentConfig(tools=[add]),
)
return {"result": response.candidates[0].content.parts[0].text}
Loading
Loading