KI-Projekte – Künstliche Intelligenz für Maker – Pollux Labs https://polluxlabs.net Arduino, ESP32 & ESP8266 | Projekte & Tutorials Wed, 06 Nov 2024 11:01:32 +0000 de hourly 1 https://wordpress.org/?v=6.6.2 https://polluxlabs.net/wp-content/uploads/2020/05/cropped-pollux-labs-p-32x32.png KI-Projekte – Künstliche Intelligenz für Maker – Pollux Labs https://polluxlabs.net 32 32 Narratron – Schattenspiel und Geschichten von der KI https://polluxlabs.net/raspberry-pi-projekte/narratron-schattenspiel-und-geschichten-von-der-ki/ Sun, 16 Jun 2024 08:03:36 +0000 https://polluxlabs.net/?p=16638 Narratron – Schattenspiel und Geschichten von der KI Weiterlesen »

]]>
Bei Pollux Labs findest du zahlreiche KI-Projekte, mit denen du dir zum Beispiel Bilder erklären und die aktuelle Nachrichtenlage zusammenfassen lassen kannst. Ein weiteres interessantes Projekt habe ich bei Creative Applications gefunden: Narratron.

Hierbei handelt es sich um ein Gerät, das Schattenspiel-Figuren erkennt und auf dieser Basis per künstlicher Intelligenz eine Geschichte entwickelt, vertont und illustriert. Die beiden Maker Aria Xiying Bao und Yubo Zhao haben hierfür ein ansprechendes Gehäuse gedruckt, in dem die Hardware untergebracht ist – und das an Spielzeug aus alten Zeiten erinnert, wie zum Beispiel kleine Fernseher, deren Bilder man per Klick weiterdreht.

Hier eine Demonstration des Projekts:

Du findest es auf der Webseite von Creative Applications.

Technologie

Zum Einsatz kommt in diesem Projekt unter anderem Googles Teachable Machine, OpenAIs GPT-4 und Stable Diffusion für die Erzeugung der Bilder. Falls dich dieses Projekt interessiert und du es nachbauen möchtest, findest du hierfür hilfreiche Projekte auf Pollux Labs:

Die beiden Entwickler haben leider nicht den Code für ihr Projekt veröffentlicht – aber mit den genannten Tutorials kommst du schon ein ganzes Stück weiter. Hardwareseitig schweigen sie sich auch aus, aber ich würde vermuten, dass du darin als Hauptbestandteile einen Raspberry Pi Zero (oder sogar ein kleineres Board) und eine Kamera mit starker Beleuchtung finden könntest.

Auch einen Projektor muss es darin geben, denn die von Stable Diffusion erstellten Bilder, werden auf eine Leinwand bzw. helle Fläche projiziert.

Alles in allem ist dieses Projekt eine tolle Demonstration, wie moderne KI-Anwendungen sich mit der haptischen und gegenständlichen Welt verbinden lassen – auch wenn von künstlicher Intelligenz geschriebene und vorgelesene Geschichten verständlicherweise nicht jedermanns Sache sein dürften.

]]>
Codestral und Claude 3.5 Sonnet in VS Code verwenden https://polluxlabs.net/python-tutorials-und-projekte/codestral-und-claude-3-5-sonnet-in-vs-code-verwenden/ Thu, 13 Jun 2024 19:17:51 +0000 https://polluxlabs.net/?p=16572 Codestral und Claude 3.5 Sonnet in VS Code verwenden Weiterlesen »

]]>
Vielleicht kennst du schon den GitHub Copilot – ein Programmier-Assistent, den du z.B. in Visual Studio Code verwenden kannst. Eine Alternative bietet das französische KI-Unternehmen Mistral AI: Codestral – ein Sprachmodell, das auf Programmiersprachen spezialisiert ist.

Codestral kannst du entweder ähnlich wie den Copilot verwenden oder damit chatten, wie du es von ChatGPT gewohnt bist. Aktuell (Juni ’24) bietet Mistral für das Sprachmodell eine Testphase an, sodass du es kostenlos verwenden kannst. Aber auch nach Ende dieser Phase dürften die Preise der API anfallen, die nach Anzahl der tatsächlich verwendeten Token abgerechnet wird – im Gegensatz zu den pauschalen 10$ des GitHub Copilots.

In diesem Tutorial erfährst du, wie du mit Codestral Code erstellen kannst und es in Visual Studio Code einbettest, damit das Modell dir dort bei deinen Projekten zur Seite steht.

Update zu claude 3.5 Sonnet

Kurz nach der Veröffentlichung erschien das Modell Claude 3.5 Sonnet von Anthropic. Dieses Sprachmodell erzielt meiner Meinung noch bessere Ergebnisse. Wie du Claude 3.5 in VS Code einbettest, erfährst du weiter unten in diesem Tutorial.

Das ist Codestral

Ende Mai 2024 hat Mistral AI ihr neuestes Sprachmodell vorgestellt, das auf die Erstellung von Code spezialisiert ist. Codestral beherrscht laut Angaben des Entwicklers über 80 Programmiersprachen, darunter Python, C++, Java und JavaScript. Mit 22 Mrd. Parametern und einen Kontextfenster von 32.000 Token soll es alle anderen bis zur Veröffentlichung verfügbaren Sprachmodelle in vielen Benchmarks übertreffen.

Codestral Benchmark Ergebnisse

Auch wenn es hierbei um keine Quantensprünge im Vergleich zum in den einzelnen Sprachen jeweils dahinter liegenden LLM handelt, ist Codestral doch offensichtlich ein sehr ernstzunehmender Mitspieler.

Das Unternehmen Mistral AI wurde 2023 in Paris gegründet und versteht sich selbst als europäische Alternative zu amerikanischen Anbietern wie OpenAI, Meta oder Google. Die Qualität ihrer Arbeit kann dabei überzeugen – neben dem hier vorgestellten Sprachmodell hat es auch Mixtral 8x7B entwickelt, eins der besten derzeit verfügbaren Large Language Models.

Eine Besonderheit ist dabei die Veröffentlichung als Open Source. Du kannst die Modelle von Mistral AI deshalb zu nichtkommerziellen Zwecken also über Ollama lokal auf deinem eigenen Rechner installieren und nutzen – falls dieser stark genug dafür ist.

Chatten mit Codestral

Um die Fähigkeiten von Codestral zu testen, brauchst du nichts weiter als ein kostenloses Nutzerkonto. Um eines anzulegen, besuche die Webseite von Mistral AI, klicke auf Log in und dann auf Registrieren. Nachdem du deine verwendete E-Mail-Adresse verifiziert hast, musst du einen Workspace anlegen. Vergib einen Namen deiner Wahl und wähle Einzelnutzer (es sei denn du registriert dich als Unternehmen).

Lies und akzeptiere die Nutzungsbedingungen und klicke anschließend auf Workspace erstellen – fertig. Im Menü oben siehst du nun den Punkt Le Chat. Klicke hierauf und es öffnet sich ein Bereich, den du so ähnlich vermutlich bereits von ChatGPT kennst.

Rechts findest du ein Eingabefeld, in das du deine Frage bzw. Anweisung eintragen kannst. Darunter befindet sich ein Dropdown-Menü, in dem du das Sprachmodell einstellst. Wähle hier Codestral aus.

Anschließend kann es gleich mit einem Test weitergehen:

Schreibe einen Sketch für den Arduino, der im Setup "Hello world" im Seriellen Monitor ausgibt.

Und hier das das Ergebnis in Le Chat:

void setup() {
  // Öffne die serielle Verbindung mit einem Baudrate von 9600
  Serial.begin(9600);

  // Schreibe "Hello world" in den Seriellen Monitor
  Serial.println("Hello world");
}

void loop() {
  // Hier ist nichts, da wir nur im Setup eine Nachricht ausgeben wollen
}

Diese einfache Aufgabe hat Codestral also gemeistert. Den Prompt habe ich auf Deutsch geschrieben. In der Dokumentation zum Sprachmodell ist Englisch als Eingabesprache vermerkt – möglicherweise erhältst du auf Englisch bessere Ergebnisse bei komplizierteren Anweisungen, da dein deutschsprachiger Prompt nicht erst übersetzt werden muss.

So weit, so gut. Falls du möchtest, teste hier doch ein paar härtere Nüsse. Beeindruckend ist jedenfalls die Geschwindigkeit, mit der Antworten generiert werden – die scheint mir tatsächlich sogar etwas höher als jene des momentan aktuellen OpenAI-Modells GPT-4o zu sein.

Codestral in Visual Studio Code verwenden

Nun zu einer weiteren Anwendung von Codestral. Du kannst das Modell ähnlich wie den Copilot in Visual Studio Code integrieren, damit es dir dort beim Programmieren zur Seite steht. Das bedeutet, dass du einerseits einen Chat zur Verfügung hast, ähnlich wie jenen in Le Chat auf der Webseite von Mistral AI. Andererseits kannst du direkt mit deinem Sketch oder Script interagieren, indem du Codestral ums Debugging oder eine Ergänzung deines Codes bittest.

Um Codestral in VS Code verwenden zu können, benötigst du zunächst eine Extension bzw. Plugin sowie einen API-Schlüssel von Mistral AI. Wie eingangs erwähnt, ist letzterer aktuell (Juni ’24) innerhalb der Testphase kostenlos. Und die Extension ist natürlich auch kostenlos.

Continue installieren

Öffne zunächst die Bibliothek für die Extensions uns suche nach Continue und installiere die Erweiterung mit einem Klick auf Install.

Continue.dev in VS Code installieren

Öffne nun das Plugin und wähle im ersten Screen Use your API key. Wie vorhin erwähnt, könntest du Codestral auch lokal auf deinem Rechner ausführen, sofern er leistungsstark genug ist. Auf der nächsten Seite kannst du nun im ersten Dropdown-Menü die Mistral API, und im zweiten dann Codestral auswählen.

Anschließend benötigst du den API-Key von Mistral, den du vermutlich noch nicht hast. Mit einem Klick auf Get API Key gelangst du auf die entsprechende Webseite von Mistral:

Codestral Zugang anfordern

Wähle im Menü links Codestral aus und klicke dann rechts auf den Button Zugang anfordern. Anschließend benötigst du eine Handynummer, auf die du einen Code zur Verfizierung zugesendet bekommst. Anschließend kannst du nun den API-Key erstellen, mit einem Klick auf den Button API-Schlüssel erstellen.

Kopiere anschließend den Key und trage ihn in Visual Studio Code in das entsprechende Feld ein. Mit einem Klick auf Done gelangst du auf den letzten Screen der Einrichtung. Wähle dort Free Trial (Codestral) aus und melde dich mit deinem GitHub-Konto an. Falls du noch keines hast, kannst du es dir kostenlos einrichten.

Codestral in Visual STudio Code verwenden

Das wäre nun also geschafft. Zeit für ein paar erste Tests. Für eine bessere Bedienbarkeit von Continue ziehe das Logo in VS Code vom Menü links in die rechte Sidebar. So hast du Zugriff auf den Chat, ohne dass du deinen Code im Hauptbereich verlassen musst.

Probiere es gleich aus, zum Beispiel mit dem Prompt, der auch schon in Le Chat zum Einsatz kam:

Das funktioniert schon mal. Aber das ist natürlich nicht alles: Du solltest einen Tab namens continue_tutorial.py sehen, das dir eine Einführung in das Plugin gibt.

