20 minLesson 28 of 34
Python for AI
Using the OpenAI API
Using the OpenAI API in Python
The OpenAI API gives you access to GPT-4o, DALL-E, and Whisper — building intelligence directly into your Python applications. This lesson covers everything from your first API call to building production-ready AI features.
Setup
# pip install openai python-dotenv
from openai import OpenAI
from dotenv import load_dotenv
import os
load_dotenv() # Load API key from .env file
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
# NEVER hardcode API keys in your code
Basic Text Generation
# Simple completion
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "You are a helpful Python tutor."},
{"role": "user", "content": "Explain list comprehensions in 3 sentences."}
],
temperature=0.7, # 0 = deterministic, 1 = creative
max_tokens=300
)
answer = response.choices[0].message.content
print(answer)
# Cost tracking
print(f"Input tokens: {response.usage.prompt_tokens}")
print(f"Output tokens: {response.usage.completion_tokens}")
print(f"Total: {response.usage.total_tokens}")
Multi-Turn Conversations
class Conversation:
def __init__(self, system_prompt, model="gpt-4o"):
self.model = model
self.messages = [{"role": "system", "content": system_prompt}]
def chat(self, user_message, temperature=0.7):
self.messages.append({"role": "user", "content": user_message})
response = client.chat.completions.create(
model=self.model,
messages=self.messages,
temperature=temperature
)
assistant_message = response.choices[0].message.content
self.messages.append({"role": "assistant", "content": assistant_message})
return assistant_message
def reset(self, keep_system=True):
if keep_system:
self.messages = [self.messages[0]]
else:
self.messages = []
# Interactive chatbot
conv = Conversation("You are an expert Python developer. Be concise.")
print(conv.chat("What's the difference between a list and a tuple?"))
print(conv.chat("When would I use a tuple instead?"))
print(conv.chat("Give me a quick example."))
Structured Outputs: JSON Mode
import json
def extract_product_info(description: str) -> dict:
"""Extract structured product data from free text."""
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "system",
"content": """Extract product information and return ONLY valid JSON with these fields:
{
"name": "product name",
"price": number or null,
"category": "category string",
"features": ["list", "of", "features"],
"available": true/false
}"""
},
{"role": "user", "content": description}
],
response_format={"type": "json_object"}, # Forces JSON output
temperature=0
)
return json.loads(response.choices[0].message.content)
result = extract_product_info("""
The MacBook Pro 14-inch features Apple M3 chip, 16GB RAM,
and 512GB storage. Currently available for $1,599.
""")
print(result)
# {'name': 'MacBook Pro 14-inch', 'price': 1599, 'category': 'Laptop',
# 'features': ['Apple M3 chip', '16GB RAM', '512GB storage'], 'available': True}
Function Calling / Tool Use
import json
tools = [
{
"type": "function",
"function": {
"name": "get_stock_price",
"description": "Get the current stock price for a company ticker symbol",
"parameters": {
"type": "object",
"properties": {
"ticker": {
"type": "string",
"description": "Stock ticker symbol e.g. AAPL, MSFT"
}
},
"required": ["ticker"]
}
}
}
]
def get_stock_price(ticker: str) -> dict:
"""Mock stock price lookup."""
mock_prices = {"AAPL": 185.50, "MSFT": 420.30, "GOOGL": 150.25}
price = mock_prices.get(ticker.upper())
if price:
return {"ticker": ticker, "price": price, "currency": "USD"}
return {"error": f"Unknown ticker: {ticker}"}
def run_with_tools(user_message: str) -> str:
messages = [{"role": "user", "content": user_message}]
while True:
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools,
tool_choice="auto"
)
choice = response.choices[0]
messages.append(choice.message)
if choice.finish_reason == "stop":
return choice.message.content
# Process tool calls
for tool_call in choice.message.tool_calls:
args = json.loads(tool_call.function.arguments)
result = get_stock_price(**args)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result)
})
print(run_with_tools("What's the current price of Apple and Microsoft stock?"))
Streaming Responses
def stream_response(prompt: str):
"""Stream tokens as they're generated — better UX for long responses."""
stream = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}],
stream=True
)
full_response = ""
for chunk in stream:
if chunk.choices[0].delta.content is not None:
content = chunk.choices[0].delta.content
print(content, end='', flush=True) # Print as it arrives
full_response += content
print() # New line at end
return full_response
stream_response("Write a haiku about Python programming.")
Image Generation with DALL-E
def generate_image(prompt: str, size="1024x1024", quality="standard") -> str:
"""Generate an image and return the URL."""
response = client.images.generate(
model="dall-e-3",
prompt=prompt,
size=size,
quality=quality,
n=1
)
return response.data[0].url
url = generate_image("A Python snake writing code on a laptop, digital art style")
print(f"Image URL: {url}")
Audio Transcription with Whisper
def transcribe_audio(audio_path: str, language="en") -> str:
"""Transcribe audio file to text."""
with open(audio_path, 'rb') as audio_file:
transcript = client.audio.transcriptions.create(
model="whisper-1",
file=audio_file,
language=language
)
return transcript.text
text = transcribe_audio("meeting_recording.mp3")
print(text)
Error Handling and Rate Limits
from openai import RateLimitError, APIError, APIConnectionError
import time
def resilient_api_call(messages, max_retries=3):
for attempt in range(max_retries):
try:
return client.chat.completions.create(
model="gpt-4o",
messages=messages
)
except RateLimitError:
wait = 2 ** attempt * 5 # Exponential backoff: 5s, 10s, 20s
print(f"Rate limited. Waiting {wait}s...")
time.sleep(wait)
except APIConnectionError as e:
print(f"Connection error: {e}. Retrying...")
time.sleep(2 ** attempt)
except APIError as e:
if e.status_code >= 500: # Server error — retry
time.sleep(2 ** attempt)
else:
raise # Client error (400-499) — don't retry
raise Exception(f"API call failed after {max_retries} attempts")
Next lesson: Using the Anthropic Claude API — working with Claude's unique capabilities.
📱
Get Notes Free →Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises