KoLab-Chatbot

Im Sommer 2023 entwickelten die KoLab Mitarbeiter Max Schweder und Michael Nguyen einen ChatBot-Avatar für das Digitale Koproduktions-labor. Unter Verwendung der OpenAI API baute die Entwicklung auf dem Workflow von Youtuber Sercan Altundas auf (Sarge, https://www.youtube.com/@sgt3v). 

Der Programmcode wurde auf GitHub veröffentlicht, um Künstler*innen bei der Erschaffung eigener KI-Avatare zu unterstützen:

GitHub Link folgt

Hintergrund für die Entwicklung des Bots waren wiederholte Anfragen an das Labor, ob man auf Messen und sonstigen Veranstaltungen präsent sein könnte, um sich und die Arbeit des Labs vorzustellen. Die Idee war, dass diese Aufgabe zukünftig vom Chatbot übernommen werden sollte, der Fragen der Besucher*innen zum Labor beantwortet. Außerdem fungierte der Avatar durch seine audiovisuell ansprechende Umsetzung ebenfalls als eine technische und künstlerische Demonstration.

Der Chatbot beim DigiDay 2023 der SIHK Hagen…
…und der Eröffnung der Akademie für Theater und Digitalität.

Hinweis: Die Arbeit an dem ChatBot startete Anfang April 2023 zu einem Zeitpunkt, zu dem OpenAI das Feature von “Custom GPTs” noch nicht veröffentlicht hat. Dieses wurde erst im November 2023 eingeführt. Ebenso nutzten wir APIs verschiedener Anbieter (OpenAI, Meta, Amazon), die wir wie in einem Baukastensystem zusammensetzten, um die benötigten Features zu implementieren. Auch dies ist heute einfacher und kann theoretisch über einen einzigen Anbieter umgesetzt werden.

Unabhängig davon ergaben sich im Zuge der technischen Implementierung des Bots spannende und für weitere Projekte verallgemeinerbare Fragestellungen, die es zu beantworten galt: 
Wie erweitert man das Sprachmodell mit speziellem und aktuellem Wissen?
Im Sommer 2023 hatte OpenAI zwar ChatGPT via API zugänglich gemacht, es gab aber noch keine Möglichkeit, dem Sprachmodell aktuelle Informationen hinzuzufügen, ohne selbst aufwändiges Finetuning zu betreiben.

  1. Wie bringt man das Sprachmodell dazu, stabil “in Character” zu bleiben und als Mitarbeitende des Koproduktionslabors zu antworten?
  2. Wie kann man mithilfe des Sprachmodells einen Avatar “zum Leben erwecken“, der auf gesprochene Sprache reagiert und die fragende Person darüber hinaus anschaut?
    Im Sommer 2023 hatte OpenAI noch keine eigene Text-to-Speech Lösung veröffentlicht. Bilderkennung gab es ebenfalls noch nicht.
  3. Wie geht man mit unumgänglichen Latenzen des Systems um, ohne die Nutzer zu irritieren?

Für die Entwicklung des ChatBots waren die Tutorials des Youtubers Sercan Altundas (@Sarge) https://www.youtube.com/@sgt3v  von zentraler Bedeutung. Zum damaligen Zeitpunkt hatte er eine der umfangreichsten Video-Tutorial Reihen zur Anbindung  der OpenAI API in Unity verfasst.
Der ChatBot des KoLab basiert in großen Teilen auf dieser Vorarbeit. Im besonderen geht es um diese beiden Videos:

Making ChatGPT in Unity!
https://www.youtube.com/watch?v=MQfVCY9qgEU

Making NPCs with ChatGPT in Unity!
https://www.youtube.com/watch?v=Cg4k-XPBC2Q

Kurz zusammengefasst erklärt Sarge die Verwendung der OpenAI API innerhalb von Unity. Im zweiten Video geht es dann konkret um die Animation eines ReadyPlayerMe Avatars mithilfe von Oculus Lipsync for Unity: (https://developer.oculus.com/documentation/unity/audio-ovrlipsync-unity/?locale=de_DE)

Mithilfe dieses Basis-Setups konnte Max Schweder relativ schnell einen Avatar erstellen, der gesprochene Fragen beantworten konnte. Sprachaufnahmen wurden dazu zunächst automatisch transkribiert (Speech-to-Text) und als Text-String an die API übergeben. Aus der Antwort in Textform wurde anschließend eine Sprachaufnahme des Avatars generiert (Text-to-Speech). Der mit https://readyplayer.me/ erzeugte Avatar konnte mithilfe von Lipsync die Antworten animiert wiedergeben. 

Um ChatGPT mit eigenen Informationen zu füttern, in diesem Fall Hintergrundinformationen zum Digitalen Koproduktionslabor und den dort stattfindenden Projekten, Mitarbeitenden etc., erweiterte Max dieses Setup um einige Schritte.

Zusätzlich implementierte Michael ein System, mit dem dem Avatar eine Frage per Sprache gestellt werden konnte, ohne die Notwendigkeit einen Knopf zu drücken oder ein Trigger-Wort zu verwenden (vgl. “Alexa”, “OK Google”). Dieses System erkennt automatisch, wo der Beginn und das Ende einer Frage liegen und erlaubt ebenso kurze Sprechpausen beim Stellen der Frage. Außerdem wird sichergestellt, dass der Beginn einer Frage nicht abgeschnitten wird (Latenzen beim Einschalten des Mikrofons in Unity erfordern ein ausgeklügelteres Verfahren als einen einfachen Lautstärke-Trigger). Als Ausgangsbasis diente das LASP Unity-Plugin von keijiro: https://github.com/keijiro/Lasp

Hier unser erweiterter Workflow:


State Pattern

Für die Programmierung des Bots entschieden wir uns, ein sog. “State Pattern” einzusetzen. Der Bot befindet sich demnach zu jedem Zeitpunkt in einem bestimmten Zustand bzw. State, der durch eine spezifische Handlung definiert ist. Folgende Zustände wurden dabei implementiert: 

Waiting: Der Bot wartet auf die Frage, die per Spracheingabe erfolgt.

Listening: User*innen stellen gerade eine Frage und der Bot hört bis zum Ende der Frage zu.

Understanding: Über die OpenAI API wird die Aufnahme transkribiert. Der Chatbot antwortet mit einer zufälligen Antwort aus vorgefertigten Aufnahmen (z.B. “Lass mich kurz überlegen…”),, um die Latenz zu überbrücken.

Thinking: Der “PDF-Chat” wird durchgeführt und die Textantwort wird in einen Audioclip umgewandelt. Fluid-Animationen visualisieren diesen “Denkprozess”.

Answering: Der Bot antwortet auf die gestellte Frage.

Die States werden dabei sequentiell durchlaufen ehe nach Beendigung der Antwort (Answering State) zurück in den Waiting State gesprungen wird. States können dabei nicht übersprungen werden, da jede Aktion des Bots aufeinander aufbaut. Jeweilige Zustandswechsel werden dabei über Events ausgelöst. Mögliche Events sind z.B. die Response einer API oder das Ende der Audiodatei der Bot-Antwort.

Die Verwendung des State Patterns ermöglichte eine sauber getrennte Programmierung der verschiedenen Aktionen des Bots, bei denen unterschiedliche API Calls, Lese- und Schreibprozesse sowie Sprachein- und -ausgabe erfolgen.

Einzelne States konnten dadurch auch separat voneinander getestet und debugged werden.

Embedding Prozess

LLMs werden mit einer großen Menge an allgemeinen Texten und Textbausteinen trainiert, um auf eine möglichst große Zahl von sprachlichen Situationen reagieren zu können. 

Das “Wissen”, das man hierbei von den LLMs abfragen kann, ist daher auch sehr allgemein. Liegen Ereignisse oder Informationen nach dem Trainingszeitraum der LLMs, so können sie Fragen zu diesen Ereignissen oder Informationen nicht beantworten. Unterschiedliche LLMs sind außerdem mit bestimmten Schwerpunkten trainiert und können so besser auf spezifische Themengebiete oder Fragestellungen eingehen. Im Kontext der Entwicklung unseres ChatBot-Avatars standen wir vor der Herausforderung, das allgemeine Wissen von ChatGPT um spezifische, aktuelle Informationen zum Koproduktionslabor und dessen Projekten, Mitarbeitenden und Veranstaltungen zu erweitern.

Der Embedding-Prozess bot hierfür eine innovative Lösung. Anstatt das LLM durch langwieriges und ressourcenintensives Finetuning zu spezialisieren, nutzten wir Embeddings, um spezifische Informationen zugänglich zu machen. Embeddings sind hochdimensionale Vektoren, die Textinhalte in einem kontinuierlichen Vektorraum repräsentieren. Durch das Erstellen von Embeddings für spezifische Informationen und das Einbinden dieser in den ChatGPT-Workflow konnten wir das Modell um zusätzliches, aktuelles Wissen erweitern.

Dieser Prozess beginnt mit der Auswahl relevanter Textdokumente, die Informationen über das Koproduktionslabor enthalten. Im Falle des ChatBots nutzten wir Sachstandstexte, mit denen wir unsere Arbeit im KoLab dokumentieren. Hierbei gibt es für jedes Projekt im KoLab einen eigenen Dokumentationstext. Diese Texte werden schließlich in Embeddings umgewandelt, die das LLM nutzen kann, um Antworten zu generieren, die auf diesen spezifischen Informationen basieren. Der Vorteil dieses Ansatzes liegt in seiner Effizienz und Flexibilität: Änderungen oder Ergänzungen im Informationspool können schnell umgesetzt werden, indem neue Embeddings erstellt und hinzugefügt werden, ohne das Grundmodell von ChatGPT neu trainieren zu müssen.
Um diesen Prozess im ChatBot-Avatar zu integrieren, entwickelten wir eine Pipeline, die automatisch Textdokumente in Embeddings umwandelt und diese dem ChatGPT-Modell zur Verfügung stellt. 

Prompt Zusammenbau

Das innovative an der OpenAI Schnittstelle ist, dass das Verhalten des Bots bzw. wie er auf eine Frage antworten soll, mit einer einfachen Textanweisung (Prompt) definiert werden kann. Ebenso kann der Charakter des Bots durch den Prompt gesteuert werden. Um sinnvolle Antworten zu erhalten und fehlerhafte Antworten zu vermeiden, ist es wichtig, Prompts zu testen und zu modifizieren. Der schlussendlich gewählte Prompt ist folgender:

“Du bist eine digitale Mitarbeiterin des Koproduktionslabors und hast ein Gespräch mit einem Menschen. Antworte möglichst kurz. Versuche folgende Fragen anhand der folgenden Textabschnitte aus einem langen Textdokument zu beantworten. Wenn die Frage allgemein ist, beantworte sie ohne die Textabschnitte zu beachten. Wenn es keine Textabschnitte gibt, sag, dass du dazu deine Kolleg*innen befragen müsstest und stelle dann eine Gegenfrage zum Thema KoLab oder Digitale Kunst. Sag statt Text oder Textabschnitt lieber etwas wie zum Beispiel, dass du dazu leider keine Infos hast oder etwas ähnliches, umgangsprachliches. Vermeide Abkürzungen.”

Ebenso stellte sich heraus, dass bei unsinnigen Aufnahmen (z.B. keine erkennbare Sprache, Stille, etc.) der Bot auf Basis von Textbausteinen antwortet, die er in Metadaten von Dokumenten gefunden hat. Um dies zu eliminieren, wurde ein Script erstellt, das diese Strings herausfiltert und stattdessen eine generische Antwort auswählt, z.B. “Ich habe dazu leider keine Informationen”.

User Tracking

Um das Gefühl der Echtzeit-Interaktion mit dem Bot zu verstärken, wurden die Gesichter der User*innen getrackt, sodass der Bot stets Augenkontakt hält und den Kopf immer in Richtung der Position der User*innen ausrichtet. Für das Face-Tracking ist keine spezielle Kamera nötig, da über den Unity-Inspector jede angeschlossene Kamera (d.h. auch eine eingebaute Webcam) ausgewählt werden kann.
Die Gesichtserkennung wurde mithilfe des” MediaPipe BlazeFace” Models umgesetzt: https://sites.google.com/view/perception-cv4arvr/blazeface

Bei der Unity-Integration des Models half folgendes Github Repository von keijiro: https://github.com/keijiro/BlazeFaceBarracuda


Visuelles Feedback

Um das (visuelle) Feedback des Bots zu erhöhen und User*innen einen Indikator darüber zu vermitteln, in welchem Zustand (State) der Bot sich gerade befindet, wurden verschiedene Fluid Animationen erstellt, die die Denkprozesse des Bots veranschaulichen. Vor allem während des Thinking States, in dem der PDF-Chat und API-Calls durchgeführt werden, die eine gewisse Zeit in Anspruch nehmen können, wird der “Ladeprozess” durch die sich in Bewegung setzende Fluid Animation dargestellt. 
Ebenso wird sowohl die transkribierte Frage als auch der Antworttext auf den weißen Hintergrund projiziert.

Eine Fluid-Animation auf dem Kopf des Avatars visualisiert die verschiedenen Zustände des Bots.



ChatGPT API Anbindung: Sercan Altundas (@sgt3v)
Amazon Polly Anbindung: Sercan Altundas
Avatar Animation via LipSync: Sercan Altundas
Embeddings Pipeline für “Wissen via PDF”: Max Schweder (@drzerschwederer)
Audio Recording System: Michael Nguyen (@micngu1)
Statemachine Programmierung: Michael Nguyen
Avatar Head Design: Simon Lütkehaus (@simon.lue)
Fluid and Shader Design: Max Schweder


0 Antworten zu „KoLab-Chatbot“