Bouw je eigen AI-tools met de OpenAI API

Bouw je eigen AI-tools met de OpenAI API

16 mei 2024
Erwin Matijsen
Geplaatst in Tutorial


Je hebt vast al eens gewerkt met ChatGPT van OpenAI of één van de andere varianten, Gemini van Google of Claude van Anthropic bijvoorbeeld. Zulke diensten zijn leuk en kunnen al veel voor je doen, maar interessanter wordt het als je je eigen tools kunt bouwen met AI.

In deze tutorial leer je daarom werken met de OpenAI API. Een API is een manier om vanuit je eigen programma te communiceren met een ander programma, vaak via het internet. Je kunt op deze manier de AI-modellen van OpenAI gebruiken zonder naar hun website te gaan.

Het project

In dit project maak je een script dat jou toetst over een bepaald onderwerp. Je geeft een Wikipedia-URL op en met behulp van AI maak je hier automatisch een samenvatting van én maak je drie vragen waarmee je kennis over het gegeven onderwerp kunt toetsen. Uiteraard krijg je ook de correcte antwoorden!

Let op: Account nodig

Let op: om te kunnen werken met de API van OpenAI heb je een account nodig. In tegenstelling tot ChatGPT is het gebruik van de API niet gratis, je betaalt naar gebruik. Zie deze pagina voor meer informatie over de kosten. Het kost je niet veel, zeker niet bij kleinere projecten zoals deze. Bovendien kun je een bovengrens instellen, zodat je nooit tegen onverwachte kosten aanloopt.

Maak nu eerst een account als je die nog niet hebt. Nadat je alles hebt ingesteld, kun je een apart project in de OpenAI Dashboard aanmaken. Klik eerst linksbovenin op je (organisatie)naam en vervolgens op "Create project". Maak een nieuw project aan met de naam "WikiTest".

Vervolgens maak je een API-key aan voor het project. Ga naar de API keys pagina en klik op "Create new secret key". Geef het een naam, kies het zojuist aangemaakte project en klik op "Create secret key". LET OP: kopieer de API-key direct en sla het op een veilige plek op, je krijgt het niet nogmaals te zien.

Als je een account en een API-key hebt aangemaakt, maak je een nieuw Python project aan en installeer je de drie externe packages die je gaat gebruiken: openai, wikipedia-api en python-dotenv. De openai package is de client om met de API van OpenAI te communiceren. De wikipedia-api package is een handig hulpmiddel om pagina's van Wikipedia op basis van een titel op te halen en de tekst in te lezen. Het is een client om te communiceren met de Wikipedia API. De python-dotenv package tot slot is een hulpmiddel om op een veilige manier je API-key in te kunnen lezen, waarover later meer.

shell
cd projects
mkdir wikitest && cd wikitest
python -m venv .venv
source .venv/bin/activate  # .venv\Scripts\activate.bat voor Windows
python -m pip install openai wikipedia-api python-dotenv
python -m pip freeze > requirements.txt

Je kunt de code van dit project ook op Github bekijken.

API-key

Je API-key is persoonlijk, als deze in de verkeerde handen valt kan iemand het gebruiken en draai jij voor de kosten op. Het is daarom belangrijk om deze geheim te houden. Hier zijn verschillende manieren voor. In dit project gebruik je python-dotenv. Je maakt een .env bestand in je project aan, waarin je de API-key noteert.

.env
OPENAI_API_KEY=sk-proj-123abc

Noem je API-key OPENAI_API_KEY en de openai client zal het automatisch inlezen. Zie ook de documentatie van OpenAI.

Maak ook een .gitignore-bestand aan, waarin je aangeeft dat het .env bestand niet in je repository opgenomen mag worden.

.gitignore
.env
.venv
*.pyc
__pycache__

Ook al gebruik je nu (nog) geen Git, het is toch verstandig alvast wel een .gitignore aan te maken. Ben je wel zover om versiebeheer te gaan doen met Git en je pusht je code naar bijvoorbeeld Github, dan zal je API-key niet per ongeluk meegestuurd worden.

Wikipedia pagina inlezen

Om een samenvatting van en toetsvragen over een Wikipedia-pagina te maken, moet je de pagina wel kunnen laten lezen door het AI-model. Er zijn hiervoor verschillende manieren, maar om het zo platform-onafhankelijk te houden, lees je eerst de pagina zelf in als platte tekst. Deze tekst kun je dan weer naar het model sturen.

Wikipedia heeft gelukkig een API zodat de pagina eenvoudig programmatisch is in te lezen. En met de package wikipedia-api wordt dit proces nog eenvoudiger.

Maak in je project een bestand wiki.py aan en plaats hierin de volgende code.

wiki.py
import wikipediaapi

USER_AGENT = "WikiTest (info@python-cursus.nl)"
LANGUAGE = "nl"