Darin siehst du verschiedene Code-Abschnitte und Anweisungen, die dich mit wichtigen Tastenkombinationen und den Möglichkeiten von Continue und Codestral vertraut machen.

So kannst du zum Beispiel Code markieren (im Tutorial die abgebildete Funktion) und mit der Kombination Cmd + L (Mac) wieder den Bereich rechts öffnen und eine Frage dazu stellen – also zum Beispiel was mit ihr angestellt wird. Die Kombination Cmd + I ermöglicht es dir, Code nach deinen Wünschen ändern zu lassen.

Noch praktischer ist das Debugging. Das Tutorial fordert dich im dritten Teil dazu auf, es auszuführen, was zu einem Fehler führt. Mit Cmd + Shift + R startest du die Fehlersuche, die du wieder im rechten Teil sehen kannst. Die verbesserte Funktion kannst du dann mit einem Klick in das Script einfügen – Problem gelöst.

Claude 3.5 Sonnet in VS Code einbinden

Neben Codestral eignet sich auch das LLM Claude 3.5 Sonnet von Anthropic hervorragend, um dir in Visual Studio Code zur Seite zu stehen. Um dieses Modell zu verwenden, kannst du ebenfalls Continue einsetzen – du musst lediglich deinen API Key von Anthropic und das gewünschte Modell hinterlegen.

Apropos API Key: Falls du noch keines hast, erstelle zunächst einen Account bei Anthropic. Anschließend kannst du einen Key hier erstellen. Hierfür benötigst du jedoch etwas Guthaben, denn deine Kommunikation mit Claude 3.5 wird (wie bei der API von OpenAI) nach den verwendeten Tokens abgerechnet. Das Guthaben von mindestens 5$ kannst du in deinem Konto einzahlen. Auf der Webseite von Anthropic findest du die aktuelle Preisliste für die API.

Um Claude 3.5 in Continue (und damit in VS Code) einzubinden, klicke unten links auf das Plus neben dem aktuell gewählten Modell:

Sprachmodelle in Continue auswählen

Anschließend siehst du eine Auswahl von KI-Anbietern. Wähle dort Anthropic aus. Anschließend siehst du die folgende Eingabemaske:

Trage in das erste Feld deinen API Key von Anthropic ein und wähle darunter irgendein Modell. Aktuell (Juni 24) gibt es dort nur die Modelle der Version 3 zur Auswahl, das wird sich natürlich später noch ändern. Solltest du keine Auswahl für das Modell Claude 3.5 Sonnet sehen, ist das kein Problem – in der config.json wirst du gleich das richtige Modell manuell hinterlegen.

Um diese zu öffnen, klicke auf den Button unten. Dort siehst du nun das neu hinzugefügte Claude-Modell, dass du wie folgt anpassen musst:

Hier noch einmal das momentan aktuelle Modell zum Herauskopieren:

claude-3-5-sonnet-20240620

Neben „title“ kannst du den korrekten Namen des Modells eintragen. Und das war es auch schon – wähle im Auswahl-Dropdown von Continue das neue Modell aus und probiere Claude 3.5 Sonnet aus.

Fazit

Codestral und Claude 3.5 Sonnet bieten eine wirkliche Alternative zum GitHub Copilot – sowohl in Sachen Funktionalität, Zuverlässigkeit als auch im Preis. In der Testphase von Codestral sowieso, aber auch danach und für Claude 3.5 sollten die Gebühren beim hobbymäßigen Gebrauch unterhalb der monatlichen 10$ von GitHub liegen. Nähere Informationen zu den Kosten erhältst du in der Preisliste von Mistral und jener von Anthropic.

]]>
OpenAI auf dem ESP32 verwenden https://polluxlabs.net/esp8266-projekte/openai-auf-dem-esp32-verwenden/ Thu, 09 May 2024 08:29:15 +0000 https://polluxlabs.net/?p=16436 OpenAI auf dem ESP32 verwenden Weiterlesen »

]]>
Hier bei Pollux Labs gibt es mittlerweile eine Vielzahl von Projekten, die OpenAI bzw. ChatGPT verwenden. Dabei kommt oft der Raspberry Pi und immer die Sprache Python zum Einsatz. Aber es geht auch anders: Wenn du in deinem nächsten Projekt ChatGPT oder auch DALL-E verwenden möchtest, kannst du hierfür auch OpenAI auf dem ESP32 verwenden.

In diesem Tutorial lernst du, wie du deinen ESP32 mit der API von OpenAI kommunizieren lässt, um dir Fragen beantworten und Bilder erstellen zu lassen. Du kommunizierst hierbei über den Seriellen Monitor – deine Fragen bzw. Anweisungen sendest du dabei als Nachricht an deinen ESP32 und erhältst die Antwort wie gewohnt im Textfeld des Monitors.

Für die folgende Anleitung benötigst du einen Account bei OpenAI und einen API-Key. Wie du beides erstellst, erfährst du zu Beginn dieses Tutorials.

Die Bibliothek, um OpenAI zu nutzen

Wie auch für Python gibt es für C++ eine Bibliothek, die du verwenden kannst, um ganz einfach auf die API von OpenAI zugreifen zu können.

Diese findest du aktuell jedoch nicht im Bibliotheksverwalter der Arduino IDE, sondern musst sie manuell herunterladen und in deinem Sketch verfügbar machen. Du findest sie auf der GitHub-Seite des Entwicklers Me No Dev. Klicke dort oben auf den grünen Button Code und anschließend auf Download ZIP.

GitHub-Seite der Bibliothek, um OpenAI auf dem ESP32 nutzen zu können

In deiner Arduino IDE kannst du diese Bibliothek dann ganz einfach über das Menü hinzufügen. Klicke hierfür auf Sketch -> Bibliothek einbinden -> ZIP Bibliothek hinzufügen und wähle dann die Datei, die du von GitHub heruntergeladen hast.

so verwendest du ChatGPT auf dem ESP32

Über den Menüpunkt Datei -> Beispiele -> OpenAI-ESP32 kannst du die Beispiel-Sketches finden, die in der Bibliothek enthalten sind. Wähle den Sketch ChatCompletion, der sich nun in einem neuen Fenster öffnen sollte. Trage hier zunächst die Zugangsdaten zu deinem WLAN-Netzwerk sowie deinen API-Key von OpenAI ein:

const char* ssid = "your-SSID";
const char* password = "your-PASSWORD";
const char* api_key = "your-OPENAI_API_KEY";

Etwas weiter unten im Sketch findest du folgende Zeilen:

chat.setModel("gpt-3.5-turbo");   //Model to use for completion. Default is gpt-3.5-turbo
chat.setSystem("Code geek");      //Description of the required assistant
chat.setMaxTokens(1000);          //The maximum number of tokens to generate in the completion.

In der ersten Zeile kannst du das gewünschte Sprachmodell festlegen. Voreingestellt ist GPT-3.5-turbo, mit gpt-4 kannst du jedoch auch das aktuellere Modell verwenden. Darunter kannst du die Rolle von ChatGPT einstellen. Im Beispiel ist das zunächst ein Code geek, aber wie wäre es z.B. mit einem Gärtner oder einem Designer? Deine Einstellung verhindert übrigens keine Antworten, die in einen anderen Wissenbereich fallen. Auch ein Code geek kann dir sagen, warum der Himmel blau ist.

In der nächsten Zeile kannst du einstellen, wie viele Token höchstens für die Antwort verwendet werden dürfen. Damit stellst du sicher, dass die Antworten von ChatGPT nicht zu kostspielig werden. Bei OpenAI findest du die aktuelle Preisliste. Aktuell (Mai 2024) liegst du mit 1000 Token und GPT-4 bei ungefähr 6 Cent.

In den Zeilen darunter findest du weitere Einstellungsmöglichkeiten, die du jedoch hier einmal außer Acht lassen kannst. Sobald du alles eingetragen hast, lade den Sketch auf deinen ESP32 hoch und öffne nach dem erfolgreichen Upload den Seriellen Monitor und stelle, falls nötig, eine Baudrate von 115200 ein.

Nachdem sich dein ESP32 mit deinem WLAN verbunden hat, siehst du die folgende Eingabeaufforderung:

ChatGPT im seriellen Monitor des ESP32

Hier siehst du nun also ChatGPT, das auf deine Frage oder Anweisung wartet. Um mit ChatGPT zu kommunizieren, trage oben im Feld Nachricht deine Frage ein und sende sie mit Enter ab. Testweise habe ich gefragt, warum der Himmel eigentlich blau ist. Und hier die Antwort:

Antwort von ChatGPT im Seriellen Monitor

Deine Frage wird also an die API von OpenAI übermittelt, von ChatGPT beantwortet und die Antwort in deinem Seriellen Monitor ausgegeben. Über ihr findest du die Anzahl der Tokens, die die Antwort verbraucht hat.

Falls du die Antwort nicht nur im Seriellen Monitor ausgeben, sondern zum Beispiel auf einem Display anzeigen möchtest – du findest sie in der Variablen response, die an dieser Stelle im Code befüllt wird:

String response = result.getAt(i);

Bilder mit DALL-E auf dem ESP32 erzeugen

Neben dem Chat kannst du über die API von OpenAI auch DALL-E verwenden, um damit Bilder zeichnen zu lassen. Ein Tutorial, wie du mit Python und DALL-E Bilder erzeugst, findest du übrigens auch bei Pollux Labs.

Auch hierfür verwendest du einen Sketch, der schon als Beispiel mitgeliefert wird. Öffne hierfür wieder Datei -> Beispiele -> OpenAI-ESP32 und wähle dann ImageGeneration. Trage als erstes wieder oben im Sketch deine Zugangsdaten ein. Eine weitere wichtige Stelle befindest sich etwas weiter unten:

imageGeneration.setSize(OPENAI_IMAGE_SIZE_256x256); 

Dort kannst du die Größe des Bilds angeben. Voreingestellt sind 256×256 Pixel, du kannst jedoch auch 512×512 oder 1024×2024 wählen. Im Folgenden habe ich die größte Option gewählt. Laden nun diesen Sketch auf deinen ESP32 und öffne nach dem Upload (und einem evtl. notwendigen Reset des Microcontrollers) wieder deinen Seriellen Monitor. Du erhältst wieder die Aufforderung, einen Prompt zu senden.

Ich habe es einmal mit Zeichne ein Bild eines Mannes auf dem Mond, der auf die Erde schaut – im Ukiyo-e Stil versucht. Als Ergebnis erhältst du ein URL zurück, in der letzten Zeile:

Antwort von DALL-E im Seriellen Monitor

Kopiere die gesamte URL aus dem Seriellen Monitor heraus und öffne sie in deinem Browser. Hier mein Ergebnis:

Das Ergebnis ist vielleicht nicht ganz die große Welle vor Kanagawa, aber okay, es war ja nur ein Versuch. Wie du in diesem Tutorial gesehen hast, ist die API von OpenAI also nicht nur Python und leistungsstärkeren Computern vorbehalten – auch mit einem ESP32 kannst du hier schon einiges erreichen.

]]>
Musik mit künstlicher Intelligenz komponieren https://polluxlabs.net/python-tutorials-und-projekte/musik-mit-kuenstlicher-intelligenz-komponieren/ Wed, 17 Apr 2024 08:27:56 +0000 https://polluxlabs.net/?p=16360 Musik mit künstlicher Intelligenz komponieren Weiterlesen »

]]>
Mit KI kannst du mittlerweile eine Vielzahl von Medien erzeugen: natürlich Texte, mit denen alles anfing, aber auch Bilder und Videos. Eine faszinierende Idee war aber auch immer die Komposition von Musik mit künstlicher Intelligenz – eine Kunstform, die uns täglich begleitet und gleichzeitig zutiefst an menschliches Kreativität gebunden zu sein scheint.

Ich finde, das ist sie nach wie vor, auch wenn KI massive Fortschritte in der Erzeugung (Imitation?) von Musik gemacht hat. Wie auch immer man dazu stehen möchte – spannend ist das Thema ohne Frage. In diesem Artikel stelle ich einige Möglichkeiten und interessante Projekte vor.

Musik mit Udio komponieren

Am Anfang vieler KI-Anwendungen steht ein Prompt – so auch beim Tool Udio. Die Webseite dieses Anbieters erinnert auf den ersten Blick etwas an Spotify. Du findest dort zahlreiche, nach Genres sortierte Songs von anderen Nutzern, die du dir vorab schon mal anhören kannst, um herauszufinden, was Udio so leistet, um Musik mit künstlicher Intelligenz zu produzieren.

Musik mit künstlicher Intelligenz auf udio.com komponieren

Wenn du selbst eine Song erstellen (lassen) möchtest, musst du dich zunächst registrieren. Aktuell ist das nur mit einem Google-, Discord- oder X-Konto möglich. Anschließend kannst du im Feld ganz oben deinen Prompt eintragen und mit Klick auf Create die Musikproduktion starten.

Ich habe mit folgendem Prompt versucht, einen „autofahrttauglichen“ Softrock-Song zu erstellen:

A softrock song that you would have heard in the 90s while taking a long drive on the highway. Male voice, 70s Walker Brothers influence.

Das Ergebnis kannst du dir hier anhören. Bevor du allerdings einen Song wie diesen mit gut 2 Minuten Länge erstellt hast, gibt es noch etwas mehr zu tun. Udio erstellt zunächst eine Art Preview von etwas mehr als 30 Sekunden. Diesen Schnipsel kannst du dann anschließend erweitern, indem du ein weitere Teile wie ein passendes Intro oder Outro erstellen und „drankleben“ lässt. Klicke hierfür neben dem Song auf den Button Extend und wähle die gewünschte Erweiterung.

Das klappt erstaunlich gut, denn einen unnatürlichen Übergang hörst du zwischen den Teilen nicht. Allerdings habe ich es nicht geschafft, dem Song eine richtige Struktur aus Intro, Strophe und Refrain zu geben. Vielmehr führen die Erweiterungen (Sections) das Lied immer weiter in eine Richtung, die kein wirkliches Ziel zu haben scheint. Ein menschlicher Künstler würde hier sicherlich anders vorgehen. Du kannst allerdings auch den sogenannten Manual Mode aktivieren, der dir mehr Möglichkeiten gibt, mit dem zugrundeliegenden Sprachmodell zu interagieren.

In den Songs wird natürlich auch gesungen – auf Stimme und Text kannst du hierbei Einfluss nehmen. Erstere kannst du direkt im Prompt versuchen, näher zu bestimmen. Den gewünschten Gesangstext kannst du (auch hinter dem Button Extend) hinterlegen. Deinem Shoegaze-Track mit vertonten Angeboten von Hornbach steht also nichts mehr im Wege.

Wenn du mit deinem Ergebnis zufrieden bist, kannst du deinen Song auch auf Udio veröffentlichen oder einen Link zum Anhören erstellen und teilen.

Musik mit künstlicher INtelligenz – und einem Plattenspieler

Ein spannendes Projekt zum Thema stammt von Arvind Sanjeev: Hier werden über Druckknöpfe gewünschte Attribute wie Lo-Fi oder Happy und Musikstile wie Dance oder Metal eingestellt. Außerdem kann die Geschwindigkeit und die Länge des Musikstücks vorgegeben werden. Anschließend erstellt das Gerät mit Hilfe von Metas MusicGen einen passenden Track, der dann direkt abgespielt wird. Der Plattenspieler auf der linken Seite kann dann genutzt werden, um den Song vor- oder zurückzuspulen, die Geschwindigkeit zu verändern – oder um darauf zu scratchen.

SPIN Synthesizer mit künstlicher Intelligenz von MusicGen

In der Kiste stecken neben dem Plattenspieler ein Arduino Mega, ein Raspberry Pi – und jede Menge Arbeit. Das Ergebnis ist ein Gerät, das die abstrakte künstliche Intelligenz mit einem haptischen Interface verbindet und sie so nachvollziehbar macht. Ob es praxistauglich für die Musikproduktion ist? Vermutlich nicht. Es ist vielmehr der künstlerische Versuch, neue Technologie in unsere erlernte Lebenswelt „hineinzuholen“ und erfahrbar zu machen. Einen ähnlichen Ansatz hat das Wählscheiben-Telefon mit integriertem ChatGPT, das du hier auf Pollux Labs findest.

Weitere Informationen zur Plattenspielerkiste mit MusicGen und seiner Entstehung findest du bei CreativeApplications.Net

]]>
Bilder analysieren und beschreiben lassen mit künstlicher Intelligenz https://polluxlabs.net/raspberry-pi-projekte/bilder-analysieren-und-beschreiben-lassen-mit-kuenstlicher-intelligenz/ Mon, 25 Mar 2024 08:55:39 +0000 https://polluxlabs.net/?p=16232 Bilder analysieren und beschreiben lassen mit künstlicher Intelligenz Weiterlesen »

]]>
Dass du mit Hilfe von ChatGPT bzw. DALL-E Bilder erzeugen kannst, weißt du sicherlich bereits schon. Aber es geht auch andersherum: Mit Vision von OpenAI kannst du Bilder analysieren – also herausfinden, was darauf zu sehen ist. Und: Das funktioniert auch mit Videos.

In diesem Projekt lernst du, wie du mit Python und der API von OpenAI

Was ist OpenAI Vision?

Üblicherweise kommunizierst du mit ChatGPT oder anderen Sprachmodellen über einen Text-Prompt. Du sendest eine Anforderung oder Frage – und die KI antwortet dir. Mit GPT-4 gibt es jedoch auch die Möglichkeit, zusätzlich zum Text auch ein Bild mitzusenden. Du kannst also zum Beispiel fragen, was auf dem Bild zu sehen ist. Damit machst du dir die multimodalen Eigenschaften zunutze, die dir ermöglichen, verschiedene Medientypen zu kombinieren.

Das Vision zugrunde liegende Modell gpt-4-vision-preview kannst du aktuell (März 2024) nur über die API von OpenAI nutzen. Hierfür benötigst du einen Account bei OpenAI und einen API-Key. Wie du beides erstellst, erfährst du in diesem Tutorial. Um mit der API zu interagieren, eignet sich Python. Hierfür stellt OpenAI eine Bibliothek zur Verfügung, mit der du die gewünschten Funktionen unkompliziert aufrufen kannst.

Ein einzelnes Bild beschreiben lassen

Als erstes Beispiel soll ein einzelnes Bild dienen, das du per API an ChatGPT sendest und von der KI beschreiben lässt. Dieses Bild ist lokal auf deinem Rechner gespeichert. Um es zu übertragen, konvertierst du es zunächst in das Format Base64.

Zusammen mit dem kodierten Bild sendest du deinen Prompt mit – die Frage, was auf dem Bild zu sehen ist. Nach wenigen Sekunden erhältst du die Antwort zurück, die du dann in der Konsole ausgeben kannst. Hier ein Beispiel eines Bilds eines Panthers auf dem Mond und darunter die Interpretation von ChatGPT:

Ein Panther auf dem Mond

Das sieht ChatGPT in dem Bild:

Das ist ein fiktives Bild, das eine Katze in einem Astronautenanzug darstellt. Die Katze steht auf einer unebenen, mondähnlichen Oberfläche, und im Hintergrund ist ein großer erdähnlicher Planet mit verschiedenen Monden und Sternen sowie Galaxien im Weltraum zu sehen. Es handelt sich um eine künstlerische Darstellung, die Elemente aus der Science-Fiction-Szene mit einem Hauch von Humor kombiniert, indem sie ein Haustier in den Kontext der Raumfahrt setzt.

Nicht schlecht, oder? Gut, die KI hat aus dem Panther eine Katze gemacht – aber das kann man ihr wohl verzeihen.

Das Python-Script

Um solch eine Bildbeschreibung zu erstellen, benötigst du nicht viel Code. Hier das Script, das ich dafür verwendet habe:

import base64
import requests
from openai import OpenAI
import os

#Fall nötig: Das Verzeichnis auf das setzen, in dem das Script liegt.
os.chdir(os.path.dirname(os.path.realpath(__file__)))

# OpenAI API-Key
api_key = "DEIN API-KEY VON OPENAI"

# Das Bild konvertieren
def encode_image(image_path):
  with open(image_path, "rb") as image_file:
    return base64.b64encode(image_file.read()).decode('utf-8')

# Pfad zum Bild
image_path = "panther.jpeg"

# Den Base64-String erstellen
base64_image = encode_image(image_path)

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

payload = {
  "model": "gpt-4-turbo",
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "Was ist auf dem Bild zu sehen?"
        },
        {
          "type": "image_url",
          "image_url": {
            "url": f"data:image/jpeg;base64,{base64_image}"
          }
        }
      ]
    }
  ],
  "max_tokens": 300
}

response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload)
print(response.json()["choices"][0]["message"]["content"])

Das obige Script orientiert sich an einem Beispiel von OpenAI.

Bevor du das Script laufen lässt, stelle zunächst sicher, dass du die benötigten Bibliotheken installierst hast. Trage außerdem deinen API-Key von OpenAI ein. Dann benötigst du noch den Pfad zum Bild, das du analysieren und beschreiben lassen möchtest. Trage diesen hinter image_path = ein. Falls dein Bild im gleichen Verzeichnis liegt, wie dein Script – Python dieses jedoch nicht findet, kann die Zeile ganz oben unterhalb der Moduleinbindungen hilfreich sein. Damit setzt du das Verzeichnis auf jenes, in dem dein Script gespeichert ist.

Weiter unten im Script findest du den Prompt, der deine Anweisung bzw. Frage zum Bild enthält. Hier Was ist auf dem Bild zu sehen? Je nachdem, was du genau vorhast oder wissen möchtest, kannst du diesen Prompt natürlich anpassen. Wenn du also zum Beispiel wissen möchtest, welche Farben die Blumen auf einer Wiese haben, passe den Prompt entsprechend an.

Damit die Beschreibung von ChatGPT nicht zu ausschweifend und kostspielig wird, kannst du mit max_tokens noch eine maximale Anzahl an verwendeten Tokens festlegen.

Ein Video analysieren

Was mit einem einzelnen Bild geht, funktioniert auch mit einem Video – da ein solches nichts anderes ist als aneinander gereihte Fotos. Und so stellst du ein Video ChatGPT auch bereit, nämlich Frame für Frame.

Das folgende Script öffnet eine lokal gespeicherte Video-Datei und zerlegt es in einzelne Frames. Anschließend erfolgt die Abfrage bei der API, in der du diese Einzelbilder bereitstellst und ebenfalls deinen Prompt (also deine Frage) mitsendest:

import cv2 #Nicht installiert? -> pip install opencv-python
import base64
import time
from openai import OpenAI
import os

#Fall nötig: Das Verzeichnis auf das setzen, in dem das Script liegt.
os.chdir(os.path.dirname(os.path.realpath(__file__)))

client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY", "DEIN API-KEY VON OPENAI"))

video = cv2.VideoCapture("DEIN VIDEO.mp4")

base64Frames = []
while video.isOpened():
    success, frame = video.read()
    if not success:
        break
    _, buffer = cv2.imencode(".jpg", frame)
    base64Frames.append(base64.b64encode(buffer).decode("utf-8"))

video.release()
print(len(base64Frames), "frames read.")

PROMPT_MESSAGES = [
    {
        "role": "user",
        "content": [
            "Dies sind Frames eines Videos. Beschreibe, was darin zu sehen ist.",
            *map(lambda x: {"image": x, "resize": 768}, base64Frames[0::50]),
        ],
    },
]
params = {
    "model": "gpt-4-turbo",
    "messages": PROMPT_MESSAGES,
    "max_tokens": 400,
}

result = client.chat.completions.create(**params)
print(result.choices[0].message.content)

Wie du siehst, ist das Script etwas anders aufgebaut als das erste. Hier sendest du deine Abfrage nicht per Request, sondern nutzt die Funktion client. Hinterlege wieder einen API-Key und in der Zeile video = cv2.VideoCapture(„DEIN VIDEO.mp4“) den Dateinamen des Videos, das du analysieren lasse möchtest. Falls es nicht im gleichen Ordner wie dein Script liegt, achte bitte auf den korrekten Pfad.

Im Bereich PROMPT_MESSAGE = [ findest du den Prompt, den du mitsendest. Diesen kannst du wieder an deine Wünsche anpassen. Ebenso gibt es wieder die Einstellung max_tokens – hier kann allerdings eine größere Zahl nötig sein als bei dem einzelnen Bild von vorhin. Wenn die erlaubte Anzahl an Tokens zu gering ist, erhältst du möglicherweise keine vollständige Beschreibung des Videos.

Mit dem Raspberry Pi ein Foto aufnehmen und es beschreiben lassen

Bisher hast du bereits vorhandene Bilder oder Videos verwendet. Du kannst aber natürlich auch ein Foto mit der Kamera am Raspberry Pi aufnehmen und dieses von ChatGPT beschreiben lassen. Diesmal gibst du die Analyse jedoch nicht einfach nur in der Konsole aus, sondern lässt sie dir vorlesen.

Damit baust du dir ein Gerät, das du verwenden könntest, um zum Beispiel dir unbekannte Gegenstände, Gemälde oder Gebäude zu identifizieren. Auch für Menschen mit eingeschränktem oder überhaupt keinem Sehvermögen könnte das eine interessante und hilfreiche Anwendung sein.

Raspberry Pi mit Kamera

Das Projekt aufbauen

Ausgelöst wird die Kamera und die anschließende Analyse durch einen gedrückten Button am Raspberry Pi. Schließe diesen wie folgt an. Einen Pulldown- oder Pullup-Widerstand benötigst du hierbei nicht.

Button am Raspberry Pi

Wie du die Kamera anschließt, habe ich in diesem Projekt zur Objekterkennung am Raspberry Pi beschrieben. Allerdings verwende ich darin noch die Option Legacy Camera, die du nun eigentlich nicht mehr benötigst. Leider war das Thema „Kamera am Raspberry Pi“ eine Zeitlang etwas komplex, weswegen es schwierig ist, eine Patentlösung anzubieten, die für die meisten Versionen von Pi und zugehörigem Betriebssystem passt.

Möglicherweise wirst du hier etwas herumprobieren müssen. Im Folgenden verwende ich das Betriebssystem Debian Bookworm (64 Bit) und die Bibliothek Picamera2. Ob deine Kamera korrekt angeschlossen ist und funktioniert, kannst du übrigens im Terminal schnell testen. Führe dafür einfach den folgenden Befehl aus:

libcamera-still -o test.jpg

Wenn alles funktioniert, erscheint ein Vorschaufenster mit dem aktuellen Kamerabild. In diesem Fall steht dem folgenden Python-Script dann nichts mehr im Wege.

Das Python-Script

Das folgende Script erweitert die hier vorangegangen Programme ein wenig. Zunächst wird die Bildbeschreibung erst ausgeführt, sobald der angeschlossene Button gedrückt wurde. Dann wird die Kamera gestartet, ein Foto aufgenommen und dieses dann an ChatGPT übertragen. Nachdem die Antwort vorliegt, wird diese in Sprache umgewandelt und vorgelesen.

Mehr zum Thema „Text in Sprache umwandeln“ findest du übrigens in diesem Tutorial bei uns. Und noch ein Hinweis: Möglicherweise fragst du dich, was mit deinen aufgenommen Fotos passiert, nachdem du sie an ChatGPT übertragen hast. Laut Angaben von OpenAI werden diese nicht für das Training der KI verwendet. Falls du hier jedoch sichergehen möchtest, solltest du auf die Verwendung dieser Fotos vielleicht lieber verzichten.

Hier das Script:

import cv2 #Nicht installiert? -> pip install opencv-python
import base64
from openai import OpenAI #pip install openai
import os
from picamera2 import Picamera2 #pip install picamera2
import RPi.GPIO as GPIO
import pygame #pip install pygame
import time
from pathlib import Path

GPIO.setmode(GPIO.BOARD)
buttonPin = 16
GPIO.setup(buttonPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# Dateiname des aufgenommenen Fotos
image_file = 'image.jpg'

def main():

    # Ein Foto machen
    print("Ich nehme ein Foto auf.")
    picam2 = Picamera2()
    camera_config = picam2.create_still_configuration(main={"size": (1920, 1080)}, lores={"size": (640, 480)}, display="lores")
    picam2.configure(camera_config)
    picam2.start()
    time.sleep(2)
    picam2.capture_file(image_file)
 
    client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY", "DEIN OPENAI API-KEY"))

    image = cv2.imread(image_file)
    _, buffer = cv2.imencode(".jpg", image)
    base64Image = base64.b64encode(buffer).decode("utf-8")

    print("Ich beschreibe das Foto.")

    PROMPT_MESSAGES = [
        {
            "role": "user",
            "content": [
                "Dies ist ein Foto. Beschreibe, was darauf zu sehen ist.",
                {"image": base64Image, "resize": 768},
            ],
        },
    ]
    params = {
        "model": "gpt-4-turbo",
        "messages": PROMPT_MESSAGES,
        "max_tokens": 200,
    }

    result = client.chat.completions.create(**params)
    description = result.choices[0].message.content
    print(description)

    #Vertonung
    speech_file_path = Path(__file__).parent / "vision.mp3"
    response = client.audio.speech.create(
    model="tts-1",
    voice="alloy",
    input=description
    )
    response.stream_to_file(speech_file_path)
    
    pygame.init()
    pygame.mixer.init()
    pygame.mixer.music.load(speech_file_path)
    pygame.mixer.music.play()
    while pygame.mixer.music.get_busy():
        pass
    pygame.quit()

if __name__ == "__main__":
    while True:
        buttonState = GPIO.input(buttonPin)
        if buttonState == GPIO.LOW: 
            main()
        else:
            print(".")

Wie du siehst, kommen hier noch ein paar weitere Bibliotheken ins Spiel. Wie du sie mit Pip im Terminal installiert, steht als Kommentar jeweils dahinter.

Sobald du alles vorbereitet hast, starte das Script (Kopfhörer bzw. Lautsprecher nicht vergessen). Nachdem du den Button gedrückt hast, sollte das Foto übertragen werden und dir die Bildbeschreibung vorgelesen werden. Hab ein bisschen Geduld, so richtig schnell wird das leider nicht funktionieren – aber es sollte meistens deutlich unter einer Minute dauern.

]]>
Deine persönlichen Radio-Nachrichten auf dem Raspberry Pi https://polluxlabs.net/raspberry-pi-projekte/deine-persoenlichen-radio-nachrichten-auf-dem-raspberry-pi/ Fri, 15 Mar 2024 09:12:31 +0000 https://polluxlabs.net/?p=16173 Deine persönlichen Radio-Nachrichten auf dem Raspberry Pi Weiterlesen »

]]>
Aktuelle Nachrichten selbst zu lesen ist nicht immer möglich – manchmal sind sie vorgelesen gerade praktischer. Nur informiert dich das Radio üblicherweise nur zur vollen Stunde. Dieses Raspberry Pi Projekt schafft Abhilfe: Du besorgst dir die aktuellen Nachrichten von tagesschau.de, fasst sie mit ChatGPT radiotauglich zusammen und lässt sie dir vorlesen.

Mit diesem Projekt lernst du, wie du in Python mit Web Scraping Inhalte von Webseiten herunterlädst, wie du ChatGPT per API verwendest und Texte vertonen lassen kannst. Außerdem erfährst du, wie du per Python-Script MP3s erzeugst und diese auf deinem Raspberry Pi abspielst.

Aufbau des Raspberry Pis

Deine eigene Nachrichtensendung soll auf Knopfdruck starten – hierfür benötigst du einen Button, den du an die Pins des Raspberry Pis anschließt. Orientiere dich hierbei an folgender Skizze:

Button am Raspberry Pi

Einen Pullup- bzw. Pulldown-Widerstand benötigst du hier nicht, das erledigt dein Raspberry Pi intern. Neben dem Button benötigst du noch einen Lautsprecher, über den du die vertonten Nachrichten ausgeben kannst. Hierfür eignen sich z.B. Modelle, die du per 3,5mm Klinkenstecker direkt an den Audioausgang anschließen kannst.

Der API-Key von OpenAI

Falls du noch keinen Account bei OpenAI und auch noch keinen API-Key hast, musst du beides noch schnell einrichten, bevor du ChatGPT und die Funktion zum Vertonen von Texten nutzen kannst. In diesem Tutorial erfährst du, wie.

Im folgenden Python-Script kannst du dann deinen API-Key eintragen, um die Features von OpenAI verwenden zu können.

Das Python-Script

Kommen wir zum Code des Projekts. Hier führst du mehrere Funktionen aus – um die aktuellen Nachrichten von tagesschau.de zu laden, um sie zu kürzen und „radiotauglich“ zu machen, und um sie vorlesen zu lassen.

Hier zunächst das vollständige Script:

import requests
from bs4 import BeautifulSoup
from openai import OpenAI
from pathlib import Path
import pygame
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BOARD)
buttonPin = 16
GPIO.setup(buttonPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

def main():
    client = OpenAI(
      api_key="DEIN API-KEY",
    )

    url = 'https://www.tagesschau.de/'

    def getNews():
        nonlocal url
        response = requests.get(url)
        soup = BeautifulSoup(response.text, 'html.parser')
        links = soup.find_all('a', class_='teaser__link')
        for link in links:
            link['href'] = url + link['href']
        return links[:5]

    def getArticle(link):
        response = requests.get(link.get('href'))
        soup = BeautifulSoup(response.text, 'html.parser')
        headline = soup.find('meta', property='og:title')['content'] + '\n'
        paragraphs = soup.find_all('p')
        text = ""
        for paragraph in paragraphs:
            if paragraph.find_parent('div', class_='teaser-absatz__teaserinfo') is None and paragraph.find_parent('div', class_='teaser-xs__teaserinfo') is None:
                text += paragraph.get_text() + '\n'
        return headline, text

    def get_summary(text):
        completion = client.chat.completions.create(
        model="gpt-3.5-turbo", 
        messages=[
        {"role": "system", "content": "Du schreibst Nachrichten fürs Radio."},
        {"role": "user", "content": "Fasse den folgenden Text zusammen: {}".format(text)}]
        )
        summary_text = headline + completion.choices[0].message.content
        return summary_text

    def speech(summary_text):
        speech_file_path = Path(__file__).parent / "news.mp3"
        response = client.audio.speech.create(
        model="tts-1",
        voice="alloy",
        input=summary_text
        )
        response.stream_to_file(speech_file_path)
        pygame.init()
        pygame.mixer.init()
        pygame.mixer.music.load(speech_file_path)
        pygame.mixer.music.play()
        while pygame.mixer.music.get_busy():
            pass
        pygame.quit()

    news_links = getNews()
    for link in news_links:
        headline, text = getArticle(link)
        summary_text = get_summary(text)
        speech(summary_text)

if __name__ == "__main__":
    while True:
        buttonState = GPIO.input(buttonPin)
        if buttonState == GPIO.LOW: 
            main()
        else:
            print(".")

So funktioniert das Script

Sobald du den Button gedrückt hast, wird die Funktion main() aufgerufen. Den Code hierfür findest du ganz am Ende des Scripts. Innerhalb von main() werden mehrere verschachtelte Funktionen definiert, die jeweils für einen bestimmten Teil des Prozesses verantwortlich sind.

Die Funktion getNews() sendet eine GET-Anfrage an eine vordefinierte URL (in unserem Fall ‚https://www.tagesschau.de/‘), analysiert die HTML-Antwort, um alle Links mit der Klasse teaser__link zu finden, und gibt die ersten fünf dieser Links zurück.

Die Funktion getArticle(link) nimmt einen dieser Links als Argument, sendet eine GET-Anfrage an die URL des Links und analysiert ebenso die HTML-Antwort, um die Überschrift und den Text des Artikels zu extrahieren. Dazu sucht sie den meta-Tag mit der Eigenschaft og:title für die Überschrift und alle p-Tags für den Text. Anschließend werden die Überschrift und der Text zurückgegeben.

Die Funktion get_summary(text) nimmt den Text als Argument und verwendet ChatGPT, um eine Zusammenfassung des Textes zu erstellen. Anschließend werden die Überschrift des Artikels und die generierte Zusammenfassung miteinander verknüpft und zurückgegeben.

Die Funktion speech(summary_text) nimmt den zusammengefassten Text als Argument und verwendet die OpenAI-API, um den Text in Sprache umzuwandeln. Anschließend wird der vertonte Text in einer Datei gespeichert und mit pygame abgespielt.

Die benötigten Module

Du benötigst du folgenden Module bzw. Bibliotheken, damit das Script läuft:

import requests
from bs4 import BeautifulSoup
from openai import OpenAI
from pathlib import Path
import pygame
import RPi.GPIO as GPIO

Falls du BeautifulSoup, OpenAI und PyGame noch nicht auf deinem System installiert sind, hole das mit den folgenden Befehlen im Terminal nach:

pip install beautifulsoup4
pip install openai
pip install pygame

Die Bibliothek Beautiful Soup verwendest du fürs Web Scraping. Das bedeutet, dass du hiermit die Texte einer beliebigen Webseite auslesen und in deinem Script weiterverwenden kannst. Mit dem Modul von OpenAI greifst du auf deren Services zu und PyGame verwendest du für die Tonausgabe. Die anderen Module sollten bereits verfügbar sein.

Nachdem du eine Button an deinem Raspberry Pi angebracht und die benötigten Module installiert hast, trage deinen API-Key ein und starte das Python-Script. Nach wenigen Sekunden sollte deine persönlichen Radio-Nachrichten starten.

Möchtest du doch lieber „echtes“ Radio hören? In diesem Tutorial lernst du, wie du dir ein ESP32 Internetradio baust.

]]>
KI-Videos mit Stable Video Diffusion erstellen https://polluxlabs.net/python-tutorials-und-projekte/ki-videos-mit-stable-video-diffusion/ Mon, 27 Nov 2023 10:47:30 +0000 https://polluxlabs.net/?p=15413 KI-Videos mit Stable Video Diffusion erstellen Weiterlesen »

]]>
Auf Pollux Labs konntest du bereits viel über Bildgenerierung mit ChatGPT und deepAI erfahren – aber wie sieht es mit Videos aus? Stable Diffusion hat im November 2023 eine frühe Version einer Software veröffentlicht, die auf Basis eines Ausgangsbilds ein kleines KI-Video erstellen kann. In diesem Tutorial erfährst du, wie das geht.

Ein kurzer Hinweis: Dieses Tutorial behandelt eine frühe Version und ist auf dem Stand Ende November ’23. Wie du weißt, entwickelt sich die KI-Welt rasant – also möglicherweise hat sie sich schon weitergedreht, wenn du diese Zeilen hier liest.

Das kann Stable Video Diffusion

Gegenwärtig kannst du mit Stable Video Diffusion eine kurze Video-Sequenz erstellen, die entweder 14 oder 25 Frames lang ist. Als Ausgangspunkt dient ein einzelnes Bild, das zwingend im Format 576×1024 Pixel vorliegen muss. Künftig ist auch eine Version geplant, die auf Basis eines Textprompts Videos erstellen kann, für die du dich bereits in eine Warteliste eintragen kannst.

Testweise habe ich eine kleine Animation einer Gummiente auf einem Fluss erstellt. Hier das Ergebnis:

Das Ausgangsbild hierfür habe ich mit ChatGPT erstellt (Hier ein Tutorial, wie du per API Bilder mit ChatGPT erzeugen kannst).

So erstellst du ein KI-Video auf Basis eines Bilds

Du findest auf Github das Repository von Stable Video Diffusion. Wenn du Erfahrung mit dem Klonen und Einrichten von Repositorys hast, kannst du lokal auf deinem Computer installieren. In diesem Video auf Youtube erhältst du weitere Information zum Download des benötigten KI-Modells und zu ComfyUI – einer Oberfläche, mit der du Stable Diffusion verwenden kannst.

Für einen ersten Test gibt es jedoch eine einfachere Möglichkeit, die dir viel Zeit spart.

Auf der Webseite von Replicate findest du eine Online-Version von Stable Video Diffusion, mit der du ohne großen Aufwand experimentieren kannst. Du musst lediglich ein Ausgangsbild im erwähnten Format von 576×1024 Pixeln hochladen und für einen ersten Test auf Run klicken. Das Video wird dann direkt in deinem Browser erstellt:

Stable Video Diffusion replicate Ente

Auf der rechten Seite erscheint dann das fertige Video (oder eher eine kurze Animation), die auf Basis des Bilds links erzeugt wurde. Hinweis: Ein von ChatGPT erzeugtes Bild hat im Landscape-Format nicht ganz die richtige Größe für die Video-Generierung. Passe die Auflösung deshalb vor dem Upload manuell an.

Wie du im Video oben siehst, versucht Stable Video Diffusion zu erkennen, was sich auf dem statischen Bild für eine Animation eignen könnte. In unserem Fall ist das natürlich das Wasser des Flusses und die Ente, die darauf schwimmt. Selbst kannst du noch keine Vorgaben machen, was im Video passieren soll – also ob z.B. ein Stück Treibholz ins Bild schwimmt.

Voreingestellt sind 14 Frames, die mit den voreingestellten Frames pro Sekunde ein KI-Video von circa 2 Sekunden Länge ergeben. Du kannst aber die Videolänge auch auf 25 Frames erhöhen. Außerdem kannst du noch die Frames per Second definieren und auch mit weiteren Werten, wie der „Menge“ an Bewegung, die im fertigen Video zu sehen sein soll, experimentieren.

Hier das Ergebnis eines Baums im Sturm mit 25 Frames, 15 Frames pro Sekunde und einer motion_bucket_id von 255:

Wie du hier siehst, geht es zwar rund mit den Wolken – der Baum scheint vom Sturm allerdings eher unbeeindruckt zu sein, abgesehen von ein paar herumwehenden Blättern. Hier fehlt einfach noch die Möglichkeit, konkret etwas vorzugeben, das Stable Diffusion dann auch verstehen und umsetzen kann.

Wenn du dein Ergebnis speichern möchtest, kannst du das Video als MP4-Datei herunterladen.

Dass künstliche Intelligenz auch Videos auf Basis konkreter Vorgaben erstellen kann, war eine Frage der Zeit – und Stable Video Diffusion ist sicherlich auch nicht die erste Anwendung dieser Art. Und doch ist das Ergebnis bereits beeindruckend. Die (nahe) Zukunft dürfte noch einige Verbesserungen bereithalten: Längere Videos mit besserer Steuerung, was in ihnen geschehen soll.

]]>
Text To Speech mit Python – So vertonst du Texte https://polluxlabs.net/raspberry-pi-projekte/text-to-speech-mit-python-so-vertonst-du-texte/ Mon, 13 Nov 2023 12:54:54 +0000 https://polluxlabs.net/?p=15278 Text To Speech mit Python – So vertonst du Texte Weiterlesen »

]]>
In diesem Tutorial lernst du zwei Methoden kennen, mit denen du in Python Text in gesprochene Sprache umwandeln kannst. Mit Text to Speech kannst in deinen Projekten zum Beispiel eine Sprachausgabe umsetzen.

Die erste Möglichkeit ist die Python-Bibliothek gTTS, mit der du kostenlos Texte vertonen lassen kannst. Dieses Modul habe ich im Projekt ChatGPT im Telefon eingesetzt. Als zweite Methode lernst du eine API-Funktion von openAI kennen. Diese Variante ist kostenpflichtig – allerdings hört sich das Ergebnis hierfür auch weit besser an.

Text to Speech mit gTTS (Google Text-to-Speech)

Wenn dein Projekt keine astreine Aussprache erfordert, ist die Bibliothek gTTS eine gute Wahl. Die Qualität ist nicht schlecht, allerdings hakt es bei der Aussprache oft bei Abkürzungen oder die Betonung von Satzteilen kommt durch das ein oder andere Komma durcheinander. Dafür kannst du mit diesem Python-Modul den Google-Service kostenlos verwenden – was sicherlich ein gutes Argument für einen Test ist.

Installiere zunächst die Bibliothek mit dem Befehl

pip install gtts

Um die Sprachausgabe zu testen, reichen drei Zeilen Python-Code:

from gtts import gTTS

tts = gTTS('Hello, world. This is a first test.')
tts.save('hello.mp3')

Nachdem du das kleine Script ausgeführt hast, öffne die Datei hello.mp3 und lausche dem Ergebnis. Bist du zufrieden?

Du kannst übrigens auch deutsche Texte vertonen lassen. Füge hierfür den Parameter lang=’de‘ hinzu:

tts = gTTS('Hallo, das ist einer erster Test.', lang='de')

Das war im Prinzip schon alles. Wenn du wissen möchtest, wie du die MP3 direkt mit deinem Python-Script abspielen kannst, wirf einen Blick in das oben verlinkte Projekt. Weitere Infos über gTTS erhältst du hier.

Text To Speech mit openAI

Wenn dir eine gute Sprachqualität ein paar Cent wert ist, ist OpenAI einen Versuch wert. Neben dem allseits bekannten ChatGPT findest du dort auch eine API-Funktion, mit der du Text vertonen lassen kannst. Die Integration in dein Python-Script ist dabei ähnlich einfach wie mit gTTS. Allerdings kostet der Service derzeit (November 2023) 0,015 € je 1.000 Zeichen – was ein recht überschaubarer Preis ist. Die aktuelle Preisliste findest du hier unter Audio models.

Wenn du noch nicht mit OpenAI experimentiert hast, erfährst du in diesem Tutorial, wie du dort ein Konto und einen API-Key erstellst.

Nachdem du die Bibliothek openai (mit pip install openai) installiert hast, binde sie in deinem Python-Script ein. Zusätzlich benötigst du noch das Modul pathlib der Bibliothek Path, das aber bereits vorinstalliert ist.

from pathlib import Path
from openai import OpenAI

Anschließend hinterlegst du deine API-Key von OpenAI:

client = OpenAI(
  api_key="DEIN API-KEY",
)

Und schon kann es mit der Vertonung losgehen. Du gibst zunächst an, wie die erzeugte MP3 heißen soll – hier speech.mp3:

speech_file_path = Path(__file__).parent / "speech.mp3"

Anschließend legst du ein paar Parameter fest: Zunächst das Modell – hier hast du die Wahl zwischen tts-1 und tts-1-hd. Letzteres hat eine etwas höhere Qualität und ist auch teurer. Für die allermeisten Anwendungen dürfte das einfachere Modell jedoch ausreichen. Der Parameter voice gibt vor, welche Stimme verwendet werden soll. Derzeit gibt es sechs Stimmen, die du hier probehören kannst. Dort findest du auch aktuelle Informationen und Updates zu Text to Speech mit OpenAI.

Zuletzt fehlt nur noch der Text, den du vertonen lassen möchtest und der Befehl zum Speichern der MP3:

response = client.audio.speech.create(
  model="tts-1",
  voice="alloy",
  input="Das Pferd frisst keinen Gurkensalat."
)

response.stream_to_file(speech_file_path)

Und das war schon alles. Führe das Script aus – sobald es fertig ist, findest du im gleichen Ordner die Datei speech.mp3 mit deiner Sprachausgabe. Hier nun das gesamte Script:

from pathlib import Path
from openai import OpenAI

client = OpenAI(
  api_key="DEIN API-KEY",
)

speech_file_path = Path(__file__).parent / "speech.mp3"
response = client.audio.speech.create(
  model="tts-1",
  voice="alloy",
  input="Das Pferd frisst keinen Gurkensalat."
)

response.stream_to_file(speech_file_path)

Mit den oben beschriebenen Bibliotheken und Services hast du nun zwei Methoden zur Hand, wie du in deinem Projekt Text to Speech anwenden kannst. Ob dir eine kostenlose Vertonung reicht, oder du etwas qualitativ hochwertigeres benötigst, hängt natürlich vom Einsatzgebiet ab.

]]>
Kochen mit ChatGPT und REWE-Angeboten https://polluxlabs.net/python-tutorials-und-projekte/kochen-mit-chatgpt-und-rewe-angeboten/ Fri, 03 Nov 2023 00:06:20 +0000 https://polluxlabs.net/?p=15215 Kochen mit ChatGPT und REWE-Angeboten Weiterlesen »

]]>
Dass ChatGPT mittlerweile mit einem Bild deines Kühlschrankinhalts kochen kann, ist bekannt. Aber wie wäre es einmal mit einem Gericht, dessen Zutatenliste nur aus Sonderangeboten deines nächstgelegenen REWE-Markts besteht? In diesem Projekt probierst du genau das aus: Du fragst die aktuellen REWE-Angebote per API ab und lässt ChatGPT daraus Rezeptideen erstellen – Kochen mit ChatGPT.

Zum Einsatz kommen hierbei zwei Python-Scripts – das erste, um die ID deines Wunsch-Supermarkts herauszufinden und die zweite für die Abfrage der Angebote und die Erstellung der Rezepte. Wenn du möchtest, kannst du letzteres auch automatisieren: Auf deinem Raspberry Pi könnte ein Cronjob jeden Montag die aktuellen Angebote abrufen und ChatGPT dir daraus sieben Rezepte für die ganze Woche erstellen.

Noch ein Hinweis vorab: Bei diesem Projekt handelt es sich natürlich um eine Spielerei – ob die von ChatGPT vorgeschlagenen Gerichte wirklich schmecken, ist leider nicht so ganz sicher. Aber bei den ersten Tests kam schon ansprechende Speisen heraus, z.B. Süßkartoffel-Kürbis-Auflauf, Mediterrane Hähnchenschenkel mit frischen Kräutern und Zitronen-Butter oder Rouladen nach Landhaus-Art. Sowohl die Zutatenliste auch die Anweisungen zur Zubereitungen klangen nicht abwegig. Ein Versuch ist es allemal Wert – und dieser Versuch erweitert auf jeden Fall deine Fähigkeiten.

Finde die ID deines REWE-Markts heraus

Bevor du die Angebote des REWE-Markts deiner Wahl abrufen kannst, benötigst du den marketCode dieses Markts. Den kannst du ganz leicht mit einem kleinen Python-Script herausfinden:

import requests
import json

# Trage hier deinen Standort ein
search_term = 'Karlsruhe'
url = f'https://www.rewe.de/api/marketsearch?searchTerm={search_term}'

# Stelle die Anfrage an die API.
response = requests.get(url)

# Überprüfe, ob die Anfrage erfolgreich war (HTTP Status Code 200).
if response.status_code == 200:
    # Parse die Antwort als JSON.
    data = response.json()

    # Schön formatierte Ausgabe des JSON.
    print(json.dumps(data, indent=4))
else:
    print('Fehler bei der Anfrage:', response.status_code)

Um die Märkte an deinem Standort zu finden, trage diesen in die Variable search_term ein – in meinem Fall ist das Karlsruhe. Wenn du das Script nun ausführst, erhältst du die Antwort als JSON. Hier die ersten beiden Einträge einer möglichen Antwort der API:

{
        "wwIdent": "831008",
        "isReweDortmund": false,
        "companyName": "REWE Ponzer GmbH & Co. oHG",
        "contactStreet": "Hans - Sachs - Str. 8",
        "contactZipCode": "76133",
        "contactCity": "Karlsruhe",
        "marketHeadline": "REWE Markt",
        "openingInfo": {
            "willOpen": {
                "onDay": 5,
                "at": "07:00"
            }
        }
    },
    {
        "wwIdent": "840913",
        "isReweDortmund": false,
        "companyName": "REWE Christopher Lannert oHG",
        "contactStreet": "Josef-Schofer-Str. 14",
        "contactZipCode": "76187",
        "contactCity": "Karlsruhe",
        "marketHeadline": "REWE Markt",
        "openingInfo": {
            "willOpen": {
                "onDay": 5,
                "at": "07:00"
            }
        }
    },

Gleich der jeweils erste Key wwIdent ist die ID bzw. marketCode, den du später benötigst. Suche dir also den gewünschten Markt aus der Liste heraus und notiere dir die ID.

Aktuelle Angebote finden

Bevor es mit dem nächsten Python-Script losgehen kann, musst du noch die Bibliothek cloudscraper installieren. Diese benötigst du, das die API von REWE eigentlich keine automatisierten Abfragen zulässt. Mit dieser Bibliothek kannst du diese Sperre allerdings umgehen. Achte deshalb bitte darauf, keinen „Unfug“ anzustellen und z.B. zahllose Anfragen an die API zu stellen.

Um die Bibliothek zu installieren, gib im Terminal bzw. in der Konsole folgenden Befehl ein:

pip install cloudscraper

Außerdem benötigst du noch die Bibliothek openai, mit der du die API von ChatGPT ansteuern kannst. Diese installierst du wie folgt:

pip install openai

Nun kann es mit dem Script losgehen. Zunächst bindest du die beiden genannten Bibliotheken ein und hinterlegst deine gefundene ID sowie die URL für die Abfrage:

import cloudscraper
from openai import OpenAI

# Deine ID, hier ein Beispiel aus Karlsruhe
market_id = '831008'
# Die Basis-URL der API
url = f'https://mobile-api.rewe.de/api/v3/all-offers?marketCode={market_id}'

Anschließend bereitest du cloudscraper vor, erstellst einen leeren String, in den die gefundenen Sonderangebote geschrieben werden – und erstellst eine Liste der Angebotskategorien, die überhaupt für Rezepte in Frage kommen. Es gibt natürlich auch Angebote in den Kategorien Haushalt, Tierfutter, Spirituosen etc., mit denen wir aber hier nichts anfangen können.

# Erstellen ein Cloudscraper-Objekt
scraper = cloudscraper.create_scraper()

# Stelle die GET-Anfrage
response = scraper.get(url)

# Initialisiere einen leeren String für die Titel der Angebote
titles_string = ''

# Eine Liste der gewünschten Kategorietitel
desired_categories = {
    'Frische & Kühlung',
    'Süßes & Salziges',
    'Obst & Gemüse',
    'Nahrungsmittel',
    'Tiefkühl'
}

Nun fehlt nur noch die eigentliche Abfrage. Hier stellst du sicher, dass in der Variablen titles (für die Namen der angebotenen Artikel) nur jene aus den vorgegebenen Kategorien gespeichert werden.

# Überprüfe  den Statuscode der Antwort
if response.status_code == 200:
    # Wenn der Statuscode 200 ist, war die Anfrage erfolgreich
    # Konvertiere die Antwort in JSON
    data = response.json()
    
    # Extrahiere die Angebote, die den gewünschten Kategorietiteln entsprechen
    titles = [
        offer['title']
        for category in data['categories']
        for offer in category['offers']
        if 'rawValues' in offer and 'categoryTitle' in offer['rawValues']
        and offer['rawValues']['categoryTitle'] in desired_categories
    ]
    
    # Erstelle einen String mit den gefilterten Titeln, getrennt durch Kommas
    titles_string = ', '.join(titles)
    
    # Ausgabe des Strings
    print("Gefilterte Titel:", titles_string)
else:
    # Wenn der Statuscode nicht 200 ist, gab es ein Problem mit der Anfrage
    print(f'Fehler: {response.status_code}')

Rezepte erstellen lassen mit ChatGPT

Nun folgt der zweite Teil des Scripts. Hier fragst du ChatGPT über die API nach Rezeptideen, die auf den gefundenen Sonderangeboten basieren. Hierfür benötigst du einen API-Key von OpenAI. In diesem Tutorial erfährst du, wie du dir den benötigten Key erstellst.

Du hinterlegst im Script also deinen Key und erstellst gleich danach die Abfrage:

client = OpenAI(
  api_key="DEIN API-KEY",
)

print("Ich erstelle Gerichte...")
completion = client.chat.completions.create(
#model="gpt-3.5-turbo", 
model="gpt-4",
messages=[
{"role": "system", "content": "Du bist ein KI-Koch, der aus vorgegebenen Zutaten Rezepte für Gerichte entwirft."},
{"role": "user", "content": "Es folgt eine Liste von Zutaten. Kreiere hieraus 3 Rezepte für leckere Gerichte. Gehe davon aus, dass die Küchen-Basics wie Salz, Pfeffer, Öl, Butter etc. bereits vorhanden sind. Hier die Liste: {}".format(titles_string)}]
)

print(completion.choices[0].message.content)

Du findest im obigen Code zwei Zeilen, mit denen du auswählen kannst, ob du das Modell 3.5 oder die neuere Version 4 verwenden möchtest. Kommentiere einfach die nicht gewünschte Version aus.

