diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Call orchestration service.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Call orchestration service.yml new file mode 100644 index 000000000..2f12245db --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Call orchestration service.yml @@ -0,0 +1,198 @@ +info: + name: Call orchestration service + type: http + seq: 10 + +http: + method: POST + url: "{{deploymentUrl}}/v2/completion" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource_group}}" + - name: Content-Type + value: application/json + - name: ai-inference-observability-persistence-mode + value: full + - name: ai-inference-observability-labels + value: ext.ai.sap.com/test=true + - name: ai-object-store-secret-name + value: inference-observability + body: + type: json + data: |- + { + "config": { + "modules": { + "prompt_templating": { + "prompt": { + "template": [ + { + "role": "user", + "content": "What is the speed of light?" + } + ] + }, + "model": { + "name": "gpt-5-mini", + "version": "latest", + "params": { + "max_completion_tokens": 3000 + } + } + } + } + } + } + auth: inherit + +runtime: + scripts: + - type: after-response + code: |- + if ( res.status == 200 ){ + bru.setEnvVar("inferenceId", res.getHeader("ai-inference-id")); + } + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{deploymentUrl}}/v2/completion" + method: POST + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + - name: ai-inference-observability-persistence-mode + value: full + - name: ai-inference-observability-labels + value: ext.ai.sap.com/test=true + disabled: true + - name: ai-object-store-secret-name + value: inference-observability + body: + type: json + data: |- + { + "config": { + "modules": { + "prompt_templating": { + "prompt": { + "template": [ + { + "role": "user", + "content": "What is the speed of light?" + } + ] + }, + "model": { + "name": "gpt-5-mini", + "version": "latest", + "params": { + "max_completion_tokens": 3000 + } + } + } + } + } + } + response: + status: 200 + statusText: OK + headers: + - name: date + value: Thu, 26 Mar 2026 13:11:20 GMT + - name: content-type + value: application/json + - name: ai-inference-id + value: 493452f3-6f81-4300-9bb7-52a58e6dcf99 + - name: content-length + value: "1996" + - name: x-upstream-service-time + value: "11624" + body: + type: json + data: |- + { + "request_id": "28ed9d67-2497-90f1-bd6d-28eb3532102f", + "intermediate_results": { + "templating": [ + { + "content": "What is the speed of light?", + "role": "user" + } + ], + "llm": { + "id": "chatcmpl-DNemX4kXudVcEIEjq2IIxqBNmi0GB", + "object": "chat.completion", + "created": 1774530681, + "model": "gpt-5-mini-2025-08-07", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "The speed of light in vacuum (symbol c) is exactly 299,792,458 metres per second by definition of the metre. That is about 3.00 × 10^8 m/s, ≈186,282 miles per second, or ≈1.079×10^9 km/h. \n\nNote: in materials (air, glass, water, etc.) light travels more slowly; c is the maximum speed at which information and causal effects can propagate according to relativity." + }, + "finish_reason": "stop" + } + ], + "usage": { + "completion_tokens": 367, + "prompt_tokens": 13, + "total_tokens": 380, + "prompt_tokens_details": { + "audio_tokens": 0, + "cached_tokens": 0 + }, + "completion_tokens_details": { + "accepted_prediction_tokens": 0, + "audio_tokens": 0, + "reasoning_tokens": 256, + "rejected_prediction_tokens": 0 + } + } + } + }, + "final_result": { + "id": "chatcmpl-DNemX4kXudVcEIEjq2IIxqBNmi0GB", + "object": "chat.completion", + "created": 1774530681, + "model": "gpt-5-mini-2025-08-07", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "The speed of light in vacuum (symbol c) is exactly 299,792,458 metres per second by definition of the metre. That is about 3.00 × 10^8 m/s, ≈186,282 miles per second, or ≈1.079×10^9 km/h. \n\nNote: in materials (air, glass, water, etc.) light travels more slowly; c is the maximum speed at which information and causal effects can propagate according to relativity." + }, + "finish_reason": "stop" + } + ], + "usage": { + "completion_tokens": 367, + "prompt_tokens": 13, + "total_tokens": 380, + "prompt_tokens_details": { + "audio_tokens": 0, + "cached_tokens": 0 + }, + "completion_tokens_details": { + "accepted_prediction_tokens": 0, + "audio_tokens": 0, + "reasoning_tokens": 256, + "rejected_prediction_tokens": 0 + } + } + } + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Check deployment status.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Check deployment status.yml new file mode 100644 index 000000000..6f14566c5 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Check deployment status.yml @@ -0,0 +1,92 @@ +info: + name: Check deployment status + type: http + seq: 9 + +http: + method: GET + url: "{{AI_API}}/lm/deployments/{{deploymentId}}" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + auth: inherit + +runtime: + scripts: + - type: after-response + code: |- + if ( res.status === 200 ){ + let data = res.getBody(); + if ( data.status == "RUNNING" ){ + bru.setEnvVar("deploymentUrl", data.deploymentUrl); + } + } + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/lm/deployments/{{deploymentId}}" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: date + value: Thu, 26 Mar 2026 12:21:25 GMT + - name: content-type + value: application/json + - name: content-length + value: "722" + - name: access-control-allow-origin + value: "null" + - name: access-control-allow-credentials + value: "false" + - name: cache-control + value: no-store, must-revalidate + - name: x-upstream-service-time + value: "41" + body: + type: json + data: |- + { + "id": "db664f32e41f2694", + "createdAt": "2026-03-26T11:44:12Z", + "modifiedAt": "2026-03-26T11:44:12Z", + "status": "RUNNING", + "details": { + "scaling": { + "backendDetails": {}, + "backend_details": {} + }, + "resources": { + "backendDetails": {}, + "backend_details": {} + } + }, + "scenarioId": "orchestration", + "configurationId": "a660a213-5933-4b2c-872b-c1dbb3e771c2", + "latestRunningConfigurationId": "a660a213-5933-4b2c-872b-c1dbb3e771c2", + "lastOperation": "CREATE", + "targetStatus": "RUNNING", + "submissionTime": "2026-03-26T11:45:18Z", + "startTime": "2026-03-26T11:46:33Z", + "configurationName": "orchestration-config", + "deploymentUrl": "https://api.ai.internalprod.eu-central-1.aws.ml.hana.ondemand.com/v2/inference/deployments/db664f32e41f2694" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Check resource group status.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Check resource group status.yml new file mode 100644 index 000000000..4aa852d73 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Check resource group status.yml @@ -0,0 +1,55 @@ +info: + name: Check resource group status + type: http + seq: 3 + +http: + method: GET + url: "{{AI_API}}/admin/resourceGroups/{{resource-group}}" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: Content-Type + value: application/json + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/admin/resourceGroups/{{resource-group}}" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: Content-Type + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: date + value: Thu, 26 Mar 2026 11:41:42 GMT + - name: content-type + value: application/json + - name: content-length + value: "281" + - name: x-upstream-service-time + value: "53" + body: + type: json + data: |- + { + "resourceGroupId": "test-inference-obs", + "status": "PROVISIONED", + "tenantId": "882ce703-31d9-4330-927c-d5e427ebfb87", + "zoneId": "882ce703-31d9-4330-927c-d5e427ebfb87", + "labels": [], + "statusMessage": "All onboarding steps are completed.", + "createdAt": "2026-03-26T11:41:25+00:00" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Create object store secret.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Create object store secret.yml new file mode 100644 index 000000000..f24f7c644 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Create object store secret.yml @@ -0,0 +1,85 @@ +info: + name: Create object store secret + type: http + seq: 5 + +http: + method: POST + url: "{{ai_api_url}}/admin/objectStoreSecrets" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: Content-Type + value: application/json + - name: AI-Resource-Group + value: "{{resource_group}}" + body: + type: json + data: |- + { + "name": "inference-observability", + "type": "S3", + "bucket": "hcp-b60330de-a879-4848-9a3d-0ac828f4517c", + "endpoint": "s3.eu-central-1.amazonaws.com", + "region": "eu-central-1", + "pathPrefix": "testing", + "data": { + "AWS_ACCESS_KEY_ID": "{{AWS_ACCESS_KEY_ID}}", + "AWS_SECRET_ACCESS_KEY": "{{AWS_SECRET_ACCESS_KEY}}" + } + } + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/admin/objectStoreSecrets" + method: POST + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: Content-Type + value: application/json + - name: AI-Resource-Group + value: "{{resource-group}}" + body: + type: json + data: |- + { + "name": "inference-observability", + "type": "S3", + "bucket": "inference-observability-302710561802-eu-central-1-an", + "endpoint": "s3.eu-central-1.amazonaws.com", + "region": "eu-central-1", + "pathPrefix": "testing", + "data": { + "AWS_ACCESS_KEY_ID": "{{AWS_ACCESS_KEY_ID}}", + "AWS_SECRET_ACCESS_KEY": "{{AWS_SECRET_ACCESS_KEY}}" + } + } + response: + status: 202 + statusText: Accepted + headers: + - name: date + value: Thu, 26 Mar 2026 14:04:14 GMT + - name: content-type + value: application/json + - name: content-length + value: "38" + - name: location + value: /objectStoreSecrets/inference-observability-object-store-secret + - name: x-upstream-service-time + value: "116" + body: + type: json + data: |- + { + "message": "secret has been created" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Create orchestration service configuration.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Create orchestration service configuration.yml new file mode 100644 index 000000000..703b6cd3d --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Create orchestration service configuration.yml @@ -0,0 +1,89 @@ +info: + name: Create orchestration service configuration + type: http + seq: 7 + +http: + method: POST + url: "{{ai_api_url}}/lm/configurations" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource_group}}" + - name: Content-Type + value: application/json + body: + type: json + data: |- + { + "name": "orchestration-config", + "executableId": "orchestration", + "scenarioId": "orchestration" + } + auth: inherit + +runtime: + scripts: + - type: after-response + code: |- + if ( res.status === 200 ) { + let data = res.getBody(); + bru.setEnvVar("configurationId", data.id); + } + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/lm/configurations" + method: POST + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + body: + type: json + data: |- + { + "name": "orchestration-config", + "executableId": "orchestration", + "scenarioId": "orchestration" + } + response: + status: 201 + statusText: Created + headers: + - name: date + value: Thu, 26 Mar 2026 11:41:59 GMT + - name: location + value: https://api.ai.internalprod.eu-central-1.aws.ml.hana.ondemand.com:None/api/v2/configurations/a660a213-5933-4b2c-872b-c1dbb3e771c2 + - name: content-type + value: application/json + - name: content-location + value: https://api.ai.internalprod.eu-central-1.aws.ml.hana.ondemand.com:None/api/v2/configurations/a660a213-5933-4b2c-872b-c1dbb3e771c2 + - name: content-length + value: "83" + - name: access-control-allow-origin + value: "null" + - name: access-control-allow-credentials + value: "false" + - name: cache-control + value: no-store, must-revalidate + - name: x-upstream-service-time + value: "89" + body: + type: json + data: |- + { + "id": "a660a213-5933-4b2c-872b-c1dbb3e771c2", + "message": "Configuration created" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Create resource group.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Create resource group.yml new file mode 100644 index 000000000..e1a827427 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Create resource group.yml @@ -0,0 +1,64 @@ +info: + name: Create resource group + type: http + seq: 2 + +http: + method: POST + url: "{{AI_API}}/admin/resourceGroups" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: Content-Type + value: application/json + body: + type: json + data: |- + { + "resourceGroupId": "{{resource-group}}" + } + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/admin/resourceGroups" + method: POST + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: Content-Type + value: application/json + body: + type: json + data: |- + { + "resourceGroupId": "{{resource-group}}" + } + response: + status: 202 + statusText: Accepted + headers: + - name: date + value: Thu, 26 Mar 2026 14:03:49 GMT + - name: content-type + value: application/json + - name: content-length + value: "95" + - name: location + value: /resourcegroups/inferenceobservability + - name: x-upstream-service-time + value: "143" + body: + type: json + data: |- + { + "resourceGroupId": "inferenceobservability", + "tenantId": "882ce703-31d9-4330-927c-d5e427ebfb87" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Deploy orchestration service.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Deploy orchestration service.yml new file mode 100644 index 000000000..980b94929 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Deploy orchestration service.yml @@ -0,0 +1,85 @@ +info: + name: Deploy orchestration service + type: http + seq: 8 + +http: + method: POST + url: "{{ai_api_url}}/lm/deployments" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource_group}}" + - name: Content-Type + value: application/json + body: + type: json + data: |- + { + "configurationId": "69b1ddb0-0cfa-4584-8b8c-b1f9ac04aa58" + } + auth: inherit + +runtime: + scripts: + - type: after-response + code: |- + if ( res.status == 202 ){ + let data = res.getBody(); + bru.setEnvVar("deploymentId", data.id); + } + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/lm/deployments" + method: POST + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + body: + type: json + data: |- + { + "configurationId": "{{configurationId}}" + } + response: + status: 202 + statusText: Accepted + headers: + - name: date + value: Thu, 26 Mar 2026 11:44:12 GMT + - name: location + value: https://api.ai.internalprod.eu-central-1.aws.ml.hana.ondemand.com:None/api/v2/deployments/db664f32e41f2694 + - name: content-type + value: application/json + - name: content-length + value: "105" + - name: access-control-allow-origin + value: "null" + - name: access-control-allow-credentials + value: "false" + - name: cache-control + value: no-store, must-revalidate + - name: x-upstream-service-time + value: "144" + body: + type: json + data: |- + { + "id": "db664f32e41f2694", + "deploymentUrl": "", + "message": "Deployment scheduled.", + "status": "UNKNOWN" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Fetch object store secrets.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Fetch object store secrets.yml new file mode 100644 index 000000000..5b1da28c8 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Fetch object store secrets.yml @@ -0,0 +1,69 @@ +info: + name: Fetch object store secrets + type: http + seq: 4 + +http: + method: GET + url: "{{ai_api_url}}/admin/objectStoreSecrets" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource_group}}" + - name: Content-Type + value: application/json + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/admin/objectStoreSecrets" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: date + value: Thu, 26 Mar 2026 12:51:46 GMT + - name: content-type + value: application/json + - name: content-length + value: "662" + - name: x-upstream-service-time + value: "118" + body: + type: json + data: |- + { + "count": 1, + "resources": [ + { + "metadata": { + "serving.kubeflow.org/s3-usehttps": "", + "serving.kubeflow.org/s3-verifyssl": "", + "serving.kubeflow.org/s3-endpoint": "s3.eu-central-1.amazonaws.com", + "serving.kubeflow.org/s3-region": "eu-central-1", + "storage.ai.sap.com/type": "S3", + "storage.ai.sap.com/bucket": "inference-observability-302710561802-eu-central-1-an", + "storage.ai.sap.com/endpoint": "s3.eu-central-1.amazonaws.com", + "storage.ai.sap.com/region": "eu-central-1", + "storage.ai.sap.com/pathPrefix": "testing" + }, + "name": "inference-observability" + } + ] + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Get a single delete Request.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Get a single delete Request.yml new file mode 100644 index 000000000..c8de89f01 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Get a single delete Request.yml @@ -0,0 +1,63 @@ +info: + name: Get a single delete Request + type: http + seq: 19 + +http: + method: GET + url: "{{AI_API}}/observability/inferencesDeleteRequests/{{deleteRequestId}}" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferencesDeleteRequests/{{deleteRequestId}}" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: content-type + value: application/json + - name: date + value: Thu, 26 Mar 2026 14:33:56 GMT + - name: content-length + value: "193" + - name: x-upstream-service-time + value: "21" + body: + type: json + data: |- + { + "status": "COMPLETED", + "filters": { + "labelSelectors": [ + { + "key": "ext.ai.sap.com/medium", + "value": "Mobile" + } + ] + }, + "submittedAt": "2026-03-26T14:16:33.0235469Z", + "completedAt": "2026-03-26T14:20:10.1378612Z" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Get all deployments.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Get all deployments.yml new file mode 100644 index 000000000..b0ee30107 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Get all deployments.yml @@ -0,0 +1,86 @@ +info: + name: Get all deployments + type: http + seq: 6 + +http: + method: GET + url: "{{ai_api_url}}/lm/deployments" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource_group}}" + - name: Content-Type + value: application/json + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/lm/deployments" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: date + value: Thu, 26 Mar 2026 12:41:25 GMT + - name: content-type + value: application/json + - name: content-length + value: "751" + - name: access-control-allow-origin + value: "null" + - name: access-control-allow-credentials + value: "false" + - name: cache-control + value: no-store, must-revalidate + - name: x-upstream-service-time + value: "40" + body: + type: json + data: |- + { + "count": 1, + "resources": [ + { + "id": "db664f32e41f2694", + "createdAt": "2026-03-26T11:44:12Z", + "modifiedAt": "2026-03-26T11:44:12Z", + "status": "RUNNING", + "details": { + "scaling": { + "backendDetails": {}, + "backend_details": {} + }, + "resources": { + "backendDetails": {}, + "backend_details": {} + } + }, + "scenarioId": "orchestration", + "configurationId": "a660a213-5933-4b2c-872b-c1dbb3e771c2", + "latestRunningConfigurationId": "a660a213-5933-4b2c-872b-c1dbb3e771c2", + "lastOperation": "CREATE", + "targetStatus": "RUNNING", + "submissionTime": "2026-03-26T11:45:18Z", + "startTime": "2026-03-26T11:46:33Z", + "configurationName": "orchestration-config", + "deploymentUrl": "https://api.ai.internalprod.eu-central-1.aws.ml.hana.ondemand.com/v2/inference/deployments/db664f32e41f2694" + } + ] + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Get inference feedback.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Get inference feedback.yml new file mode 100644 index 000000000..632c9452c --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Get inference feedback.yml @@ -0,0 +1,63 @@ +info: + name: Get inference feedback + type: http + seq: 14 + +http: + method: GET + url: "{{AI_API}}/observability/inferences/{{inferenceId}}/feedback" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferences/4ba60b4a-30ee-9070-9671-3fbca68ed085/feedback" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: default + - name: Content-Encoding + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: content-type + value: application/json + - name: date + value: Tue, 17 Mar 2026 09:47:40 GMT + - name: content-length + value: "118" + - name: server + value: istio-envoy + - name: x-upstream-service-time + value: "597" + body: + type: json + data: |- + { + "count": 2, + "resources": [ + { + "content": "This was another great suggestions" + }, + { + "content": "This was a great suggestions" + } + ] + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Get token.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Get token.yml new file mode 100644 index 000000000..fbccde2d9 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Get token.yml @@ -0,0 +1,49 @@ +info: + name: Get token + type: http + seq: 1 + +http: + method: POST + url: "{{ai_auth_url}}/oauth/token" + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + params: + - name: grant_type + value: client_credentials + type: query + disabled: true + body: + type: form-urlencoded + data: + - name: grant_type + value: client_credentials + - name: client_id + value: "{{client_id}}" + - name: client_secret + value: "{{client_secret}}" + auth: + type: bearer + token: "{{access_token}}" + +runtime: + scripts: + - type: before-request + code: |- + const client_id = bru.getEnvVar("CLIENT_ID"); + const client_secret = bru.getEnvVar("CLIENT_SECRET"); + const credentials = btoa(client_id + ":" + client_secret); + bru.setEnvVar("credentials", credentials); + - type: after-response + code: |- + if ( res.status === 200 ) { + let data = res.getBody(); + bru.setEnvVar("access_token", data.access_token); + } + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Post a delete request.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Post a delete request.yml new file mode 100644 index 000000000..bcb7c0055 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Post a delete request.yml @@ -0,0 +1,84 @@ +info: + name: Post a delete request + type: http + seq: 17 + +http: + method: POST + url: "{{AI_API}}/observability/inferencesDeleteRequests" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + body: + type: json + data: |- + { + "labelSelectors": [ + { + "key": "ext.ai.sap.com/medium", + "value": "Mobile" + } + ] + } + auth: inherit + +runtime: + scripts: + - type: after-response + code: |- + if (res.status === 202){ + let data = res.body; + bru.setEnvVar("deleteRequestId", data.id); + } + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferencesDeleteRequests" + method: POST + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + body: + type: json + data: |- + { + "labelSelectors": [ + { + "key": "ext.ai.sap.com/medium", + "value": "Mobile" + } + ] + } + response: + status: 202 + statusText: Accepted + headers: + - name: content-type + value: application/json + - name: date + value: Thu, 26 Mar 2026 14:16:33 GMT + - name: content-length + value: "46" + - name: x-upstream-service-time + value: "50" + body: + type: json + data: |- + { + "id": "806030dc-2047-47f9-a74d-8d88ed59e4d3" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Post feedback to an inference.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Post feedback to an inference.yml new file mode 100644 index 000000000..e8ec1f233 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Post feedback to an inference.yml @@ -0,0 +1,69 @@ +info: + name: Post feedback to an inference + type: http + seq: 13 + +http: + method: POST + url: "{{AI_API}}/observability/inferences/{{inferenceId}}/feedback" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + body: + type: json + data: |- + [{ + "content": { + "stars": 5 + } + }] + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferences/4ba60b4a-30ee-9070-9671-3fbca68ed085/feedback" + method: POST + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: default + - name: Content-Encoding + value: application/json + body: + type: json + data: |- + [{ + "content": "This was another great suggestions" + }] + response: + status: 202 + statusText: Accepted + headers: + - name: content-type + value: application/json + - name: date + value: Tue, 17 Mar 2026 09:47:36 GMT + - name: content-length + value: "31" + - name: server + value: istio-envoy + - name: x-upstream-service-time + value: "330" + body: + type: json + data: |- + { + "message": "feedback stored." + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Post labels to an inference.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Post labels to an inference.yml new file mode 100644 index 000000000..fd13f1c54 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Post labels to an inference.yml @@ -0,0 +1,73 @@ +info: + name: Post labels to an inference + type: http + seq: 15 + +http: + method: POST + url: "{{AI_API}}/observability/inferences/{{inferenceId}}/labels" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + body: + type: json + data: |- + [ + { + "key": "ext.ai.sap.com/medium", + "value": "Mobile" + } + ] + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferences/4ba60b4a-30ee-9070-9671-3fbca68ed085/labels" + method: POST + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: default + - name: Content-Encoding + value: application/json + body: + type: json + data: |- + [ + { + "key": "ext.ai.sap.com/medium", + "value": "Mobile" + } + ] + response: + status: 201 + statusText: Created + headers: + - name: content-type + value: application/json + - name: date + value: Tue, 17 Mar 2026 10:07:05 GMT + - name: content-length + value: "38" + - name: server + value: istio-envoy + - name: x-upstream-service-time + value: "206" + body: + type: json + data: |- + { + "message": "inference label stored." + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Retrieve all delete requests.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Retrieve all delete requests.yml new file mode 100644 index 000000000..affe23f78 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Retrieve all delete requests.yml @@ -0,0 +1,83 @@ +info: + name: Retrieve all delete requests + type: http + seq: 18 + +http: + method: GET + url: "{{AI_API}}/observability/inferencesDeleteRequests" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferencesDeleteRequests" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: content-type + value: application/json + - name: date + value: Thu, 26 Mar 2026 14:29:06 GMT + - name: content-length + value: "507" + - name: x-upstream-service-time + value: "34" + body: + type: json + data: |- + { + "count": 2, + "deletionRequests": [ + { + "status": "COMPLETED", + "filters": { + "labelSelectors": [ + { + "key": "ext.ai.sap.com/medium", + "value": "mobile" + } + ] + }, + "submittedAt": "2026-03-26T14:10:49.9673768Z", + "completedAt": "2026-03-26T14:15:11.3320086Z", + "id": "6a984a41-1df7-4864-887c-3a7b85f45521" + }, + { + "status": "COMPLETED", + "filters": { + "labelSelectors": [ + { + "key": "ext.ai.sap.com/medium", + "value": "Mobile" + } + ] + }, + "submittedAt": "2026-03-26T14:16:33.0235469Z", + "completedAt": "2026-03-26T14:20:10.1378612Z", + "id": "806030dc-2047-47f9-a74d-8d88ed59e4d3" + } + ] + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Retrieve all inferences with label.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Retrieve all inferences with label.yml new file mode 100644 index 000000000..db9d7af28 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Retrieve all inferences with label.yml @@ -0,0 +1,108 @@ +info: + name: Retrieve all inferences with label + type: http + seq: 16 + +http: + method: GET + url: "{{AI_API}}/observability/inferences?labelSelector=ext.ai.sap.com/medium=Mobile" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + params: + - name: labelSelector + value: ext.ai.sap.com/medium=Mobile + type: query + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferences?labelSelector=ext.ai.sap.com/medium=Mobile" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: default + - name: Content-Type + value: application/json + params: + - name: labelSelector + value: ext.ai.sap.com/medium=Mobile + type: query + response: + status: 200 + statusText: OK + headers: + - name: content-type + value: application/json + - name: date + value: Tue, 17 Mar 2026 10:59:44 GMT + - name: server + value: istio-envoy + - name: x-upstream-service-time + value: "298" + - name: transfer-encoding + value: chunked + body: + type: json + data: |- + { + "count": 1, + "resources": [ + { + "id": "4ba60b4a-30ee-9070-9671-3fbca68ed085", + "labels": [ + { + "key": "ext.ai.sap.com/use-case", + "value": "Accounting" + }, + { + "key": "ext.ai.sap.com/medium", + "value": "Mobile" + } + ], + "source": "llmaccess", + "resourceGroup": "default", + "deploymentId": "d64b3328cf209947", + "modelName": "gpt-4o", + "modelVersion": "2024-08-06", + "streaming": true, + "responseHttpCode": 200, + "inputTokens": 21, + "outputTokens": 15, + "latency": 637.341, + "request": "{\"url\": \"http://rg-openai-exploration-us.openai.azure.com/openai/deployments/gpt-4o-2024-08-06/chat/completions?api-version=2025-03-01-preview\", \"headers\": {\"Content-Type\": \"application/json\", \"api-key\": \"7f32c2cf9bf645e3b5cc0df2943b35bc\"}, \"body\": \"{\\\"messages\\\": [{\\\"role\\\": \\\"system\\\", \\\"content\\\": \\\"You are a helpful assistant.\\\"}, {\\\"role\\\": \\\"user\\\", \\\"content\\\": \\\"Tell me a joke\\\"}], \\\"temperature\\\": 1, \\\"stream\\\": true}\"}", + "response": "{\"choices\":[],\"created\":0,\"id\":\"\",\"model\":\"\",\"object\":\"\",\"prompt_filter_results\":[{\"prompt_index\":0,\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}]}, {\"choices\":[{\"content_filter_results\":{},\"delta\":{\"content\":\"\",\"refusal\":null,\"role\":\"assistant\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"chatcmpl-DICL1F0EvnX4LeZOIlojYaKgD4FTf\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"Vqem\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fp_e9b9b028d7\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\"Why\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"chatcmpl-DICL1F0EvnX4LeZOIlojYaKgD4FTf\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"lYY\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fp_e9b9b028d7\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" don't\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"chatcmpl-DICL1F0EvnX4LeZOIlojYaKgD4FTf\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fp_e9b9b028d7\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" skeleton\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"chatcmpl-DICL1F0EvnX4LeZOIlojYaKgD4FTf\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"6CVftWn8HPiXo\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fp_e9b9b028d7\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\"s\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"chatcmpl-DICL1F0EvnX4LeZOIlojYaKgD4FTf\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"ipq7o\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fp_e9b9b028d7\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" fight\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"chatcmpl-DICL1F0EvnX4LeZOIlojYaKgD4FTf\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fp_e9b9b028d7\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" each\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"chatcmpl-DICL1F0EvnX4LeZOIlojYaKgD4FTf\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"O\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fp_e9b9b028d7\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" other\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"chatcmpl-DICL1F0EvnX4LeZOIlojYaKgD4FTf\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fp_e9b9b028d7\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\"?\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"chatcmpl-DICL1F0EvnX4LeZOIlojYaKgD4FTf\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"SN28G\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fp_e9b9b028d7\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" \\n\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"chatcmpl-DICL1F0EvnX4LeZOIlojYaKgD4FTf\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"LX\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fp_e9b9b028d7\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\"They\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"chatcmpl-DICL1F0EvnX4LeZOIlojYaKgD4FTf\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"2u\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fp_e9b9b028d7\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" don't\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"chatcmpl-DICL1F0EvnX4LeZOIlojYaKgD4FTf\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fp_e9b9b028d7\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" have\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"chatcmpl-DICL1F0EvnX4LeZOIlojYaKgD4FTf\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"2\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fp_e9b9b028d7\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" the\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"chatcmpl-DICL1F0EvnX4LeZOIlojYaKgD4FTf\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"Ai\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fp_e9b9b028d7\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" guts\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"chatcmpl-DICL1F0EvnX4LeZOIlojYaKgD4FTf\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"D\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fp_e9b9b028d7\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\"!\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"chatcmpl-DICL1F0EvnX4LeZOIlojYaKgD4FTf\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"ndseD\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fp_e9b9b028d7\"}, {\"choices\":[{\"content_filter_results\":{},\"delta\":{},\"finish_reason\":\"stop\",\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"chatcmpl-DICL1F0EvnX4LeZOIlojYaKgD4FTf\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fp_e9b9b028d7\"}, [DONE]", + "createdAt": "2026-03-11T11:48:24.3133655Z", + "objectStoreSecretName": "feedback-service-e2e-test-secret", + "feedback": [ + { + "content": { + "stars": 5 + } + }, + { + "content": "This was another great suggestions" + }, + { + "content": "This was a good response" + }, + { + "content": "This was a great suggestions" + } + ] + } + ] + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Retrieve all inferences.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Retrieve all inferences.yml new file mode 100644 index 000000000..3018cad12 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Retrieve all inferences.yml @@ -0,0 +1,165 @@ +info: + name: Retrieve all inferences + type: http + seq: 11 + +http: + method: GET + url: "{{AI_API}}/observability/inferences" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferences" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: content-type + value: application/json + - name: date + value: Thu, 26 Mar 2026 14:33:04 GMT + - name: x-upstream-service-time + value: "110" + - name: transfer-encoding + value: chunked + body: + type: json + data: |- + { + "count": 1, + "resources": [ + { + "id": "4ea1c986-ec03-4011-9731-c752b4188b3f", + "source": "orchestration", + "resourceGroup": "inferenceobservability", + "deploymentId": "d51944c2eeb63099", + "modelName": "gpt-5-mini", + "modelVersion": "latest", + "responseHttpCode": 200, + "inputTokens": 13, + "outputTokens": 383, + "latency": 8.058194893994369, + "request": { + "config": { + "modules": { + "prompt_templating": { + "prompt": { + "template": [ + { + "role": "user", + "content": "What is the speed of light?" + } + ] + }, + "model": { + "name": "gpt-5-mini", + "version": "latest", + "params": { + "max_completion_tokens": 3000 + } + } + } + } + } + }, + "response": { + "request_id": "37928603-f35e-91c8-9baf-b81eadc41ad7", + "intermediate_results": { + "templating": [ + { + "content": "What is the speed of light?", + "role": "user" + } + ], + "llm": { + "id": "chatcmpl-DNg3RvrIBf1CNGmyhaClr1ZHt1UUv", + "object": "chat.completion", + "created": 1774535573, + "model": "gpt-5-mini-2025-08-07", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "The speed of light in vacuum (symbol c) is exactly 299,792,458 meters per second. \n\nQuick equivalents and notes:\n- ≈ 299,792.458 km/s\n- ≈ 186,282.397 miles/s (≈ 670,616,629 mph)\n- Often rounded to 3.00 × 10^8 m/s for rough calculations.\n- In materials light travels slower by the refractive index n: v = c/n.\n- In special relativity c is the ultimate speed limit for information and for objects with mass." + }, + "finish_reason": "stop" + } + ], + "usage": { + "completion_tokens": 383, + "prompt_tokens": 13, + "total_tokens": 396, + "prompt_tokens_details": { + "audio_tokens": 0, + "cached_tokens": 0 + }, + "completion_tokens_details": { + "accepted_prediction_tokens": 0, + "audio_tokens": 0, + "reasoning_tokens": 256, + "rejected_prediction_tokens": 0 + } + } + } + }, + "final_result": { + "id": "chatcmpl-DNg3RvrIBf1CNGmyhaClr1ZHt1UUv", + "object": "chat.completion", + "created": 1774535573, + "model": "gpt-5-mini-2025-08-07", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "The speed of light in vacuum (symbol c) is exactly 299,792,458 meters per second. \n\nQuick equivalents and notes:\n- ≈ 299,792.458 km/s\n- ≈ 186,282.397 miles/s (≈ 670,616,629 mph)\n- Often rounded to 3.00 × 10^8 m/s for rough calculations.\n- In materials light travels slower by the refractive index n: v = c/n.\n- In special relativity c is the ultimate speed limit for information and for objects with mass." + }, + "finish_reason": "stop" + } + ], + "usage": { + "completion_tokens": 383, + "prompt_tokens": 13, + "total_tokens": 396, + "prompt_tokens_details": { + "audio_tokens": 0, + "cached_tokens": 0 + }, + "completion_tokens_details": { + "accepted_prediction_tokens": 0, + "audio_tokens": 0, + "reasoning_tokens": 256, + "rejected_prediction_tokens": 0 + } + } + } + }, + "createdAt": "2026-03-26T14:33:01.7065395Z", + "objectStoreSecretName": "inference-observability" + } + ] + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Retrieve one inference.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Retrieve one inference.yml new file mode 100644 index 000000000..c3b8b0eb9 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/Retrieve one inference.yml @@ -0,0 +1,160 @@ +info: + name: Retrieve one inference + type: http + seq: 12 + +http: + method: GET + url: "{{AI_API}}/observability/inferences/{{inferenceId}}" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferences/{{inferenceId}}" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: content-type + value: application/json + - name: date + value: Thu, 26 Mar 2026 14:33:22 GMT + - name: x-upstream-service-time + value: "226" + - name: transfer-encoding + value: chunked + body: + type: json + data: |- + { + "id": "4ea1c986-ec03-4011-9731-c752b4188b3f", + "source": "orchestration", + "resourceGroup": "inferenceobservability", + "deploymentId": "d51944c2eeb63099", + "modelName": "gpt-5-mini", + "modelVersion": "latest", + "responseHttpCode": 200, + "inputTokens": 13, + "outputTokens": 383, + "latency": 8.058194893994369, + "request": { + "config": { + "modules": { + "prompt_templating": { + "prompt": { + "template": [ + { + "role": "user", + "content": "What is the speed of light?" + } + ] + }, + "model": { + "name": "gpt-5-mini", + "version": "latest", + "params": { + "max_completion_tokens": 3000 + } + } + } + } + } + }, + "response": { + "request_id": "37928603-f35e-91c8-9baf-b81eadc41ad7", + "intermediate_results": { + "templating": [ + { + "content": "What is the speed of light?", + "role": "user" + } + ], + "llm": { + "id": "chatcmpl-DNg3RvrIBf1CNGmyhaClr1ZHt1UUv", + "object": "chat.completion", + "created": 1774535573, + "model": "gpt-5-mini-2025-08-07", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "The speed of light in vacuum (symbol c) is exactly 299,792,458 meters per second. \n\nQuick equivalents and notes:\n- ≈ 299,792.458 km/s\n- ≈ 186,282.397 miles/s (≈ 670,616,629 mph)\n- Often rounded to 3.00 × 10^8 m/s for rough calculations.\n- In materials light travels slower by the refractive index n: v = c/n.\n- In special relativity c is the ultimate speed limit for information and for objects with mass." + }, + "finish_reason": "stop" + } + ], + "usage": { + "completion_tokens": 383, + "prompt_tokens": 13, + "total_tokens": 396, + "prompt_tokens_details": { + "audio_tokens": 0, + "cached_tokens": 0 + }, + "completion_tokens_details": { + "accepted_prediction_tokens": 0, + "audio_tokens": 0, + "reasoning_tokens": 256, + "rejected_prediction_tokens": 0 + } + } + } + }, + "final_result": { + "id": "chatcmpl-DNg3RvrIBf1CNGmyhaClr1ZHt1UUv", + "object": "chat.completion", + "created": 1774535573, + "model": "gpt-5-mini-2025-08-07", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "The speed of light in vacuum (symbol c) is exactly 299,792,458 meters per second. \n\nQuick equivalents and notes:\n- ≈ 299,792.458 km/s\n- ≈ 186,282.397 miles/s (≈ 670,616,629 mph)\n- Often rounded to 3.00 × 10^8 m/s for rough calculations.\n- In materials light travels slower by the refractive index n: v = c/n.\n- In special relativity c is the ultimate speed limit for information and for objects with mass." + }, + "finish_reason": "stop" + } + ], + "usage": { + "completion_tokens": 383, + "prompt_tokens": 13, + "total_tokens": 396, + "prompt_tokens_details": { + "audio_tokens": 0, + "cached_tokens": 0 + }, + "completion_tokens_details": { + "accepted_prediction_tokens": 0, + "audio_tokens": 0, + "reasoning_tokens": 256, + "rejected_prediction_tokens": 0 + } + } + } + }, + "createdAt": "2026-03-26T14:33:01.7065395Z", + "objectStoreSecretName": "inference-observability" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/opencollection.yml b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/opencollection.yml new file mode 100644 index 000000000..10b440fbe --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/Bruno_collection/opencollection.yml @@ -0,0 +1,10 @@ +opencollection: 1.0.0 + +info: + name: FeedbackService Test +bundled: false +extensions: + bruno: + ignore: + - node_modules + - .git diff --git a/tutorials/ai-core-genaihub-inference-observability/ai-core-genaihub-inference-observability.md b/tutorials/ai-core-genaihub-inference-observability/ai-core-genaihub-inference-observability.md new file mode 100644 index 000000000..a67f0c991 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/ai-core-genaihub-inference-observability.md @@ -0,0 +1,368 @@ +--- +parser: v2 +auto_validation: true +time: 45 +primary_tag: software-product>sap-ai-core +tags: [ tutorial>beginner, topic>artificial-intelligence, topic>machine-learning, software-product>sap-ai-core ] +author_name: Smita Naik +author_profile: https://github.com/I321506 +--- + +# Inference Observability & Feedback Workflow in SAP AI Core + In this tutorial, you will learn how to execute AI inferences and leverage Inference Observability in SAP AI Core to track, analyze, and improve model responses using feedback and labeling mechanisms. + +## You will learn + +- How to execute inference using orchestration or foundation models +- How to record and retrieve inference details +- How to add feedback to improve responses +- How to use labels for filtering and analysis + +## Prerequisites +1. **BTP Account** + If you do not already have a commercial SAP Business Technology Platform (BTP) account, you can use **BTP Advanced Trial**. + [Create a BTP Account](https://developers.sap.com/group.btp-setup.html) +2. **For SAP Developers or Employees** + Internal SAP stakeholders should refer to the following documentation: [How to create BTP Account For Internal SAP Employee](https://me.sap.com/notes/3493139), [SAP AI Core Internal Documentation](https://help.sap.com/docs/sap-ai-core) +3. **For External Developers, Customers, or Partners** + Follow this tutorial to set up your environment and entitlements: [External Developer Setup Tutorial](https://developers.sap.com/tutorials/btp-cockpit-entitlements.html), [SAP AI Core External Documentation](https://help.sap.com/docs/sap-ai-core?version=CLOUD) +4. **Create BTP Instance and Service Key for SAP AI Core** + Follow the steps to create an instance and generate a service key for SAP AI Core. Ensure to use service plan **extended**: + [Create Service Key and Instance](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/create-service-key?version=CLOUD) +5. **AI Core Setup Guide** + Step-by-step guide to set up and get started with SAP AI Core: + [AI Core Setup Tutorial](https://developers.sap.com/tutorials/ai-core-genaihub-provisioning.html) +6. An **Extended** SAP AI Core service plan is required, as the Generative AI Hub is not available in the Free or Standard plans. For more details, refer to +[SAP AI Core Service Plans](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/service-plans?version=CLOUD) +7. **Bruno Tool Version** + Ensure you are using **Bruno version 3.1 or higher**. + Versions up to 3.0 do not support `.yml` files used in this tutorial. + You can download the latest version from: https://www.usebruno.com/ + +## Pre-Read + +In real-world AI applications, executing a model is only the first step. Once deployed, it becomes essential to monitor how the model behaves with actual user inputs, identify issues, and continuously improve the system. + +Inference Observability in SAP AI Core provides this capability by recording inference requests, responses, metadata, and feedback for later analysis. + +This feature works with both: + + - Orchestration services + - Foundation model deployments + +By enabling observability, AI systems move from being black-box models to transparent and trackable systems. + +**Note:** Inference data is recorded only when explicitly enabled using observability headers in the request. + +### Bruno Collection + +To simplify execution, this tutorial provides a pre-configured Bruno collection containing all required API requests. + +This collection includes: + + - Inference execution + - Observability APIs + - Feedback APIs + - Label management APIs + +👉 Download the Bruno collection from the link below: + +[Download Bruno Collection](ADD GITHUB LINK TO DOWNLOAD BRUNO COLLECTION HERE) + +**Import the Bruno Collection** + + - Open Bruno + - Navigate to Collections + - Click on open Collection + - Upload the downloaded folder files + +**Configure Environment Variables** + +After importing the collection: + + - Select any request (e.g., Get Token) + - Click on No Environment → Configure + - Provide the following values from your service key: + - ai_auth_url + - ai_api_url + - client_id + - client_secret + - resource_group + - Save the environment + - Select the configured environment before executing requests + +**Generate Access Token** + - Open the Get Token request + - Click Send to generate the access token + +Note: If the token expires during execution, regenerate it using the same request. + +### Initial Setup Overview + +Before working with inference observability, certain foundational components must be in place. + +**Setup & Authentication** + +You must first authenticate your API requests using an access token generated from your SAP AI Core service key. This ensures all subsequent API calls are securely authorized. + +**Resource & Deployment Setup** + +Inference execution requires an active deployment. You can use either: + + - An orchestration service + - A foundation model deployment + +This deployment acts as the endpoint where inference requests are sent and processed. + +**Object Store (S3) Setup** + +To store complete inference data (request, response, and feedback), an **Amazon S3 object store** must be configured. + + - Required when using **full persistence mode** + - Not required if storing **metadata only** + +**Important:** Only **S3 object stores** are supported by inference observability + +### Execute Inference and Enable Observability + +In this step, you will execute an inference request and enable observability to record the interaction. + +📂 Bruno File: + +Call orchestration service.yml + +**Step 1: Open the Request** + +Navigate to the **Call orchestration service** request in the Bruno collection. +This request is used to send prompts to the deployed orchestration or foundation model. + +**Step 2: Configure Headers** + +Ensure the following headers are included: + +```http +Authorization: Bearer +ai-resource-group: +ai-inference-observability-persistence-mode: full +ai-object-store-secret-name: +``` +These headers enable inference recording and specify where the data should be stored. + +**Step 3: Update Request Body** + +Provide the input prompt in the request body. For example: + +```json +{ + "config": { + "modules": { + "prompt_templating": { + "prompt": { + "template": [ + { + "role": "user", + "content": "What is the importance of AI in today's world?" + } + ] + }, + "model": { + "name": "anthropic--claude-3-haiku", + "version": "latest", + "params": { + "max_completion_tokens": 3000 + } + } + } + } + } +} +``` +**Step 4: Execute the Request** + +Click Send to execute the request. + +![img](img/img_001.png) + +**Step 5: Observe the Response** + - The model generates a response + - A response header ai-inference-id is returned + +This ID uniquely identifies the inference and acts as a reference for all subsequent operations such as retrieval, feedback submission, and labeling. + +**Explanation** + +At this stage: + + - The inference is executed + - Observability is enabled + - The request and response are recorded + +This forms the foundation for tracking and analysis. + +![img](img/img_002.png) + +**Important:** Only inferences sent to orchestration services or foundation model deployments are recorded in Inference Observability. + +### Retrieve and Analyze Inference (Observability) + +Once an inference is recorded, you can retrieve its details for analysis. + +📂 Bruno File + +Retrieve one inference.yml + +**Step 1: Open the Request** + +Navigate to the **Retrieve one inference** request. + +**Step 2: Provide Inference ID** + +Replace the placeholder with the **Inference ID** obtained from the previous step. + +**Step 3: Execute the Request** + +Click **Send** to fetch the inference details. + +![img](img/img_003.png) + +**Step 4: Analyze the Response** + +The response includes: + + - Model details + - Input and output tokens + - Latency + - Request and response payload (in full mode) + +**Explanation** + +This step allows you to: + + - Debug incorrect outputs + - Understand model behavior + - Analyze performance metrics + +👉 This is the core of **Inference Observability** + +#### Retrieve All Inferences + +Once multiple inferences are recorded, you can retrieve them collectively to analyze overall usage and system behavior. + +📂 Bruno File + +Retrieve all inferences.yml + +![img](img/img_004.png) + +This request returns all recorded inferences within the resource group, enabling broader monitoring and analysis. + +#### Retrieve Inferences Using Labels + +You can filter inferences using labels to perform targeted analysis across specific environments or use cases. + +📂 Bruno File + +Retrieve all inferences with label.yml + +![img](img/img_006.png) + +This request retrieves inferences that match the specified label criteria. + +### Add Feedback to Improve Responses + +Feedback helps improve the quality of AI responses over time by capturing user evaluation of model outputs. + +📂 Bruno File + +Post feedback to an inference.yml + +**Step 1: Open the Request** + +Navigate to the feedback request in the Bruno collection. + +**Step 2: Provide Inference ID** + +Replace the placeholder with the required inference ID + +**Step 3: Update Payload** + +```json +[ + { + "content": { + "stars": 5 + } + } +] +``` +**Step 4: Execute the Request** + +Click **Send** to submit feedback. + +**Explanation** + - Feedback is stored along with the inference + - Multiple feedback entries can be added + +![img](img/img_005.png) + +> **Important:** Feedback is supported only when persistence mode is set to `full`. + +### Retrieve Feedback + +Once feedback is added, you can retrieve it to analyze response quality and user ratings. + +📂 Bruno File + +Get inference feedback.yml + +This request retrieves all feedback associated with a specific inference, enabling evaluation of response quality. + +![img](img/img_007.png) + +### Use Labels for Filtering and Analysis + +Labels allow you to categorize and organize inference data for better monitoring and targeted analysis. + +📂 Bruno File + +Post labels to an inference.yml + +**Step 1: Open the Request** + +Navigate to the label request. + +**Step 2: Provide Payload** + +```json +[ + { + "key": "ext.ai.sap.com/medium", + "value": "mobile" + } +] +``` + +**Step 3: Execute the Request** + +Click Send to attach labels. + +![img](img/img_008.png) + +**Explanation** + +Labels help: + - Categorize inferences + - Filter results + - Perform targeted analysis + +**Note:** + - Label keys must use the prefix ext.ai.sap.com + - Maximum of 16 labels per inference + - Keys and values must not exceed 64 characters + +### Cleanup (Optional) + +Cleanup is performed using the delete inference API, where you can specify filters such as time range and labels. + +> **Important:** Only metadata is deleted. Request, response, and feedback stored in the object store (S3) are not removed. + diff --git a/tutorials/ai-core-genaihub-inference-observability/environments/wdftest.yml b/tutorials/ai-core-genaihub-inference-observability/environments/wdftest.yml new file mode 100644 index 000000000..088ec5477 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/environments/wdftest.yml @@ -0,0 +1,24 @@ +name: credentials +variables: + - name: ai_auth_url + value: + - name: ai_api_url + value: + - name: client_id + value: + - name: client_secret + value: + - name: resource_group + value: + - name: common_endpoint + value: /v2/lm/document-grounding + - name: deploymentUrl + value: + - name: credentials + value: dW5**********== + - name: access_token + value: + - name: AWS_ACCESS_KEY_ID + value: + - name: AWS_SECRET_ACCESS_KEY + value: diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Call_orchestration_service.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Call_orchestration_service.yml new file mode 100644 index 000000000..8ec42d4cd --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Call_orchestration_service.yml @@ -0,0 +1,198 @@ +info: + name: Call orchestration service + type: http + seq: 10 + +http: + method: POST + url: "{{deploymentUrl}}/v2/completion" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource_group}}" + - name: Content-Type + value: application/json + - name: ai-inference-observability-persistence-mode + value: full + - name: ai-inference-observability-labels + value: ext.ai.sap.com/test=true + - name: ai-object-store-secret-name + value: inference-observability + body: + type: json + data: |- + { + "config": { + "modules": { + "prompt_templating": { + "prompt": { + "template": [ + { + "role": "user", + "content": "What is the speed of light?" + } + ] + }, + "model": { + "name": "gpt-5-mini", + "version": "latest", + "params": { + "max_completion_tokens": 3000 + } + } + } + } + } + } + auth: inherit + +runtime: + scripts: + - type: after-response + code: |- + if ( res.status == 200 ){ + bru.setEnvVar("inferenceId", res.getHeader("ai-inference-id")); + } + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{deploymentUrl}}/v2/completion" + method: POST + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + - name: ai-inference-observability-persistence-mode + value: full + - name: ai-inference-observability-labels + value: ext.ai.sap.com/test=true + disabled: true + - name: ai-object-store-secret-name + value: inference-observability + body: + type: json + data: |- + { + "config": { + "modules": { + "prompt_templating": { + "prompt": { + "template": [ + { + "role": "user", + "content": "What is the speed of light?" + } + ] + }, + "model": { + "name": "gpt-5-mini", + "version": "latest", + "params": { + "max_completion_tokens": 3000 + } + } + } + } + } + } + response: + status: 200 + statusText: OK + headers: + - name: date + value: Thu, 26 Mar 2026 13:11:20 GMT + - name: content-type + value: application/json + - name: ai-inference-id + value: 493452f3-6f81-4300-9bb7-52a58e6dcf99 + - name: content-length + value: "1996" + - name: x-upstream-service-time + value: "11624" + body: + type: json + data: |- + { + "request_id": "", + "intermediate_results": { + "templating": [ + { + "content": "What is the speed of light?", + "role": "user" + } + ], + "llm": { + "id": "", + "object": "chat.completion", + "created": 1774530681, + "model": "gpt-5-mini-2025-08-07", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "The speed of light in vacuum (symbol c) is exactly 299,792,458 metres per second by definition of the metre. That is about 3.00 × 10^8 m/s, ≈186,282 miles per second, or ≈1.079×10^9 km/h. \n\nNote: in materials (air, glass, water, etc.) light travels more slowly; c is the maximum speed at which information and causal effects can propagate according to relativity." + }, + "finish_reason": "stop" + } + ], + "usage": { + "completion_tokens": 367, + "prompt_tokens": 13, + "total_tokens": 380, + "prompt_tokens_details": { + "audio_tokens": 0, + "cached_tokens": 0 + }, + "completion_tokens_details": { + "accepted_prediction_tokens": 0, + "audio_tokens": 0, + "reasoning_tokens": 256, + "rejected_prediction_tokens": 0 + } + } + } + }, + "final_result": { + "id": "", + "object": "chat.completion", + "created": 1774530681, + "model": "gpt-5-mini-2025-08-07", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "The speed of light in vacuum (symbol c) is exactly 299,792,458 metres per second by definition of the metre. That is about 3.00 × 10^8 m/s, ≈186,282 miles per second, or ≈1.079×10^9 km/h. \n\nNote: in materials (air, glass, water, etc.) light travels more slowly; c is the maximum speed at which information and causal effects can propagate according to relativity." + }, + "finish_reason": "stop" + } + ], + "usage": { + "completion_tokens": 367, + "prompt_tokens": 13, + "total_tokens": 380, + "prompt_tokens_details": { + "audio_tokens": 0, + "cached_tokens": 0 + }, + "completion_tokens_details": { + "accepted_prediction_tokens": 0, + "audio_tokens": 0, + "reasoning_tokens": 256, + "rejected_prediction_tokens": 0 + } + } + } + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Check_deployment_status.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Check_deployment_status.yml new file mode 100644 index 000000000..3b0e5c39d --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Check_deployment_status.yml @@ -0,0 +1,92 @@ +info: + name: Check deployment status + type: http + seq: 9 + +http: + method: GET + url: "{{AI_API}}/lm/deployments/{{deploymentId}}" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + auth: inherit + +runtime: + scripts: + - type: after-response + code: |- + if ( res.status === 200 ){ + let data = res.getBody(); + if ( data.status == "RUNNING" ){ + bru.setEnvVar("deploymentUrl", data.deploymentUrl); + } + } + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/lm/deployments/{{deploymentId}}" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: date + value: Thu, 26 Mar 2026 12:21:25 GMT + - name: content-type + value: application/json + - name: content-length + value: "722" + - name: access-control-allow-origin + value: "null" + - name: access-control-allow-credentials + value: "false" + - name: cache-control + value: no-store, must-revalidate + - name: x-upstream-service-time + value: "41" + body: + type: json + data: |- + { + "id": "", + "createdAt": "2026-03-26T11:44:12Z", + "modifiedAt": "2026-03-26T11:44:12Z", + "status": "RUNNING", + "details": { + "scaling": { + "backendDetails": {}, + "backend_details": {} + }, + "resources": { + "backendDetails": {}, + "backend_details": {} + } + }, + "scenarioId": "orchestration", + "configurationId": "", + "latestRunningConfigurationId": "", + "lastOperation": "CREATE", + "targetStatus": "RUNNING", + "submissionTime": "2026-03-26T11:45:18Z", + "startTime": "2026-03-26T11:46:33Z", + "configurationName": "orchestration-config", + "deploymentUrl": "" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Check_resource_group_status.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Check_resource_group_status.yml new file mode 100644 index 000000000..521b8c6ad --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Check_resource_group_status.yml @@ -0,0 +1,55 @@ +info: + name: Check resource group status + type: http + seq: 3 + +http: + method: GET + url: "{{AI_API}}/admin/resourceGroups/{{resource-group}}" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: Content-Type + value: application/json + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/admin/resourceGroups/{{resource-group}}" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: Content-Type + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: date + value: Thu, 26 Mar 2026 11:41:42 GMT + - name: content-type + value: application/json + - name: content-length + value: "281" + - name: x-upstream-service-time + value: "53" + body: + type: json + data: |- + { + "resourceGroupId": "test-inference-obs", + "status": "PROVISIONED", + "tenantId": "", + "zoneId": "", + "labels": [], + "statusMessage": "All onboarding steps are completed.", + "createdAt": "2026-03-26T11:41:25+00:00" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Create_object_store_secret.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Create_object_store_secret.yml new file mode 100644 index 000000000..076665929 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Create_object_store_secret.yml @@ -0,0 +1,85 @@ +info: + name: Create object store secret + type: http + seq: 5 + +http: + method: POST + url: "{{ai_api_url}}/admin/objectStoreSecrets" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: Content-Type + value: application/json + - name: AI-Resource-Group + value: "{{resource_group}}" + body: + type: json + data: |- + { + "name": "inference-observability", + "type": "S3", + "bucket": "", + "endpoint": "s3.eu-central-1.amazonaws.com", + "region": "eu-central-1", + "pathPrefix": "testing", + "data": { + "AWS_ACCESS_KEY_ID": "{{AWS_ACCESS_KEY_ID}}", + "AWS_SECRET_ACCESS_KEY": "{{AWS_SECRET_ACCESS_KEY}}" + } + } + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/admin/objectStoreSecrets" + method: POST + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: Content-Type + value: application/json + - name: AI-Resource-Group + value: "{{resource-group}}" + body: + type: json + data: |- + { + "name": "inference-observability", + "type": "S3", + "bucket": "", + "endpoint": "s3.eu-central-1.amazonaws.com", + "region": "eu-central-1", + "pathPrefix": "testing", + "data": { + "AWS_ACCESS_KEY_ID": "{{AWS_ACCESS_KEY_ID}}", + "AWS_SECRET_ACCESS_KEY": "{{AWS_SECRET_ACCESS_KEY}}" + } + } + response: + status: 202 + statusText: Accepted + headers: + - name: date + value: Thu, 26 Mar 2026 14:04:14 GMT + - name: content-type + value: application/json + - name: content-length + value: "38" + - name: location + value: /objectStoreSecrets/inference-observability-object-store-secret + - name: x-upstream-service-time + value: "116" + body: + type: json + data: |- + { + "message": "secret has been created" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Create_orchestration_service_configuration.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Create_orchestration_service_configuration.yml new file mode 100644 index 000000000..bd9624e3b --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Create_orchestration_service_configuration.yml @@ -0,0 +1,89 @@ +info: + name: Create orchestration service configuration + type: http + seq: 7 + +http: + method: POST + url: "{{ai_api_url}}/lm/configurations" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource_group}}" + - name: Content-Type + value: application/json + body: + type: json + data: |- + { + "name": "orchestration-config", + "executableId": "orchestration", + "scenarioId": "orchestration" + } + auth: inherit + +runtime: + scripts: + - type: after-response + code: |- + if ( res.status === 200 ) { + let data = res.getBody(); + bru.setEnvVar("configurationId", data.id); + } + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/lm/configurations" + method: POST + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + body: + type: json + data: |- + { + "name": "orchestration-config", + "executableId": "orchestration", + "scenarioId": "orchestration" + } + response: + status: 201 + statusText: Created + headers: + - name: date + value: Thu, 26 Mar 2026 11:41:59 GMT + - name: location + value: + - name: content-type + value: application/json + - name: content-location + value: + - name: content-length + value: "83" + - name: access-control-allow-origin + value: "null" + - name: access-control-allow-credentials + value: "false" + - name: cache-control + value: no-store, must-revalidate + - name: x-upstream-service-time + value: "89" + body: + type: json + data: |- + { + "id": "", + "message": "Configuration created" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Create_resource_group.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Create_resource_group.yml new file mode 100644 index 000000000..10b435f16 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Create_resource_group.yml @@ -0,0 +1,64 @@ +info: + name: Create resource group + type: http + seq: 2 + +http: + method: POST + url: "{{AI_API}}/admin/resourceGroups" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: Content-Type + value: application/json + body: + type: json + data: |- + { + "resourceGroupId": "{{resource-group}}" + } + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/admin/resourceGroups" + method: POST + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: Content-Type + value: application/json + body: + type: json + data: |- + { + "resourceGroupId": "{{resource-group}}" + } + response: + status: 202 + statusText: Accepted + headers: + - name: date + value: Thu, 26 Mar 2026 14:03:49 GMT + - name: content-type + value: application/json + - name: content-length + value: "95" + - name: location + value: /resourcegroups/ + - name: x-upstream-service-time + value: "143" + body: + type: json + data: |- + { + "resourceGroupId": "", + "tenantId": "" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Deploy_orchestration_service.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Deploy_orchestration_service.yml new file mode 100644 index 000000000..4d5f1a1ce --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Deploy_orchestration_service.yml @@ -0,0 +1,85 @@ +info: + name: Deploy orchestration service + type: http + seq: 8 + +http: + method: POST + url: "{{ai_api_url}}/lm/deployments" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource_group}}" + - name: Content-Type + value: application/json + body: + type: json + data: |- + { + "configurationId": "" + } + auth: inherit + +runtime: + scripts: + - type: after-response + code: |- + if ( res.status == 202 ){ + let data = res.getBody(); + bru.setEnvVar("deploymentId", data.id); + } + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/lm/deployments" + method: POST + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + body: + type: json + data: |- + { + "configurationId": "{{configurationId}}" + } + response: + status: 202 + statusText: Accepted + headers: + - name: date + value: Thu, 26 Mar 2026 11:44:12 GMT + - name: location + value: + - name: content-type + value: application/json + - name: content-length + value: "105" + - name: access-control-allow-origin + value: "null" + - name: access-control-allow-credentials + value: "false" + - name: cache-control + value: no-store, must-revalidate + - name: x-upstream-service-time + value: "144" + body: + type: json + data: |- + { + "id": "", + "deploymentUrl": "", + "message": "Deployment scheduled.", + "status": "UNKNOWN" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Fetch_object_store_secrets.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Fetch_object_store_secrets.yml new file mode 100644 index 000000000..b4de12774 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Fetch_object_store_secrets.yml @@ -0,0 +1,69 @@ +info: + name: Fetch object store secrets + type: http + seq: 4 + +http: + method: GET + url: "{{ai_api_url}}/admin/objectStoreSecrets" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource_group}}" + - name: Content-Type + value: application/json + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/admin/objectStoreSecrets" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: date + value: Thu, 26 Mar 2026 12:51:46 GMT + - name: content-type + value: application/json + - name: content-length + value: "662" + - name: x-upstream-service-time + value: "118" + body: + type: json + data: |- + { + "count": 1, + "resources": [ + { + "metadata": { + "serving.kubeflow.org/s3-usehttps": "", + "serving.kubeflow.org/s3-verifyssl": "", + "serving.kubeflow.org/s3-endpoint": "s3.eu-central-1.amazonaws.com", + "serving.kubeflow.org/s3-region": "eu-central-1", + "storage.ai.sap.com/type": "S3", + "storage.ai.sap.com/bucket": "", + "storage.ai.sap.com/endpoint": "s3.eu-central-1.amazonaws.com", + "storage.ai.sap.com/region": "eu-central-1", + "storage.ai.sap.com/pathPrefix": "testing" + }, + "name": "inference-observability" + } + ] + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Get_a_single_delete_Request.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Get_a_single_delete_Request.yml new file mode 100644 index 000000000..c8de89f01 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Get_a_single_delete_Request.yml @@ -0,0 +1,63 @@ +info: + name: Get a single delete Request + type: http + seq: 19 + +http: + method: GET + url: "{{AI_API}}/observability/inferencesDeleteRequests/{{deleteRequestId}}" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferencesDeleteRequests/{{deleteRequestId}}" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: content-type + value: application/json + - name: date + value: Thu, 26 Mar 2026 14:33:56 GMT + - name: content-length + value: "193" + - name: x-upstream-service-time + value: "21" + body: + type: json + data: |- + { + "status": "COMPLETED", + "filters": { + "labelSelectors": [ + { + "key": "ext.ai.sap.com/medium", + "value": "Mobile" + } + ] + }, + "submittedAt": "2026-03-26T14:16:33.0235469Z", + "completedAt": "2026-03-26T14:20:10.1378612Z" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Get_all_deployments.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Get_all_deployments.yml new file mode 100644 index 000000000..5b749d84b --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Get_all_deployments.yml @@ -0,0 +1,86 @@ +info: + name: Get all deployments + type: http + seq: 6 + +http: + method: GET + url: "{{ai_api_url}}/lm/deployments" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource_group}}" + - name: Content-Type + value: application/json + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/lm/deployments" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: date + value: Thu, 26 Mar 2026 12:41:25 GMT + - name: content-type + value: application/json + - name: content-length + value: "751" + - name: access-control-allow-origin + value: "null" + - name: access-control-allow-credentials + value: "false" + - name: cache-control + value: no-store, must-revalidate + - name: x-upstream-service-time + value: "40" + body: + type: json + data: |- + { + "count": 1, + "resources": [ + { + "id": "", + "createdAt": "2026-03-26T11:44:12Z", + "modifiedAt": "2026-03-26T11:44:12Z", + "status": "RUNNING", + "details": { + "scaling": { + "backendDetails": {}, + "backend_details": {} + }, + "resources": { + "backendDetails": {}, + "backend_details": {} + } + }, + "scenarioId": "orchestration", + "configurationId": "", + "latestRunningConfigurationId": "", + "lastOperation": "CREATE", + "targetStatus": "RUNNING", + "submissionTime": "2026-03-26T11:45:18Z", + "startTime": "2026-03-26T11:46:33Z", + "configurationName": "orchestration-config", + "deploymentUrl": "" + } + ] + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Get_inference_feedback.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Get_inference_feedback.yml new file mode 100644 index 000000000..9f9c0a9b7 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Get_inference_feedback.yml @@ -0,0 +1,63 @@ +info: + name: Get inference feedback + type: http + seq: 14 + +http: + method: GET + url: "{{AI_API}}/observability/inferences/{{inferenceId}}/feedback" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferences//feedback" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: default + - name: Content-Encoding + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: content-type + value: application/json + - name: date + value: Tue, 17 Mar 2026 09:47:40 GMT + - name: content-length + value: "118" + - name: server + value: istio-envoy + - name: x-upstream-service-time + value: "597" + body: + type: json + data: |- + { + "count": 2, + "resources": [ + { + "content": "This was another great suggestions" + }, + { + "content": "This was a great suggestions" + } + ] + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Get_token.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Get_token.yml new file mode 100644 index 000000000..fbccde2d9 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Get_token.yml @@ -0,0 +1,49 @@ +info: + name: Get token + type: http + seq: 1 + +http: + method: POST + url: "{{ai_auth_url}}/oauth/token" + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + params: + - name: grant_type + value: client_credentials + type: query + disabled: true + body: + type: form-urlencoded + data: + - name: grant_type + value: client_credentials + - name: client_id + value: "{{client_id}}" + - name: client_secret + value: "{{client_secret}}" + auth: + type: bearer + token: "{{access_token}}" + +runtime: + scripts: + - type: before-request + code: |- + const client_id = bru.getEnvVar("CLIENT_ID"); + const client_secret = bru.getEnvVar("CLIENT_SECRET"); + const credentials = btoa(client_id + ":" + client_secret); + bru.setEnvVar("credentials", credentials); + - type: after-response + code: |- + if ( res.status === 200 ) { + let data = res.getBody(); + bru.setEnvVar("access_token", data.access_token); + } + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Post_a_delete_request.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Post_a_delete_request.yml new file mode 100644 index 000000000..44b15aa9c --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Post_a_delete_request.yml @@ -0,0 +1,84 @@ +info: + name: Post a delete request + type: http + seq: 17 + +http: + method: POST + url: "{{AI_API}}/observability/inferencesDeleteRequests" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + body: + type: json + data: |- + { + "labelSelectors": [ + { + "key": "ext.ai.sap.com/medium", + "value": "Mobile" + } + ] + } + auth: inherit + +runtime: + scripts: + - type: after-response + code: |- + if (res.status === 202){ + let data = res.body; + bru.setEnvVar("deleteRequestId", data.id); + } + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferencesDeleteRequests" + method: POST + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + body: + type: json + data: |- + { + "labelSelectors": [ + { + "key": "ext.ai.sap.com/medium", + "value": "Mobile" + } + ] + } + response: + status: 202 + statusText: Accepted + headers: + - name: content-type + value: application/json + - name: date + value: Thu, 26 Mar 2026 14:16:33 GMT + - name: content-length + value: "46" + - name: x-upstream-service-time + value: "50" + body: + type: json + data: |- + { + "id": "" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Post_feedback_to_an_inference.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Post_feedback_to_an_inference.yml new file mode 100644 index 000000000..a220c6b5f --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Post_feedback_to_an_inference.yml @@ -0,0 +1,69 @@ +info: + name: Post feedback to an inference + type: http + seq: 13 + +http: + method: POST + url: "{{AI_API}}/observability/inferences/{{inferenceId}}/feedback" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + body: + type: json + data: |- + [{ + "content": { + "stars": 5 + } + }] + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferences//feedback" + method: POST + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: default + - name: Content-Encoding + value: application/json + body: + type: json + data: |- + [{ + "content": "This was another great suggestions" + }] + response: + status: 202 + statusText: Accepted + headers: + - name: content-type + value: application/json + - name: date + value: Tue, 17 Mar 2026 09:47:36 GMT + - name: content-length + value: "31" + - name: server + value: istio-envoy + - name: x-upstream-service-time + value: "330" + body: + type: json + data: |- + { + "message": "feedback stored." + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Post_labels_to_an_inference.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Post_labels_to_an_inference.yml new file mode 100644 index 000000000..27d099546 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Post_labels_to_an_inference.yml @@ -0,0 +1,73 @@ +info: + name: Post labels to an inference + type: http + seq: 15 + +http: + method: POST + url: "{{AI_API}}/observability/inferences/{{inferenceId}}/labels" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + body: + type: json + data: |- + [ + { + "key": "ext.ai.sap.com/medium", + "value": "Mobile" + } + ] + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferences//labels" + method: POST + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: default + - name: Content-Encoding + value: application/json + body: + type: json + data: |- + [ + { + "key": "ext.ai.sap.com/medium", + "value": "Mobile" + } + ] + response: + status: 201 + statusText: Created + headers: + - name: content-type + value: application/json + - name: date + value: Tue, 17 Mar 2026 10:07:05 GMT + - name: content-length + value: "38" + - name: server + value: istio-envoy + - name: x-upstream-service-time + value: "206" + body: + type: json + data: |- + { + "message": "inference label stored." + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Retrieve_all_delete_requests.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Retrieve_all_delete_requests.yml new file mode 100644 index 000000000..4d397b10d --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Retrieve_all_delete_requests.yml @@ -0,0 +1,83 @@ +info: + name: Retrieve all delete requests + type: http + seq: 18 + +http: + method: GET + url: "{{AI_API}}/observability/inferencesDeleteRequests" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferencesDeleteRequests" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: content-type + value: application/json + - name: date + value: Thu, 26 Mar 2026 14:29:06 GMT + - name: content-length + value: "507" + - name: x-upstream-service-time + value: "34" + body: + type: json + data: |- + { + "count": 2, + "deletionRequests": [ + { + "status": "COMPLETED", + "filters": { + "labelSelectors": [ + { + "key": "ext.ai.sap.com/medium", + "value": "mobile" + } + ] + }, + "submittedAt": "2026-03-26T14:10:49.9673768Z", + "completedAt": "2026-03-26T14:15:11.3320086Z", + "id": "" + }, + { + "status": "COMPLETED", + "filters": { + "labelSelectors": [ + { + "key": "ext.ai.sap.com/medium", + "value": "Mobile" + } + ] + }, + "submittedAt": "2026-03-26T14:16:33.0235469Z", + "completedAt": "2026-03-26T14:20:10.1378612Z", + "id": "" + } + ] + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Retrieve_all_inferences.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Retrieve_all_inferences.yml new file mode 100644 index 000000000..b3cccebe9 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Retrieve_all_inferences.yml @@ -0,0 +1,165 @@ +info: + name: Retrieve all inferences + type: http + seq: 11 + +http: + method: GET + url: "{{AI_API}}/observability/inferences" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferences" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: content-type + value: application/json + - name: date + value: Thu, 26 Mar 2026 14:33:04 GMT + - name: x-upstream-service-time + value: "110" + - name: transfer-encoding + value: chunked + body: + type: json + data: |- + { + "count": 1, + "resources": [ + { + "id": "", + "source": "orchestration", + "resourceGroup": "", + "deploymentId": "", + "modelName": "gpt-5-mini", + "modelVersion": "latest", + "responseHttpCode": 200, + "inputTokens": 13, + "outputTokens": 383, + "latency": 8.058194893994369, + "request": { + "config": { + "modules": { + "prompt_templating": { + "prompt": { + "template": [ + { + "role": "user", + "content": "What is the speed of light?" + } + ] + }, + "model": { + "name": "gpt-5-mini", + "version": "latest", + "params": { + "max_completion_tokens": 3000 + } + } + } + } + } + }, + "response": { + "request_id": "", + "intermediate_results": { + "templating": [ + { + "content": "What is the speed of light?", + "role": "user" + } + ], + "llm": { + "id": "", + "object": "chat.completion", + "created": 1774535573, + "model": "gpt-5-mini-2025-08-07", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "The speed of light in vacuum (symbol c) is exactly 299,792,458 meters per second. \n\nQuick equivalents and notes:\n- ≈ 299,792.458 km/s\n- ≈ 186,282.397 miles/s (≈ 670,616,629 mph)\n- Often rounded to 3.00 × 10^8 m/s for rough calculations.\n- In materials light travels slower by the refractive index n: v = c/n.\n- In special relativity c is the ultimate speed limit for information and for objects with mass." + }, + "finish_reason": "stop" + } + ], + "usage": { + "completion_tokens": 383, + "prompt_tokens": 13, + "total_tokens": 396, + "prompt_tokens_details": { + "audio_tokens": 0, + "cached_tokens": 0 + }, + "completion_tokens_details": { + "accepted_prediction_tokens": 0, + "audio_tokens": 0, + "reasoning_tokens": 256, + "rejected_prediction_tokens": 0 + } + } + } + }, + "final_result": { + "id": "", + "object": "chat.completion", + "created": 1774535573, + "model": "gpt-5-mini-2025-08-07", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "The speed of light in vacuum (symbol c) is exactly 299,792,458 meters per second. \n\nQuick equivalents and notes:\n- ≈ 299,792.458 km/s\n- ≈ 186,282.397 miles/s (≈ 670,616,629 mph)\n- Often rounded to 3.00 × 10^8 m/s for rough calculations.\n- In materials light travels slower by the refractive index n: v = c/n.\n- In special relativity c is the ultimate speed limit for information and for objects with mass." + }, + "finish_reason": "stop" + } + ], + "usage": { + "completion_tokens": 383, + "prompt_tokens": 13, + "total_tokens": 396, + "prompt_tokens_details": { + "audio_tokens": 0, + "cached_tokens": 0 + }, + "completion_tokens_details": { + "accepted_prediction_tokens": 0, + "audio_tokens": 0, + "reasoning_tokens": 256, + "rejected_prediction_tokens": 0 + } + } + } + }, + "createdAt": "2026-03-26T14:33:01.7065395Z", + "objectStoreSecretName": "inference-observability" + } + ] + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Retrieve_all_inferences_with_label.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Retrieve_all_inferences_with_label.yml new file mode 100644 index 000000000..e85820d7c --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Retrieve_all_inferences_with_label.yml @@ -0,0 +1,108 @@ +info: + name: Retrieve all inferences with label + type: http + seq: 16 + +http: + method: GET + url: "{{AI_API}}/observability/inferences?labelSelector=ext.ai.sap.com/medium=Mobile" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + params: + - name: labelSelector + value: ext.ai.sap.com/medium=Mobile + type: query + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferences?labelSelector=ext.ai.sap.com/medium=Mobile" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: default + - name: Content-Type + value: application/json + params: + - name: labelSelector + value: ext.ai.sap.com/medium=Mobile + type: query + response: + status: 200 + statusText: OK + headers: + - name: content-type + value: application/json + - name: date + value: Tue, 17 Mar 2026 10:59:44 GMT + - name: server + value: istio-envoy + - name: x-upstream-service-time + value: "298" + - name: transfer-encoding + value: chunked + body: + type: json + data: |- + { + "count": 1, + "resources": [ + { + "id": "", + "labels": [ + { + "key": "ext.ai.sap.com/use-case", + "value": "Accounting" + }, + { + "key": "ext.ai.sap.com/medium", + "value": "Mobile" + } + ], + "source": "llmaccess", + "resourceGroup": "default", + "deploymentId": "", + "modelName": "gpt-4o", + "modelVersion": "2024-08-06", + "streaming": true, + "responseHttpCode": 200, + "inputTokens": 21, + "outputTokens": 15, + "latency": 637.341, + "request": "{\"url\": \"http://rg-openai-exploration-us.openai.azure.com/openai/deployments/gpt-4o-2024-08-06/chat/completions?api-version=2025-03-01-preview\", \"headers\": {\"Content-Type\": \"application/json\", \"api-key\": \"\"}, \"body\": \"{\\\"messages\\\": [{\\\"role\\\": \\\"system\\\", \\\"content\\\": \\\"You are a helpful assistant.\\\"}, {\\\"role\\\": \\\"user\\\", \\\"content\\\": \\\"Tell me a joke\\\"}], \\\"temperature\\\": 1, \\\"stream\\\": true}\"}", + "response": "{\"choices\":[],\"created\":0,\"id\":\"\",\"model\":\"\",\"object\":\"\",\"prompt_filter_results\":[{\"prompt_index\":0,\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}]}, {\"choices\":[{\"content_filter_results\":{},\"delta\":{\"content\":\"\",\"refusal\":null,\"role\":\"assistant\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"Vqem\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\"Why\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"lYY\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" don't\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" skeleton\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"6CVftWn8HPiXo\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\"s\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"ipq7o\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" fight\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" each\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"O\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" other\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\"?\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"SN28G\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" \\n\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"LX\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\"They\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"2u\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" don't\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" have\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"2\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" the\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"Ai\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" guts\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"D\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"\"}, {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"protected_material_text\":{\"detected\":false,\"filtered\":false},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\"!\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"ndseD\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"\"}, {\"choices\":[{\"content_filter_results\":{},\"delta\":{},\"finish_reason\":\"stop\",\"index\":0,\"logprobs\":null}],\"created\":1773229703,\"id\":\"\",\"model\":\"gpt-4o-2024-08-06\",\"obfuscation\":\"\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"\"}, [DONE]", + "createdAt": "2026-03-11T11:48:24.3133655Z", + "objectStoreSecretName": "feedback-service-e2e-test-secret", + "feedback": [ + { + "content": { + "stars": 5 + } + }, + { + "content": "This was another great suggestions" + }, + { + "content": "This was a good response" + }, + { + "content": "This was a great suggestions" + } + ] + } + ] + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Retrieve_one_inference.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Retrieve_one_inference.yml new file mode 100644 index 000000000..2c5f50ec6 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/Retrieve_one_inference.yml @@ -0,0 +1,160 @@ +info: + name: Retrieve one inference + type: http + seq: 12 + +http: + method: GET + url: "{{AI_API}}/observability/inferences/{{inferenceId}}" + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +examples: + - name: example + request: + url: "{{AI_API}}/observability/inferences/{{inferenceId}}" + method: GET + headers: + - name: Authorization + value: Bearer {{access_token}} + - name: AI-Resource-Group + value: "{{resource-group}}" + - name: Content-Type + value: application/json + response: + status: 200 + statusText: OK + headers: + - name: content-type + value: application/json + - name: date + value: Thu, 26 Mar 2026 14:33:22 GMT + - name: x-upstream-service-time + value: "226" + - name: transfer-encoding + value: chunked + body: + type: json + data: |- + { + "id": "", + "source": "orchestration", + "resourceGroup": "", + "deploymentId": "", + "modelName": "gpt-5-mini", + "modelVersion": "latest", + "responseHttpCode": 200, + "inputTokens": 13, + "outputTokens": 383, + "latency": 8.058194893994369, + "request": { + "config": { + "modules": { + "prompt_templating": { + "prompt": { + "template": [ + { + "role": "user", + "content": "What is the speed of light?" + } + ] + }, + "model": { + "name": "gpt-5-mini", + "version": "latest", + "params": { + "max_completion_tokens": 3000 + } + } + } + } + } + }, + "response": { + "request_id": "", + "intermediate_results": { + "templating": [ + { + "content": "What is the speed of light?", + "role": "user" + } + ], + "llm": { + "id": "", + "object": "chat.completion", + "created": 1774535573, + "model": "gpt-5-mini-2025-08-07", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "The speed of light in vacuum (symbol c) is exactly 299,792,458 meters per second. \n\nQuick equivalents and notes:\n- ≈ 299,792.458 km/s\n- ≈ 186,282.397 miles/s (≈ 670,616,629 mph)\n- Often rounded to 3.00 × 10^8 m/s for rough calculations.\n- In materials light travels slower by the refractive index n: v = c/n.\n- In special relativity c is the ultimate speed limit for information and for objects with mass." + }, + "finish_reason": "stop" + } + ], + "usage": { + "completion_tokens": 383, + "prompt_tokens": 13, + "total_tokens": 396, + "prompt_tokens_details": { + "audio_tokens": 0, + "cached_tokens": 0 + }, + "completion_tokens_details": { + "accepted_prediction_tokens": 0, + "audio_tokens": 0, + "reasoning_tokens": 256, + "rejected_prediction_tokens": 0 + } + } + } + }, + "final_result": { + "id": "", + "object": "chat.completion", + "created": 1774535573, + "model": "gpt-5-mini-2025-08-07", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "The speed of light in vacuum (symbol c) is exactly 299,792,458 meters per second. \n\nQuick equivalents and notes:\n- ≈ 299,792.458 km/s\n- ≈ 186,282.397 miles/s (≈ 670,616,629 mph)\n- Often rounded to 3.00 × 10^8 m/s for rough calculations.\n- In materials light travels slower by the refractive index n: v = c/n.\n- In special relativity c is the ultimate speed limit for information and for objects with mass." + }, + "finish_reason": "stop" + } + ], + "usage": { + "completion_tokens": 383, + "prompt_tokens": 13, + "total_tokens": 396, + "prompt_tokens_details": { + "audio_tokens": 0, + "cached_tokens": 0 + }, + "completion_tokens_details": { + "accepted_prediction_tokens": 0, + "audio_tokens": 0, + "reasoning_tokens": 256, + "rejected_prediction_tokens": 0 + } + } + } + }, + "createdAt": "2026-03-26T14:33:01.7065395Z", + "objectStoreSecretName": "inference-observability" + } diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/environments/wdftest.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/environments/wdftest.yml new file mode 100644 index 000000000..088ec5477 --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/environments/wdftest.yml @@ -0,0 +1,24 @@ +name: credentials +variables: + - name: ai_auth_url + value: + - name: ai_api_url + value: + - name: client_id + value: + - name: client_secret + value: + - name: resource_group + value: + - name: common_endpoint + value: /v2/lm/document-grounding + - name: deploymentUrl + value: + - name: credentials + value: dW5**********== + - name: access_token + value: + - name: AWS_ACCESS_KEY_ID + value: + - name: AWS_SECRET_ACCESS_KEY + value: diff --git a/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/opencollection.yml b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/opencollection.yml new file mode 100644 index 000000000..10b440fbe --- /dev/null +++ b/tutorials/ai-core-genaihub-inference-observability/img/FeedbackService Test/opencollection.yml @@ -0,0 +1,10 @@ +opencollection: 1.0.0 + +info: + name: FeedbackService Test +bundled: false +extensions: + bruno: + ignore: + - node_modules + - .git diff --git a/tutorials/ai-core-genaihub-inference-observability/img/img_001.png b/tutorials/ai-core-genaihub-inference-observability/img/img_001.png new file mode 100644 index 000000000..fd85a9cf9 Binary files /dev/null and b/tutorials/ai-core-genaihub-inference-observability/img/img_001.png differ diff --git a/tutorials/ai-core-genaihub-inference-observability/img/img_002.png b/tutorials/ai-core-genaihub-inference-observability/img/img_002.png new file mode 100644 index 000000000..62a692ac0 Binary files /dev/null and b/tutorials/ai-core-genaihub-inference-observability/img/img_002.png differ diff --git a/tutorials/ai-core-genaihub-inference-observability/img/img_003.png b/tutorials/ai-core-genaihub-inference-observability/img/img_003.png new file mode 100644 index 000000000..bd3a05662 Binary files /dev/null and b/tutorials/ai-core-genaihub-inference-observability/img/img_003.png differ diff --git a/tutorials/ai-core-genaihub-inference-observability/img/img_004.png b/tutorials/ai-core-genaihub-inference-observability/img/img_004.png new file mode 100644 index 000000000..221ec793f Binary files /dev/null and b/tutorials/ai-core-genaihub-inference-observability/img/img_004.png differ diff --git a/tutorials/ai-core-genaihub-inference-observability/img/img_005.png b/tutorials/ai-core-genaihub-inference-observability/img/img_005.png new file mode 100644 index 000000000..0717a7131 Binary files /dev/null and b/tutorials/ai-core-genaihub-inference-observability/img/img_005.png differ diff --git a/tutorials/ai-core-genaihub-inference-observability/img/img_006.png b/tutorials/ai-core-genaihub-inference-observability/img/img_006.png new file mode 100644 index 000000000..1f246a6c1 Binary files /dev/null and b/tutorials/ai-core-genaihub-inference-observability/img/img_006.png differ diff --git a/tutorials/ai-core-genaihub-inference-observability/img/img_007.png b/tutorials/ai-core-genaihub-inference-observability/img/img_007.png new file mode 100644 index 000000000..ce5dcf351 Binary files /dev/null and b/tutorials/ai-core-genaihub-inference-observability/img/img_007.png differ diff --git a/tutorials/ai-core-genaihub-inference-observability/img/img_008.png b/tutorials/ai-core-genaihub-inference-observability/img/img_008.png new file mode 100644 index 000000000..633a47f3b Binary files /dev/null and b/tutorials/ai-core-genaihub-inference-observability/img/img_008.png differ