Große LLMs auf jedem Rechner ausführen!

Große LLMs auf jedem Rechner ausführen!

Worum geht es?

Wäre es nicht toll, wenn du jedes Open-Source Sprachmodell auf deiner Hardware ausführen könntest, egal wie groß es ist?
Die Sache ist, dass man bis jetzt sehr teure Hardware mit großem Speicher und super teure GPUs braucht. Oder man mietet sich Rechenpower irgendwo in der Cloud… auch nicht gerade günstig.

Jetzt gibt es allerdings etwas tolles, aus meiner Sicht: https://petals.ml/

Damit kannst du Modelle wie LLaMA-65B, Guanaco, BLOOM-176B oder BLOOMZ ausführen!

 

Wie funktioniert das?

Kurz: ja die gute alte Torrent-Zeit ist zurück! Nur diesmal geht es nicht um (illegal) heruntergeladene Filme, sondern um geteilte Rechenpower!

Wie bei den (Film-)Torrents, werden die benötigten Teile auf viele Rechner verteilt, d.h. Teile des Modells und vor allem die notwendige Berechnung verteilt sich auf zahlreiche Computer.

Dabei kannst du in unterschiedlichen Rollen teilnehmen: Client oder Server. Als Client nutzt du die Kapazität des Netzwerks und kannst entweder das Modell nutzen (Inference) oder Fine-Tuning betreiben. Als Server-Teilnehmer bietest du deine Rechenzeit für alle an.

Du kannst aber auch ein privates Netzwerk aufbauen, wenn du z.B. mehrere Rechner zur Verfügung hast.

Du kannst natürlich auch beide Rollen gleichzeitig einnehmen.

Die Nutzung

Wenn du das jetzt nutzen möchtest, dann brauchst du lediglich ein paar Zeilen Python-Code auszuführen. Dazu gehst du auf https://petals.ml/ und besorgst dir den Code, den du dann einfach auf deinem Rechner (oder z.B. in Google Colaboratory) ausführst. Eine genaue Anleitung findest du in dem GitHub-Repostiory des Projektes: https://github.com/bigscience-workshop/petals

 

Meine Meinung

Ich habe das Projekt gerade erst entdeckt und hatte noch nicht die Gelegenheit ausführlich damit zu spielen. Es eröffnet aber meines Erachtens einige Möglichkeiten. So kann man mit den großen Modellen erstmal experimentieren, ohne viel Geld ausgeben zu müssen.

Ob es für ein „ernsthaftes“ Projekt oder gar für kommerzielle Anwendungen ausreicht, muss sich noch zeigen. Unklar ist (für mich) noch, wie es mit dem Datenschutz aussieht. Letztendlich müssen ja schließlich deine Prompts verteilt werden, damit sie auf fremden Rechnern berechnet werden können.

Auch die Performance muss betrachtet werden, denn es macht sicherlich einen Unterschied, ob direkt verfügbare performante Hardware die Berechnungen durchführt oder ob die Daten erstmal über das Netztwerk laufen müssen.

Ausserdem hängt das Ganze davon ab, dass Leute bereitwillig ihre Rechenkapazität zur Verfügung stellen! Das wäre doch endlich mal ein vernünftiger Einsatzgrund für eine Blockchain! wink Also ein Belohnungssystem, das die gespendete Rechenzeit registriert und dir dafür, z.B. die Rechenzeit des Gesamtsystems anbietet oder Vorrang gibt.
Wenn ich ausreichend damit gespielt habe, werde ich ggfs. ein kurzes Tutorial erstellen.

ChatGPT Code Interpreter Plugin für alle verfügbar

ChatGPT Code Interpreter Plugin für alle verfügbar

Das Code Interpreter Plugin für ChatGPT wurde nun nach längerer closed beta Phase für alle ChatGPT+ Nutzer freigegeben. Dieses Plugin ist aus meiner Sicht ein Game-Changer!

Was ist das Code Interpreter Plugin?

Der Name des Plugins ist aus meiner Sicht nicht gut gewählt, denn der Name drückt nicht aus, wozu dieses Plugin in der Lage ist! Mit dem Plugin kannst du alle möglichen Arten von Dokumenten in ChatGPT hochladen und auf unterschiedliche Arten und Weisen verarbeiten oder bearbeiten lassen. Je nach dem was du verlangst, kannst du auch ein Ergebnis herunterladen, z.B. kannst du ChatGPT mit einer CSV-Datei füttern und bitten dazu eine Grafik zu erstellen, die du dann herunterladen kannst!

 

Wie funktioniert das Plugin?

Bevor ich dir ein paar Beispiele zeige, möchte ich die technischen Hintergrunde des Plugins erläutern. 

Damit das Plugin in der Lage ist, die Aufgaben auszuführen, wurde ChatGPT um die Möglichkeit erweitert, (Python) Code zu erzeugen und auszuführen. D.h. anhand deines Prompts erzeugt sich ChatGPT den notwendigen Code selbst, führt in aus, verbessert ihn, erstellt weiteren Code… usw. bis das Ergebnis zur Verfügung steht. Die Ausgaben des Codes wertet ChatGPT außerdem aus, bevor es dir die endgültige Antwort gibt.

Was das Plugin so anstellt, kann man sich netterweise anschauen, wenn man auf den Knopf „Show work“ klickt. So zum Beispiel:

 

Hier habe ich zuvor eine CSV-Datei hochgeladen, die meinen Gas-Verbrauch enthält (die gleiche Datei, die ich in dem Prompt-Tutorial verwendet habe). In diesem Beispiel nutzt ChatGPT diesen Python-Code um die Daten zu analysieren und ein Diagramm zu erstellen.

Was man hier sieht, ist eine Art Agentensystem. D.h. die Aufgabe wird in Teilaufgaben unterteilt, der notwendige Code erzeugt und die Resultate werden ausgewertet und weiter verarbeitet usw. Das sind ähnliche Ansätze wie bei AutoGPT und ähnlichen KI-Agentensystemen.

Beispiele

Es gibt fast unbegrenzte Möglichkeiten das Plugin zu nutzen. Hier zeige ich dir ein paar davon.

Also insgesamt ist das Ding in der Lage, Sachen wie Datenanalyse, Bildbearbeitung, Programmierung, Übersetzen von Code in eine andere Programmiersprache, Videobearbeitung, animierte GIFs erstellen, ….

Datenanalyse

Eines der coolsten Features ist die Datenanalyse. Dazu können wir eine Datei mit Daten hochladen, z.B. als CSV-Datei. Falls du keine Daten zur Hand hast, aber gerne damit spielen möchtest, dann gibt es z.B. bei https://www.kaggle.com/datasets/ zahlreiche Datensätze, die man herunterladen kann.

Ich habe mir einfach mal folgenden Datensatz heruntergeladen: https://www.kaggle.com/datasets/konradb/global-income-statistics. Offensichtlich enthält er Angaben zum Einkommen weltweit. Ohne wirklich den Inhalt im Detail zu kennen, kann man jetzt die Datei hochladen und um eine erste Analyse bitten:

Ok, das ist schon mal ein erster Überblick, welche Felder enthalten sind und was sie vermutlich bedeuten. Wenn wir noch nicht wissen was wir analysieren können, fragen wir doch ChatGPT! wink

Alles klar, mich interessiert hier die Hypothese 3. Also lassen wir das mal analysieren und natürlich mit Unterstützung von Grafiken!

Es folgen noch weitere Analysen usw. Hier war ich beim Erstellen des Prompts sehr faul, daher ist das Ergebnis sicher nicht optimal. Das Diagramm könnte z.B. besser skaliert sein etc. Aber es zeigt wo es hingehen kann.

Wo es noch hingehen kann z.B.: eine Powerpoint-Präsentation daraus erstellen usw.

Bildbearbeitung

Wir können auch Bilder hochladen und etwas mit diesen Bildern anstellen lassen. Hier erstmal ein Beispiel, wo ich die Person im Vordergrund freistellen möchte (ja ja, dafür gibt es natürlich Bildverarbeitung etc…. aber es geht halt sehr schnell). Also bastle ich mir schnell ein Bild… da Leonardo.ai gerade Downtime hat, habe ich mal mit firefly.adobe.com eins erstellt:

Schauen wir mal, ob ChatGPT den Mann freistellen kann…

 

 

… nun es ist daran gescheitert. Es war ein Drama in mehreren Akten. Fast menschlich hat es Probleme beim Programmieren gehabt. Inkompatible Funktionen etc… arme KI 😉

Auch wenn es nicht so gut funktioniert hat, so sieht man aber sehr gut, wie ChatGPT hier vorgeht und versucht sich zu verbessern!

Fazit

Es ist lange nicht perfekt, aber es ist ein echt wichtiges und cooles Feature, das sehr nützlich sein kann. Die Hauptstärken sehe ich bei der Datenanalyse und bei der Visualisierung. Klar kann man das auch alles ohne KI, mit den entsprechenden Tools, erreichen. Aber es geht aus meiner Sicht um die Unterstützung und die Arbeitserleichterung.

OpenAI (ChatGPT) API Tutorial – Teil #3 Funktionen (Function calling) 

OpenAI (ChatGPT) API Tutorial – Teil #3 Funktionen (Function calling) 

Einleitung

Im Teil #2 der Tutorial-Reihe habe ich dir einen Überblick über die unterschiedlichen Modelle gegeben und etwas unterhaltsamer gezeigt, wie man mit Dall-E Bilder anhand eines Prompts generieren lassen kann.

In diesem (letzten) Teil möchte ich dir ein relativ neues Feature vorstellen: Funktionsaufrufe oder function calling. Das klingt auf den ersten Blick nicht so spannend aber dahinter verbirgt sich eigentlich etwas sehr Nützliches. Eventuell kennst du schon die Plugins, die man bei der Verwendung von ChatGPT in der Bezahlversion nutzen kann. Mit den Funktionsaufrufen kannst du ähnliches auch über die API erreichen und sogar viel mehr, denn wir können unsere eigenen Funktionen einbinden.

Function calling