Als Anweisung (system) an ChatGPT legst du fest, dass die KI als Ideengeber für Rezepte fungieren soll. Mit dem eigentlichen Prompt (user) legst du dann fest, was du möchtest. Im obigen Beispiel sind es drei Rezepte, für die übliche Zutaten wie Salz und Pfeffer enthalten sein dürfen, auch wenn sie nicht in den Angeboten zu finden sind. An diesen Prompt hängst du dann einfach die Liste der Angebote an.

Hier hast du natürlich einiges an Spielraum. So könntest du z.B. nur vegetarische Gerichte entwerfen lassen und ChatGPT Unverträglichkeiten mitteilen.

Die Antwort der künstlichen Intelligenz sieht dann beispielsweise folgendermaßen aus:

Rezept 1: Rinderrouladen mit Apfel-Rotkohl und Maronen

Zutaten:
- Rinder-Rouladen
- Petersilie
- Rote Tafeläpfel
- REWE Beste Wahl Apfelrotkohl
- REWE Bio Gekochte Maronen

1. Die Rinderrouladen flach ausbreiten, mit Salz und Pfeffer würzen und mit gehackter Petersilie bestreuen. Die Rouladen aufrollen und mit Küchengarn befestigen.
2. Die Rouladen in einem großen Topf mit Öl scharf anbraten und anschließend beiseite stellen.
3. Die Äpfel schälen, vierteln, entkernen und klein schneiden. Zusammen mit dem Apfelrotkohl in den Topf geben und ca. 5 Minuten dünsten.
4. Die Rinderrouladen zurück in den Topf geben und bei niedriger Hitze 60 Minuten köcheln lassen.
5. 10 Minuten vor Ende der Kochzeit die gekochten Maronen hinzufügen.
6. Abschmecken und servieren.

Klingt doch halbwegs plausibel, oder? Eine Beilage wäre vielleicht noch gut und dass der Rotkohl in den gleichen Topf wie die Rouladen soll, ist auch nicht ganz einleuchtend. Auch wenn du die Rezepte nicht 1:1 übernehmen solltest, erhältst du mit diesem Projekt recht brauchbare Ideen für Gerichte, die deinen Geldbeutel schonen. Ich wünsche dir jedenfalls schon einmal guten Appetit!

Hier nun das vollständige Python-Script:

import cloudscraper
from openai import OpenAI

# # Deine ID, hier ein Beispiel aus Karlsruhe
market_id = '831008'
# Die Basis-URL der API
url = f'https://mobile-api.rewe.de/api/v3/all-offers?marketCode={market_id}'

# Erstellen ein Cloudscraper-Objekt
scraper = cloudscraper.create_scraper()

# Stelle die GET-Anfrage
response = scraper.get(url)

# Initialisiere einen leeren String für die Titel der Angebote
titles_string = ''

# Eine Liste der gewünschten Kategorietitel
desired_categories = {
    'Frische & Kühlung',
    'Süßes & Salziges',
    'Obst & Gemüse',
    'Nahrungsmittel',
    'Tiefkühl'
}

# Überprüfe  den Statuscode der Antwort
if response.status_code == 200:
    # Wenn der Statuscode 200 ist, war die Anfrage erfolgreich
    # Konvertiere die Antwort in JSON
    data = response.json()
    
    # Extrahiere die Angebote, die den gewünschten Kategorietiteln entsprechen
    titles = [
        offer['title']
        for category in data['categories']
        for offer in category['offers']
        if 'rawValues' in offer and 'categoryTitle' in offer['rawValues']
        and offer['rawValues']['categoryTitle'] in desired_categories
    ]
    
    # Erstelle einen String mit den gefilterten Titeln, getrennt durch Kommas
    titles_string = ', '.join(titles)
    
    # Ausgabe des Strings
    print("Gefilterte Titel:", titles_string)
else:
    # Wenn der Statuscode nicht 200 ist, gab es ein Problem mit der Anfrage
    print(f'Fehler: {response.status_code}')


# Mit ChatGPT Rezepte erstellen
client = OpenAI(
  api_key="DEIN API-KEY",
)

print("Ich erstelle Gerichte...")
completion = client.chat.completions.create(
#model="gpt-3.5-turbo", 
model="gpt-4",
messages=[
{"role": "system", "content": "Du bist ein KI-Koch, der aus vorgegebenen Zutaten Rezepte für Gerichte entwirft."},
{"role": "user", "content": "Es folgt eine Liste von Zutaten. Kreiere hieraus 3 Rezepte für leckere Gerichte. Gehe davon aus, dass die Küchen-Basics wie Salz, Pfeffer, Öl, Butter etc. bereits vorhanden sind. Hier die Liste: {}".format(titles_string)}]
)

print(completion.choices[0].message.content)
  
]]>
Arduino Schnarchstopper mit Künstlicher Intelligenz https://polluxlabs.net/arduino-projekte/arduino-schnarchstopper-mit-kuenstlicher-intelligenz/ Fri, 13 Oct 2023 11:19:01 +0000 https://polluxlabs.net/?p=14697 Arduino Schnarchstopper mit Künstlicher Intelligenz Weiterlesen »

]]>
Schnarchen ist ärgerlich, klar. Dagegen gibt es Geräte, Kissen, Apps und viele andere Mittelchen – aber die meisten davon dürften kaum halten, was sie versprechen. Falls du schnarchst und versprochen hast, dich darum zu kümmern, kannst du mit diesem Tutorial dein Leiden mit deinem Hobby verbinden: Du baust einen Arduino Schnarchstopper mit künstlicher Intelligenz.

Zum Einsatz kommt ein Arduino Nano 33 BLE Sense und ein Vibrationsmotor*. Auf dem Microcontroller läuft ein KI-Modell, das über das Mikrofon des Arduinos erkennt, ob du schnarchst. Ist das der Fall, springt der Motor an und weckt dich (hoffentlich).

Aufbau des Schnarchstoppers

Neben dem Arduino Nano 33 BLE Sense benötigst du nur einen Vibrationsmotor und ein Verbindungskabel für eine 9V-Batterie. Der Motor sollte stark genug sein, um dich wecken zu können – wobei es natürlich auch darauf ankommt, wo du den Schnarchstopper platzierst. Wenn du eine Armbinde verwendest, kann der Vibrationsmotor beispielsweise direkt auf deinem Oberarm oder auch oberhalb des Handgelenks direkt auf deiner Haut aufliegen. Hierfür eignet sich zum Beispiel das Band, das dem Spiel Ring Fit für die Nintendo Switch* beiliegt.

Statt Vibration kannst du natürlich auch zu anderen Mitteln greifen. Ein Piezo-Summer dürfte dich wohl mit Sicherheit aus dem Schlaf reißen – leider aber auch deine Bettgenossin oder deinen Bettgenossen. Im Folgenden bleibst du beim Vibrationsmotor. Der Aufbau sieht dann so aus:

Schnarchstopper Hardware

Falls du einen Arduino mit Header-Pins hast, kannst du die Kabel der beiden Bauteile entsprechend anpassen. Löte hierfür jeweils zwei Kabel mit einer Buchse an, die du dann am Arduino aufstecken kannst. Hier der Aufbau als Skizze:

Skizze des Aufbaus der Hardware

Das passende KI-Modell und der Sketch

Damit der Schnarchstopper dein Schnarchen erkennt, benötigst du ein KI-Modell, das du in deinem Arduino Sketch verwendest.

Dieses Tutorial ist angelehnt an diesem Projekt auf GitHub – mit ein paar Anpassungen. Der Maker metanav hat dort schon viel Vorarbeit geleistet, die du weiterverwenden kannst. Lade dir auf GitHub oder direkt hier das Projekt als ZIP-Datei herunter:

Download KI-Modell

Entpacke anschließend die ZIP-Datei und öffne den Sketch tflite_micro_snoring_detection.ino, den du im Ordner Snoring-Guardian-main > snoring_detection_inferencing > examples >tflite_micro_snoring_detection findest.

Anschließend bindest du die mitgelieferte Bibliothek ein. Darin enthalten ist das KI-Modell, das du verwenden wirst. Öffne in der Arduino IDE den Menüpunkt Sketch > Bibliothek einbinden > ZIP-Bibliothek hinzufügen und wähle die Datei Snoring_detection_inferencing.zip

Den Arduino NANO und eine weitere Bibliothek installieren

Falls du du den Arduino Nano 33 BLE Sense in der Arduino IDE noch nicht verfügbar gemacht hast, hole das schnell nach. Öffne hierfür den Boardverwalter im Menü links, suche nach Arduino Nano BLE Sense und installiere die aktuelle Version von Arduino Mbed OS Nano Boards.

Installation des Arduino Nano 33 BLE Sense

Außerdem benötigst du noch die Bibliothek RingBuf, die du über den Bibliotheksverwalter installieren kannst. Aber Achtung: Die gleichnamige Bibliothek funktioniert nicht auf dem Arduino Nano. Installiere stattdessen die Bibliothek RingBuffer von Jean-Luc – Locoduino:

Installation der Bibliothek RingBuffer

Für einen Test wähle in der Arduino IDE dein Board aus und klicke oben links auf den Haken für die Überprüfung des Sketchs. Die Kompilierung nimmt einige Zeit in Anspruch, aber wenn die richtigen Bibliotheken installiert bzw. eingebunden wurden und die Verbindung zum Arduino Nano steht, sollte sie erfolgreich abgeschlossen werden:

Ausgabe nach Upload des Sketchs

Anpassungen im Sketch

Du kannst den Sketch für den Schnarchstopper direkt auf deinen Arduino hochladen und verwenden, aber je nachdem, welchen Vibrationsmotor (oder welches andere Bauteil) du verwendest, musst du ein paar Kleinigkeiten anpassen.

Im Sketch kümmert sich die Funktion void run_vibration() um den Start des Motors. Im Beispiel-Sketch sieht sie wie folgt aus:

void run_vibration()
{
  if (alert)
  {
    is_motor_running = true;

    for (int i = 0; i < 2; i++)
    {
      analogWrite(vibratorPin, 30);
      delay(1000);
      analogWrite(vibratorPin, 0);
      delay(1500);
    }
    
    is_motor_running = false;
  } else {
    if (is_motor_running)
    {
      analogWrite(vibratorPin, 0);
    }
  }
  yield();
}

Hier wird der Motor 3 Mal jeweils für eine Sekunde gestartet, mit einer Pause von 1,5 Sekunden dazwischen. Hierfür wird analogWrite() mit einem Wert von 30 verwendet. Der Vibrationsmotor, den ich verwende, versteht allerdings nur Ein und Aus. Falls das bei dir auch der Fall ist, ändere die betreffende Stelle folgendermaßen:

for (int i = 0; i < 2; i++) {
  digitalWrite(vibratorPin, HIGH);
  delay(5000);
  digitalWrite(vibratorPin, LOW);
  delay(1000);
}

Hier verwendest du digitalWrite() und sendest damit entweder ein HIGH oder LOW an den Motor. Ebenfalls sind dort die Lauf- und Pausenzeiten geändert – die fünf Sekunden zielen hier eher auf Schnarcher mit einem tiefen Schlaf.

Und noch eine Anpassung: Wenn du deinen Vibrationsmotor wie in der Skizze oben an den Pin D2 angecshlossen hast, ändere noch die entsprechende Zeile im Sketch:

int vibratorPin = 2;