def read_wiki(titel):
    """Lees een Wikipedia-artikel in."""

    # Initialiseer de Wikipedia client
    wiki = wikipediaapi.Wikipedia(
        user_agent=USER_AGENT,
        language=LANGUAGE,
        extract_format=wikipediaapi.ExtractFormat.WIKI
    )

    # Haal de pagina op, op basis van titel
    page = wiki.page(titel)

    # Controleer of de pagina bestaat
    if not page.exists():
        raise ValueError("Pagina bestaat niet")

    # Geef de tekst terug
    return page.text

Met deze functie kun je een Wikipedia-pagina inlezen op basis van een op te geven titel. Zorg ervoor dat je de USER_AGENT aanpast naar je eigen gegevens.

Zie de documentatie van Wikipedia API voor meer over het gebruik van de package.

Samenvatting en toets maken

Nu je een Wikipedia-pagina in kunt lezen, is de volgende stap het maken van een samenvatting en toetsvragen over de tekst. Hiervoor gebruik je een AI-model, in dit voorbeeld via de API van OpenAI. In de kern is het werken met de API van OpenAI eenvoudig. De aanroep ziet er als volgt uit:

openai
client = OpenAI()
response = client.chat.completions.create(
    model=MODEL,  # Bijvoorbeeld 'gpt-4o'
    response_format={"type": "json_object"},
    messages=[system_message, user_message]
)

Je roept de completions-endpoint aan, met het gekozen model, de bericht(en) die je wilt sturen en optioneel een formaat waarin het antwoord teruggegeven moet worden.

Er zijn nog meer opties beschikbaar, maar voor nu volstaat dit. Zie de documentatie voor meer informatie.

De berichten (messages) bestaan uit een lijst met één of meer berichten. Een bericht bestaat uit een dict met de sleutels role en content. De rollen zijn onder ander system, user en assistant. De berichten zijn de berichten die je ook in ChatGPT zou zien, dus jouw berichten en de reactie van het model (assistant). Het verschil hier is dat je ook de reactie van het model op kunt sturen. Dit kan nodig zijn als je een applicatie maakt waarbij je de geschiedenis van het gesprek wilt behouden.

De messages voor dit project kun je als volgt opstellen:

messages
    # Bereid de instructies voor
    # Zorg ervoor dat het model JSON teruggeeft
    system_message = {
        "role": "system",
        "content": """
            Je bent een assistent die Wikipediapagina's samenvat en vragen bedenkt voor
            studenten om hun kennis te toetsen. Je reageert altijd in JSON.
            """
    }

    # Zorg ook voor een voorbeeld van hoe de JSON eruit moet zien.
    # Er zijn geen garanties dat het model zich hier aan houdt, maar
    # in de praktijk gaat het 99% van de tijd wel goed.
    user_prompt = """
        Lees de tekst die hierna volgt\n.
        Maak een samenvatting van de tekst in maximaal drie zinnen\n.
        Maak drie meerkeuzevragen met opties A, B en C over het onderwerp.
        Er kan steeds 1 antwoord goed zijn\n.
        Geef van elke vraag aan wat het goede antwoord is (A, B of C)\n.
        Gebruik het volgende JSON-schema: \n\n

        {
            "samenvatting": "De samenvatting",
            "vragen: [
                {
                    "vraag": "De eerste vraag",
                    "opties: ["A: Optie A", "B: Optie B", "C: Optie C"],
                    "antwoord": A
                },
                {
                    "vraag": "De tweede vraag",
                    "opties: ["A: Optie A", "B: Optie B", "C: Optie C"],
                    "antwoord": B
                },
            ]
        }

        De tekst is als volgt:\n\n
        """

    user_message = {
        "role": "user",
        "content": user_prompt + text
    }

Hierbij is text op het de een-na-laatste regel de ingelezen Wikipediapagina.

Het is erg belangrijk om in je prompt aan te geven dat je JSON als output wilt, ook al heb je dit eerder al aangegeven bij het aanroepen van de API. In dit geval is dat in de system prompt gedaan. Zie de JSON mode documentatie voor meer toelichting hierop.

Het is ook belangrijk om een voorbeeld te geven van de gewenste JSON-structuur. Zo weet het model beter wat het terug moet geven. Doe je dit niet, dan is de kans groter dat bijvoorbeeld de sleutels ("vraag", "opties", "antwoord", etc.) soms een andere naam krijgen (bijvoorbeeld "antwoordopties" in plaats van "opties"). Omdat je later met de sleutels wilt werken, wil je wel dat dit consistent is.

Werken met Large Language Models blijft fundamenteel onzeker. Door het opgeven van voorbeelden haal je veel van de onzekerheid weg, maar het is niet gegarandeerd dat de gewenste JSON-structuur elke keer wordt teruggegeven. Houd hier rekening mee in de rest van je code.

Plaats bovenstaande nu in een functie create_text, in een bestand toets.py.

toets.py
def create_test(text):
    """
    Gebruik OpenAI om de opgegeven tekst samen te vatten en er een toets over te maken.
    """
    client = OpenAI()

    # Bereid de instructies voor
    # Zorg ervoor dat het model JSON teruggeeft
    # ...

    # Haal de response op
    # ...

    return response.choices[0].message.content