Ok was ist das jetzt genau? Grundsätzlich können wir bei der „Unterhaltung“ mit dem Sprachmodell eine Liste von Funktionen mitgeben. Zu jeder Funktion gibt es eine Beschreibung, wofür die Funktion gut ist. Das hilft dem Sprachmodell bei der Entscheidung, ob es notwendig oder hilfreich ist, diese Funktion zum Lösen der Aufgabe aufzurufen. Zusätzlich zu der textuellen Beschreibung müssen wir auch die Parameter der Funktion angeben. Auch hier gehört zu jedem Parameter eine textuelle Beschreibung dazu, damit das Sprachmodell weiß wozu ein Parameter dient.

Aber ruft jetzt OpenAI die Funktion auf? Nein. Es ist vielmehr so, dass das Sprachmodell uns als Antwort mitteilt, dass ein Funktionsaufruf notwendig ist, den wir dann mit unserem Programm ausführen. Die API gibt dabei an, mit welchen Parametern und Werten die Funktion aufgerufen werden soll.

Wenn die Antwort des Funktionsaufrufes vorliegt, übermitteln wir das Ergebnis an das Sprachmodell und es arbeitet also weiter mit diesen Daten und erzeugt entweder eine Antwort und wenn nötigt, fordert uns auf weitere Funktionen aufzurufen.

Ob ein Funktionsaufruf notwendig ist, entscheidet das Modell selbst. Auch wenn wir eine Reihe von Funktionen angeben, so kann das Modell entscheiden, dass ein Funktionsaufruf nicht notwendig ist. Allerdings kann man das auch beeinflussen. So kann man entweder eine bestimmte Funktion vorgeben oder man kann auch angeben, dass keine Funktion ausgeführt werden soll.

Demoanwendung

Schauen wir uns ein Beispiel an. In dem Beispiel definiere ich eine Funktion, die in der Lage ist die Feiertage in Deutschland zurückzugeben. Da das Sprachmodell auf dem Datenstand von 2021 (zum Zeitpunkt der Erstellung) ist, kann es u.U. nicht wissen, welche Feiertage aktuell sind. Gut rein hypothetisch kann es das wissen, denn Feiertage werden ja nicht ausgewürfelt und stehen lange im Voraus fest. 

Hierfür nutzen wir eine öffentliche REST-Schnittstelle, die tatsächlich von der Bundesrepublik betrieben wird. Hier übrigens eine Liste aller Schnittstellen: https://bund.dev/apis

Schauen wir uns den ersten Code-Ausschnitt an:

import openai
import json
import requests
openai.api_key = "Füge hier deinen API-Key ein"
feiertage_api_url = "https://feiertage-api.de/api/"
prompt = "Wir haben den 3.7.2023, wann ist der nächste gesetzliche Feiertag in Hessen?"
messages = [{"role": "user", "content": prompt}]
def feiertage(jahr):
print(f"Hole Feiertage für Jahr {jahr}")
print(feiertage_api_url + "?jahr=" + jahr)
return requests.get(feiertage_api_url + "?jahr=" + jahr).json()

Als erstes importieren wir eine Reihe von Bibliotheken. Die Bibliotheken json und requests benötigen wir für die Kommunikation mit der Feiertage-API.

Anschließend übergeben wir, wie wir das schon kennen, den API-Key an openai. 

Der Prompt, der uns hier interessiert , fragt nach dem nächsten Feiertag in Hessen. Theoretisch weiß das Modell nichts über Feiertage nach 2021 und das sollte dazu führen, dass ein Funktionsaufruf notwendig wird. Da das Modell auch nicht weiß, welches Datum wir aktuell haben, sind wir so nett und geben das mit an.

Zuletzt definieren wir unsere Funktion feiertage. Diese akzeptiert einen Pflichtparameter für das Jahr, in dem der Feiertag liegen soll. Das Einzige was die Funktion macht, ist den Feiertags-Endpunkt aufzurufen und das Resultat als JSON zurück zu geben.

Jetzt wo wir die Funktion fertig haben, ist es Zeit die Übergabe an das Modell vorzubereiten:

functions = [
{
"name": "feiertage",
"description": "Ermittelt die gesetzlichen Feiertage in Deutschland",
"parameters": {
"type": "object",
"properties": {
"jahr": {"type": "string", "description": "Das Jahr in dem die Feiertage liegen sollen, Beispiel '2023'"},
},
"required": ["jahr"],
},
}
]

Wir legen eine Variable functions an, die eine Liste von Funktionsdefinitionen enthält.

Das Feld „name“ enthält wenig überraschend den Namen der Funktion. In dem Feld „description“ beschreiben wir, was die Funktion leistet. Wie schon weiter oben beschrieben, dient es dazu dem Modell mitzuteilen was die Funktion leistet.

Anschließend beschreiben wir die Parameter der Funktion. Der entscheidende Teil dabei ist „properties„. Wir benennen dort die Parameter und geben an welchen Datentyp sie haben. Ganz wichtig natürlich die Beschreibung, damit das Modell weiß wozu der Parameter dient.

Die Pflichtangaben landen in der Liste „required„, hier in unserem Fall ist der Parameter „jahr“ ein Pflichtfeld.

Jetzt ist es so, dass das Modell sich einen Funktionsaufruf wünschen kann. Dabei gibt es den Namen der Funktion plus die Werte der Parameter an. Das bekommen wir mehr oder weniger in textueller Form als JSON. Damit wir die Funktion anhand dessen aufrufen können, schreiben wir uns eine Hilfsfunktion, dessen Aufgabe es ist, mithilfe der Antwort die passende Funktion inkl. Parameter aufzurufen und das Ergebnis zurück liefert. 

def execute_function_call(message):
if message["function_call"]["name"] == "feiertage":
jahr = json.loads(message["function_call"]["arguments"])["jahr"]
results = feiertage(jahr)
else:
results = f"Fehler! Es existiert keine Funktion mit dem Namen: {message['function_call']['name']}"
return results

Unserer Hilfsfunktion nimmt eine OpenAI-API-Antwort als Parameter an. Sie wirft dann einen Blick auf das Feld „function_call“ und schaut, welche Funktion gemeint ist.

Wir kennen aktuell nur eine Funktion, nämlich „feiertage“. Kommt etwas anderes zurück, so geben wir lediglich eine Fehlerantwort zurück.

Andernfalls extrahieren wir die Parameter aus der Antwort und rufen die Funktion auf und geben das Ergebnis zurück.

Jetzt sind wir soweit, dass wir die OpenAI-API aufrufen können:

response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=messages,
functions = functions
)
print(response)
ai_msg = response["choices"][0]["message"]
messages.append(ai_msg)
if ai_msg.get("function_call"):
results = execute_function_call(ai_msg)
print(results)
messages.append({"role": "user", "content": ""})
response = openai.ChatCompletion.create(model="gpt-3.5-turbo",messages=messages,functions = functions)
print(response)

Wir rufen, so wie wir das bereits kennen, die ChatCompletion API auf. Neben der Liste der Prompts und die Angabe des Modells, übergeben wir nun auch die Liste der Funktionen über den Parameter functions.

Da wir uns im Chat-Modus befinden, fügen wir die Antwort der AI in die Liste der Nachrichten ein (siehe den ersten Teil der Tutorial-Reihe, falls dir unklar ist, warum wir das so machen).

Jetzt kann es sein, dass das Modell anstelle eines menschlich lesbaren Textes nur einen Funktionsaufruf anfordert. Das prüfen wir in dem wir in der Antwort nachschauen, ob das Feld „function_call“ mit einem Wert befüllt ist. Ist das der Fall, so rufen wir unsere Hilfsfunktion execute_function_call auf, die ihrerseits unsere Feiertags-Funktion aufruft.

Das Resultat des Funktionsaufrufes fügen wir in die Liste der Prompts ein und rufen erneut die ChatCompletion API auf. Jetzt bekommt das Sprachmodell die notwendigen Daten und kann uns eine finale Antwort liefern:

{
"id": "chatcmpl-7YqFEqFINsLnzX2GJa3uYeGo6UNNO",
"object": "chat.completion",
"created": 1688538336,
"model": "gpt-3.5-turbo-0613",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"function_call": {
"name": "feiertage",
"arguments": "{\n  \"jahr\": \"2023\"\n}"
}
},
"finish_reason": "function_call"
}
],
"usage": {
"prompt_tokens": 99,
"completion_tokens": 18,
"total_tokens": 117
}
}
Hole Feiertage für Jahr 2023
https://feiertage-api.de/api/?jahr=2023
{'BW': {'Neujahrstag': {'datum': '2023-01-01', 'hinweis': ''}, 'Heilige Drei Könige': {'datum': '2023-01-06', 'hinweis': ''}, 'Gründonnerstag': {'datum': '2023-04-06', 'hinweis': 'Gemäß § 4 Abs. 3 des Feiertagsgesetzes von Baden-Württemberg[10] haben Schüler am Gründonnerstag und am Reformationstag schulfrei. In der Regel legt das Kultusministerium die Ferientermine so fest, dass diese beiden Tage in die Osterferien bzw. in die Herbstferien fallen.'}, 'Karfreitag': {'datum': '2023-04-07', 'hinweis': ''}, 'Ostermontag': {'datum': '2023-04-10', 'hinweis': ''}, 'Tag der Arbeit': {'datum': '2023-05-01', 'hinweis': ''}, 'Christi Himmelfahrt': {'datum': '2023-05-18', 'hinweis': ''}, 'Pfingstmontag': {'datum': '2023-05-29', 'hinweis': ''}, 'Fronleichnam': {'datum': '2023-06-08', 'hinweis': ''}, 'Tag der Deutschen Einheit': {'datum': '2023-10-03', 'hinweis': ''}, 'Reformationstag': {'datum': '2023-10-31', 'hinweis': 'Gemäß § 4 Abs. 3 des Feiertagsgesetzes von Baden-Württemberg[10] haben Schüler am Gründonnerstag und am Reformationstag schulfrei. In der Regel legt das Kultusministerium die Ferientermine so fest, dass diese beiden Tage in die Osterferien bzw. in die Herbstferien fallen.'}, 'Allerheiligen': {'datum': '2023-11-01', 'hinweis': ''}, '1. Weihnachtstag': {'datum': '2023-12-25', 'hinweis': ''}, '2. Weihnachtstag': {'datum': '2023-12-26', 'hinweis': ''}}, 'BY': {'Neujahrstag': {'datum': '2023-01-01', 'hinweis': ''}, 'Heilige Drei Könige': {'datum': '2023-01-06', 'hinweis': ''}, 'Karfreitag': {'datum': '2023-04-07', 'hinweis': ''}, 'Ostermontag': {'datum': '2023-04-10', 'hinweis': ''}, 'Tag der Arbeit': {'datum': '2023-05-01', 'hinweis': ''}, 'Christi Himmelfahrt': {'datum': '2023-05-18', 'hinweis': ''}, 'Pfingstmontag': {'datum': '2023-05-29', 'hinweis': ''}, 'Fronleichnam': {'datum': '2023-06-08', 'hinweis': ''}, 'Augsburger Friedensfest': {'datum': '2023-08-08', 'hinweis': 'Das Augsburger Friedensfest ist nur im Stadtgebiet Augsburg (nicht jedoch im angrenzenden Umland) gesetzlicher Feiertag (Art. 1 Abs. 2 Bayerisches Feiertagsgesetz[7]).'}, 'Mariä Himmelfahrt': {'datum': '2023-08-15', 'hinweis': 'Mariä Himmelfahrt ist in Bayern in von den derzeit 1704[8] (Zensus 2011, bis 2013: 1700) Gemeinden mit überwiegend katholischer Bevölkerung gesetzlicher Feiertag, in den restlichen 352 (Zensus 2011, bis 2013: 356) Gemeinden nicht. Gemäß Art. 1 Abs. 3 des Bayerischen Feiertagsgesetzes[7] ist es Aufgabe des Bayerischen Landesamtes für Statistik und Datenverarbeitung, festzustellen, in welchen Gemeinden Mariä Himmelfahrt gesetzlicher Feiertag ist. Die aktuelle Festlegung beruht auf dem Ergebnis der letzten in der Bundesrepublik Deutschland durchgeführten Volkszählung vom 25. Mai 1987. Gemäß Art 4. Abs. 3 des Bayerischen Feiertagsgesetzes entfällt im gesamten Bundesland zu Mariä Himmelfahrt an Schulen aller Gattungen der Unterricht. Diese Festlegung gilt ausdrücklich auch in den Teilen Bayerns, in denen dieser Tag kein gesetzlicher Feiertag ist. Eine Übersichtskarte aller Gemeinden, in denen Mariä Himmelfahrt ein Feiertag ist, kann beim Bayerischen Landesamt für Statistik und Datenverarbeitung heruntergeladen werden (Link siehe unter "Weitere Weblinks").'}, 'Tag der Deutschen Einheit': {'datum': '2023-10-03', 'hinweis': ''}, 'Allerheiligen': {'datum': '2023-11-01', 'hinweis': ''}, 'Buß- und Bettag': {'datum': '2023-11-22', 'hinweis': 'Gemäß Art. 4 Nr. 3 des Bayerischen Feiertagsgesetzes[7] entfällt im gesamten Bundesland am Buß- und Bettag an allen Schulen der Unterricht.'}, '1. Weihnachtstag': {'datum': '2023-12-25', 'hinweis': ''}, '2. Weihnachtstag': {'datum': '2023-12-26', 'hinweis': ''}}, 'BE': {'Neujahrstag': {'datum': '2023-01-01', 'hinweis': ''}, 'Frauentag': {'datum': '2023-03-08', 'hinweis': ''}, 'Karfreitag': {'datum': '2023-04-07', 'hinweis': ''}, 'Ostermontag': {'datum': '2023-04-10', 'hinweis': ''}, 'Tag der Arbeit': {'datum': '2023-05-01', 'hinweis': ''}, 'Christi Himmelfahrt': {'datum': '2023-05-18', 'hinweis': ''}, 'Pfingstmontag': {'datum': '2023-05-29', 'hinweis': ''}, 'Tag der Deutschen Einheit': {'datum': '2023-10-03', 'hinweis': ''}, '1. Weihnachtstag': {'datum': '2023-12-25', 'hinweis': ''}, '2. Weihnachtstag': {'datum': '2023-12-26', 'hinweis': ''}}, 'BB': {'Neujahrstag': {'datum': '2023-01-01', 'hinweis': ''}, 'Karfreitag': {'datum': '2023-04-07', 'hinweis': ''}, 'Ostersonntag': {'datum': '2023-04-09', 'hinweis': ''}, 'Ostermontag': {'datum': '2023-04-10', 'hinweis': ''}, 'Tag der Arbeit': {'datum': '2023-05-01', 'hinweis': ''}, 'Christi Himmelfahrt': {'datum': '2023-05-18', 'hinweis': ''}, 'Pfingstsonntag': {'datum': '2023-05-28', 'hinweis': ''}, 'Pfingstmontag': {'datum': '2023-05-29', 'hinweis': ''}, 'Tag der Deutschen Einheit': {'datum': '2023-10-03', 'hinweis': ''}, 'Reformationstag': {'datum': '2023-10-31', 'hinweis': ''}, '1. Weihnachtstag': {'datum': '2023-12-25', 'hinweis': ''}, '2. Weihnachtstag': {'datum': '2023-12-26', 'hinweis': ''}}, 'HB': {'Neujahrstag': {'datum': '2023-01-01', 'hinweis': ''}, 'Karfreitag': {'datum': '2023-04-07', 'hinweis': ''}, 'Ostermontag': {'datum': '2023-04-10', 'hinweis': ''}, 'Tag der Arbeit': {'datum': '2023-05-01', 'hinweis': ''}, 'Christi Himmelfahrt': {'datum': '2023-05-18', 'hinweis': ''}, 'Pfingstmontag': {'datum': '2023-05-29', 'hinweis': ''}, 'Tag der Deutschen Einheit': {'datum': '2023-10-03', 'hinweis': ''}, 'Reformationstag': {'datum': '2023-10-31', 'hinweis': ''}, '1. Weihnachtstag': {'datum': '2023-12-25', 'hinweis': ''}, '2. Weihnachtstag': {'datum': '2023-12-26', 'hinweis': ''}}, 'HH': {'Neujahrstag': {'datum': '2023-01-01', 'hinweis': ''}, 'Karfreitag': {'datum': '2023-04-07', 'hinweis': ''}, 'Ostermontag': {'datum': '2023-04-10', 'hinweis': ''}, 'Tag der Arbeit': {'datum': '2023-05-01', 'hinweis': ''}, 'Christi Himmelfahrt': {'datum': '2023-05-18', 'hinweis': ''}, 'Pfingstmontag': {'datum': '2023-05-29', 'hinweis': ''}, 'Tag der Deutschen Einheit': {'datum': '2023-10-03', 'hinweis': ''}, 'Reformationstag': {'datum': '2023-10-31', 'hinweis': ''}, '1. Weihnachtstag': {'datum': '2023-12-25', 'hinweis': ''}, '2. Weihnachtstag': {'datum': '2023-12-26', 'hinweis': ''}}, 'HE': {'Neujahrstag': {'datum': '2023-01-01', 'hinweis': ''}, 'Karfreitag': {'datum': '2023-04-07', 'hinweis': ''}, 'Ostermontag': {'datum': '2023-04-10', 'hinweis': ''}, 'Tag der Arbeit': {'datum': '2023-05-01', 'hinweis': ''}, 'Christi Himmelfahrt': {'datum': '2023-05-18', 'hinweis': ''}, 'Pfingstmontag': {'datum': '2023-05-29', 'hinweis': ''}, 'Fronleichnam': {'datum': '2023-06-08', 'hinweis': ''}, 'Tag der Deutschen Einheit': {'datum': '2023-10-03', 'hinweis': ''}, '1. Weihnachtstag': {'datum': '2023-12-25', 'hinweis': ''}, '2. Weihnachtstag': {'datum': '2023-12-26', 'hinweis': ''}}, 'MV': {'Neujahrstag': {'datum': '2023-01-01', 'hinweis': ''}, 'Frauentag': {'datum': '2023-03-08', 'hinweis': ''}, 'Karfreitag': {'datum': '2023-04-07', 'hinweis': ''}, 'Ostermontag': {'datum': '2023-04-10', 'hinweis': ''}, 'Tag der Arbeit': {'datum': '2023-05-01', 'hinweis': ''}, 'Christi Himmelfahrt': {'datum': '2023-05-18', 'hinweis': ''}, 'Pfingstmontag': {'datum': '2023-05-29', 'hinweis': ''}, 'Tag der Deutschen Einheit': {'datum': '2023-10-03', 'hinweis': ''}, 'Reformationstag': {'datum': '2023-10-31', 'hinweis': ''}, '1. Weihnachtstag': {'datum': '2023-12-25', 'hinweis': ''}, '2. Weihnachtstag': {'datum': '2023-12-26', 'hinweis': ''}}, 'NI': {'Neujahrstag': {'datum': '2023-01-01', 'hinweis': ''}, 'Karfreitag': {'datum': '2023-04-07', 'hinweis': ''}, 'Ostermontag': {'datum': '2023-04-10', 'hinweis': ''}, 'Tag der Arbeit': {'datum': '2023-05-01', 'hinweis': ''}, 'Christi Himmelfahrt': {'datum': '2023-05-18', 'hinweis': ''}, 'Pfingstmontag': {'datum': '2023-05-29', 'hinweis': ''}, 'Tag der Deutschen Einheit': {'datum': '2023-10-03', 'hinweis': ''}, 'Reformationstag': {'datum': '2023-10-31', 'hinweis': ''}, '1. Weihnachtstag': {'datum': '2023-12-25', 'hinweis': ''}, '2. Weihnachtstag': {'datum': '2023-12-26', 'hinweis': ''}}, 'NW': {'Neujahrstag': {'datum': '2023-01-01', 'hinweis': ''}, 'Karfreitag': {'datum': '2023-04-07', 'hinweis': ''}, 'Ostermontag': {'datum': '2023-04-10', 'hinweis': ''}, 'Tag der Arbeit': {'datum': '2023-05-01', 'hinweis': ''}, 'Christi Himmelfahrt': {'datum': '2023-05-18', 'hinweis': ''}, 'Pfingstmontag': {'datum': '2023-05-29', 'hinweis': ''}, 'Fronleichnam': {'datum': '2023-06-08', 'hinweis': ''}, 'Tag der Deutschen Einheit': {'datum': '2023-10-03', 'hinweis': ''}, 'Allerheiligen': {'datum': '2023-11-01', 'hinweis': ''}, '1. Weihnachtstag': {'datum': '2023-12-25', 'hinweis': ''}, '2. Weihnachtstag': {'datum': '2023-12-26', 'hinweis': ''}}, 'RP': {'Neujahrstag': {'datum': '2023-01-01', 'hinweis': ''}, 'Karfreitag': {'datum': '2023-04-07', 'hinweis': ''}, 'Ostermontag': {'datum': '2023-04-10', 'hinweis': ''}, 'Tag der Arbeit': {'datum': '2023-05-01', 'hinweis': ''}, 'Christi Himmelfahrt': {'datum': '2023-05-18', 'hinweis': ''}, 'Pfingstmontag': {'datum': '2023-05-29', 'hinweis': ''}, 'Fronleichnam': {'datum': '2023-06-08', 'hinweis': ''}, 'Tag der Deutschen Einheit': {'datum': '2023-10-03', 'hinweis': ''}, 'Allerheiligen': {'datum': '2023-11-01', 'hinweis': ''}, '1. Weihnachtstag': {'datum': '2023-12-25', 'hinweis': ''}, '2. Weihnachtstag': {'datum': '2023-12-26', 'hinweis': ''}}, 'SL': {'Neujahrstag': {'datum': '2023-01-01', 'hinweis': ''}, 'Karfreitag': {'datum': '2023-04-07', 'hinweis': ''}, 'Ostermontag': {'datum': '2023-04-10', 'hinweis': ''}, 'Tag der Arbeit': {'datum': '2023-05-01', 'hinweis': ''}, 'Christi Himmelfahrt': {'datum': '2023-05-18', 'hinweis': ''}, 'Pfingstmontag': {'datum': '2023-05-29', 'hinweis': ''}, 'Fronleichnam': {'datum': '2023-06-08', 'hinweis': ''}, 'Mariä Himmelfahrt': {'datum': '2023-08-15', 'hinweis': ''}, 'Tag der Deutschen Einheit': {'datum': '2023-10-03', 'hinweis': ''}, 'Allerheiligen': {'datum': '2023-11-01', 'hinweis': ''}, '1. Weihnachtstag': {'datum': '2023-12-25', 'hinweis': ''}, '2. Weihnachtstag': {'datum': '2023-12-26', 'hinweis': ''}}, 'SN': {'Neujahrstag': {'datum': '2023-01-01', 'hinweis': ''}, 'Karfreitag': {'datum': '2023-04-07', 'hinweis': ''}, 'Ostermontag': {'datum': '2023-04-10', 'hinweis': ''}, 'Tag der Arbeit': {'datum': '2023-05-01', 'hinweis': ''}, 'Christi Himmelfahrt': {'datum': '2023-05-18', 'hinweis': ''}, 'Pfingstmontag': {'datum': '2023-05-29', 'hinweis': ''}, 'Fronleichnam': {'datum': '2023-06-08', 'hinweis': 'Fronleichnam ist kein gesetzlicher Feiertag außer in folgenden katholisch geprägten Gemeinden des sorbischen Siedlungsgebietes im Landkreis Bautzen:\n\t\t\t\tBautzen (nur in den Ortsteilen Bolbritz und Salzenforst), Crostwitz, Göda (nur im Ortsteil Prischwitz), Großdubrau (nur im Ortsteil Sdier), Hoyerswerda (nur im Ortsteil Dörgenhausen), Königswartha (nicht im Ortsteil Wartha), Nebelschütz, Neschwitz (nur in den Ortsteilen Neschwitz und Saritsch), Panschwitz-Kuckau, Puschwitz, Räckelwitz, Radibor, Ralbitz-Rosenthal und Wittichenau. Entscheidend ist dabei der Arbeitsort, nicht der Wohnort eines Arbeitnehmers.\n\t\t\t\tDie gesetzliche Grundlage für diese durch die Fronleichnamsverordnung festgelegte Regelung ergibt sich aus § 1 Abs. 1 des Sächsischen Feiertagsgesetzes.[5]'}, 'Tag der Deutschen Einheit': {'datum': '2023-10-03', 'hinweis': ''}, 'Reformationstag': {'datum': '2023-10-31', 'hinweis': ''}, 'Buß- und Bettag': {'datum': '2023-11-22', 'hinweis': ''}, '1. Weihnachtstag': {'datum': '2023-12-25', 'hinweis': ''}, '2. Weihnachtstag': {'datum': '2023-12-26', 'hinweis': ''}}, 'ST': {'Neujahrstag': {'datum': '2023-01-01', 'hinweis': ''}, 'Heilige Drei Könige': {'datum': '2023-01-06', 'hinweis': ''}, 'Karfreitag': {'datum': '2023-04-07', 'hinweis': ''}, 'Ostermontag': {'datum': '2023-04-10', 'hinweis': ''}, 'Tag der Arbeit': {'datum': '2023-05-01', 'hinweis': ''}, 'Christi Himmelfahrt': {'datum': '2023-05-18', 'hinweis': ''}, 'Pfingstmontag': {'datum': '2023-05-29', 'hinweis': ''}, 'Tag der Deutschen Einheit': {'datum': '2023-10-03', 'hinweis': ''}, 'Reformationstag': {'datum': '2023-10-31', 'hinweis': ''}, '1. Weihnachtstag': {'datum': '2023-12-25', 'hinweis': ''}, '2. Weihnachtstag': {'datum': '2023-12-26', 'hinweis': ''}}, 'SH': {'Neujahrstag': {'datum': '2023-01-01', 'hinweis': ''}, 'Karfreitag': {'datum': '2023-04-07', 'hinweis': ''}, 'Ostermontag': {'datum': '2023-04-10', 'hinweis': ''}, 'Tag der Arbeit': {'datum': '2023-05-01', 'hinweis': ''}, 'Christi Himmelfahrt': {'datum': '2023-05-18', 'hinweis': ''}, 'Pfingstmontag': {'datum': '2023-05-29', 'hinweis': ''}, 'Tag der Deutschen Einheit': {'datum': '2023-10-03', 'hinweis': ''}, 'Reformationstag': {'datum': '2023-10-31', 'hinweis': ''}, '1. Weihnachtstag': {'datum': '2023-12-25', 'hinweis': ''}, '2. Weihnachtstag': {'datum': '2023-12-26', 'hinweis': ''}}, 'TH': {'Neujahrstag': {'datum': '2023-01-01', 'hinweis': ''}, 'Karfreitag': {'datum': '2023-04-07', 'hinweis': ''}, 'Ostermontag': {'datum': '2023-04-10', 'hinweis': ''}, 'Tag der Arbeit': {'datum': '2023-05-01', 'hinweis': ''}, 'Christi Himmelfahrt': {'datum': '2023-05-18', 'hinweis': ''}, 'Pfingstmontag': {'datum': '2023-05-29', 'hinweis': ''}, 'Fronleichnam': {'datum': '2023-06-08', 'hinweis': 'Fronleichnam ist kein gesetzlicher Feiertag außer im gesamten Landkreis Eichsfeld (79 Gemeinden am 31. Dezember 2013, Auflistung siehe dort) sowie in folgenden Gemeinden des Unstrut-Hainich-Kreises und des Wartburgkreises:\n\t\t\t\tAnrode (nur in den Ortsteilen Bickenriede und Zella), Brunnhartshausen (nur in den Ortsteilen Föhlritz und Steinberg), Buttlar, Dünwald (nur in den Ortsteilen Beberstedt und Hüpstedt), Geisa, Rodeberg (nur im Ortsteil Struth), Schleid, Südeichsfeld und Zella/Rhön.\n\t\t\t\tDie gesetzliche Grundlage für diese Regelung ergibt sich aus § 2 Abs. 2 und § 10 Abs. 1 des Thüringer Feiertagsgesetzes.[6]'}, 'Weltkindertag': {'datum': '2023-09-20', 'hinweis': ''}, 'Tag der Deutschen Einheit': {'datum': '2023-10-03', 'hinweis': ''}, 'Reformationstag': {'datum': '2023-10-31', 'hinweis': ''}, '1. Weihnachtstag': {'datum': '2023-12-25', 'hinweis': ''}, '2. Weihnachtstag': {'datum': '2023-12-26', 'hinweis': ''}}, 'NATIONAL': {'Neujahrstag': {'datum': '2023-01-01', 'hinweis': ''}, 'Karfreitag': {'datum': '2023-04-07', 'hinweis': ''}, 'Ostermontag': {'datum': '2023-04-10', 'hinweis': ''}, 'Tag der Arbeit': {'datum': '2023-05-01', 'hinweis': ''}, 'Christi Himmelfahrt': {'datum': '2023-05-18', 'hinweis': ''}, 'Pfingstmontag': {'datum': '2023-05-29', 'hinweis': ''}, 'Tag der Deutschen Einheit': {'datum': '2023-10-03', 'hinweis': ''}, '1. Weihnachtstag': {'datum': '2023-12-25', 'hinweis': ''}, '2. Weihnachtstag': {'datum': '2023-12-26', 'hinweis': ''}}}
{
"id": "chatcmpl-7YqFGOa3vJ6Ls9YiPj0JRolY6O0Zy",
"object": "chat.completion",
"created": 1688538338,
"model": "gpt-3.5-turbo-0613",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "{\n  \"jahr\": \"2023\"\n}\nDer n\u00e4chste gesetzliche Feiertag in Hessen nach dem 3.7.2023 ist der Tag der deutschen Einheit am 3. Oktober 2023."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 124,
"completion_tokens": 50,
"total_tokens": 174
}
}

Das hier ist natürlich die unverarbeitete Antwort, um besser zeigen zu können, was passiert.

Zuerst sehen wir nämlich, dass das Modell einen Funktionsaufruf haben möchte und gibt uns für den Parameter „jahr“ den Wert „2023“ an.

Wir sehen dann, dass unserer Funktion die Feiertage von der API anfragt und die Antwort enthält alle Feiertage für dieses Jahr.

Nachdem das Model diese Daten verdaut hat, sehen wir die finale Antwort: „{„jahr“: „2023“} Der nächste gesetzliche Feiertag in Hessen nach dem 3.7.2023 ist der Tag der deutschen Einheit am 3. Oktober 2023.„.

Wir haben ja keine Angaben gemacht, wie die Antwort ausgegeben werden soll, daher die etwas fummelige Ausgabe mit der Angabe des Parameters vor dem eigentlichen Text.

Hinweise

Der Beispielcode ist äußerst rudimentär und müsste deutlich überarbeitet werden. Wenn wir auf den ersten Prompt keine Funktionsaufruf-Empfehlung bekommen hätten, dann würde sich das Programm ohne jede weitere Ausgabe einfach beenden. Das müsste man viel eleganter gestalten und eine Routine schrieben, die sich darum kümmert zu schauen, ob wir eine Text- oder Funktions-Antwort vorliegen haben und entsprechend handelt.