Lade nun den Sketch auf deinen Arduino Nano hoch – du findest ihn ganz am Ende dieses Tutorials.

Den Schnarchstopper testen

Jetzt ist es so weit – sobald der Sketch erfolgreich auf deinem Arduino gelandet ist, öffne den Seriellen Monitor in der IDE. Dort siehst du die Vorhersagen, die das KI-Modell macht auf Basis der Geräusche, die es über das eingebaute Mikrofon des Arduinos erhält:

Ausgabe des Schnarchstoppers im seriellen Monitor

Im oben rot markierten Fall war das ein normales Hintergrundgeräusch (noise) mit einer Wahrscheinlichkeit von 99,219 %. Das hier jemand geschnarcht hat, war hingegen nur zu 0,781 % wahrscheinlich.

Es ist vermutlich etwas peinlich, aber imitiere nun mehrmals hintereinander typische Schnarchlaute. Du wirst sehen, dass die interne LED des Arduinos aufleuchtet und sich die Ausgabe im Seriellen Monitor entsprechend verändert. Sobald mehrmals ein Schnarchen erkannt wurde, springt auch der Vibrationsmotor an und vibriert im von dir in der Funktion run_vibration() definierten Rhythmus.

Als nächstes wird es Zeit für ein paar „echte“ Tests in der Nacht. Da du deinen Arduino Nano auch mit einer 9V-Batterie versorgen kannst, steht deinen Versuchen im Bett nichts im Wege. Vermutlich musst du mehrere Möglichkeiten der Positionierung des Motors ausprobieren, um von seinen Vibrationen aufzuwachen bzw. um dem Mikrofon des Arduinos zu ermöglichen, dich einwandfrei beim Schnarchen aufzunehmen. Sollte letzteres nicht der Fall sein, kann es zu Fehlalarmen kommen.

Und natürlich gibt es keine Garantie, dass dein neuer Schnarchstopper überhaupt zu ruhigen Nächten führt…

Entwickle dein eigenes KI-Modell

Da du bisher ein vorgefertigtes Modell verwendet hast, ist es möglich, dass es für dich nicht bestmöglich funktioniert. Jeder schnarcht schließlich anders – und die Schnarchgeräusche, die für das Training des Modells verwendet wurden, können stark von deinen eigenen abweichen.

Falls du also einen Schritt weitergehen möchtest, ist das kein Problem – nur etwas Arbeit. Auf Pollux Labs findest du Tutorials, wie du den Service Edge Impulse verwenden kannst, um ein persönliches KI-Modell zu entwickeln. Dort erfährst du, wie du deinen Arduino Nano 33 BLE Sense mit Edge Impulse verbindest, damit Daten sammelst und dein eigenes Modell trainierst. Im letztgenannten Tutorial geht es zwar um Bewegungsdaten, aber ähnlich funktioniert auch das Training mit Audio.

Apropos Audio, um ausreichend Schnarchtöne zu sammeln, eignet sich bereits dein Smartphone. Starte einfach eine Tonaufnahme und lass das Smartphone die Nacht über neben dir liegen. Die entsprechenden Passagen in der Audiodatei kannst du dann in Edge Impulse weiterverarbeiten.

Und nun viel Spaß und Erfolg beim Experimentieren mit deinem Schnarchstopper!

Der vollständige Sketch

Hier nun der gesamte Sketch mit den genannten Anpassungen:

// If your target is limited in memory remove this macro to save 10K RAM
#define EIDSP_QUANTIZE_FILTERBANK   0

/**
   Define the number of slices per model window. E.g. a model window of 1000 ms
   with slices per model window set to 4. Results in a slice size of 250 ms.
   For more info: https://docs.edgeimpulse.com/docs/continuous-audio-sampling
*/
#define EI_CLASSIFIER_SLICES_PER_MODEL_WINDOW 3

/* Includes ---------------------------------------------------------------- */
#include <PDM.h>
#include <Scheduler.h>
#include <RingBuf.h>
#include <snore_detection_inferencing.h>

/** Audio buffers, pointers and selectors */
typedef struct {
  signed short *buffers[2];
  unsigned char buf_select;
  unsigned char buf_ready;
  unsigned int buf_count;
  unsigned int n_samples;
} inference_t;

static inference_t inference;
static bool record_ready = false;
static signed short *sampleBuffer;
static bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal
static int print_results = -(EI_CLASSIFIER_SLICES_PER_MODEL_WINDOW);

bool alert = false;

RingBuf<uint8_t, 10> last_ten_predictions;
int greenLED = 23;
int vibratorPin = D2;   // Vibration motor connected to D2 PWM pin
bool is_motor_running = false;

void run_vibration() {
  if (alert) {
    is_motor_running = true;

    for (int i = 0; i < 2; i++) {
      digitalWrite(vibratorPin, HIGH);
      delay(5000);
      digitalWrite(vibratorPin, LOW);
      delay(1000);
    }

    is_motor_running = false;
  } else {
    if (is_motor_running) {
      analogWrite(vibratorPin, LOW);
    }
  }
  yield();
}



/**
   @brief      Printf function uses vsnprintf and output using Arduino Serial

   @param[in]  format     Variable argument list
*/
void ei_printf(const char *format, ...) {
  static char print_buf[1024] = { 0 };

  va_list args;
  va_start(args, format);
  int r = vsnprintf(print_buf, sizeof(print_buf), format, args);
  va_end(args);

  if (r > 0) {
    Serial.write(print_buf);
  }
}

/**
   @brief      PDM buffer full callback
               Get data and call audio thread callback
*/
static void pdm_data_ready_inference_callback(void)
{
  int bytesAvailable = PDM.available();

  // read into the sample buffer
  int bytesRead = PDM.read((char *)&sampleBuffer[0], bytesAvailable);

  if (record_ready == true) {
    for (int i = 0; i<bytesRead >> 1; i++) {
      inference.buffers[inference.buf_select][inference.buf_count++] = sampleBuffer[i];

      if (inference.buf_count >= inference.n_samples) {
        inference.buf_select ^= 1;
        inference.buf_count = 0;
        inference.buf_ready = 1;
      }
    }
  }
}

/**
   @brief      Init inferencing struct and setup/start PDM

   @param[in]  n_samples  The n samples

   @return     { description_of_the_return_value }
*/
static bool microphone_inference_start(uint32_t n_samples)
{
  inference.buffers[0] = (signed short *)malloc(n_samples * sizeof(signed short));

  if (inference.buffers[0] == NULL) {
    return false;
  }

  inference.buffers[1] = (signed short *)malloc(n_samples * sizeof(signed short));

  if (inference.buffers[0] == NULL) {
    free(inference.buffers[0]);
    return false;
  }

  sampleBuffer = (signed short *)malloc((n_samples >> 1) * sizeof(signed short));

  if (sampleBuffer == NULL) {
    free(inference.buffers[0]);
    free(inference.buffers[1]);
    return false;
  }

  inference.buf_select = 0;
  inference.buf_count = 0;
  inference.n_samples = n_samples;
  inference.buf_ready = 0;

  // configure the data receive callback
  PDM.onReceive(&pdm_data_ready_inference_callback);

  PDM.setBufferSize((n_samples >> 1) * sizeof(int16_t));

  // initialize PDM with:
  // - one channel (mono mode)
  // - a 16 kHz sample rate
  if (!PDM.begin(1, EI_CLASSIFIER_FREQUENCY)) {
    ei_printf("Failed to start PDM!");
  }

  // set the gain, defaults to 20
  PDM.setGain(127);

  record_ready = true;

  return true;
}

/**
   @brief      Wait on new data

   @return     True when finished
*/
static bool microphone_inference_record(void)
{
  bool ret = true;

  if (inference.buf_ready == 1) {
    ei_printf(
      "Error sample buffer overrun. Decrease the number of slices per model window "
      "(EI_CLASSIFIER_SLICES_PER_MODEL_WINDOW)\n");
    ret = false;
  }

  while (inference.buf_ready == 0) {
    delay(1);
  }

  inference.buf_ready = 0;

  return ret;
}

/**
   Get raw audio signal data
*/
static int microphone_audio_signal_get_data(size_t offset, size_t length, float * out_ptr)
{
  numpy::int16_to_float(&inference.buffers[inference.buf_select ^ 1][offset], out_ptr, length);

  return 0;
}

/**
   @brief      Stop PDM and release buffers
*/
static void microphone_inference_end(void)
{
  PDM.end();
  free(inference.buffers[0]);
  free(inference.buffers[1]);
  free(sampleBuffer);
}


void setup()
{
  Serial.begin(115200);

  pinMode(greenLED, OUTPUT);
  pinMode(greenLED, LOW); 
  pinMode(vibratorPin, OUTPUT);  // sets the pin as output

  // summary of inferencing settings (from model_metadata.h)
  ei_printf("Inferencing settings:\n");
  ei_printf("\tInterval: %.2f ms.\n", (float)EI_CLASSIFIER_INTERVAL_MS);
  ei_printf("\tFrame size: %d\n", EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE);
  ei_printf("\tSample length: %d ms.\n", EI_CLASSIFIER_RAW_SAMPLE_COUNT / 16);
  ei_printf("\tNo. of classes: %d\n", sizeof(ei_classifier_inferencing_categories) /
            sizeof(ei_classifier_inferencing_categories[0]));

  run_classifier_init();
  if (microphone_inference_start(EI_CLASSIFIER_SLICE_SIZE) == false) {
    ei_printf("ERR: Failed to setup audio sampling\r\n");
    return;
  }

  Scheduler.startLoop(run_vibration);
}

void loop()
{

  bool m = microphone_inference_record();

  if (!m) {
    ei_printf("ERR: Failed to record audio...\n");
    return;
  }

  signal_t signal;
  signal.total_length = EI_CLASSIFIER_SLICE_SIZE;
  signal.get_data = &microphone_audio_signal_get_data;
  ei_impulse_result_t result = {0};

  EI_IMPULSE_ERROR r = run_classifier_continuous(&signal, &result, debug_nn);
  if (r != EI_IMPULSE_OK) {
    ei_printf("ERR: Failed to run classifier (%d)\n", r);
    return;
  }

  if (++print_results >= (EI_CLASSIFIER_SLICES_PER_MODEL_WINDOW)) {
    // print the predictions
    ei_printf("Predictions ");
    ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)",
              result.timing.dsp, result.timing.classification, result.timing.anomaly);
    ei_printf(": \n");

    for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
      ei_printf("    %s: %.5f\n", result.classification[ix].label,
                result.classification[ix].value);

      if (ix == 1 && !is_motor_running && result.classification[ix].value > 0.9) {
        if (last_ten_predictions.isFull()) {
          uint8_t k;
          last_ten_predictions.pop(k);
        }

        last_ten_predictions.push(ix);

        uint8_t count = 0;

        for (uint8_t j = 0; j < last_ten_predictions.size(); j++) {
          count += last_ten_predictions[j];
          //ei_printf("%d, ", last_ten_predictions[j]);
        }
        //ei_printf("\n");
        ei_printf("Snoring\n");
        pinMode(greenLED, HIGH); 
        if (count >= 5) {
          ei_printf("Trigger vibration motor\n");
          alert = true;
        }
      }  else {
        ei_printf("Noise\n");
        pinMode(greenLED, LOW); 
        alert = false;
      }

      print_results = 0;
    }
  }
}


#if !defined(EI_CLASSIFIER_SENSOR) || EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_MICROPHONE
#error "Invalid model for current sensor."
#endif
]]>