Intermediate

Developing Generative AI Applications with Python and OpenAI

Use the OpenAI API end to end: GPT models, prompt engineering, practical apps and building your own chatbot.

Table of Contents

  1. Course Overview
  2. Introduction to Large Language Models (LLM) and OpenAI
  3. Overview of GPT Models (Generative Pre-trained Transformer)
  4. Getting Started with the OpenAI API
  5. Mastering Prompt Engineering
  6. Practical Applications of the OpenAI API
  7. Training Your Own Chatbot
  8. The Future of OpenAI and NLP

1. Course Overview

This course teaches how to build generative AI applications using the OpenAI API with Python. It covers:

  • Introduction to Large Language Models (LLMs) and OpenAI
  • Overview of GPT (Generative Pre-trained Transformer) models
  • Getting started with OpenAI APIs
  • Mastering prompt engineering
  • Practical API applications
  • Building a basic chatbot and fine-tuning
  • The future of OpenAI and NLP

Prerequisites: Python knowledge and familiarity with Python APIs/libraries.


2. Introduction to Large Language Models (LLM) and OpenAI

2.1 Life Before LLMs

Before LLMs, searches worked by keywords: you typed a few words into Google and got a list of websites. Everything changed in late November 2022 with the launch of ChatGPT.

Instead of searching quotes question mark rules, you can now ask:

“Do I include a question mark inside or outside the quotes?”

And you get a natural language, conversational answer — much more intuitive.

Before LLMs:  "quotes question mark rules"     → list of links
With LLMs:    "Do I include a ? inside quotes?" → natural answer

2.2 What is an LLM?

A LLM (Large Language Model) is a type of AI model designed to understand and generate human-like text. It uses mathematics and statistics to understand relationships between words.

LLM = Autocomplete on steroids
      trained on immense amounts of data
      in a conversational manner

ChatGPT is an LLM based on the GPT-3.5 (Generative Pre-trained Transformer 3.5) architecture.

Historical comparison of voice assistants:

AssistantEraType
ELIZA1960sFirst “chatterbot” (pattern matching)
Siri2011Basic voice assistant
Alexa2014Amazon voice assistant
ChatGPT2022Advanced conversational LLM

2.3 The Journey to LLMs

timeline
    title Evolution toward LLMs
    section Foundations
        N-grams / Statistical Models : Foundations of word sequences
    section Neural Networks
        RNNs and LSTMs : Modeling contextual relationships
    section Transformers
        2017 : "Attention Is All You Need" (Vaswani et al.)
              Revolutionary Transformer architecture
    section Pre-training
        2018 : BERT (Google)
               GPT-1 (OpenAI)
    section Modern LLMs
        2019 : GPT-2
        2020 : GPT-3 (175B parameters)
        2022 : GPT-3.5 / ChatGPT
        2023 : GPT-4

Key milestones:

  1. N-grams and statistical models — understanding word sequences
  2. RNNs and LSTMs — modeling contextual relationships
  3. Attention mechanism (Transformer) — parallel processing revolution (2017)
  4. BERT (Google, 2018) — large-scale pre-training
  5. OpenAI GPT series — from GPT-1 (2018) to GPT-4

2.4 Advantages, Challenges, Applications, and Ethical Considerations

Advantages of LLMs

✅ Natural language understanding and generation
✅ Automation of language tasks
✅ Accessibility (text-to-speech, speech-to-text)
✅ Creative content generation
✅ Multilingual support

Challenges

⚠️  Bias and fairness (LLMs inherit biases from training data)
⚠️  Misinformation (generation of false text — "hallucination")
⚠️  Ethical dilemmas (authenticity, intellectual property)
⚠️  Computational resource consumption

Important: LLMs can generate incorrect or invented information — a phenomenon called “hallucination”. Always verify facts!

Applications

DomainApplication
MediaContent generation, articles
Customer serviceChatbots, virtual assistants
LanguagesMachine translation
DevelopmentCode generation
MedicineMedical literature analysis
EducationPersonalized learning

2.5 About OpenAI

  • Founded in December 2015
  • Mission: Ensure that the development of AGI (Artificial General Intelligence) benefits humanity
  • Creators of the GPT series and ChatGPT
  • Leader in responsible AI (bias, misinformation, ethics)

2.6 ChatGPT Demo

Capabilities demonstrated in ChatGPT:

1. Natural language Q&A
   → "What is your perspective on the ethical dilemmas surrounding AI?"

2. Creative generation
   → "Write a story about a time-traveling computer programmer"

3. Translation
   → "Translate the story into Spanish"

4. Code generation
   → Python, SQL code, etc.

ChatGPT vs OpenAI API difference:

ChatGPTOpenAI API
Conversational web interfaceProgrammatic access
Integrated browsing, code executionMore flexibility
For end usersFor developers

3. Overview of GPT Models

3.1 Understanding GPT Models

GPT = Generative Pre-trained Transformer

TermMeaning
GenerativeCapable of generating human-like text
Pre-trainedTrained on immense textual datasets
TransformerArchitecture based on the attention mechanism (2017 paper)

3.2 LLM Architecture — The Transformer

The Transformer was introduced in the paper “Attention Is All You Need” (Vaswani et al., 2017).

graph TB
    subgraph Encoder
        A[Input text] --> B[Tokenization]
        B --> C[Positional Encoding]
        C --> D[Multi-Head Attention]
        D --> E[Feed-Forward Network]
    end
    subgraph Decoder
        E --> F[Multi-Head Attention]
        F --> G[Feed-Forward Network]
        G --> H[Output text]
    end

    style Encoder fill:#dbeafe,stroke:#3b82f6
    style Decoder fill:#dcfce7,stroke:#22c55e

Key components of the Transformer architecture:

  1. Encoder-Decoder structure — Encoder processes input text, decoder generates output text
  2. Self-Attention mechanism — Each word evaluates the importance of other words in the sentence
  3. Multi-Head Attention — Multiple attention mechanisms in parallel
  4. Positional Encoding — Encodes the position of words in the sequence
  5. Feed-Forward Neural Networks — Transformation of representations

Simplified explanation (LEGO analogy):