Außerdem ist es nicht so schön wie der OpenAI-API Aufruf einfach in den if-Block kopiert wurde. Das gehört natürlich ein eigene Funktion ausgelagert etc.

Zu guter Letzt noch ein Hinweis zu einem optionalen Parameter, den wir mitgeben können: „function_call“ (so ähnlich wie in der Antwort). Damit können wir steuern, welche Funktion angesprochen werden soll oder ob gar keine Funktionsaufrufe gewünscht sind. Beispiele:

# Bestimmte Funktion soll aufgerufen werden
function_call: {"name": "<Name der Funktion>"}
# Kein Funktionsaufruf erwünscht:
function_call: "none"
# Standardwert ist "auto"
function_call: "auto"

Ende

Das war jetzt der letzte Teil der Serie. Mit den Funktionsaufrufen haben wir ein mächtiges Werkzeug kennengelernt. Es ermöglicht uns eine Art Plugins bereit zu stellen und Daten, die dem Modell sonst unzugänglich wären, bereit zu stellen.

Den Code findest du in meinem GitHub-Repository unter: https://github.com/ki-zeitalter/openai-api-tutorial/blob/main/openai_functions_tutorial.ipynb.

Mit den Funktionen können wir auch so etwas wie Agenten implementieren. D.h. die Funktionsaufrufe können zu weiteren automatisch erzeugten Prompts führen, z.B. um eine komplexe Aufgabe in viele Teilschritte zu teilen.

Was wir in dieser Tutorialreihe gesehen haben ermöglicht uns sehr coole Sachen umzusetzen. Allerdings ist es nicht der eleganteste Weg, wie man das erreichen kann. Es gibt Frameworks, die das Ganze kapseln und die Komplexität verbergen. Insbesondere möchte ich hier LangChain empfehlen. Ein Tutorial zu LangChain ist bereits in Arbeit! wink

Ich hoffe dir haben die Tutorials gefallen und ich würde mich über jedes Feedback sehr freuen!

Die anderen Teile der Serie

Teil 1: OpenAI (ChatGPT) API Tutorial – Teil #1 

Teil 2: OpenAI (ChatGPT) API Tutorial – Teil #2 Modelle und Dall-E

OpenAI (ChatGPT) API Tutorial – Teil #3 Funktionen (Function calling) 

OpenAI (ChatGPT) API Tutorial – Teil #2 Modelle und Dall-E

Einleitung

Im Teil #1 der Tutorial-Reihe haben wir uns mit der Chat Completions API beschäftigt und einen Chatbot erstellt. Hier kommst du zum Teil #1: https://ki-zeitalter.de/openai-chatgpt-api-tutorial-teil-1/

In diesem Teil gebe ich dir erstmal eine Übersicht über die unterschiedlichen Modelle, die man auswählen kann. Die Modellauswahl kann Einfluss auf die Qualität der Antworten haben, aber auch auf die Antwortgeschwindigkeit und nicht zuletzt auf die Kosten.

Die Modelle

OpenAI bietet eine vielfältige Reihe von Modellen mit unterschiedlichen Fähigkeiten und Preisen an. 

GPT-4

GPT-4 ist eine Sammlung von Modellen, die auf GPT-3.5 aufbauen und natürliche Sprache oder Code verstehen und generieren können. GPT-4 befindet sich derzeit in einer eingeschränkten Beta-Version und ist nur für diejenigen zugänglich, die dafür Zugriffsrechte erhalten haben. Es handelt sich um ein großes multimodales Modell, das schwierige Aufgaben mit größerer Genauigkeit als jedes bisherigen Modelle lösen kann, dank seines breiteren Allgemeinwissens und fortgeschrittenen Schlussfolgerungsfähigkeiten.

GPT-3.5

Die Modelle GPT-3.5 können natürliche Sprache oder Code verstehen und generieren. Das leistungsfähigste und kosteneffektivstes Modell in der GPT-3.5-Reihe ist gpt-3.5-turbo, das für Chats optimiert wurde, aber auch gut für traditionelle Vervollständigungsaufgaben geeignet ist.

DALL·E

DALL·E ist ein AI-System, das realistische Bilder und Kunst aus einer natürlichen Sprachbeschreibung erstellen kann. Es unterstützen die Fähigkeit, ein neues Bild mit einer bestimmten Größe zu erstellen, ein vorhandenes Bild zu bearbeiten oder Variationen eines vom Benutzer bereitgestellten Bildes zu erstellen.

Whisper

Whisper ist ein Modell, das Audio in Text umwandeln kann. Es ist ein Allzweck-Spracherkennungsmodell, das auf einem großen Datensatz verschiedener Audiodaten trainiert wurde und auch Aufgaben wie mehrsprachige Spracherkennung, Sprachübersetzung und Sprachidentifikation erfüllen kann.

Embeddings

Embedding-Modelle können Text in eine numerische Form umwandeln. Sie sind nützlich für Suchaufgaben, Clustering, Empfehlungen, Anomalieerkennung und Klassifizierungsaufgaben.

Moderation

Das Moderationsmodell ist darauf ausgelegt, zu erkennen, ob ein Text sensibel oder unsicher sein könnte. Es bietet Klassifikationsfähigkeiten, die nach Inhalten in folgenden Kategorien suchen: Hass, Bedrohung, Selbstschädigung, sexueller Inhalt und Gewalt.

GPT-3

Die Modelle GPT-3 können natürliche Sprache verstehen und generieren. Diese Modelle wurden durch die leistungsfähigeren Modelle der GPT-3.5 Generation abgelöst.

 

Bildgenerierung mit Dall-E

Kommen wir jetzt zu dem spannenderen Teil des Tutorials. Ich zeige dir, wie wir mit der OpenAI API Bilder anhand einer Textbeschreibung erstellen können.

Dabei werden uns drei verschiedene Möglichkeiten angeboten: ein komplett neues Bild erzeugen, ein vorhandenes Bild wird erweitert und Variationen eines existierenden Bildes.

Zum Zeitpunkt der Erstellung dieses Tutorials befindet sich die API noch im Beta-Stadium, d.h. das eine oder andere könnte nicht richtig funktionieren oder Funktionalität wird geändert.

Über die API können wir uns Bilder in den Größen 256×256, 512×512 oder 1024×1024 Pixel erstellen lassen. Pro Anfrage können wir uns 1-10 Bilder erzeugen lassen.

Schauen wir uns das erste Beispiel an. In diesem Beispiel erzeugen wir ein neues Bild, das anhand unser „Prompts“ ein Bild erzeugt. Wie man alle Voraussetzungen für die Nutzung der API erfüllt, wie API-Key und die Installation der notwendigen Bibliotheken, erfährst du im ersten Teil der Tutorial-Reihe.

Erstellung eines Bildes anhand eines Prompts

import openai
openai.api_key = "Füge hier deinen API-Key ein!"
prompt = "Eine schöne Seenlandschaft"
response = openai.Image.create(
prompt=prompt,
n=1,
size="256x256"
)
image_url = response['data'][0]['url']
print(image_url)

Wenn alles gut gegangen ist, erzeugt der obige Code ein Bild mit den Maßen 256 x 256 Pixel. Das schöne ist, es versteht auch auf Deutsch geschriebene Prompts.

Als Ergebnis erhalten wir hier eine URL, die zum Anzeigen/Download des Bildes führt. Die URL wird hier im Beispiel lediglich ausgegeben, also einfach kopieren und im Browser einfügen. In meinem Fall habe ich dieses doch recht nette Ergebnis bekommen:

Da wir n=1 angegeben haben, hat uns Dall-E nur ein Bild erzeugt und damit haben wir auch nur eine URL als Ergebnis bekommen. Bei n > 1 hätten wir entsprechend viele URLs erhalten.

Mit dem Parameter response_format können wir auch angeben, dass wir das Bild als Base64 kodierte Daten bekommen wollen: response_format=“b64_json“. Dann entfällt das Laden des Ergebnisses von der URL

Übrigens kannst du über https://labs.openai.com/ deine Prompts ausprobieren und einige Beispiele anschauen.

Damit wir das Bild in unserer Anwendung verwenden könne, wäre es sicherlich nett, wenn wir das Bild mit Python auch herunterladen. Das geht zum Glück sehr einfach. Dazu erweitern wir das Beispiel folgendermaßen:

import requests
import os
def bild_herunterladen(url, dateiname):
# Die Bilddatei herunterladen
bild = requests.get(url)
# Die Bilddatei auf dem Laufwerk speichern
with open(dateiname, "wb") as datei:
datei.write(bild.content)
bild_herunterladen(image_url, 'bild-1.png')

Da die URL keinen Dateinamen enthält, geben wir den Dateinamen hier einfach selbst an.

Bildbereiche neu erzeugen lassen

