Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated to a new model #109

Merged
merged 1 commit into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 52 additions & 63 deletions labs/function-calling/function-calling.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,6 @@
"### Result\n",
"![result](result.png)\n",
"\n",
"### TOC\n",
"- [0️⃣ Initialize notebook variables](#0)\n",
"- [1️⃣ Create the Azure Resource Group](#1)\n",
"- [2️⃣ Create deployment using 🦾 Bicep](#2)\n",
"- [3️⃣ Get the deployment outputs](#3)\n",
"- [4️⃣ Deploy the function](#4)\n",
"- [🧪 Test the Function API](#function)\n",
"- [🧪 Test OpenAI function calling](#functioncalling)\n",
"- [🗑️ Clean up resources](#clean)\n",
"\n",
"### Prerequisites\n",
"- [Python 3.12 or later version](https://www.python.org/) installed\n",
"- [Pandas Library](https://pandas.pydata.org/) installed\n",
Expand Down Expand Up @@ -61,42 +51,47 @@
},
"outputs": [],
"source": [
"import os\n",
"import json\n",
"import datetime\n",
"import requests\n",
"import os, sys, json\n",
"sys.path.insert(1, '../../shared') # add the shared directory to the Python path\n",
"import utils\n",
"\n",
"deployment_name = os.path.basename(os.path.dirname(globals()['__vsc_ipynb_file__']))\n",
"resource_group_name = f\"lab-{deployment_name}\" # change the name to match your naming style\n",
"resource_group_location = \"westeurope\"\n",
"\n",
"apim_resource_name = \"apim\"\n",
"apim_resource_location = \"westeurope\"\n",
"apim_resource_sku = \"Basicv2\"\n",
"openai_resources = [ {\"name\": \"openai1\", \"location\": \"swedencentral\"} ] # list of OpenAI resources to deploy. Clear this list to use only the mock resources\n",
"openai_resources_sku = \"S0\"\n",
"openai_model_name = \"gpt-35-turbo\"\n",
"openai_model_version = \"1106\"\n",
"openai_deployment_name = \"gpt-35-turbo\"\n",
"openai_api_version = \"2024-03-01-preview\"\n",
"\n",
"openai_model_name = \"gpt-4o-mini\"\n",
"openai_model_version = \"2024-07-18\"\n",
"openai_model_sku = \"GlobalStandard\"\n",
"openai_model_capacity = 20\n",
"openai_deployment_name = \"gpt-4o-mini\"\n",
"openai_api_version = \"2024-10-21\"\n",
"\n",
"openai_specification_url='https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cognitiveservices/data-plane/AzureOpenAI/inference/stable/2024-02-01/inference.json'\n",
"openai_backend_pool = \"openai-backend-pool\"\n",
"mock_backend_pool = \"mock-backend-pool\"\n",
"mock_webapps = [ ]\n",
"\n",
"log_analytics_name = \"workspace\"\n",
"app_insights_name = 'insights'\n",
"\n",
"function_app_name = \"function\"\n",
"storage_account_name = \"storage\"\n"
"storage_account_name = \"storage\"\n",
"\n",
"utils.print_ok('Notebook initialized')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<a id='1'></a>\n",
"### 1️⃣ Create the Azure Resource Group\n",
"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."
"### 1️⃣ Verify the Azure CLI and the connected Azure subscription\n",
"\n",
"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."
]
},
{
Expand All @@ -105,11 +100,16 @@
"metadata": {},
"outputs": [],
"source": [
"resource_group_stdout = ! az group create --name {resource_group_name} --location {resource_group_location}\n",
"if resource_group_stdout.n.startswith(\"ERROR\"):\n",
" print(resource_group_stdout)\n",
"else:\n",
" print(\"✅ Azure Resource Group \", resource_group_name, \" created ⌚ \", datetime.datetime.now().time())"
"output = utils.run(\"az account show\", \"Retrieved az account\", \"Failed to get the current az account\")\n",
"\n",
"if output.success and output.json_data:\n",
" current_user = output.json_data['user']['name']\n",
" tenant_id = output.json_data['tenantId']\n",
" subscription_id = output.json_data['id']\n",
"\n",
" utils.print_info(f\"Current user: {current_user}\")\n",
" utils.print_info(f\"Tenant ID: {tenant_id}\")\n",
" utils.print_info(f\"Subscription ID: {subscription_id}\")"
]
},
{
Expand All @@ -119,7 +119,7 @@
"<a id='2'></a>\n",
"### 2️⃣ Create deployment using 🦾 Bicep\n",
"\n",
"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. "
"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.\n"
]
},
{
Expand All @@ -128,29 +128,21 @@
"metadata": {},
"outputs": [],
"source": [
"if len(openai_resources) > 0:\n",
" backend_id = openai_backend_pool if len(openai_resources) > 1 else openai_resources[0].get(\"name\")\n",
"elif len(mock_webapps) > 0:\n",
" backend_id = mock_backend_pool if len(mock_backend_pool) > 1 else mock_webapps[0].get(\"name\")\n",
"\n",
"with open(\"policy.xml\", 'r') as policy_xml_file:\n",
" policy_template_xml = policy_xml_file.read()\n",
" policy_xml = policy_template_xml.replace(\"{backend-id}\", backend_id)\n",
" policy_xml_file.close()\n",
"open(\"policy.xml\", 'w').write(policy_xml)\n",
"# Create the resource group if doesn't exist\n",
"utils.create_resource_group(resource_group_name, resource_group_location)\n",
"\n",
"# Define the Bicep parameters\n",
"bicep_parameters = {\n",
" \"$schema\": \"https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#\",\n",
" \"contentVersion\": \"1.0.0.0\",\n",
" \"parameters\": {\n",
" \"mockWebApps\": { \"value\": mock_webapps },\n",
" \"mockBackendPoolName\": { \"value\": mock_backend_pool },\n",
" \"openAIBackendPoolName\": { \"value\": openai_backend_pool },\n",
" \"openAIConfig\": { \"value\": openai_resources },\n",
" \"openAIDeploymentName\": { \"value\": openai_deployment_name },\n",
" \"openAISku\": { \"value\": openai_resources_sku },\n",
" \"openAIModelName\": { \"value\": openai_model_name },\n",
" \"openAIModelVersion\": { \"value\": openai_model_version },\n",
" \"openAIModelSKU\": { \"value\": openai_model_sku },\n",
" \"openAIAPISpecURL\": { \"value\": openai_specification_url },\n",
" \"apimResourceName\": { \"value\": apim_resource_name},\n",
" \"apimResourceLocation\": { \"value\": apim_resource_location},\n",
Expand All @@ -161,20 +153,24 @@
" \"storageAccountName\": { \"value\": storage_account_name }\n",
" }\n",
"}\n",
"\n",
"# Write the parameters to the params.json file\n",
"with open('params.json', 'w') as bicep_parameters_file:\n",
" bicep_parameters_file.write(json.dumps(bicep_parameters))\n",
"\n",
"! az deployment group create --name {deployment_name} --resource-group {resource_group_name} --template-file \"main.bicep\" --parameters \"params.json\"\n",
"\n",
"open(\"policy.xml\", 'w').write(policy_template_xml)\n"
"# Run the deployment\n",
"output = utils.run(f\"az deployment group create --name {deployment_name} --resource-group {resource_group_name} --template-file main.bicep --parameters params.json\",\n",
" f\"Deployment '{deployment_name}' succeeded\", f\"Deployment '{deployment_name}' failed\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<a id='3'></a>\n",
"### 3️⃣ Get the deployment outputs\n"
"### 3️⃣ Get the deployment outputs\n",
"\n",
"Retrieve the required outputs from the Bicep deployment."
]
},
{
Expand All @@ -183,23 +179,13 @@
"metadata": {},
"outputs": [],
"source": [
"deployment_stdout = ! az deployment group show --name {deployment_name} -g {resource_group_name} --query properties.outputs.apimSubscriptionKey.value -o tsv\n",
"apim_subscription_key = deployment_stdout.n\n",
"deployment_stdout = ! az deployment group show --name {deployment_name} -g {resource_group_name} --query properties.outputs.apimResourceGatewayURL.value -o tsv\n",
"apim_resource_gateway_url = deployment_stdout.n\n",
"print(\"👉🏻 API Gateway URL: \", apim_resource_gateway_url)\n",
"\n",
"deployment_stdout = ! az deployment group show --name {deployment_name} -g {resource_group_name} --query properties.outputs.logAnalyticsWorkspaceId.value -o tsv\n",
"workspace_id = deployment_stdout.n\n",
"print(\"👉🏻 Workspace ID: \", workspace_id)\n",
"\n",
"deployment_stdout = ! az deployment group show --name {deployment_name} -g {resource_group_name} --query properties.outputs.applicationInsightsAppId.value -o tsv\n",
"app_id = deployment_stdout.n\n",
"print(\"👉🏻 App ID: \", app_id)\n",
"\n",
"deployment_stdout = ! az deployment group show --name {deployment_name} -g {resource_group_name} --query properties.outputs.functionAppResourceName.value -o tsv\n",
"function_app_resource_name = deployment_stdout.n\n",
"print(\"👉🏻 Function Name: \", function_app_resource_name)\n"
"# Obtain all of the outputs from the deployment\n",
"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",
"\n",
"if output.success and output.json_data:\n",
" apim_resource_gateway_url = utils.get_deployment_output(output, 'apimResourceGatewayURL', 'APIM API Gateway URL')\n",
" apim_subscription_key = utils.get_deployment_output(output, 'apimSubscriptionKey', 'APIM Subscription Key (masked)', True)\n",
" function_app_resource_name = utils.get_deployment_output(output, 'functionAppResourceName', 'Function App Resource Name')\n"
]
},
{
Expand Down Expand Up @@ -235,6 +221,8 @@
"metadata": {},
"outputs": [],
"source": [
"import requests\n",
"\n",
"request = { \"location\": \"London\", \"unit\": \"celsius\" }\n",
"url = apim_resource_gateway_url + \"/weather\"\n",
"response = requests.post(url, headers = {'api-key':apim_subscription_key}, json = request)\n",
Expand Down Expand Up @@ -265,6 +253,7 @@
"metadata": {},
"outputs": [],
"source": [
"# type: ignore\n",
"from openai import AzureOpenAI\n",
"import uuid\n",
"\n",
Expand Down Expand Up @@ -390,7 +379,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.2"
"version": "3.12.9"
}
},
"nbformat": 4,
Expand Down
71 changes: 11 additions & 60 deletions labs/function-calling/main.bicep
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
@description('List of Mock webapp names used to simulate OpenAI behavior.')
param mockWebApps array = []

@description('The name of the OpenAI mock backend pool')
param mockBackendPoolName string = 'openai-backend-pool'

@description('The description of the OpenAI mock backend pool')
param mockBackendPoolDescription string = 'Load balancer for multiple OpenAI Mocking endpoints'

@description('List of OpenAI resources to create. Add pairs of name and location.')
param openAIConfig array = []
Expand All @@ -25,6 +17,9 @@ param openAIModelName string
@description('Model Version')
param openAIModelVersion string

@description('Model SKU')
param openAIModelSKU string

@description('Model Capacity')
param openAIModelCapacity int = 20

Expand Down Expand Up @@ -162,6 +157,10 @@ param functionAPIDescription string = 'Weather API'

var resourceSuffix = uniqueString(subscription().id, resourceGroup().id)

var policyXml = loadTextContent('policy.xml')
var updatedPolicyXml = replace(policyXml, '{backend-id}', (length(openAIConfig) > 1) ? 'openai-backend-pool' : openAIConfig[0].name)


resource cognitiveServices 'Microsoft.CognitiveServices/accounts@2021-10-01' = [for config in openAIConfig: if(length(openAIConfig) > 0) {
name: '${config.name}-${resourceSuffix}'
location: config.location
Expand All @@ -188,7 +187,7 @@ resource deployment 'Microsoft.CognitiveServices/accounts/deployments@2023-05-01
}
}
sku: {
name: 'Standard'
name: openAIModelSKU
capacity: openAIModelCapacity
}
}]
Expand Down Expand Up @@ -247,7 +246,7 @@ resource apiPolicy 'Microsoft.ApiManagement/service/apis/policies@2021-12-01-pre
parent: api
properties: {
format: 'rawxml'
value: loadTextContent('policy.xml')
value: updatedPolicyXml
}
}

