Use Azure OpenAI in Foundry Models
This topic covers the Azure OpenAI service in depth — provisioning resources, deploying models, calling the Chat Completions API from Python, generating images with DALL-E, transcribing audio with Whisper, and working with multimodal models that understand both text and images.
This topic uses from Topic 1: token, LLM, prompt, grounding, RAG, model catalog, deployment, dictionary (Python), and messages array. New concepts below are all introduced before code uses them.
Azure OpenAI terms — defined before code
The primary Azure OpenAI API endpoint. You send a conversation history (a list of messages with roles) and the model generates the next message. This is how GPT-4o works — you give it the conversation so far and it responds as the assistant.
The first message in the conversation with role: "system".
It sets the model's behaviour, persona, and constraints before any user
interaction. Example: "You are a friendly customer service agent for Contoso Bank.
Only answer questions about banking products."
A message with role: "user" — what the human said.
In a real conversation there are multiple alternating user and assistant messages.
This is the input the model responds to.
A message with role: "assistant" — what the AI previously said.
In multi-turn conversations, you include previous assistant responses in the messages
array so the model has memory of the conversation history.
The list of all messages in the conversation, sent to the API. Each message is a dictionary with "role" and "content" keys. The model reads the entire array to understand the conversation context before generating the next response.
The older Azure OpenAI API (now deprecated for most models). You send a single text prompt and the model completes it. The exam still references this — but prefer Chat Completions for GPT-3.5-turbo and GPT-4o onwards.
Azure OpenAI requires you to specify an API version in every call —
e.g. "2024-02-01". This ensures your code doesn't break
when Azure releases new API versions. Always specify the version explicitly.
Model name: the actual AI model — e.g. gpt-4o.
Deployment name: the name you gave your deployment in Foundry —
e.g. "my-gpt4o". In Python code, you always use the deployment
name, not the model name, in the model= parameter.
A model that accepts multiple types of input — text AND images. GPT-4o is multimodal: you can include an image in the user message and ask "What is in this image?" The model understands and responds to both.
An Azure OpenAI model that generates images from text descriptions (prompts). You send a text description like "a golden retriever playing in autumn leaves, photorealistic" and it returns a URL to a generated image. Current version in Azure: DALL-E 3.
An OpenAI audio model available in Azure. It transcribes speech from audio files into text. Supports 57 languages. Used in Azure OpenAI for high-accuracy transcription beyond what Azure AI Speech offers.
Standard: pay per token (pay-as-you-go). Good for variable traffic. May be subject to throttling at peak times. Provisioned Managed: you reserve a fixed number of tokens per minute (PTU). Guaranteed throughput. Higher upfront cost. Best for predictable production workloads.
Creating an Azure OpenAI resource
Azure OpenAI is a separate resource type from standard Azure AI Services. It requires a separate application and approval process for new customers.
portal.azure.com → search "Azure OpenAI" → + Create → Fill in: subscription, resource group, region, name, pricing tier (S0). Note: not all regions have all models — choose East US or West Europe for widest availability.
ai.azure.com → your project → Models + endpoints → + Deploy model → Select from catalog (e.g. gpt-4o) → Give deployment a name → Choose deployment type (Standard or Provisioned) → Set token limit → Deploy.
Azure portal → your Azure OpenAI resource → Keys and Endpoint. Endpoint format: https://your-name.openai.azure.com/. This is different from the cognitiveservices.azure.com format used by other AI services.
Azure OpenAI endpoints use the domain openai.azure.com,
not cognitiveservices.azure.com. The exam shows endpoints
and asks which service they belong to.
https://my-resource.openai.azure.com/ → Azure OpenAI
https://my-resource.cognitiveservices.azure.com/ → Other AI services
https://my-resource.search.windows.net → Azure AI Search
How to call GPT-4o from Python
The Chat Completions API is the primary way to interact with GPT models. Before the code, understand the three roles in a conversation:
The instructions that govern how the model behaves. Set once at the start. The model "reads" this before anything else. Defines persona, constraints, and tone. Think of it as the briefing you give the AI before it starts working.
What the human (your application's user) is saying. In a multi-turn conversation there are multiple user messages, alternating with assistant messages. This is the input the model is responding to.
What the model has previously said. You include previous assistant responses in the messages array so the model "remembers" the conversation history. Without these, the model has no memory of previous turns.
Single-turn call (one question, one answer)
import os
from openai import AzureOpenAI # Install: pip install openai
# Create the Azure OpenAI client
# azure_endpoint: your Azure OpenAI resource endpoint (openai.azure.com)
# api_key: your Azure OpenAI key
# api_version: ALWAYS specify — ensures consistent behaviour as Azure updates
client = AzureOpenAI(
azure_endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT"),
api_key = os.environ.get("AZURE_OPENAI_KEY"),
api_version = "2024-02-01"
)
# chat.completions.create() sends the conversation to the model
# model=: your DEPLOYMENT NAME (not the model name like "gpt-4o")
# messages=: a list of dictionaries — each one is a message with role and content
response = client.chat.completions.create(
model = "my-gpt4o", # Your deployment name from Foundry
messages = [
{
"role" : "system", # System message sets behaviour
"content": "You are a helpful AI assistant that explains things simply."
},
{
"role" : "user", # User message is the question
"content": "What is the difference between AI and machine learning?"
}
]
)
# Extract the model's response text
# response.choices is a list of possible responses (usually 1)
# [0] gets the first response
# .message.content is the text the model generated
answer = response.choices[0].message.content
print(f"Response: {answer}")
# You can also check token usage (important for cost monitoring)
# response.usage shows how many tokens were used
print(f"Tokens used — Prompt: {response.usage.prompt_tokens}, "
f"Completion: {response.usage.completion_tokens}, "
f"Total: {response.usage.total_tokens}")
Multi-turn conversation (chatbot)
For a chatbot, you maintain the conversation history by appending each message to the list before sending. New Python concept: list.append() — adds a new item to the end of a list. Explained in comments.
import os
from openai import AzureOpenAI
client = AzureOpenAI(
azure_endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT"),
api_key = os.environ.get("AZURE_OPENAI_KEY"),
api_version = "2024-02-01"
)
# Start with just the system message in the conversation history
# This list grows as the conversation continues
conversation_history = [
{"role": "system", "content": "You are a helpful banking assistant."}
]
# Simulate a 2-turn conversation
user_inputs = [
"What is the current interest rate on savings accounts?",
"How does that compare to a fixed-term deposit?" # Follow-up question
]
# New concept: for loop over a list (from Part 1 Topic 4)
# "for user_input in user_inputs:" runs once for each item in the list
for user_input in user_inputs:
# Step 1: Add the user's message to the history
# list.append() adds a new item to the END of the list
# So conversation_history grows by one message each iteration
conversation_history.append({
"role" : "user",
"content": user_input
})
# Step 2: Send the ENTIRE conversation history to the model
# The model reads all previous messages and responds in context
response = client.chat.completions.create(
model = "my-gpt4o",
messages = conversation_history # Full history — not just the latest message
)
# Step 3: Extract the assistant's reply
assistant_reply = response.choices[0].message.content
print(f"User: {user_input}")
print(f"Assistant: {assistant_reply}\n")
# Step 4: Add the assistant's reply to the history
# This is crucial — without this the model loses memory of what it said
conversation_history.append({
"role" : "assistant",
"content": assistant_reply
})
The exam shows message arrays with some content removed and asks which role goes where. Remember: system = instructions/persona (written by developer), user = human input (from the end user), assistant = previous AI responses (from earlier in the conversation). System always comes first. User and assistant alternate after that.
Using GPT models to write code
GPT-4o and GPT-3.5-turbo are excellent at generating, explaining, and fixing code. The same Chat Completions API is used — you just craft a code-focused prompt.
import os
from openai import AzureOpenAI
client = AzureOpenAI(
azure_endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT"),
api_key = os.environ.get("AZURE_OPENAI_KEY"),
api_version = "2024-02-01"
)
# Code generation — the system prompt tells the model to act as a coding assistant
# The user message asks for code in Python
response = client.chat.completions.create(
model = "my-gpt4o",
messages = [
{
"role" : "system",
"content": "You are an expert Python developer. Provide clean, commented code."
},
{
"role" : "user",
"content": "Write a Python function that reads a CSV file and returns a list of dictionaries, "
"where each dictionary represents a row with column names as keys."
}
]
)
# The model returns Python code as text inside its response
generated_code = response.choices[0].message.content
print(generated_code)
Generating images from text descriptions
DALL-E 3 in Azure OpenAI generates images from text prompts. The API is different from Chat Completions — you call the images endpoint and get back a URL to the generated image.
DALL-E parameters you need to know
| Parameter | Options | What it controls |
|---|---|---|
size | "1024x1024", "1792x1024", "1024x1792" | Image dimensions. Square, landscape, or portrait. |
quality | "standard", "hd" | "hd" produces more detailed images with sharper details. Costs more tokens. |
style | "vivid", "natural" | "vivid" = hyper-real and dramatic. "natural" = more photographic and realistic. |
n | 1 (DALL-E 3 only supports 1) | Number of images to generate. DALL-E 3 always generates 1. |
import os
from openai import AzureOpenAI
client = AzureOpenAI(
azure_endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT"),
api_key = os.environ.get("AZURE_OPENAI_KEY"),
api_version = "2024-02-01"
)
# images.generate() calls the DALL-E model — different endpoint from chat.completions
# model=: the name of your DALL-E deployment (e.g. "dall-e-3")
# prompt=: text description of the image you want generated
# size=: image dimensions
# quality=: "standard" or "hd" (higher detail)
# n=: number of images (DALL-E 3 only supports n=1)
result = client.images.generate(
model = "dall-e-3", # Your DALL-E deployment name
prompt = "A futuristic city skyline at sunset, with flying cars and neon lights, "
"photorealistic style, ultra-high detail",
size = "1792x1024", # Landscape format
quality = "hd", # High definition
n = 1 # DALL-E 3 only generates 1 image at a time
)
# The response contains the URL of the generated image
# result.data is a list (we only have 1 image since n=1)
# .url is the temporary URL where you can download the image
# Note: DALL-E URLs expire after a short time — download and save the image promptly
image_url = result.data[0].url
print(f"Generated image URL: {image_url}")
# result.data[0].revised_prompt contains the prompt DALL-E actually used
# DALL-E 3 may revise your prompt to add safety details
revised = result.data[0].revised_prompt
print(f"Revised prompt: {revised}")
• DALL-E 3 only generates 1 image per request (n=1 always)
• Image URLs are temporary — they expire. Download and store the image immediately.
• DALL-E 3 may revise your prompt slightly — check revised_prompt
• Available sizes: 1024x1024, 1792x1024 (landscape), 1024x1792 (portrait)
• Content filters apply to DALL-E prompts — harmful image requests are blocked
Transcribing audio to text with OpenAI's Whisper
Whisper is an OpenAI speech-to-text model available in Azure OpenAI. It transcribes audio files into text with high accuracy across 57 languages.
import os
from openai import AzureOpenAI
client = AzureOpenAI(
azure_endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT"),
api_key = os.environ.get("AZURE_OPENAI_KEY"),
api_version = "2024-02-01"
)
# New concept: "with open(...) as f:" — opens a file safely
# The "with" statement (from Part 1 Topic 4) ensures the file is closed
# automatically when the block finishes — even if an error occurs
# "rb" means read in binary mode (required for audio files)
with open("meeting_recording.mp3", "rb") as audio_file:
# audio.transcriptions.create() sends the audio to Whisper for transcription
# model=: your Whisper deployment name in Foundry
# file=: the open audio file object
transcription = client.audio.transcriptions.create(
model = "whisper", # Your Whisper deployment name
file = audio_file, # The audio file to transcribe
language = "en" # Optional: specify language for better accuracy
)
# .text contains the full transcription as a single string
print(f"Transcription: {transcription.text}")
Both transcribe speech. Exam scenarios distinguish them:
Use Whisper (Azure OpenAI) when: scenario mentions Azure OpenAI,
the solution already uses OpenAI models, highest possible transcription accuracy
needed, or the question says "using OpenAI".
Use Azure AI Speech when: scenario mentions real-time streaming
transcription, custom speech models (your domain vocabulary), intent recognition,
speaker identification, or text-to-speech (Whisper only does speech-to-text).
Sending images to GPT-4o
GPT-4o is multimodal — it can understand images as well as text. You include image data in the user message content and the model analyses and responds to it. This is useful for image description, visual Q&A, document analysis with images, and more.
import os
import base64 # Built-in Python module for encoding binary data as text
from openai import AzureOpenAI
client = AzureOpenAI(
azure_endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT"),
api_key = os.environ.get("AZURE_OPENAI_KEY"),
api_version = "2024-02-01"
)
# Method 1: Send image as a URL (the model downloads and reads it)
# Works if the image is publicly accessible on the internet
response_url = client.chat.completions.create(
model = "my-gpt4o",
messages = [
{
"role": "user",
"content": [ # Content can be a LIST when combining text + images
{
"type": "text", # Text part of the message
"text": "What items are visible in this image? List them."
},
{
"type" : "image_url", # Image part of the message
"image_url": {
"url" : "https://example.com/my-image.jpg",
"detail": "high" # "high" = full resolution analysis
# "low" = faster, lower cost
# "auto" = model decides
}
}
]
}
]
)
print(response_url.choices[0].message.content)
# Method 2: Send image as base64-encoded data (for private/local images)
# base64 converts binary file data into a text string safe for JSON
with open("local_image.jpg", "rb") as img_file:
# base64.b64encode() encodes the binary image as base64 bytes
# .decode("utf-8") converts those bytes to a regular text string
image_data = base64.b64encode(img_file.read()).decode("utf-8")
response_b64 = client.chat.completions.create(
model = "my-gpt4o",
messages = [{
"role": "user",
"content": [
{"type": "text", "text": "Describe this image in detail."},
{
"type": "image_url",
"image_url": {
# data:image/jpeg;base64, tells the model this is base64 data
"url": f"data:image/jpeg;base64,{image_data}"
}
}
]
}]
)
print(response_b64.choices[0].message.content)
GPT-4o Vision — Use when you want the AI to reason
about an image and generate a natural language response. "Describe this
product photo." "What's wrong with this X-ray?" "Summarise what this
chart shows." Rich reasoning, conversational output.
Azure AI Vision — Use when you need structured outputs:
detect objects, extract text (OCR), identify faces, generate tags, get
bounding boxes. Faster, cheaper, more structured. Not conversational.
Azure OpenAI — what the exam specifically tests
1. model= uses deployment name, not model name — In Python code,
model="my-gpt4o-deploy" not model="gpt-4o".
The deployment name is what you set when deploying in Foundry.
2. Azure OpenAI endpoint = openai.azure.com — Not
cognitiveservices.azure.com. Know all three endpoint patterns.
3. DALL-E 3 always n=1 — It only generates one image per request.
Also: URLs expire — you must download and store the image.
4. Content as a list for multimodal — When mixing text and images,
the content field in the message dictionary is a list of
content objects (text object + image_url object), not a simple string.
5. api_version is always required — Azure OpenAI requires you
to specify the API version explicitly. A question may show code missing
api_version and ask why it fails.
Test your understanding
5 questions — select an answer to see the explanation immediately.
A developer creates an Azure OpenAI deployment named "gpt4-prod" using the gpt-4o model. When calling the API in Python, what should the model= parameter be set to?
B is correct. In Azure OpenAI, the model= parameter in Python code takes the deployment name — the name you assigned when deploying the model in Foundry or Azure OpenAI Studio. In this case "gpt4-prod". Not the actual model name ("gpt-4o"), not a prefixed name, not a versioned name. This is a common mistake — people write model="gpt-4o" and get a 404 error because Azure looks for a deployment called "gpt-4o" which doesn't exist.