Bekijk de complete code op Github

De toets afnemen

Je hebt nu de code om een Wikpedia-pagina in te lezen en de code om hiervan met behulp van AI een samenvatting en een toets van te maken. De laatste stap is het daadwerkelijk afnemen van de toets. Voor dit voorbeeld kun je het eenvoudig houden door de input-functie te gebruiken. Uiteraard zou je het uitgebreider kunnen maken door er bijvoorbeeld een webapplicatie van te maken.

Maak hiervoor een functie take_test in het bestand toets.py. In vereenvoudigde vorm ziet het eerste deel van deze functie er als volgt uit:

toets.py
def take_test():
    print("Geef de titel op (haal dit uit de url, na '/wiki/'")
    titel = input("Titel: ")

    # Lees de Wikipedia-pagina in
    text = read_wiki(titel=titel)

    # Maak de samenvatting en toets
    result = create_test(text=text)

    # Zet om van JSON naar dict
    result_json = json.loads(result)
    samenvatting = result_json.get("samenvatting")
    vragen = result_json.get("vragen")

In een volledige versie gebruik je try/except-blokken om eventuele fouten af te handelen.

Het laatste deel van de functie:

toets.py
def take_test():
    # ...

    # Toon samenvatting
    print("\nSAMENVATTING")
    print(samenvatting)

    # Begin de toets. Elke vraag bestaat uit een `dict` met vraag,
    # opties en correct antwoord.
    print("TOETS")
    for vraag in vragen:
        print(f"Vraag: {vraag['vraag']}\n")
        for optie in vraag["opties"]:
            print(optie)

        user_antwoord = input("Wat is je antwoord (A, B of C)? ")
        if user_antwoord.upper() == vraag["antwoord"]:
            print("Goed!\n")
        else:
            print(f"Helaas, het goede antwoord is {vraag['antwoord']}\n")

Toon eerst de samenvatting. Vervolgens itereer je over alle vragen en de antwoordopties en controleer je of de gebruiker hetzelfde antwoord geeft als het goede antwoord.

Bekijk de complete code op Github

Nu rest alleen nog de code aan te roepen in main.py:

main.py
from dotenv import load_dotenv
from toets import take_test

if __name__ == '__main__':
    load_dotenv()
    take_test()

Gebruik load_dotenv() om je .env bestand met je API-sleutel van OpenAI in te lezen. Vervolgens roep je take_test() aan en ben je klaar om je code uit te proberen!

shell
python main.py

Over welke Wikipediapagina wil je een toets maken?
Geef de titel op (haal dit uit de url, na '/wiki/'
Titel: Guido_van_Rossum

SAMENVATTING
Guido van Rossum is een Nederlandse informaticus, bekend als de ontwerper van de programmeertaal Python. Hij ontving in 1999 de Dr. Dobb's
Journal Excellence in Programming Award en diverse andere accolades voor zijn bijdragen aan de softwareontwikkeling.
Van Rossum woonde in Nederland en sinds 1995 in de VS, en werkte voor bedrijven zoals Google, Dropbox en Microsoft.

TOETS
Vraag: In welk jaar ontwierp Guido van Rossum de programmeertaal Python?

A: 1980
B: 1989
C: 1999
Wat is je antwoord (A, B of C)? b
Goed!

// etc

Conclusie

In deze tutorial heb je een eenvoudig programma gemaakt dat een Wikipedia-pagina inleest en er vervolgens met behulp van de OpenAI API een samenvatting van maakt en er een toets over maakt. Het is een eenvoudig voorbeeld om te laten zien dat je ook op andere manieren AI-modellen kunt gebruiken dan via een chat-interface.

Het voordeel is dat je hiermee bepaalde taken kunt automatiseren, dus niet steeds weer je opdrachten in een chat typen! Een ander voordeel is dat je eenvoudig je eigen input mee kunt geven, zoals documenten of inhoud uit spreadsheets. Vervolgens kun je de response weer programmatisch verwerken.

Dit voorbeeld was met OpenAI, maar bekijk ook eens de API's van andere aanbieders. Veelal hebben ze zelf ook een Python-client en is de werking vrijwel hetzelfde als die van OpenAI. Enkele voorbeelden:

De mogelijkheden zijn eindeloos. Veel succes!

Over de auteur


Erwin Matijsen

Erwin Matijsen

Erwin is de oprichter van python-cursus.nl. In allerlei rollen heeft hij Python ingezet, van het eenvoudiger maken van zijn werk tot het opleveren van complete (web)applicaties. Met vrouw en kinderen woont hij in Havelte (Drenthe), midden in de prachtige natuur. Daar wandelt hij graag, zeker ook omdat de beste ingevingen tijdens een wandeling - weg van de computer - lijken te komen.



Contact

Vragen, opmerkingen?

Heb je vragen, opmerkingen, suggesties of tips naar aanleiding van deze blog? Neem dan contact met ons op, of laat het weten via Mastodon of LinkedIN.