Expand Down Expand Up @@ -282,45 +281,14 @@ resource backendOpenAI 'Microsoft.ApiManagement/service/backends@2023-05-01-prev
}
}]

resource backendMock 'Microsoft.ApiManagement/service/backends@2023-05-01-preview' = [for (mock, i) in mockWebApps: if(length(openAIConfig) == 0 && length(mockWebApps) > 0) {
name: mock.name
parent: apimService
properties: {
description: 'backend description'
url: '${mock.endpoint}/openai'
protocol: 'http'
circuitBreaker: {
rules: [
{
failureCondition: {
count: 3
errorReasons: [
'Server errors'
]
interval: 'PT5M'
statusCodeRanges: [
{
min: 429
max: 429
}
]
}
name: 'mockBreakerRule'
tripDuration: 'PT1M'
}
]
}
}
}]

resource backendPoolOpenAI 'Microsoft.ApiManagement/service/backends@2023-05-01-preview' = if(length(openAIConfig) > 1) {
name: openAIBackendPoolName
parent: apimService
// BCP035: protocol and url are not needed in the Pool type. This is an incorrect error.
#disable-next-line BCP035
properties: {
description: openAIBackendPoolDescription
type: 'Pool'
// protocol: 'http' // the protocol is not needed in the Pool type
// url: '${cognitiveServices[0].properties.endpoint}/openai' // the url is not needed in the Pool type
pool: {
services: [for (config, i) in openAIConfig: {
id: '/backends/${backendOpenAI[i].name}'
Expand All @@ -330,23 +298,6 @@ resource backendPoolOpenAI 'Microsoft.ApiManagement/service/backends@2023-05-01-
}
}

resource backendPoolMock 'Microsoft.ApiManagement/service/backends@2023-05-01-preview' = if(length(openAIConfig) == 0 && length(mockWebApps) > 1) {
name: mockBackendPoolName
parent: apimService
properties: {
description: mockBackendPoolDescription
type: 'Pool'
// protocol: 'http' // the protocol is not needed in the Pool type
// url: '${mockWebApps[0].endpoint}/openai' // the url is not needed in the Pool type
pool: {
services: [for (webApp, i) in mockWebApps: {
id: '/backends/${backendMock[i].name}'
}
]
}
}
}

resource apimSubscription 'Microsoft.ApiManagement/service/subscriptions@2023-05-01-preview' = {
name: openAISubscriptionName
parent: apimService
Expand Down