Das war, finde ich, doch recht einfach bis jetzt. Schauen wir uns noch die anderen Varianten an. D.h. wir laden ein Bild hoch und lassen es editieren.

Damit Dall-E auch weiss, welche Bereiche des Bildes geändert werden sollen, muss man die entsprechenden Stellen transparent machen. Das geht meist recht einfach in einer Bildverarbeitung wie Photoshop oder Gimp usw. Oder wir nutzen dafür eine AI, wie https://removal.ai, mit dessen Hilfe wir den Hintergrund entfernen können. Genau das habe ich gemacht. Zuerst habe ich ein Bild von einer jungen Frau in einer Stadt generieren lassen:

Anschließend habe ich https://removal.ai genutzt, um den Hintergrund zu entfernen:

 

Und jetzt sind wir bereit Dall-E „zu bitten“ etwas neues in dem transparenten Bereich zu erzeugen.

 

import PIL.Image
import io
rgba_image = PIL.Image.open("woman_transparent.png")
rgba_image = rgba_image.convert('RGBA')
img_byte_arr = io.BytesIO()
rgba_image.save(img_byte_arr, format='PNG')
img_byte_arr = img_byte_arr.getvalue()
response = openai.Image.create_edit(
image=img_byte_arr,
prompt="Eine junge Frau in einer Kunstgalerie",
n=1,
size="512x512"
)
image_url = response['data'][0]['url']

Das Bild, das ich als Eingabe verwendet muss im RGBA-Format vorliegen, also ein Bildformat mit eine Alpha-Kanal für die Transparenz. Wir nutzen hier die PIL-Bibliothek um das Bild zunächst zu laden und dann in RGBA zu konvertieren.

Die API braucht aber die rohen Bytes der Bilddaten, daher nutzen wir io um aus dem PIL Bild die Bytes zu bekommen.

Zuletzt rufen wir die API-Funktion create_edit auf und geben einen Prompt mit. In meinem Beispiel möchte ich, dass die Frau in einer Kunstgalerie steht. Das Ergebnis, das ich erhalten habe sieht wie folgt aus:

Übrigens empfiehlt es sich im Prompt das gesamte Bild zu beschreiben, d.h. nicht nur den Hintergrund, sondern auch was sonst zu sehen ist. Das hilft der KI den Kontext zu verstehen.

Bildvariationen

Die letzte Variante lässt Dall-E das Bild modifizieren. Wir laden dazu ein Bild hoch aber diesmal haben wir keine Möglichkeit einen Prompt mitzugeben. Schauen wir uns den Code dazu an:

import PIL.Image
import io
rgba_image = PIL.Image.open("young-woman-edited.png")
img_byte_arr = io.BytesIO()
rgba_image.save(img_byte_arr, format='PNG')
img_byte_arr = img_byte_arr.getvalue()
response = openai.Image.create_variation(
image=img_byte_arr,
n=1,
size="512x512"
)
image_url = response['data'][0]['url']

Der Code ist dem vorherigen Beispiel sehr ähnlich. Nur in diesem Fall brauchen wir keine transparenten Bereiche und das Format muss nicht unbedingt im RGBA vorliegen.

Nachdem wir das Ausgangsbild geladen haben, rufen wir die create_variation Funktion auf. Wie zuvor erhalten wir hier eine Bild-URL und in meinem Fall sah das Ergebnis so aus:

Ok ok…. das Ergebnis ist, öhm sagen wir mal Dall-E hat sich große Mühe gegeben! wink

Aber wer weiß, wenn man ein paar Versuche startet, dann kommt womöglich etwas brauchbares heraus. Außerdem ist damit zu rechnen, dass die Modelle weiter trainiert werden und mit der Zeit besser werden. Dall-E befindet sich außerdem noch in der Beta-Phase.

Ende Teil #2

Das war Teil #2 der Tutorial-Reihe über die OpenAI API (ChatGPT). Ich hoffe es hat dir etwas gebracht. Ich hoffe man sieht, dass man mit nur wenigen Zeilen Code, etwas tolles kreieren kann! 

Ausblick

Im letzten Teil der Reihe zeige ich dir ein sehr cooles und relativ neues Feature: „functions“. Mit „functions“ können wir über die API unsere oder andere APIs praktisch einbinden. Das eröffnet ganz neue Möglichkeiten und wir können Funktionalitäten wie die ChatGPT-Plugins uvm. umsetzen!

OpenAI (ChatGPT) API Tutorial – Teil #3 Funktionen (Function calling) 

OpenAI (ChatGPT) API Tutorial – Teil #1

Einleitung

Du möchtest eine Anwendung erstellen, die ChatGPT benutzt? Dann ist dieses Tutorial für dich richtig. Hier lernst du die unterschiedlichen APIs von OpenAI kennen und zu nutzen.

Wir schauen uns an, wie man einzelne Prompts an die API schicken kann und Antworten alà ChatGPT zurück bekommt. Ich gebe dir eine Übersicht über die unterschiedlichen Sprachmodelle, die man verwendent kann. In einem erweitertem Beispiel zeige ich dir, wie man eine eigene Chatbot-Seite erstellt.

ChatGPT ist im Grunde genommen einfach nur eine Webanwendung, die im Hintergrund die OpenAI API nutzt. Es nimmt bei der Nutzung einige Voreinstellungen vor, die wir mit der API selbst definieren können. So werden wir uns den Spaß erlauben einen eigenen Chat zu schreiben, bei dem der KI-Assistent mürrisch antwortet. Wir können außerdem die Kreativität der Antworten beeinflussen.

Außerdem lernst du die weiteren APIs kennen, mit denen du Bilder mit Dall-E erzeugen kannst und wie man Sprache zu Text transkripieren kann.

Damit du alles aus der API rausholen kannst, empfähle ich dir mein Tutorial rund um die Prompts: Prompt Leitfaden: bessere Ergebnisse aus ChatGPT und Co holen

Einrichtung

Bevor du loslegen kannst, brauchst du für die Nutzung von der OpenAI API einen API-Key. Beachte, dass die Nutzung kostenpflichtig ist. Meiner Erfahrung nach entstehen nur sehr geringe Kosten, wenn man nur ein wenig ausprobiert. Bis jetzt bewegt sich das alles im Cent-Bereich. Beachte bitte das Kapitel, wo ich dir erkläre, wie man vermeiden kann zu hohe Kosten zu verursachen!

API-Key

Zunächst musst du dich auf https://platform.openai.com/ registrieren. Hier wirst du aufgefordert erstmal Zahlungsdaten zu hinterlegen.  Wichtig: schau dir alles an, vor allem die Preisinformationen.

Danach kannst du dir unter https://platform.openai.com/account/api-keys  einen API-Key anlegen. Ich empfehle für jede Anwendung etc. einen eigenen Key zu machen. Die Keys kannst du nämlich als ungültig markieren, z.B. nachdem du deine Tests abgeschlossen hast.

Wichtig: wenn dir der Key angezeigt wird, dann musst du ihn sofort kopieren und irgendwo notieren, denn er wird dir nicht noch einmal angezeigt. Im schlimmsten Fall musst du einen neuen anlegen.

Wichtige Einstellungen

Du kannst im Menü Billing/Usage limits festlegen, wie viel du maximal ausgeben möchtest. Stelle dort bevor du etwas probierst für dich akzeptable Werte ein.

 

Hier kannst du zwei Werte einstellen: „Hard limit“ und „Soft limit“.

Über „Hard limit“ stellst du, wie der Name schon sagt, ein hartes Limit ein. D.h. es wird maximal bis zu diesem Betrag abgebucht.

Das „Soft limit“ ist die Schwelle, die dazu dient, dich zu warnen. Sobald diese Grenze überschritten wird, wirst du per E-Mail informiert.

Stelle unbedingt für dich vernünftige Werte ein, bevor du mit deinen Versuchen startest!

Python

Die Beispiele, die ich in diesem Tutorial zeige, sind in Python geschrieben. Wenn du lieber eine andere Programmiersprache verwenden möchtest, so geht das natürlich auch. Du findest auf https://platform.openai.com/docs/libraries eine Übersicht über weitere Bibliotheken für andere Programmiersprachen. Während Python und Node.js von OpenAI direkt angeboten werden, gibt es für jede erdenkliche andere Sprachen eine Liste von Community-Bibliotheken.

Wenn du bei Python bleibst, dann hast du mehrere Möglichkeiten. Zum einen kannst du auf deinem Rechner Python installieren. Auf https://www.python.org/downloads/ findest du für dein Betriebssystem die passende Version. Folge dort einfach den Instruktionen für die Installation.

Wenn du lieber nichts installieren willst, dann gibt es im Internet einige Online-Möglichkeiten. Diese bieten dir meist kostenlos die Möglichkeit eine Python-Umgebung zu nutzen. Meist mit einem Online-Editor usw. Nutze eine Suchmaschine deiner Wahl und suche z.B. „python online programmieren“. Da wird einiges angeboten.

Ganz gut ist z.B. https://replit.com/. Anfangs ist die Seite etwas unübersichtlich und man muss erstmal schauen, wo es weiter geht. Hier suchst du den Button „Create a Repl“ und wählst Python als Sprache aus. Dann erhälst du eine Arbeitsumgebung mit Editor und die Möglichkeit den Code auszuführen.

Was ich allerdings am liebsten nutze, sind die Workspaces auf GitHub. Du musst die einen GitHub-Account anlegen (ist kostenlos) und dann ein Repository. In dem Repository kannst du dann einen Workspace erstellen. Darin hast du Visual Studio Code als Editor und eine Python-Laufzeitumgebung. 

 

 

 

Die Chat Completions API

Es gibt zwei unterschiedliche APIs mit denen wir durch Prompt-Eingaben Text generieren lassen können, die Completions API und die Chat Completions API. Die APIs unterscheiden sich leicht in der Nutzung. Dieses Tutorial wird nur die Chat Completions API nutzen, da diese alles abdeckt was man benötigt und von der Nutzung her intuitiver ist.

Wir schauen uns ein sehr einfaches Beispiel an, um ein Gefühl zu bekommen, wie die API funktionert.

