Skip to content

Commit d7ecfd8

Browse files
committed
Improvements in the tocken metrics emitting
1 parent f587560 commit d7ecfd8

File tree

4 files changed

+101
-130
lines changed

4 files changed

+101
-130
lines changed

labs/backend-pool-load-balancing/main.bicep

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,15 @@ param openAIAPIVersion string
2121
// RESOURCES
2222
// ------------------
2323

24-
// 1. Cognitive Services
24+
// 1. API Management
25+
module apimModule '../../modules/apim/v1/apim.bicep' = {
26+
name: 'apimModule'
27+
params: {
28+
apimSku: apimSku
29+
}
30+
}
31+
32+
// 2. Cognitive Services
2533
module openAIModule '../../modules/cognitive-services/v1/openai.bicep' = {
2634
name: 'openAIModule'
2735
params: {
@@ -34,14 +42,7 @@ module openAIModule '../../modules/cognitive-services/v1/openai.bicep' = {
3442
}
3543
}
3644

37-
// 2. API Management
38-
module apimModule '../../modules/apim/v1/apim.bicep' = {
39-
name: 'apimModule'
40-
params: {
41-
apimSku: apimSku
42-
}
43-
}
44-
45+
// 3. APIM OpenAI API
4546
module openAIAPIModule '../../modules/apim/v1/openai-api.bicep' = {
4647
name: 'openAIAPIModule'
4748
params: {

labs/token-metrics-emitting/main.bicep

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
// Typically, parameters would be decorated with appropriate metadata and attributes, but as they are very repetetive in these labs we omit them for brevity.
66

7+
param apimSku string
78
param openAIConfig array = []
89
param openAIModelName string
910
param openAIModelVersion string
@@ -19,9 +20,6 @@ var apiManagementName = 'apim-${resourceSuffix}'
1920
var openAISubscriptionName = 'openai-subscription'
2021
var openAISubscriptionDescription = 'OpenAI Subscription'
2122
var openAIAPIName = 'openai'
22-
var updatedPolicyXml = loadTextContent('policy-updated.xml')
23-
var azureRoles = loadJsonContent('../../modules/azure-roles.json')
24-
var cognitiveServicesOpenAIUserRoleDefinitionID = resourceId('Microsoft.Authorization/roleDefinitions', azureRoles.CognitiveServicesOpenAIUser)
2523

2624
// ------------------
2725
// RESOURCES
@@ -47,35 +45,39 @@ module appInsightsModule '../../modules/monitor/v1/appinsights.bicep' = {
4745
var appInsightsId = appInsightsModule.outputs.id
4846
var appInsightsInstrumentationKey = appInsightsModule.outputs.instrumentationKey
4947

50-
// 3. Cognitive Services
48+
// 3. API Management
49+
module apimModule '../../modules/apim/v1/apim.bicep' = {
50+
name: 'apimModule'
51+
params: {
52+
apimSku: apimSku
53+
appInsightsInstrumentationKey: appInsightsInstrumentationKey
54+
appInsightsId: appInsightsId
55+
}
56+
}
57+
58+
// 4. Cognitive Services
5159
module openAIModule '../../modules/cognitive-services/v1/openai.bicep' = {
5260
name: 'openAIModule'
5361
params: {
5462
openAIConfig: openAIConfig
5563
openAIDeploymentName: openAIDeploymentName
5664
openAIModelName: openAIModelName
5765
openAIModelVersion: openAIModelVersion
66+
apimPrincipalId: apimModule.outputs.principalId
5867
lawId: lawId
5968
}
6069
}
6170

62-
var extendedOpenAIConfig = openAIModule.outputs.extendedOpenAIConfig
63-
64-
// 4. API Management
65-
module apimModule '../../modules/apim/v1/apim.bicep' = {
66-
name: 'apimModule'
71+
// 5. APIM OpenAI API
72+
module openAIAPIModule '../../modules/apim/v1/openai-api.bicep' = {
73+
name: 'openAIAPIModule'
6774
params: {
68-
policyXml: updatedPolicyXml
69-
openAIConfig: extendedOpenAIConfig
70-
appInsightsInstrumentationKey: appInsightsInstrumentationKey
71-
appInsightsId: appInsightsId
75+
policyXml: loadTextContent('policy.xml')
76+
openAIConfig: openAIModule.outputs.extendedOpenAIConfig
7277
openAIAPIVersion: openAIAPIVersion
73-
openAISubscriptionName: openAISubscriptionName
74-
openAISubscriptionDescription: openAISubscriptionDescription
7578
}
7679
}
7780

78-
var apimPrincipalId = apimModule.outputs.principalId
7981

8082
// We presume the APIM resource has been created as part of this bicep flow.
8183
resource apim 'Microsoft.ApiManagement/service@2024-06-01-preview' existing = {
@@ -89,7 +91,7 @@ resource api 'Microsoft.ApiManagement/service/apis@2024-06-01-preview' existing
8991
parent: apim
9092
name: openAIAPIName
9193
dependsOn: [
92-
apim
94+
openAIAPIModule
9395
]
9496
}
9597

@@ -108,16 +110,6 @@ resource apimSubscriptions 'Microsoft.ApiManagement/service/subscriptions@2024-0
108110
]
109111
}]
110112

111-
// 5. RBAC Assignment
112-
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if(length(openAIConfig) > 0) {
113-
scope: resourceGroup()
114-
name: guid(subscription().id, resourceGroup().id, openAIConfig[0].name, cognitiveServicesOpenAIUserRoleDefinitionID)
115-
properties: {
116-
roleDefinitionId: cognitiveServicesOpenAIUserRoleDefinitionID
117-
principalId: apimPrincipalId
118-
principalType: 'ServicePrincipal'
119-
}
120-
}
121113

122114
// ------------------
123115
// OUTPUTS
Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,25 @@
1-
Placeholder file to suppress bicep error. The file is replaced when the lab is executed.
2-
3-
Do not check in updated versions of this file.
1+
<policies>
2+
<inbound>
3+
<base />
4+
<authentication-managed-identity resource="https://cognitiveservices.azure.com" output-token-variable-name="managed-id-access-token" ignore-error="false" />
5+
<set-header name="Authorization" exists-action="override">
6+
<value>@("Bearer " + (string)context.Variables["managed-id-access-token"])</value>
7+
</set-header>
8+
<set-backend-service backend-id="openai1" />
9+
<azure-openai-emit-token-metric namespace="openai">
10+
<dimension name="Subscription ID" value="@(context.Subscription.Id)" />
11+
<dimension name="Client IP" value="@(context.Request.IpAddress)" />
12+
<dimension name="API ID" value="@(context.Api.Id)" />
13+
<dimension name="User ID" value="@(context.Request.Headers.GetValueOrDefault("x-user-id", "N/A"))" />
14+
</azure-openai-emit-token-metric>
15+
</inbound>
16+
<backend>
17+
<base />
18+
</backend>
19+
<outbound>
20+
<base />
21+
</outbound>
22+
<on-error>
23+
<base />
24+
</on-error>
25+
</policies>

labs/token-metrics-emitting/token-metrics-emitting.ipynb

Lines changed: 47 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"\n",
2424
"### TOC\n",
2525
"- [0️⃣ Initialize notebook variables](#0)\n",
26-
"- [1️⃣ Create the Azure Resource Group](#1)\n",
26+
"- [1️⃣ Verify the Azure CLI and the connected Azure subscription](#1)\n",
2727
"- [2️⃣ Create deployment using 🦾 Bicep](#2)\n",
2828
"- [3️⃣ Get the deployment outputs](#3)\n",
2929
"- [🧪 Test the API using a direct HTTP call](#requests)\n",
@@ -57,35 +57,42 @@
5757
},
5858
{
5959
"cell_type": "code",
60-
"execution_count": 1,
60+
"execution_count": null,
6161
"metadata": {
6262
"metadata": {}
6363
},
6464
"outputs": [],
6565
"source": [
66-
"import os\n",
66+
"import os, sys, json\n",
67+
"sys.path.insert(1, '../../shared') # add the shared directory to the Python path\n",
68+
"import utils\n",
6769
"\n",
6870
"deployment_name = os.path.basename(os.path.dirname(globals()['__vsc_ipynb_file__']))\n",
6971
"resource_group_name = f\"lab-{deployment_name}\" # change the name to match your naming style\n",
7072
"resource_group_location = \"westeurope\"\n",
7173
"\n",
74+
"apim_sku = 'Basicv2'\n",
75+
"\n",
7276
"openai_resources = [\n",
7377
" {\"name\": \"openai1\", \"location\": \"swedencentral\"}\n",
7478
"]\n",
7579
"\n",
7680
"openai_model_name = \"gpt-35-turbo\"\n",
7781
"openai_model_version = \"0613\"\n",
7882
"openai_deployment_name = \"gpt-35-turbo\"\n",
79-
"openai_api_version = \"2024-02-01\"\n"
83+
"openai_api_version = \"2024-02-01\"\n",
84+
"\n",
85+
"utils.print_ok('Notebook initiaized')"
8086
]
8187
},
8288
{
8389
"cell_type": "markdown",
8490
"metadata": {},
8591
"source": [
8692
"<a id='1'></a>\n",
87-
"### 1️⃣ Create the Azure Resource Group\n",
88-
"All resources deployed in this lab will be created in the specified resource group. Skip this step if you want to use an existing resource group."
93+
"### 1️⃣ Verify the Azure CLI and the connected Azure subscription\n",
94+
"\n",
95+
"The following commands ensure that you have the latest version of the Azure CLI and that the Azure CLI is connected to your Azure subscription."
8996
]
9097
},
9198
{
@@ -94,17 +101,11 @@
94101
"metadata": {},
95102
"outputs": [],
96103
"source": [
97-
"# %load ../../shared/snippets/create-az-resource-group.py\n",
98-
"# type: ignore\n",
99-
"\n",
100-
"import datetime\n",
101-
"\n",
102-
"resource_group_stdout = ! az group create --name {resource_group_name} --location {resource_group_location}\n",
103-
"\n",
104-
"if resource_group_stdout.n.startswith(\"ERROR\"):\n",
105-
" print(resource_group_stdout)\n",
106-
"else:\n",
107-
" print(f\"✅ Azure Resource Group {resource_group_name} created ⌚ {datetime.datetime.now().time()}\")\n"
104+
"output = utils.run(\"az account show\", \"Retrieved az account\", \"Failed to get the current az account\")\n",
105+
"if output.success and output.json_data:\n",
106+
" current_user = output.json_data['user']['name']\n",
107+
" subscription_id = output.json_data['id']\n",
108+
" tenant_id = output.json_data['tenantId']"
108109
]
109110
},
110111
{
@@ -114,7 +115,7 @@
114115
"<a id='2'></a>\n",
115116
"### 2️⃣ Create deployment using 🦾 Bicep\n",
116117
"\n",
117-
"This lab uses [Bicep](https://learn.microsoft.com/azure/azure-resource-manager/bicep/overview?tabs=bicep) to declarative define all the resources that will be deployed. Change the parameters or the [main.bicep](main.bicep) directly to try different configurations. "
118+
"This lab uses [Bicep](https://learn.microsoft.com/azure/azure-resource-manager/bicep/overview?tabs=bicep) to declarative define all the resources that will be deployed in the specified resource group. Change the parameters or the [main.bicep](main.bicep) directly to try different configurations. "
118119
]
119120
},
120121
{
@@ -123,32 +124,25 @@
123124
"metadata": {},
124125
"outputs": [],
125126
"source": [
126-
"# %load ../../shared/snippets/create-az-deployment.py\n",
127-
"# type: ignore\n",
128-
"\n",
129-
"import json\n",
130-
"\n",
131-
"backend_id = \"openai-backend-pool\" if len(openai_resources) > 1 else openai_resources[0].get(\"name\")\n",
127+
"# create the resource group if doesn't exist\n",
128+
"utils.create_resource_group(True, resource_group_name, resource_group_location)\n",
132129
"\n",
130+
"# update the APIM policy file before the deployment\n",
131+
"policy_xml = None\n",
133132
"with open(\"policy.xml\", 'r') as policy_xml_file:\n",
134-
" policy_xml = policy_xml_file.read()\n",
135-
"\n",
136-
" if \"{backend-id}\" in policy_xml:\n",
137-
" policy_xml = policy_xml.replace(\"{backend-id}\", backend_id)\n",
138-
"\n",
139-
" if \"{aad-client-application-id}\" in policy_xml:\n",
140-
" policy_xml = policy_xml.replace(\"{aad-client-application-id}\", client_id)\n",
141-
"\n",
142-
" if \"{aad-tenant-id}\" in policy_xml:\n",
143-
" policy_xml = policy_xml.replace(\"{aad-tenant-id}\", tenant_id)\n",
144-
"\n",
133+
" policy_template_xml = policy_xml_file.read()\n",
134+
" if \"{backend-id}\" in policy_template_xml:\n",
135+
" policy_xml = policy_template_xml.replace(\"{backend-id}\", str(\"openai-backend-pool\" if len(openai_resources) > 1 else openai_resources[0].get(\"name\"))) \n",
145136
" policy_xml_file.close()\n",
146-
"open(\"policy-updated.xml\", 'w').write(policy_xml)\n",
137+
"if policy_xml is not None:\n",
138+
" open(\"policy.xml\", 'w').write(policy_xml)\n",
147139
"\n",
140+
"# define the BICEP parameters\n",
148141
"bicep_parameters = {\n",
149142
" \"$schema\": \"https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#\",\n",
150143
" \"contentVersion\": \"1.0.0.0\",\n",
151144
" \"parameters\": {\n",
145+
" \"apimSku\": { \"value\": apim_sku },\n",
152146
" \"openAIConfig\": { \"value\": openai_resources },\n",
153147
" \"openAIDeploymentName\": { \"value\": openai_deployment_name },\n",
154148
" \"openAIModelName\": { \"value\": openai_model_name },\n",
@@ -157,10 +151,14 @@
157151
" }\n",
158152
"}\n",
159153
"\n",
154+
"# write the parameters to a file \n",
160155
"with open('params.json', 'w') as bicep_parameters_file:\n",
161156
" bicep_parameters_file.write(json.dumps(bicep_parameters))\n",
162157
"\n",
163-
"! az deployment group create --name {deployment_name} --resource-group {resource_group_name} --template-file \"main.bicep\" --parameters \"params.json\"\n"
158+
"# run the deployment\n",
159+
"output = utils.run(f\"az deployment group create --name {deployment_name} --resource-group {resource_group_name} --template-file main.bicep --parameters params.json\", \n",
160+
" f\"Deployment '{deployment_name}' succeeded\", f\"Deployment '{deployment_name}' failed\")\n",
161+
"open(\"policy.xml\", 'w').write(policy_template_xml)\n"
164162
]
165163
},
166164
{
@@ -170,7 +168,7 @@
170168
"<a id='3'></a>\n",
171169
"### 3️⃣ Get the deployment outputs\n",
172170
"\n",
173-
"We are now at the stage where we only need to retrieve the gateway URL and the subscription before we are ready for testing."
171+
"Retrieve the required outputs from the Bicep deployment."
174172
]
175173
},
176174
{
@@ -179,59 +177,17 @@
179177
"metadata": {},
180178
"outputs": [],
181179
"source": [
182-
"# %load ../../shared/snippets/deployment-outputs.py\n",
183-
"# type: ignore\n",
184-
"\n",
185180
"# Obtain all of the outputs from the deployment\n",
186-
"stdout = ! az deployment group show --name {deployment_name} -g {resource_group_name} --query properties.outputs -o json\n",
187-
"outputs = json.loads(stdout.n)\n",
188-
"\n",
189-
"# Extract the individual properties\n",
190-
"apim_service_id = outputs.get('apimServiceId', {}).get('value', '')\n",
191-
"apim_subscription_key = outputs.get('apimSubscriptionKey', {}).get('value', '')\n",
192-
"apim_subscription1_key = outputs.get('apimSubscription1Key', {}).get('value', '')\n",
193-
"apim_subscription2_key = outputs.get('apimSubscription2Key', {}).get('value', '')\n",
194-
"apim_subscription3_key = outputs.get('apimSubscription3Key', {}).get('value', '')\n",
195-
"apim_resource_gateway_url = outputs.get('apimResourceGatewayURL', {}).get('value', '')\n",
196-
"workspace_id = outputs.get('logAnalyticsWorkspaceId', {}).get('value', '')\n",
197-
"app_id = outputs.get('applicationInsightsAppId', {}).get('value', '')\n",
198-
"app_insights_name = outputs.get('applicationInsightsName', {}).get('value', '')\n",
199-
"function_app_resource_name = outputs.get('functionAppResourceName', {}).get('value', '')\n",
200-
"cosmosdb_connection_string = outputs.get('cosmosDBConnectionString', {}).get('value', '')\n",
201-
"\n",
202-
"# Print the extracted properties if they are not empty\n",
203-
"if apim_service_id:\n",
204-
" print(f\"👉🏻 APIM Service Id: {apim_service_id}\")\n",
205-
"\n",
206-
"if apim_subscription_key:\n",
207-
" print(f\"👉🏻 APIM Subscription Key (masked): ****{apim_subscription_key[-4:]}\")\n",
208-
"\n",
209-
"if apim_subscription1_key:\n",
210-
" print(f\"👉🏻 APIM Subscription Key 1 (masked): ****{apim_subscription1_key[-4:]}\")\n",
211-
"\n",
212-
"if apim_subscription2_key:\n",
213-
" print(f\"👉🏻 APIM Subscription Key 2 (masked): ****{apim_subscription2_key[-4:]}\")\n",
214-
"\n",
215-
"if apim_subscription3_key:\n",
216-
" print(f\"👉🏻 APIM Subscription Key 3 (masked): ****{apim_subscription3_key[-4:]}\")\n",
217-
"\n",
218-
"if apim_resource_gateway_url:\n",
219-
" print(f\"👉🏻 APIM API Gateway URL: {apim_resource_gateway_url}\")\n",
220-
"\n",
221-
"if workspace_id:\n",
222-
" print(f\"👉🏻 Workspace ID: {workspace_id}\")\n",
223-
"\n",
224-
"if app_id:\n",
225-
" print(f\"👉🏻 App ID: {app_id}\")\n",
226-
"\n",
227-
"if app_insights_name:\n",
228-
" print(f\"👉🏻 Application Insights Name: {app_insights_name}\")\n",
229-
"\n",
230-
"if function_app_resource_name:\n",
231-
" print(f\"👉🏻 Function Name: {function_app_resource_name}\")\n",
232-
"\n",
233-
"if cosmosdb_connection_string:\n",
234-
" print(f\"👉🏻 Cosmos DB Connection String: {cosmosdb_connection_string}\")\n"
181+
"output = utils.run(f\"az deployment group show --name {deployment_name} -g {resource_group_name}\", f\"Retrieved deployment: {deployment_name}\", f\"Failed to retrieve deployment: {deployment_name}\")\n",
182+
"if output.success and output.json_data:\n",
183+
" apim_service_id = utils.get_deployment_output(output, 'apimServiceId', 'APIM Service Id')\n",
184+
" apim_subscription1_key = utils.get_deployment_output(output, 'apimSubscription1Key', 'APIM Subscription 1 Key (masked)', True)\n",
185+
" apim_subscription2_key = utils.get_deployment_output(output, 'apimSubscription2Key', 'APIM Subscription 2 Key (masked)', True)\n",
186+
" apim_subscription3_key = utils.get_deployment_output(output, 'apimSubscription3Key', 'APIM Subscription 3 Key (masked)', True)\n",
187+
" apim_resource_gateway_url = utils.get_deployment_output(output, 'apimResourceGatewayURL', 'APIM API Gateway URL')\n",
188+
" app_insights_name = utils.get_deployment_output(output, 'applicationInsightsName', 'Application Insights Name')\n",
189+
"\n",
190+
"\n"
235191
]
236192
},
237193
{
@@ -464,7 +420,7 @@
464420
],
465421
"metadata": {
466422
"kernelspec": {
467-
"display_name": ".venv",
423+
"display_name": "Python 3",
468424
"language": "python",
469425
"name": "python3"
470426
},

0 commit comments

Comments
 (0)