Transformer = LEGO instruction book for building sentences
  1. Break the sentence into pieces (tokens)
  2. Look at how the pieces relate to each other
  3. Mix information to understand the overall meaning
  4. Repeat very quickly for each sentence

3.3 Evolution of the GPT Family

graph LR
    GPT1["GPT-1 (2018)
    117M parameters
    40 GB of data
    512 token context"] -->
    GPT2["GPT-2 (2019)
    1.5B parameters
    Doubled context"] -->
    GPT3["GPT-3 (2020)
    175B parameters
    570 GB of data
    Zero-shot / Few-shot"] -->
    GPT35["GPT-3.5 (2022)
    ChatGPT launched!
    Focus on ethics"] -->
    GPT4["GPT-4 (2023)
    Multimodal
    Images + text"]

    style GPT1 fill:#fef3c7
    style GPT2 fill:#fde68a
    style GPT3 fill:#fbbf24
    style GPT35 fill:#f59e0b
    style GPT4 fill:#d97706
ModelYearParametersDataWhat’s New
GPT-12018117M~40 GBFirst GPT model
GPT-220191.5BLarger corpusDoubled context (1024 tokens)
GPT-32020175B570+ GBZero-shot, multilingual (30 languages)
GPT-3.52022ChatGPT, ethical focus
GPT-42023Multimodal (text + images)

3.4 Impact of Model Size

The larger the model:

  • ✅ Better contextual understanding
  • ✅ More fluent and creative text
  • ✅ Better performance on complex tasks
  • ✅ Enhanced multilingual capabilities
  • ⚠️ More computational resources required
  • ⚠️ Higher environmental and practical costs

3.5 Rival LLM Models

OpenAI is not alone in the market:

ModelCompanyCharacteristics
ClaudeAnthropicSafety-first approach, reduces harmful responses
PaLM / PaLM 2GooglePowers Google Bard
LLaMA / LLaMA 2Meta (Facebook)Open-source, available since February 2023
GeminiGoogleSuccessor to PaLM 2

4. Getting Started with the OpenAI API

4.1 OpenAI Platform Overview

Getting started resources:

  • Platform: platform.openai.com
  • Documentation: platform.openai.com/docs
  • API Reference: platform.openai.com/docs/api-reference
  • Tokenizer: platform.openai.com/tokenizer

“Starter Pack” — What you need:

1. Course demo files
2. OpenAI account with credits + API key
3. Python installed locally
4. Jupyter Notebook or VS Code

Creating an API key:

  1. Navigate to platform.openai.com
  2. Menu → View API keys → Create a new secret key
  3. ⚠️ Store the key securely — it cannot be retrieved after creation

4.2 Using the API Directly with Python

Installation:

pip install requests

Complete example — Direct API call:

import os
import requests
import json

# Load the API key from a file
key_location = 'path/to/your/api_key.txt'
with open(key_location, 'r') as file:
    api_key = file.readline().strip()

# Define the prompt
prompt = "To build great software"

# Endpoint URL
endpoint = "https://api.openai.com/v1/chat/completions"

# Headers with authentication
headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {api_key}"
}

# Request parameters
max_tokens = 50
payload = {
    "model": "gpt-3.5-turbo",
    "messages": [{"role": "user", "content": prompt}],
    "max_tokens": max_tokens
}

# API call
response = requests.post(endpoint, headers=headers, json=payload)

# Extract and display the response
completion_text = response.json()["choices"][0]["message"]["content"].strip()
print("Completion for '" + prompt + "'\n" + completion_text)

# Display the full formatted response
print(json.dumps(response.json(), indent=2))

JSON response structure:

{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "created": 1234567890,
  "model": "gpt-3.5-turbo",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "The model's response..."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 10,
    "completion_tokens": 50,
    "total_tokens": 60
  }
}

4.3 Using the Official Python Library

Installation:

pip install openai
# If an update is needed:
pip install openai --upgrade

Example with the official library:

import openai
import os

# API key
key_location = 'path/to/your/api_key.txt'
with open(key_location, 'r') as file:
    api_key = file.readline().strip()

openai.api_key = api_key

# Prompt
prompt = "To build great software"

# Call with completion model (legacy)
completion_params = {
    "model": "davinci-002",
    "prompt": prompt,
    "max_tokens": 50
}
response = openai.Completion.create(**completion_params)
completion_text = response.choices[0].text.strip()
print("Generated completion:", prompt + completion_text)

# Chat Completion call (recommended)
conversation = [
    {"role": "user", "content": "How can I build great software?"}
]
response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=conversation
)
reply = response['choices'][0]['message']['content']
print(reply)

Direct API vs Python Library comparison:

CriterionDirect APIPython Library
ControlMore fine-grained, more flexibleLess direct control
WeightLightweight (simple HTTP request)More dependencies
EaseMore error-proneSimpler, less code
MaintenanceManualOfficially maintained
TokenizationManualAutomatic

4.4 Anatomy of an API Call

import os
import requests
import json

# Load the key
key_location = 'path/to/api_key.txt'
with open(key_location, 'r') as file:
    api_key = file.readline().strip()

def make_openai_request(prompt):
    """Sends a POST request to the OpenAI API"""
    url = 'https://api.openai.com/v1/chat/completions'
    
    # Headers: authentication + content type
    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {api_key}'
        # Optional: 'OpenAI-Organization': 'org-...'
    }
    
    # Request body
    data = {
        "model": "gpt-3.5-turbo",       # Model to use
        "messages": [                    # Conversation history
            {"role": "user", "content": prompt}
        ],
        "temperature": 0.7              # Creativity (0=deterministic, 2=very creative)
    }

    response = requests.post(url, headers=headers, json=data, timeout=20)

    if response.status_code == 200:
        return response.json()
    print('Request failed with code:', response.status_code)
    return None

result = make_openai_request("Tell me a joke")
print(json.dumps(result, indent=2))

Roles in messages:

graph LR
    User["👤 user
    The end user
    who interacts"] -->|sends message| API
    System["⚙️ system
    Instructions / context
    for the model"] -->|configures behavior| API
    API -->|generates response| Assistant["🤖 assistant
    The model's
    responses"]

    style User fill:#dbeafe
    style System fill:#fef3c7
    style Assistant fill:#dcfce7

Important parameters:

ParameterDescriptionValues
modelModel to usegpt-3.5-turbo, gpt-4, etc.
messagesList of conversation messagesArray of {role, content} objects
temperatureResponse creativity/randomness0 to 2 (default: 1)
max_tokensToken output limitPositive integer
top_pCumulative probability filtering0 to 1

4.5 Listing and Retrieving Models

import json
import os
import requests

key_location = 'path/to/api_key.txt'
with open(key_location, 'r') as file:
    api_key = file.readline().strip()

def make_openai_request(url, data=None):
    headers = {'Authorization': f'Bearer {api_key}'}
    if data:
        headers['Content-Type'] = 'application/json'
    response = requests.get(url, headers=headers, json=data, timeout=20)
    if response.status_code == 200:
        return response.json()
    print('Request failed:', response.status_code)
    return None

# List all available models
LIST_URL = "https://api.openai.com/v1/models"
list_result = make_openai_request(LIST_URL)
if list_result:
    print(json.dumps(list_result, indent=2))

# Retrieve a specific model
RETRIEVE_URL = "https://api.openai.com/v1/models/gpt-3.5-turbo-instruct-0914"
retri_result = make_openai_request(RETRIEVE_URL)
if retri_result:
    print(json.dumps(retri_result, indent=2))

Note: Not all models are available at all endpoints. For example, whisper-1 is not supported in chat/completions.

4.6 Model Pricing

Pricing is based on the number of tokens (input + output):

General rule: 1 token ≈ 4 characters ≈ 0.75 word
ModelIndicative price (at time of course)Note
GPT-3.5-turbo~$0.0015 / 1000 tokensVery affordable
GPT-4~$0.03 / 1000 tokens~20x more expensive

Best practices for cost control:

  • Use max_tokens to limit output
  • Monitor usage in the usage section of the response
  • Set a soft limit (email alert) and a hard limit in the platform
  • Start with GPT-3.5, switch to GPT-4 only if necessary

4.7 Chat Completions — Zero-shot and Few-shot

Complete example — Chat Completions with roles:

import os
import requests
import json

key_location = 'path/to/api_key.txt'
with open(key_location, 'r') as file:
    api_key = file.readline().strip()

def make_openai_request(url, data=None):
    headers = {'Authorization': f'Bearer {api_key}'}
    if data:
        headers['Content-Type'] = 'application/json'
    response = requests.post(url, headers=headers, json=data, timeout=20)
    if response.status_code == 200:
        return response.json()
    print('Request failed:', response.status_code)
    return None

URL = "https://api.openai.com/v1/chat/completions"
data = {
    "model": "gpt-3.5-turbo",
    "messages": [
      {
        "role": "system",
        "content": "You are an angry customer."
      },
      {
        "role": "user",
        "content": "Hello!"
      },
      {
        "role": "assistant",
        "content": "Hello there. I need to express my extreme dissatisfaction..."
      },
      {
        "role": "user",
        "content": "What seems to be the problem?"
      }
    ],
    "temperature": 0.7
}
result = make_openai_request(URL, data)
if result:
    print(json.dumps(result, indent=2))

Zero-shot vs Few-shot Prompting:

graph LR
    subgraph Zero-shot
        ZP["Prompt without examples
        Model generates a response
        based solely on its training"]
    end
    subgraph Few-shot
        FP["Prompt with 1-5 examples
        Model learns the format
        from the provided examples"]
    end
    subgraph Multi-shot
        MP["Prompt with multiple examples
        Better accuracy
        for specific tasks"]
    end

    style Zero-shot fill:#dbeafe
    style Few-shot fill:#dcfce7
    style Multi-shot fill:#fef3c7

4.8 Image Generation

Endpoint: /v1/images/generations

import json
import os
import requests

key_location = 'path/to/api_key.txt'
with open(key_location, 'r') as file:
    api_key = file.readline().strip()

URL = "https://api.openai.com/v1/images/generations"
headers = {'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json'}
data = {
    "prompt": "A majestic mountain landscape at sunset",
    "n": 2,              # Number of images to generate
    "size": "1024x1024"  # Sizes: "256x256", "512x512", "1024x1024"
}

response = requests.post(URL, headers=headers, json=data, timeout=20)
if response.status_code == 200:
    result = response.json()
    print(json.dumps(result, indent=2))
    # Response contains URLs to generated images

With the Python library (equivalent):

import openai
openai.api_key = api_key
response = openai.Image.create(
    prompt="A majestic mountain landscape at sunset",
    n=2,
    size="1024x1024"
)

4.9 Image Editing

Endpoint: /v1/images/edits

Allows editing an image by providing an original image + a mask (transparent area = area to modify) + a prompt describing the full image.

import os
import requests
import json

key_location = 'path/to/api_key.txt'
with open(key_location, 'r') as file:
    api_key = file.readline().strip()

URL = "https://api.openai.com/v1/images/edits"
headers = {'Authorization': f'Bearer {api_key}'}

# Provide both the original image AND the mask
files = {
    "image": open("./landscape1.png", "rb"),
    "mask": open("./mask1.png", "rb")  # Transparent area = area to edit
}
data = {
    "prompt": "A majestic mountain with snow-capped peaks",
    "n": 1,
    "size": "1024x1024"
}

response = requests.post(URL, headers=headers, files=files, data=data, timeout=20)
if response.status_code == 200:
    result = response.json()
    print(json.dumps(result, indent=2))

Constraints: Images must be square and less than 4 MB.

Mask illustration:

Original image     Mask                Result
┌──────────────┐  ┌──────────────┐   ┌──────────────┐
│              │  │ ████████████ │   │  [SNOW] ✨   │
│  🏔 Mountain │  │              │   │  🏔 Mountain │
│              │  │              │   │              │
└──────────────┘  └──────────────┘   └──────────────┘
                   Black area = preserved
                   Transparent area = edited

4.10 Image Variations

Endpoint: /v1/images/variations

Generates a variation of an existing image — similar but not identical.

import os
import requests
import json

key_location = 'path/to/api_key.txt'
with open(key_location, 'r') as file:
    api_key = file.readline().strip()

URL = "https://api.openai.com/v1/images/variations"
headers = {'Authorization': f'Bearer {api_key}'}
files = {
    "image": open("./landscape1.png", "rb")
}
data = {
    "n": 2,
    "size": "1024x1024"
}

response = requests.post(URL, headers=headers, files=files, data=data, timeout=20)
if response.status_code == 200:
    result = response.json()
    print(json.dumps(result, indent=2))

With the Python library:

response = openai.Image.create_variation(
    image=open("landscape1.png", "rb"),
    n=1,
    size="1024x1024"
)

4.11 Embeddings

Embeddings are vector representations of texts or images in a lower-dimensional space.

Embedding = Vector of floating-point numbers
Distance between vectors = Semantic similarity
  Small distance → Very similar
  Large distance → Very different

Usage example:

import json
import os
import requests

key_location = 'path/to/api_key.txt'
with open(key_location, 'r') as file:
    api_key = file.readline().strip()

URL = "https://api.openai.com/v1/embeddings"
headers = {
    'Content-Type': 'application/json',
    'Authorization': f'Bearer {api_key}'
}
data = {
    "input": "The quick brown fox jumps over the lazy dog",
    "model": "text-embedding-ada-002"
}

response = requests.post(URL, headers=headers, json=data, timeout=20)
result = response.json()
# result["data"][0]["embedding"] = [0.0023, -0.009, 0.0012, ...]
# 1536-dimensional vector for ada-002
print(json.dumps(result, indent=2))

Embedding use cases:

  • Semantic search
  • Document clustering
  • Content recommendations
  • Anomaly detection
  • Classification

4.12 Audio Transcription (Whisper)

Model: whisper-1 — general-purpose speech recognition (open-source available)

Endpoint: /v1/audio/transcriptions

import json
import os
import requests

key_location = 'path/to/api_key.txt'
with open(key_location, 'r') as file:
    api_key = file.readline().strip()

URL = "https://api.openai.com/v1/audio/transcriptions"
headers = {'Authorization': f'Bearer {api_key}'}
files = {
    "file": open("./speech_sample.mp3", "rb")
}
data = {
    "model": "whisper-1"
    # "prompt": "...",     # Optional: guide the style
    # "temperature": 0,   # Optional: creativity
    # "response_format": "json"  # Default: json
}

response = requests.post(URL, headers=headers, files=files, data=data, timeout=20)
result = response.json()
print(json.dumps(result, indent=2))
# → {"text": "Two roads diverged in a wood, and I..."}

With the Python library:

with open("speech_sample.mp3", "rb") as audio_file:
    transcript = client.audio.transcriptions.create(
        model="whisper-1",
        file=audio_file
    )
print(transcript.text)

4.13 Audio Translation

Endpoint: /v1/audio/translations

Translates audio from any language into English.

import json
import os
import requests

key_location = 'path/to/api_key.txt'
with open(key_location, 'r') as file:
    api_key = file.readline().strip()

URL = "https://api.openai.com/v1/audio/translations"
headers = {'Authorization': f'Bearer {api_key}'}
files = {
    "file": open("./german_sample.mp3", "rb")  # German audio
}
data = {
    "model": "whisper-1"
}

response = requests.post(URL, headers=headers, files=files, data=data, timeout=20)
result = response.json()
print(json.dumps(result, indent=2))
# Input (German): "Wir denken selten an das, was wir haben, aber immer an das, was uns fehlt."
# Output (English): "We rarely think about what we have, but always think about what we are missing."

With the Python library:

with open("german_sample.mp3", "rb") as audio_file:
    translation = client.audio.translations.create(
        model="whisper-1",
        file=audio_file
    )

4.14 Content Moderation

Endpoint: /v1/moderations

Checks whether content complies with OpenAI’s usage policy. Categories checked:

hate | hate/threatening | harassment | harassment/threatening
self-harm | self-harm/intent | self-harm/instructions
sexual | sexual/minors
violence | violence/graphic
import json
import os
import requests

key_location = 'path/to/api_key.txt'
with open(key_location, 'r') as file:
    api_key = file.readline().strip()

URL = "https://api.openai.com/v1/moderations"
headers = {
    'Content-Type': 'application/json',
    'Authorization': f'Bearer {api_key}'
}

# Example 1: Harmless text
data = {"input": "I love spending time with friends."}
response = requests.post(URL, headers=headers, json=data, timeout=20)
# → flagged: false

# Example 2: Potentially problematic text
data = {"input": "I want to harm someone."}
response = requests.post(URL, headers=headers, json=data, timeout=20)
result = response.json()
print(json.dumps(result, indent=2))
# → flagged: true
# → categories: {harassment: true, harassment/threatening: true}

4.15 File Management

Endpoint: /v1/files

Useful notably for fine-tuning. Four operations:

import json
import os
import requests

key_location = 'path/to/api_key.txt'
with open(key_location, 'r') as file:
    api_key = file.readline().strip()

def make_get_request(url):
    headers = {'Authorization': f'Bearer {api_key}'}
    response = requests.get(url, headers=headers, timeout=20)
    if response.status_code == 200:
        return response.json()
    return None

def make_delete_request(url):
    headers = {'Authorization': f'Bearer {api_key}'}
    response = requests.delete(url, headers=headers, timeout=20)
    if response.status_code == 200:
        return response.json()
    return None

def make_post_request(url, data, files):
    headers = {'Authorization': f'Bearer {api_key}'}
    response = requests.post(url, headers=headers, data=data, files=files, timeout=20)
    if response.status_code == 200:
        return response.json()
    return None

# 1. List files
list_result = make_get_request("https://api.openai.com/v1/files")
print(json.dumps(list_result, indent=2))

# 2. Upload a file
upload_result = make_post_request(
    "https://api.openai.com/v1/files",
    data={"purpose": "fine-tune"},
    files={"file": open("./training_data.jsonl", "rb")}
)
uploaded_file_id = upload_result["id"]

# 3. Retrieve file info
retrieve_result = make_get_request(f"https://api.openai.com/v1/files/{uploaded_file_id}")

# 4. Delete a file
delete_result = make_delete_request(f"https://api.openai.com/v1/files/{uploaded_file_id}")

Response file format:

{
  "id": "file-abc123",
  "object": "file",
  "purpose": "fine-tune",
  "filename": "training_data.jsonl",
  "bytes": 12345,
  "created_at": 1677858242,
  "status": "processed"
}

5. Mastering Prompt Engineering

5.1 Understanding Prompts

A prompt is the input provided by the user or developer to obtain a specific response from the LLM.

Poor prompt  : "Write about technology"
Effective prompt: "Write an engaging blog post about the impact of artificial
                   intelligence on everyday life, highlighting both its
                   benefits and potential concerns."

Why prompt engineering matters:

  • Precise prompts = better responses
  • The LLM generates by predicting word by word — context is critical
  • The prompt “programs” the model’s behavior

5.2 Anatomy of an Effective Prompt

graph TD
    P["Effective Prompt"] --> C["Clarity
    Unambiguous message"]
    P --> S["Specificity
    Well-defined request"]
    P --> CTX["Context
    Background information"]
    P --> F["Desired Format
    JSON, list, paragraph..."]
    P --> L["Length
    Tweet < 280 chars, long article..."]
    P --> E["Examples / Hints
    Guides the model"]

    style P fill:#f59e0b,color:#fff
    style C fill:#dbeafe
    style S fill:#dcfce7
    style CTX fill:#fef3c7
    style F fill:#fce7f3
    style L fill:#ede9fe
    style E fill:#fee2e2

Components:

ComponentDescriptionExample
ClarityUnambiguous message”Provide statistics on AI unemployment impact in the last 5 years”
SpecificityWell-defined request”List the top 5 countries with highest R&D investment in AI”
ContextBackground information”Discuss pros and cons of AI in autonomous vehicles considering ethical aspects”
FormatJSON, list, paragraph”Respond in JSON format with keys: primary, secondary”
LengthDesired limit or detail”Write a tweet (less than 280 characters)“
ExamplesGuide the modelProvide input/output examples

5.3 Tokenization

Tokenization is the splitting of text into units called tokens.

General rule: 1 token ≈ 4 characters ≈ 0.75 word
# Online tokenizer: platform.openai.com/tokenizer
# Example: "The quick brown fox jumps over the lazy dog"
# → 9 tokens, 43 characters

# Use tiktoken in Python:
# pip install tiktoken
import tiktoken

encoding = tiktoken.encoding_for_model("gpt-3.5-turbo")
tokens = encoding.encode("The quick brown fox jumps over the lazy dog")
print(f"Token count: {len(tokens)}")

Why tokenization matters:

  • Billing is based on tokens
  • Each model has a context limit (context window) in tokens
  • Some complex words split into multiple tokens
"ChatGPT"   → ["Chat", "G", "PT"]     → 3 tokens
"the"       → ["the"]                  → 1 token
"hamburger" → ["ham", "burger"]        → 2 tokens

5.4 The OpenAI Playground

The Playground (platform.openai.com/playground) is a web tool for testing prompts without coding.

Features:

  • Test different models and parameters
  • Configure SYSTEM, USER, ASSISTANT messages
  • Save presets
  • View generated code

Playground examples:

Example 1 — Simple prompt:

USER: I want to go hiking
→ Helpful response about hiking

Example 2 — With SYSTEM message:

SYSTEM: You are an angry partner
USER: I want to go hiking
→ "Fine, go. Just remember that we had plans today..."

Example 3 — Coach:

SYSTEM: You are a great coach
USER: I want to go hiking
→ Encouraging and motivating response

The effect of temperature:

temperature = 0   → Deterministic, repeatable responses
temperature = 0.7 → Good balance (recommended for most cases)
temperature = 2   → Very creative, sometimes incoherent

5.5 Six Prompt Engineering Best Practices

Practice 1: Write Clear Instructions

Include details in the request:

# Playground — System message for context
SYSTEM: "Respond only in the context of machine learning, 
         artificial intelligence and GPTs."
USER: "What is an LLM?"

Use delimiters:

prompt = """
Get keywords from text delimited by triple quotes.

\"\"\"
Large language models, such as OpenAI's GPT-3, play a crucial role...
\"\"\"
"""

Specify steps:

system_message = """
Use the following step-by-step instructions:

Step 1 - Get the keywords from the text in triple quotes with prefix "Keywords: ".
Step 2 - Translate the keywords from Step 1 into Spanish and French 
         with prefix "Translation: ".
"""

Adopt a persona:

system_message = """
Your response will be a text overflowing with euphoric comments,
each paragraph resonating with intense and vivid human emotions.
"""
prompt = "Write a thank you message to my neighbor for helping with my car. Max two paragraphs."

Practice 2: Provide a Reference Text

system_message = """
Utilize the articles enclosed within triple quotes to generate answers.
If the answer cannot be found within the provided articles, 
respond: "I could not find an answer."
"""
prompt = """
What am I?
\"\"\"
[Your reference text here]
\"\"\"
"""

Use case: Q&A on specific documents (contracts, manuals, etc.)

Practice 3: Break Down Complex Tasks

Intent Classification:

system_message = """
You will be presented with customer service inquiries. 
Categorize each query into a primary and secondary category.
Format output in JSON with keys: primary and secondary.

Primary Categories: Reservations, Room Assistance, Billing and Payments, General Inquiries

Secondary Categories:
Reservations: Room Booking, Reservation Changes, Group Reservations, Cancellations and Refunds
Room Assistance: Room Service Requests, Maintenance and Repairs, Lost and Found, Special Accommodations
Billing and Payments: Invoice Clarifications, Payment Methods, Disputes and Refunds, Discounts and Promotions
General Inquiries: Hotel Amenities, Local Attractions, Policies and Regulations, Feedback and Suggestions
"""

# Example results:
# "I want my money back"  → {"primary": "Billing and Payments", "secondary": "Disputes and Refunds"}
# "The room is dirty"     → {"primary": "Room Assistance", "secondary": "Maintenance and Repairs"}

Practice 4: Give GPT Time to “Think”

Force the model to show its reasoning before giving an answer:

system_message = """
To address user queries, follow these steps:

Step 1: Formulate your own solution to the problem independently. 
        Enclose all your work in triple quotes \"\"\".

Step 2: Compare your solution with the student's solution and evaluate correctness.
        Enclose all your work in triple quotes \"\"\".

Step 3: If the student's solution contains errors, determine a hint.
        Enclose all your work in triple quotes \"\"\".

Step 4: If the student's solution is incorrect, provide the hint 
        (outside of triple quotes) prefaced with "Hint:".
"""

Example problem:

A renovation project:
- Flooring: $20/square foot
- Labor: $50/hour
- Fixed costs: $1000 (permits) + $500 (equipment)
Total: 20x + 50y + 1500 (where x = square feet, y = hours)

Practice 5: Use External Tools

GPT is not a universal solution. For certain tasks:

graph LR
    Prompt --> Decision{What is the
    best
    approach?}
    Decision -->|Natural language| GPT["🤖 GPT
    Text understanding
    Response generation"]
    Decision -->|Precise calculations| Code["💻 Code engine
    Python, SQL, etc."]
    Decision -->|Recent documents| RAG["📚 Retrieval system
    RAG / Vector DB"]

    style GPT fill:#dcfce7
    style Code fill:#dbeafe
    style RAG fill:#fef3c7

Practice 6: Test Changes Systematically

Principle: "You can only improve what you measure"

Recommended approach:
1. Define a representative set of tests (eval)
2. Measure baseline performance
3. Modify the prompt
4. Re-measure on the complete test set
5. Keep the modification only if net positive impact

6. Practical Applications of the OpenAI API

Common workflow for all applications:

graph LR
    A["1. Prepare
    the text"] --> B["2. Use
    the OpenAI API"] --> C["3. Review and
    refine"]
    
    style A fill:#dbeafe
    style B fill:#dcfce7
    style C fill:#fef3c7

Base function reused in all examples:

import openai
import os

key_location = 'path/to/api_key.txt'
with open(key_location, 'r') as file:
    api_key = file.readline().strip()

openai.api_key = api_key

def make_openai_request(prompt):
    """Call to the OpenAI chat completions API"""
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.7
    )
    return response["choices"][0]["message"]["content"].split("\n")

6.1 Summarization

Types of summarization:

TypeDescription
ExtractiveSelects existing sentences from the original text
AbstractiveGenerates new sentences condensing the meaning (GPT method)
import openai
import os

# [setup openai.api_key as above]

input_text = """
Electric vehicles (EVs) have long been hailed as the future of transportation...
[Long text on electric vehicles and quantum batteries]
"""

prompt = f"""
You will be provided with an input text delimited by ### and your task will be 
to summarize it into a set of bullet points stored in a JSON file.

Input text: 
###
{input_text}
###
"""

summary = make_openai_request(prompt)
print("Generated summary:\n", summary)

# Length comparison
print("Original text length:", len(input_text))
print("Summary length:", len(summary[0]))

6.2 Text Classification

import openai
import os

# [setup openai.api_key]

# List of customer messages
feedback_messages = [
    "I absolutely love the product! It's even better than I hoped for.",
    "The shipping took longer than expected, but the product arrived in perfect condition.",
    "I'm really pleased with my purchase. It's high-quality and exactly what I wanted.",
    "I had a horrible experience. The item I received looks nothing like the description.",
    "The customer support team went above and beyond to help me with my problem.",
    "I'm extremely disappointed. The product doesn't match what was advertised.",
]

# Prepare classification prompt
prompt = """
Classify the following customer feedback into positive, neutral, or negative sentiment:

"""
for message in feedback_messages:
    prompt += f"- {message}\n"

# Extract classifications
classifications = make_openai_request(prompt)
for i, classification in enumerate(classifications):
    print(f"{i + 1}: {classification}")

Expected output:

1: Positive - I absolutely love the product!
2: Neutral - The shipping took longer...
3: Positive - I'm really pleased...
4: Negative - I had a horrible experience...

6.3 Sentiment Analysis

import openai
import os

# [setup openai.api_key]

def make_openai_request(prompt):
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[{"role": "user", "content": prompt}],
        temperature=0,
        max_tokens=256
    )
    return response["choices"][0]["message"]["content"].split("\n")

# Social media posts
posts = [
    "I'm overjoyed! I just received the best news of my life.",
    "I can't believe how angry I am right now. This situation is infuriating.",
    "Feeling really sad today. I miss my old friends a lot.",
    "I'm pleasantly surprised by the unexpected gift I received today!",
    "I'm so happy for my friend who just got engaged!",
    "This terrible customer service experience is making me furious!",
]

prompt = """
Analyze the sentiment of the following customer posts and provide 
a base sentiment label (happy, angry, sad, surprised, etc.)\n
"""
for post in posts:
    prompt += f'- "{post}"\n'

sentiments = make_openai_request(prompt)
for sentiment in sentiments:
    print(sentiment)

Sentiment analysis applications:

  • Social media monitoring
  • Product/service reviews
  • Market research
  • Customer support
  • Political analysis
  • Brand management

6.4 Named Entity Recognition (NER)

import openai
import os

# [setup openai.api_key]

input_text = """
Ada Lovelace was a pioneering mathematician and writer. She is often regarded 
as the first computer programmer. She worked with Charles Babbage in London, England.
"""

prompt = f"""
Perform named entity recognition on the following text:\n {input_text}
"""

print(make_openai_request(prompt))
# → Person: Ada Lovelace, Charles Babbage
# → Location: London, England
# → Role: mathematician, programmer

Types of entities recognized:

PERSON       → Names of individuals (Ada Lovelace)
ORGANIZATION → Companies, institutions (OpenAI, MIT)
LOCATION     → Places, countries, cities (London, England)
DATE         → Dates and temporal expressions (October 2013)
EVENT        → Events (Author Summit, Eurovision)

6.5 Keyword Extraction

import openai
import os

# [setup openai.api_key]

input_text = """
A few years ago everyone was talking about Big Data. Then the "Cloud" came 
and revolutionized how we work. Next, IOT was a thing. Then Artificial Intelligence, 
Machine Learning, and Deep Learning came. Now it is all about Large Language Models.
"""

prompt = f"""
Extract keywords from the following text:\n {input_text}
"""

keywords = make_openai_request(prompt)
print(keywords)
# → Big Data, Cloud, IOT, Artificial Intelligence, Machine Learning, 
#   Deep Learning, Large Language Models

Use cases:

  • Content organization
  • Search engine optimization (SEO)
  • Topic analysis
  • Document indexing

6.6 Language Translation

import openai
import os

# [setup openai.api_key]

input_text = """
The software engineer worked diligently to meet the project deadline,
because the client was counting on a timely delivery.
"""

# Translation English → German
prompt = "Translate the following text from English to German:\n" + input_text
translation = make_openai_request(prompt)
print(translation)

# Translation English → Spanish
prompt = "Translate the following text from English to Spanish:\n" + input_text
translation = make_openai_request(prompt)
print(translation)

6.7 Text Parsing

import openai
import os

# [setup openai.api_key]

input_text = """
The software engineer worked diligently to meet the project deadline,
because the client was counting on a timely delivery.
"""

prompt = "Parse the grammatical components of the following sentence:\n" + input_text
print(make_openai_request(prompt))
# → Subject: The software engineer
# → Verb: worked
# → Adverb: diligently
# → Infinitive phrase: to meet the project deadline
# → Subordinate clause: because the client was counting on a timely delivery

6.8 Paraphrasing

import openai
import os

# [setup openai.api_key]

input_text = """
The software engineer worked diligently to meet the project deadline,
because the client was counting on a timely delivery.
"""

# Standard paraphrase
prompt = "Paraphrase the following sentence while maintaining its core meaning:\n" + input_text
paraphrase = make_openai_request(prompt)
print(paraphrase)
# → "The developer put in maximum effort to deliver the project on time,
#    as the client depended on the scheduled completion."

# Creative paraphrase in pirate language!
prompt = "Paraphrase the following sentence using pirate language while maintaining its core meaning:\n" + input_text
pirate_paraphrase = make_openai_request(prompt)
print(pirate_paraphrase)
# → "The software buccaneer toiled with great vigor to meet the ship's deadline,
#    for the client be countin' on a timely delivery, arrr!"

7. Training Your Own Chatbot

7.1 Building a Basic Chatbot

Basic chatbot architecture:

graph TB
    User["👤 User"] -->|"Enters a prompt"| Chatbot
    Chatbot["🤖 Chatbot Loop"] -->|"API call"| OpenAI["OpenAI API
    gpt-3.5-turbo"]
    OpenAI -->|"Response"| Chatbot
    Chatbot -->|"Displays response"| User
    Chatbot -->|"bye/exit/quit"| End["End"]

    style Chatbot fill:#dcfce7
    style OpenAI fill:#dbeafe
import openai
import os

key_location = 'path/to/api_key.txt'
with open(key_location, 'r') as file:
    api_key = file.readline().strip()

openai.api_key = api_key

def process_chat_request(prompt):
    """Sends a prompt to the API and returns the response"""
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.7
    )
    return response["choices"][0]["message"]["content"]

print("Hello and welcome to the Assistant Chatbot! How can I help you?")

while True:
    print("User: ")
    user_prompt = input()
    response = process_chat_request(user_prompt)
    print("Chatbot: " + response)
    
    if user_prompt.lower() in ["bye", "exit", "quit"]:
        break

⚠️ Limitation: This chatbot is stateless — each call is independent. It does not remember previous context.

7.2 Chatbot with Conversation History

To maintain context, accumulate the message history:

import openai
import os
import json

key_location = 'path/to/api_key.txt'
with open(key_location, 'r') as file:
    api_key = file.readline().strip()

openai.api_key = api_key

# Conversation history (accumulated)
chat_messages = []

def process_chat_request(prompt):
    """Sends the prompt with the full conversation history"""
    chat_messages.append({"role": "user", "content": prompt})
    
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=chat_messages,   # ← Send the FULL history
        temperature=0.7
    )
    
    # Add the response to history
    chat_messages.append({
        "role": "assistant",
        "content": response["choices"][0]["message"]["content"]
    })
    
    return response["choices"][0]["message"]["content"]

# System message to customize behavior
system_message = "You are a helpful assistant that speaks like a pirate"
chat_messages = [{"role": "system", "content": system_message}]

print("Hello and welcome to the Assistant Chatbot! How can I help you?")

while True:
    print("------------------------\nUser: ")
    user_prompt = input()
    response = process_chat_request(user_prompt)
    print("Chatbot: " + response)
    
    if user_prompt.lower() in ["bye", "exit", "quit"]:
        break

Comparison: Stateless vs Stateful:

Stateless (chatbot.py)
  Turn 1: "My name is Alex"     → "Nice to meet you!"
  Turn 2: "What's my name?"     → "I don't know your name."

Stateful (chatbot-conversation.py)
  Turn 1: "My name is Alex"     → "Nice to meet you!"
  Turn 2: "What's my name?"     → "Your name is Alex!"

Conversation history structure:

[
  {"role": "system", "content": "You are a helpful assistant that speaks like a pirate"},
  {"role": "user", "content": "My name is Alex"},
  {"role": "assistant", "content": "Ahoy, Alex! Welcome aboard, matey!"},
  {"role": "user", "content": "What's my name?"},
  {"role": "assistant", "content": "Arrr, yer name be Alex, matey!"}
]

7.3 Fine-tuning a Model

Fine-tuning adapts a pre-trained model to a specific domain or task.

graph LR
    Base["Base model
    GPT-3.5 (generalist)"] -->|"Fine-tuning with
    specific data"| Fine["Fine-tuned model
    Specialized in
    your domain"]

    style Base fill:#fef3c7
    style Fine fill:#dcfce7

Fine-tuning advantages:

AdvantageDescription
QualityBetter results than with prompt engineering alone
CapacityTrain on more examples than fit in a prompt
CostShorter prompts → fewer tokens → savings
SpecializationExpert in a domain (medical, legal, your company)
SafetyGuided toward safer, more aligned responses

Training data format (JSONL):

{"messages": [
  {"role": "system", "content": "Aria is a travel advisor chatbot."},
  {"role": "user", "content": "Where should I travel in 2024?"},
  {"role": "assistant", "content": "Here are some fantastic destinations: Japan, Portugal, New Zealand..."}
]}
{"messages": [
  {"role": "system", "content": "Aria is a travel advisor chatbot."},
  {"role": "user", "content": "Tell me about the attractions in Portugal."},
  {"role": "assistant", "content": "Portugal offers historic Lisbon, beautiful Algarve beaches, and the Douro Valley..."}
]}

Complete fine-tuning code:

import os
import openai
import requests

key_location = 'path/to/api_key.txt'
with open(key_location, 'r') as file:
    api_key = file.readline().strip()

openai.api_key = api_key

def upload_file(file: str):
    """Uploads a JSONL file for fine-tuning"""
    url = "https://api.openai.com/v1/files"
    headers = {'Authorization': f'Bearer {api_key}'}
    data = {"purpose": "fine-tune"}
    files = {"file": open(file, "rb")}
    response = requests.post(url, headers=headers, data=data, files=files, timeout=20)
    if response.status_code == 200:
        return response.json()
    print('Error:', response.status_code)
    return None

def fine_tuning_model(file_id: str):
    """Launches a fine-tuning job"""
    url = "https://api.openai.com/v1/fine_tuning/jobs"
    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {api_key}'
    }
    data = {
        "training_file": file_id,
        "model": "gpt-3.5-turbo"
    }
    response = requests.post(url, headers=headers, json=data, timeout=20)
    if response.status_code == 200:
        return response.json()
    return None

def retrieve_fine_tuning(fine_tune_id: str):
    """Checks the status of a fine-tuning job"""
    url = f"https://api.openai.com/v1/fine_tuning/jobs/{fine_tune_id}"
    headers = {'Authorization': f'Bearer {api_key}'}
    response = requests.get(url, headers=headers, timeout=20)
    if response.status_code == 200:
        return response.json()
    return None

# Step 1: Upload training data
upload_result = upload_file("./training_data.jsonl")
uploaded_file_id = upload_result["id"]

# Step 2: Launch fine-tuning
fine_tune_result = fine_tuning_model(uploaded_file_id)
fine_tune_job_id = fine_tune_result["id"]

# Step 3: Wait for job completion
fine_tuned_model = ""
while True:
    job = retrieve_fine_tuning(fine_tune_job_id)
    if job["status"] == "succeeded":
        fine_tuned_model = job["fine_tuned_model"]
        break
    # Wait a few minutes between checks...

# Step 4: Use the fine-tuned model
completion_response = openai.ChatCompletion.create(
    model=fine_tuned_model,   # ← Use the fine-tuned model
    messages=[
        {"role": "system", "content": "Aria is a travel advisor chatbot."},
        {"role": "user", "content": "Where should I travel in 2024?"}
    ]
)
print(completion_response)

Complete fine-tuning process:

sequenceDiagram
    participant Dev as Developer
    participant API as OpenAI API
    participant Email as Email

    Dev->>API: POST /v1/files (training_data.jsonl)
    API-->>Dev: file_id

    Dev->>API: POST /v1/fine_tuning/jobs (file_id, model)
    API-->>Dev: fine_tune_job_id

    loop Check status
        Dev->>API: GET /v1/fine_tuning/jobs/{id}
        API-->>Dev: status: "running"
    end

    API->>Email: "Fine-tuning completed!"
    API-->>Dev: status: "succeeded", fine_tuned_model: "ft:gpt-3.5-turbo:..."

    Dev->>API: POST /v1/chat/completions (model=fine_tuned_model)
    API-->>Dev: Specialized response

8. The Future of OpenAI and NLP

Ethical Considerations

mindmap
  root((Generative AI
  Ethics))
    Bias
      Training data bias
      Potential discrimination
      Stereotypes
    Privacy
      Sensitive data
      Consent
    Misinformation
      Fake news
      Deepfakes
      Fabricated content
    Moderation
      Inappropriate content
      Necessary filtering
    Intellectual Property
      AI-generated content
      Copyright
    Consent
      Use of likeness
      Voice and images of individuals

Open Challenges in NLP

ChallengeDescription
Deep understandingDeciphering intent, emotions, hidden meanings
Bias and fairnessContinuous detection and mitigation
Linguistic diversityAll languages + cultural nuances
Language evolutionTrends, slang, neologisms
PersonalizationAdapting responses to each individual
Real-timeInteractions with minimal latency

The Future of NLP — Vision

Healthcare    → Analyze medical literature in real time
               Aid in precise diagnosis

Education     → Personalized learning
               Content adapted to each student

Entertainment → Immersive narratives
               Tailored experiences

Summary — What You Can Do Now

# Everything you know how to do with the OpenAI API:

from openai import OpenAI
client = OpenAI(api_key="your_api_key")

# 1. Chat Completions
client.chat.completions.create(model="gpt-3.5-turbo", messages=[...])

# 2. Image generation
client.images.generate(prompt="...", n=1, size="1024x1024")

# 3. Image editing
client.images.edit(image=..., mask=..., prompt="...")

# 4. Image variations
client.images.create_variation(image=..., n=1)

# 5. Embeddings
client.embeddings.create(input="...", model="text-embedding-ada-002")

# 6. Audio transcription (Whisper)
client.audio.transcriptions.create(model="whisper-1", file=...)

# 7. Audio translation
client.audio.translations.create(model="whisper-1", file=...)

# 8. Moderation
client.moderations.create(input="...")

Search Terms

developing · generative · ai · applications · python · openai · llm · application · development · artificial · intelligence · models · api · gpt · challenges · chatbot · image · llms · model · nlp · prompt · text · advantages · anatomy

Interested in this course?

Contact us to book it or get a custom training plan for your team.