Bevor wir loslegen können, müssen wir allerdings erst die OpenAI API für Python installieren. Hierfür verwenden wir pip.

$ pip install openai

Nachdem die Bibliothek installiert wurde, können wir mit dem Code anfangen und erstellen eine Python-Datei simple-example.py (fertigen Code findest du in meinem GitHub-Repository unter https://github.com/ki-zeitalter/openai-api-tutorial)

simple-example.py

import openai
openai.api_key = "Hier deinen API-Key einfügen"
prompt = "Welche APIs gibt es von OpenAI?"
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": prompt}
]
)
print(response.choices[0].message["content"])

Bevor du den Code ausführen kannst, musst du erst deinen zuvor erstellten API Key einfügen.

Führe das Python-Skript mit python simple-example.py aus und wenn alles gut gegangen ist, dann solltest du eine Ausgabe sehen, die in etwa so aussieht:

@ki-zeitalter $ python simple-example.py 
Es gibt mehrere APIs von OpenAI, einschließlich:
1. GPT-2 API: Mit dieser API können Entwickler auf den Textgenerationsdienst von OpenAI zugreifen, der auf der neuesten Version des GPT-2-Modells basiert.
2. DALL-E API: Diese API ermöglicht es Entwicklern, auf den DALL-E-Dienst von OpenAI zuzugreifen, der Bilder aus einer natürlichen Sprachbeschreibung generieren kann.
[...]

Schauen wir uns an, was hier passiert. Auf die Details der API gehe ich ein, wenn wir den Chat programmieren.

Zuerst haben wir mit dem import Befehl die OpenAI API importiert und anschliessend übergeben wir unseren API-Key an die Bibliothek.

Es erfolgt dann der Aufruf an die ChatCompletion API. Hier übergeben wir zwei Parameter model und messages.

Der model Parameter gibt an, welches zugrunde liegendes Sprachmodell verwendet werden soll. Wie du vielleicht von ChatGPT kennst, dort kannst du z.B. zwischen GPT-3.5 und GPT-4 wählen. Hier hast du einige weitere Möglichkeiten. Weiter unten gehe ich auf die unterschiedlichen Modelle ein.

Mit dem messages Parameter übergeben wir eine Liste von Nachrichten. In diesem Fall enthält die Liste nur einen Eintrag, nämlich unseren Prompt und eine Rolle.

Was es mit der Rolle auf sich hat, sehen wir in dem Chat-Beispiel später deutlicher. In diesem Fall übergeben wir die Rolle „user„. Damit sagen wir der API, dass diese Nachricht/Prompt von dem Benutzer eingegeben wurde.

Die Antwort

Zu guter letzt geben wir die Antwort aus. Hier greifen wir aber nur auf einen Teil der Antwort zu und geben es aus und zwar nur den Teil, der die eigentliche Textantwort von dem Sprachmodell. Die Antwort selbst enthält mehr Informationen, die wir uns ansehen können:

Die gesamte Antwort

{
"id": "chatcmpl-7UVUZC7EF2VG1nvehNZsjlR938uOS",
"object": "chat.completion",
"created": 1687505251,
"model": "gpt-3.5-turbo-0301",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "OpenAI bietet verschiedene APIs an, darunter:\n\n1. GPT-3 API: Eine Natural Language Processing (NLP)-API, die es erm\u00f6glicht, menschen\u00e4hnliche Texte zu generieren.\n2. DALL-E API: Eine Vision-API, die es erm\u00f6glicht, neue Bilder aus Textbeschreibungen zu generieren.\n3. Codex API: Eine API, die es erm\u00f6glicht, Codes in verschiedenen Programmiersprachen zu generieren und zu bearbeiten.\n4. API f\u00fcr maschinelles Lernen: Eine API, die es erm\u00f6glicht, Modelle f\u00fcr maschinelles Lernen zu trainieren und zu implementieren.\n5. API f\u00fcr Neuroevolution: Eine API, die es erm\u00f6glicht, neuronale Netze durch evolution\u00e4re Algorithmen zu trainieren.\n\nDiese APIs k\u00f6nnen von Entwicklern genutzt werden, um ihre Anwendungen oder Projekte mit hochwertiger KI- und NLP-Technologie zu verbessern."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 17,
"completion_tokens": 204,
"total_tokens": 221
}
}

In der Antwort sehen wir eine Reihe von Informationen. Die wichtigsten Informationen, die uns vermutlich interessieren, befinden sich in den Blöcken „choices“ und „usage„.

Innerhalb von „choices“ finden wir den Antworttext, so wie wir das weiter oben bereits gesehen haben. Zusätzlich gibt es das Feld „finish_reason„. Hier haben wir den Wert „stop“ erhalten. Das bedeutet, dass die Antwort vollständig erzeugt wurde. Für den Fall, dass ganze Verarbeitung die maximale Anzahl an Tokens überschreitet, würde man hier den Wert „length“ bekommen.

Wir sehen außerdem, dass „choices“ eine Liste ist. Das hat den Hintergrund, dass man theoretisch eine gewisse Anzahl an Antworten anfordern kann. Hier werden wir keinen Gebrauch davon machen.

Im Block „usage“ sehen wir wieviele Tokens verwendet wurden. Was Tokens sind, erkläre ich gleich. Hier wird unterschieden zwischen der Token-Anzahl für den Prompt und für die Antwort. In „total_tokens“ sieht man die Summer daraus. Diese Information kann hilfreich sein, um zu sehen, was das ganze kostet und ob wir uns der Obergrenze der Tokens annähern. Denn wir können diesen Chatverlauf ja weiter führen. Wie das geht, sehen wir im Bereich Chat.

Tokens

Wenn Sprachmodelle trainiert werden, dann werden sie mit zahlreichen Texten gefüttert. Daraus werden die Zusammenhänge gelernt.

Die einzelnen Wörter werden dabei „tokenisiert“. Das kann bedeuten, dass ein Wort einem Token entspricht, manche Wörter jedoch werden in mehrere Token aufgeteilt.

Bei der Antwortgenerierung läuft es ähnlich. Das Sprachmodell berechnet sehr vereinfacht gesagt das jeweils nächste Wort oder genauer das nächste Token.

Daher sehen wir in der Antwort, wieviele Tokens uns das gekostet hat. Die Preise für die Nutzung der API richten sich nach der Anzahl der Tokens. Dabei kosten die Tokens je nach verwendeten Modell unterschiedlich. Eine Preisübersicht findest du hier: https://openai.com/pricing. Dazu sei gesagt, dass sich die Preise pro Token unterhalb von einem Cent bewegen.

Neben dem Preis, spielt es auch eine Rolle, wie viele Tokens wir insgesamt für eine Anfrage maximal nutzen können. Da gibt es je nach Modell unterschiedliche Obergrenzen. Ist die Summe der Länge aus Anfrage und Antwort zu groß, dann wird die Antwort abgeschnitten. Hier kann es u.U. helfen die Anfrage in mehrere Teile aufzuteilen, wenn möglich. Hier findest du eine Übersicht über die Modelle und die jeweiligen Grenzen: https://platform.openai.com/docs/models.

Ein eigener (mürrischer) Chat

In diesem Abschnitt wollen wir eine einfach Webanwendung bauen, die so ähnlich funktioniert wie ChatGPT. Damit der Rahmen nicht gesprengt wird, halten wir die Anwendung möglichst einfach. Den fertigen Chat findest du in meinem GitHub-Repostory: https://github.com/ki-zeitalter/openai-api-tutorial. Checke gerne das Projekt aus, clone es und spiele damit rum oder erweitere es. Wenn du etwas cooles daraus baust, dann würde ich mich über eine Nachricht freuen! wink

Warum ist der Chat mürrisch? Einfach nur so. Damit will ich nur zeigen, was möglich ist. Du kannst es natürlich anpassen.

Aufbau

Die kleine Anwendung besteht aus einem einfachen Backend, das die Eingaben der Weboberfläche entgegen nimmt und an die OpenAI API sendet. Wir nutzen hier Flask als Webserver. Denke daran, dass wenn du vorhast etwas ernsthaftes zu bauen, dann ist Flask nicht die geeignete Wahl. Hier ist es allerdings aufgrund seiner Einfachheit, genau das Richtige.

Außerdem nutzen wir eine Handvoll weiterer Bibliotheken, die uns bei den Aufgaben helfen. Welche das sind, steht in der requirements.txt Datei.

Vorbereitung

Die notwendigen Bibliotheken müssen wir erstmal installieren. Das kannst du entweder händisch machen, indem du jede Bibliothek in requirements.txt mit pip install installierst oder du machst es direkt so:

pip install -r requirements.txt

Falls du hier „mitprogrammierst“ und nicht das Projekt aus GitHub ausgecheckt hast, dann muss du zuvor die requirements.txt Datei anlegen:

requirements.txt

openai==0.27.8
Flask==2.3.2
pyhton-dotenv==1.0.0

Frontend

Jetzt können wir mit dem Code anfangen. Zunächst legen wir im Unterverzeichnis „templates“ eine Datei mit dem Namen index.html an.

Zunächst legen wir den Header-Bereich der HTML-Datei an:

templates/index.html

<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.7.0.min.js"
integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"></script>
<title>OpenAI API Tutorial - Eigener ChatGPT</title>
</head>
[...]
</html>

Im Header importieren wir zum einen Bootstrap und JQuery. Bootstrap, eine CSS-Bibliothek, hilft uns die Webseite ein wenig hübscher aussehen zu lassen. Auf die Details dazu, gehe ich hier nicht ein. Mehr Infos findest du auf https://getbootstrap.com/

JQuery ist eine JavaScript-Bibliothek, die uns später behilflich wird auf einzelne Elemente der Seite zuzugreifen um z.B. den Senden-Button zu deaktivieren während eine Übertragung läuft.

Jetzt widmen wir uns dem body zu. Zunächst fügen wir eine Überschrift ein und einen Bereich, wo wir die bisherigen Chat-Nachrichten ausgeben:

