|
| 1 | +{ |
| 2 | + "cells": [ |
| 3 | + { |
| 4 | + "attachments": {}, |
| 5 | + "cell_type": "markdown", |
| 6 | + "metadata": {}, |
| 7 | + "source": [ |
| 8 | + "# Azure OpenAI Service API with AAD authentication\n", |
| 9 | + "\n", |
| 10 | + "The reference for the AOAI REST API `/completions` method is [here](https://docs.microsoft.com/en-us/azure/cognitive-services/openai/reference/api-reference#completions).\n", |
| 11 | + "\n", |
| 12 | + "### Prerequisites\n", |
| 13 | + "\n", |
| 14 | + "1. Setup for Azure Active Directory (AAD) authentication.\n", |
| 15 | + " * See [Setup to use AAD and test with CLI](setup_aad.md).\n", |
| 16 | + "2. A Python environment setup with all the requirements. \n", |
| 17 | + " * See the [setup_python_env.md](setup_python_env.md) page for instructions on setting up your environment. You don't need the `openai` package for this notebook, but you do need the `azure-identity` package.\n" |
| 18 | + ] |
| 19 | + }, |
| 20 | + { |
| 21 | + "cell_type": "markdown", |
| 22 | + "metadata": {}, |
| 23 | + "source": [ |
| 24 | + "### Define the API endpoint URL for your team" |
| 25 | + ] |
| 26 | + }, |
| 27 | + { |
| 28 | + "cell_type": "code", |
| 29 | + "execution_count": 1, |
| 30 | + "metadata": {}, |
| 31 | + "outputs": [], |
| 32 | + "source": [ |
| 33 | + "# Import needed libraries\n", |
| 34 | + "import os\n", |
| 35 | + "import requests\n", |
| 36 | + "import json\n", |
| 37 | + "import datetime\n", |
| 38 | + "import time" |
| 39 | + ] |
| 40 | + }, |
| 41 | + { |
| 42 | + "cell_type": "markdown", |
| 43 | + "metadata": {}, |
| 44 | + "source": [ |
| 45 | + "### Setup Parameters\n", |
| 46 | + "\n", |
| 47 | + "\n", |
| 48 | + "Here we will load the configurations from _config.json_ file to setup deployment_name, base_url and openai_api_version." |
| 49 | + ] |
| 50 | + }, |
| 51 | + { |
| 52 | + "cell_type": "code", |
| 53 | + "execution_count": 2, |
| 54 | + "metadata": {}, |
| 55 | + "outputs": [], |
| 56 | + "source": [ |
| 57 | + "# Load config values\n", |
| 58 | + "with open(r'config.json') as config_file:\n", |
| 59 | + " config_details = json.load(config_file)\n", |
| 60 | + "\n", |
| 61 | + "# Setting up the deployment name\n", |
| 62 | + "deployment_name = config_details['COMPLETIONS_MODEL']\n", |
| 63 | + "\n", |
| 64 | + "# The base URL for your Azure OpenAI resource. e.g. \"https://<your resource name>.openai.azure.com\"\n", |
| 65 | + "base_url = config_details['OPENAI_API_BASE']\n", |
| 66 | + "\n", |
| 67 | + "# Currently OPENAI API have the following versions available: 2022-12-01\n", |
| 68 | + "openai_api_version = config_details['OPENAI_API_VERSION']\n", |
| 69 | + "\n", |
| 70 | + "# Define the API endpoint URL\n", |
| 71 | + "request_url = base_url + \"/openai/deployments/\"+ deployment_name + \"/completions?api-version=\" + openai_api_version" |
| 72 | + ] |
| 73 | + }, |
| 74 | + { |
| 75 | + "cell_type": "markdown", |
| 76 | + "metadata": {}, |
| 77 | + "source": [ |
| 78 | + "## Set up AAD authentication\n", |
| 79 | + "\n", |
| 80 | + "`DefaultAzureCredential` can read your credentials from the environment after doing `az login`. \n", |
| 81 | + "\n", |
| 82 | + "In VS Code, you can use the Azure Account extension to log in with your Azure account. If you are running this notebook in VS Code, be sure to restart VS Code after you do `az login`.\n", |
| 83 | + "\n", |
| 84 | + "This article gives details on what identity `DefaultAzureCredential` uses: https://docs.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python\n", |
| 85 | + "\n", |
| 86 | + "If you get an error similar to the following, you can try using `AzureCliCredential` instead of `DefaultAzureCredential`:\n", |
| 87 | + "\n", |
| 88 | + "```\n", |
| 89 | + "DefaultAzureCredential failed to retrieve a token from the included credentials. Attempted credentials: EnvironmentCredential: EnvironmentCredential authentication unavailable. Environment variables are not fully configured. Visit https://aka.ms/azsdk/python/identity/environmentcredential/troubleshoot to troubleshoot.this issue. ManagedIdentityCredential: ManagedIdentityCredential authentication unavailable, no response from the IMDS endpoint. SharedTokenCacheCredential: Azure Active Directory error '(invalid_scope) AADSTS70011: The provided request must include a 'scope' input parameter. The provided value for the input parameter 'scope' is not valid. The scope https://cognitiveservices.azure.com is not valid. The scope format is invalid. Scope must be in a valid URI form <https://example/scope> or a valid Guid <guid/scope>. \n", |
| 90 | + "```\n" |
| 91 | + ] |
| 92 | + }, |
| 93 | + { |
| 94 | + "cell_type": "code", |
| 95 | + "execution_count": 6, |
| 96 | + "metadata": {}, |
| 97 | + "outputs": [], |
| 98 | + "source": [ |
| 99 | + "from azure.identity import DefaultAzureCredential, AzureCliCredential #DefaultAzureCredential should work but you may need AzureCliCredential to make the authentication work\n", |
| 100 | + "default_credential = AzureCliCredential()\n", |
| 101 | + "#default_credential = DefaultAzureCredential()" |
| 102 | + ] |
| 103 | + }, |
| 104 | + { |
| 105 | + "cell_type": "markdown", |
| 106 | + "metadata": {}, |
| 107 | + "source": [ |
| 108 | + "## Define method to get a prompt completion using AAD authentication\n", |
| 109 | + "\n", |
| 110 | + "The `refresh_token` function below is used to get a new token when the current token expires. The `refresh_token` method is called \n", |
| 111 | + "by the `get_completion` to get the token if it is not already set or if the token has expired." |
| 112 | + ] |
| 113 | + }, |
| 114 | + { |
| 115 | + "cell_type": "code", |
| 116 | + "execution_count": 7, |
| 117 | + "metadata": {}, |
| 118 | + "outputs": [], |
| 119 | + "source": [ |
| 120 | + "token = None\n", |
| 121 | + "\n", |
| 122 | + "def refresh_token():\n", |
| 123 | + " global token\n", |
| 124 | + " # Check if Azure token is still valid\n", |
| 125 | + " if not token or datetime.datetime.fromtimestamp(token.expires_on) < datetime.datetime.now():\n", |
| 126 | + " token = default_credential.get_token(\"https://cognitiveservices.azure.com\")\n", |
| 127 | + "\n", |
| 128 | + "def get_completion(payload):\n", |
| 129 | + " # Refresh token\n", |
| 130 | + " refresh_token()\n", |
| 131 | + " \n", |
| 132 | + " # Yes this can be optimized to only set Authorization header when token is refreshed :D\n", |
| 133 | + " headers = {\n", |
| 134 | + " \"Authorization\": f\"Bearer {token.token}\",\n", |
| 135 | + " \"Content-Type\": \"application/json\"\n", |
| 136 | + " }\n", |
| 137 | + "\n", |
| 138 | + " r = requests.post(\n", |
| 139 | + " request_url, \n", |
| 140 | + " headers=headers,\n", |
| 141 | + " json = payload\n", |
| 142 | + " )\n", |
| 143 | + " \n", |
| 144 | + " return r" |
| 145 | + ] |
| 146 | + }, |
| 147 | + { |
| 148 | + "cell_type": "markdown", |
| 149 | + "metadata": {}, |
| 150 | + "source": [ |
| 151 | + "## Test the API\n", |
| 152 | + "\n", |
| 153 | + "The payload parameters in the `get_completion` call are for illustration only and can be changed for your use case as described in the [reference](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/reference)." |
| 154 | + ] |
| 155 | + }, |
| 156 | + { |
| 157 | + "cell_type": "code", |
| 158 | + "execution_count": 10, |
| 159 | + "metadata": {}, |
| 160 | + "outputs": [ |
| 161 | + { |
| 162 | + "name": "stdout", |
| 163 | + "output_type": "stream", |
| 164 | + "text": [ |
| 165 | + "Status Code: 200\n", |
| 166 | + "Headers: \n", |
| 167 | + "{'Cache-Control': 'no-cache, must-revalidate', 'Content-Length': '1239', 'Content-Type': 'application/json', 'access-control-allow-origin': '*', 'openai-model': 'text-davinci-003', 'apim-request-id': 'be5722a6-ffad-4bcb-b988-d70971ff0c84', 'openai-processing-ms': '4552.6285', 'x-content-type-options': 'nosniff', 'x-accel-buffering': 'no', 'x-request-id': '1f720ba0-6fe8-40e7-a55e-de8cb05f6e2b', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload', 'x-ms-region': 'East US', 'Date': 'Wed, 29 Mar 2023 11:00:51 GMT'} \n", |
| 168 | + "\n", |
| 169 | + "{'id': 'cmpl-6zNpmCskuKaLc0heqY9DIOnzYAzUz', 'object': 'text_completion', 'created': 1680087646, 'model': 'text-davinci-003', 'choices': [{'text': ' there was a young girl named Alice. She lived in a small village in the middle of the forest. One day, Alice was walking through the woods when she stumbled upon a white rabbit. She followed the rabbit deep into the forest until she came to a strange looking tree. The tree had a door at the bottom with a sign that said \"Drink Me\".\\n\\nAlice was curious, so she opened the door and drank the liquid inside. Suddenly, Alice began to shrink and she soon found herself in a strange world. She encountered many strange creatures, including talking animals and a strange caterpillar who smoked a hookah.\\n\\nAlice eventually found her way back home, but she was forever changed by her experience in Wonderland. She never forgot the strange creatures and adventures she experienced.\\n\\nAlice\\'s journey was filled with lessons about friendship, courage, and the power of imagination. It taught her that nothing is impossible and that life can be filled with exciting possibilities.', 'index': 0, 'finish_reason': 'stop', 'logprobs': None}], 'usage': {'completion_tokens': 195, 'prompt_tokens': 4, 'total_tokens': 199}}\n" |
| 170 | + ] |
| 171 | + } |
| 172 | + ], |
| 173 | + "source": [ |
| 174 | + "# Example prompt for request payload\n", |
| 175 | + "prompt = \"Once upon a time\"\n", |
| 176 | + "\n", |
| 177 | + "payload = {\n", |
| 178 | + " \"prompt\": prompt,\n", |
| 179 | + " \"max_tokens\": 300,\n", |
| 180 | + " \"temperature\": 0.7,\n", |
| 181 | + " \"top_p\": 1\n", |
| 182 | + " }\n", |
| 183 | + "\n", |
| 184 | + "r = get_completion(payload)\n", |
| 185 | + "\n", |
| 186 | + "# printing the status code & headers\n", |
| 187 | + "print(f'Status Code: {r.status_code}\\nHeaders: \\n{r.headers} \\n') \n", |
| 188 | + "\n", |
| 189 | + "response = r.json()\n", |
| 190 | + "\n", |
| 191 | + "# printing the response\n", |
| 192 | + "print(f'Response:\\n {response}')" |
| 193 | + ] |
| 194 | + }, |
| 195 | + { |
| 196 | + "cell_type": "code", |
| 197 | + "execution_count": null, |
| 198 | + "metadata": {}, |
| 199 | + "outputs": [], |
| 200 | + "source": [] |
| 201 | + } |
| 202 | + ], |
| 203 | + "metadata": { |
| 204 | + "kernelspec": { |
| 205 | + "display_name": "Python 3 (ipykernel)", |
| 206 | + "language": "python", |
| 207 | + "name": "python3" |
| 208 | + }, |
| 209 | + "language_info": { |
| 210 | + "codemirror_mode": { |
| 211 | + "name": "ipython", |
| 212 | + "version": 3 |
| 213 | + }, |
| 214 | + "file_extension": ".py", |
| 215 | + "mimetype": "text/x-python", |
| 216 | + "name": "python", |
| 217 | + "nbconvert_exporter": "python", |
| 218 | + "pygments_lexer": "ipython3", |
| 219 | + "version": "3.11.1" |
| 220 | + }, |
| 221 | + "vscode": { |
| 222 | + "interpreter": { |
| 223 | + "hash": "5453039e1c3beadcd7c6bc838a2f5d2d849c1bfa9a5a5e848cf27873534572b2" |
| 224 | + } |
| 225 | + } |
| 226 | + }, |
| 227 | + "nbformat": 4, |
| 228 | + "nbformat_minor": 2 |
| 229 | +} |
0 commit comments