<body>
<div class="container">
<div class="row">
<div class="col">
<h1>OpenAI API Tutorial - Eigener ChatGPT</h1>
</div>
</div>
{% for entry in chat_entries %}
<div class="row">
<div class="col-md-1">
{{ entry['role'] }}
</div>
<div class="col">
<span style="white-space: pre-line">{{ entry['content'] }}</span>
</div>
</div>
{% endfor %}
[...]
</div>
</body>

Die for-Schleife iteriert über die chat_entries. Dabei handelt es sich um eine Variable, die im Backend-Code gehalten wird und durch Flask hier eingefügt wird. Jeder Eintrag enthält dabei die Felder für die Rolle („role„), also wer hat diesen Eintrag verfasst und den eigentlichen Text („content„).

Bei der Ausgabe des Inhaltes nutzen wir eine CSS-Style-Angabe „pre-line„. Die API liefert nämlich die Antworten als Plain-Text, also mit ganz normalen Zeilenumbrüchen. Diese werden ja in HTML ignoriert. Durch die Style-Angabe werden sie jedoch berücksichtigt.

Jetzt haben wir den Ausgabebereich definiert, fehlt noch eine Eingabemöglichkeit. Unterhalb der for-Schleife fügen wir also folgendes ein:

<form action="/send_prompt/" method="post" id="promptForm">
<div class="row">
<div class="col-md-1">user</div>
<div class="col-md-10">
<input class="form-control" id="prompt-input" type="text" placeholder="Gib hier deinen Prompt ein"
name="prompt" />
</div>
<div class="col-md-1">
<button id="sendButton" class="btn btn-primary" type="submit" name="Senden">Senden</button>
</div>
</div>
</form>

Wir haben hier also ein HTML-Formular, das die eingegebenen Daten an die Adresse „/send_prompt/“ sendet.

Wir haben ein Eingabefeld für den Prompt des Benutzers und einen Button zum Absenden.

Zu guter letzt wollen wir, wenn der Button gedrückt wird, dass der Button deaktiviert wird, damit während der Übertragung nicht noch eine Anfrage gesendet wird. Außerdem wäre eine Ladeanzeige ganz nett.

Das erreichen wir indem wir mit etwas JavaScript-Code das Absenden des Formulars abfangen. Außerdem muss BootStrap initialisiert werden, was wir hier auch erledigen. Folgenden Code fügen wir direkt nach dem Formular, vor dem </body>-Tag ein:

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
crossorigin="anonymous"></script>
<script>
$(document).ready(function () {
$("#sendButton").click(function () {
$(this).prop("disabled", true);
$(this).html(
`<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>`
);
$("#promptForm").submit();
});
});
</script>

Backend

Jetzt widmen wir uns dem Backend-Code, wo die eigentliche Arbeit passiert. Im Hauptverzeichnis des Projektes legen wir eine Datei mit dem Namen chat.py an.

Wir beginnen damit die notwendigen Bibliotheken zu importieren:

import openai
import os
from dotenv import load_dotenv, find_dotenv
from flask import Flask, render_template, request

Wir importieren, so wie wir das schon kennen, die openai Bibliothek. Ausserdem laden wir ein paar andere Bibliotheken, die benötigt werden. Die Bibliotheken „os“ und „dotenv“ ermöglichen es uns den API-Key über eine Umgebungsvariable zugänglich zu machen.

Die „flask“ Bibliothek bietet uns die Webserver-Funktionalität.

Danach müssen wir einiges an Initialisierung vornehmen:

load_dotenv(find_dotenv())
api_key = os.getenv('API_KEY')
openai.api_key  = api_key
app = Flask(__name__)

Zuerst suchen und laden wir mit load_dotenv(find_dotenv()) eine Datei mit dem Namen .env. Wir haben die Möglichkeit den API-Key per Umgebungsvariable, die wir mit Betriebssystem-Mitteln oder mittels .env zu seten.

Den ermittelten API-Key übergeben wir anschliessend an die openai Bibliothek.

Zuletzt erstellen wir eine Instanz von Flask.

Wir müssen jetzt angeben, was Flask eigentlich an den Webbrowser liefern soll, wenn wir die Seite aufrufen:

chat_entries = [{'role':'system', 'content':'Du bist ein genervter Chatbot. Du antwortest auf die Fragen, aber auf eine genervte Art und Weise'}]
@app.route('/')
def index():
return render_template('index.html', chat_entries = chat_entries)

Erstmal definieren wir die chat_entries Variable und initialisieren diese direkt mit einem Wert. Dieser Wert gibt an, dass die Rolle „system“ ein genervter Chatbot sein soll. Mehr dazu gleich.

Anschliessend definieren wir, dass wenn unser Webserver (ohne Pfad bzw. „/“) aufgerufen wird, dass dann die index.html angezeigt werden soll. Die zuvor angelegte Variable chat_entries machen wir dabei im Template bekannt.

Jetzt müssen wir den Empfangs-Endpunkt für die Formular-Eingabe definieren:

@app.route("/send_prompt/", methods=['POST'])
def send_prompt():
chat_entries.append(
{'role':'user', 'content': request.form["prompt"]}
)
print("Sende Prompt...")
response = send_prompt_to_openai()
print(f"response={response}")
chat_entries.append(response.choices[0].message)
return render_template('index.html', chat_entries=chat_entries);

Die Route definieren wir als „/send_prompt/“, wie wir es in dem Formular als Ziel definiert haben.

Jetzt fügen wir den Eingegebenen Text zu den chat_entries hinzu und geben dabei die Rolle „user“ an, da dieser Text ja von dem Benutzer stammt.

Anschliessend möchten wir die Prompts an OpenAI senden. Diese Funktion definieren wir gleich.

Die Antwort, die wir erhalten entspricht dem, was ich weiter oben beschrieben habe. Aus der Antwort extrahieren wir den „message“ Teil und fügen es den chat_entries hinzu. Der Aufbau der „message“ ist ja {‚role‘:’…‘, ‚content‘: ‚…‘} wie der initiale Wert, den wir weiter oben hinzugefügt haben.

Das bedeutet, dass wenn der Benutzer jetzt einmal einen Prompt abgeschickt hat, dass wir drei Nachrichten in der Liste haben: die Nachricht von der Rolle „system„, die Nachricht von dem Benutzer „user“ und die Antwort von OpenAI in der Rolle „assistant„. Diese drei Nachrichten zeigen wir jetzt auf der Weboberfläche an. Gibt der Benutzer nun noch einen Prompt ein und schickt ihn ab, dann haben wir nach der Antwort von OpenAI zusätzlich diese zwei Nachrichten in der Liste. So geht es praktisch immer weiter.

Der Hintergrund davon ist, dass OpenAI sich nicht merkt, was du bisher eingegeben hast. Du musst also jedes Mal die ganze Konversation übertragen. Auch die vorherigen Antworten. Diese Reihe von Nachrichten bilden also den Kontext. Das bewirkt also, dass man sich in dem nächsten Prompt auf die Nachrichten davor beziehen kann, z.B. um OpenAI zu bitten die vorherige Antwort ausführlicher zu machen usw.

Die initiale erste Nachricht, mit der Rolle „system“, gibt dem System an, wie sich der Assistent verhalten soll. Wenn du ChatGPT nutzt, dann wird dir das praktisch versteckt. Der Standard-Wert ist nämlich „You are a helpful assistant.“. Passe das einfach deinen Wünschen an.

An letzter Stelle dieser Funktion veranlassen wir Flask die Seite index.html zu zeigen und übergeben dabei wieder die Variable chat_entries.

Was noch fehlt, ist die Funktion zum Senden:

def send_prompt_to_openai(model="gpt-3.5-turbo", temperature=0):
response = openai.ChatCompletion.create(
model=model,
messages=chat_entries,
temperature=temperature
)
return response

Die Funktion zum Senden akzeptiert zwei Parameter „model“ und „temperature„, die jeweils aber mit Standardwerten vorbelegt werden.

Der Parameter model ist relativ selbsterklärend, denn damit können wir das Sprachmodell angeben.

Der Parameter temperature ist jedoch neu für uns. Mit temperature können wir steuern wie OpenAI antwortet. Bei temperature=0 antworten OpenAI relativ genau, d.h. die Antwort mit der größten Wahrscheinlichkeit wird zurück gegeben. Möchte man OpenAI etwas mehr Freiheit geben, dann kann man den Wert höher wählen, z.B temperature=0.5. Jetzt werden nicht unbedingt die wahrscheinlichsten Antworten geliefert und wenn man den gleichen Prompt wiederholt, dann gibt es mehr Variationen der Antwort. Man kann also sagen, man steuert hiermit die Kreativität. Tipp: möchte man möglichst genaue und „richtige“ Antworten bekommen, sollte man mit dem Wert 0 arbeiten. Möchte man jedoch etwas kreatives bekommen, dann wählt man einen höheren Wert.

Jetzt sind wir mit dem Chat fast fertig und müssen nur noch den Startpunkt für das Python-Skript festlegen:

if __name__ == "__main__":
app.run(host='0.0.0.0')

Beim Ausführen des Python-Skriptes wird dieser Code nun ausgeführt und Flask wird veranlasst einen Webserver zu starten.

Lege nun im gleichen Verzeichnis eine .env Datei an und trage dort deinen API-Key ein:

API_KEY=dein API-Key an dieser Stelle

Jetzt kannst du den Chat mit folgendem Befehl starten:

 

python chat.py

Die Anwendung startet und Flask wird einen Webserver auf http://localhost:5000 starten. Öffne diese URL im Browser und viel Spaß beim Chatten mit dem genervten Assistenten!

Ende Teil #1

Das war Teil #1 der Tutorial-Reihe über die OpenAI API (ChatGPT). Ich hoffe es hat dir gefallen!

Im nächsten Teil schauen uns die weiteren APIs an, mit denen man z.B. Bilder mit einem Prompt generieren kann uvm.

Ausserdem gibt es noch ein paar Hintegrund-Infos, die nützlich sein könnten, z.B. welche Modelle es gibt und was die Unterschiede sind.

Hier geht es zum zweiten Teil: https://ki-zeitalter.de/openai-chatgpt-api-tutorial-teil-2-modelle-und-dall-e/