Raspberry Pi Projekte – Pollux Labs https://polluxlabs.net Arduino, ESP32 & ESP8266 | Projekte & Tutorials Fri, 12 Apr 2024 07:13:06 +0000 de-DE hourly 1 https://wordpress.org/?v=6.5.2 https://polluxlabs.net/wp-content/uploads/2020/05/cropped-pollux-labs-p-32x32.png Raspberry Pi Projekte – Pollux Labs https://polluxlabs.net 32 32 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:

___STEADY_PAYWALL___

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.

___STEADY_PAYWALL___

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.

]]>
Mit Ollama Sprachmodelle lokal nutzen https://polluxlabs.net/raspberry-pi-projekte/mit-ollama-sprachmodelle-lokal-nutzen/ Sat, 02 Mar 2024 20:54:03 +0000 https://polluxlabs.net/?p=16091 Mit Ollama Sprachmodelle lokal nutzen Weiterlesen »

]]>
Hier auf Pollux Labs konntest du bereits darüber lesen, wie du z.B. die API von OpenAI nutzt, um mit ChatGPT zu interagieren. Aber das geht auch lokal auf deinem eigenen Rechner – zwar nicht mit ChatGPT, dafür jedoch mit anderen Sprachmodellen wie Mistral, Gemma, Llama2 und vielen anderen. Hierfür nutzt du das Tool Ollama. In diesem Tutorial erfährst du, wie du es installierst, einrichtest und mit Python mit dem Modell deiner Wahl interagierst.

Ollama installieren

Wenn du einen Mac oder Windows benutzt, musst du Ollama erst hier auf der offziellen Webseite herunterladen.

Ollama herunterladen

Falls du Linux verwendest, gib im Terminal den folgenden Befehl ein:

curl -fsSL https://ollama.com/install.sh | sh

Entpacke nach dem Download die ZIP-Datei (Mac) und starte das Programm oder starte direkt die .exe (Windows). Anschließend führt dich ein Wizard durch die nächsten Schritte, damit du Ollama im Terminal verwenden kannst. Am Ende erhältst du den Befehl für einen ersten Test.

___STEADY_PAYWALL___

Ollama-Wizard

Kopiere den Befehl und gib in im Terminal bzw. der Konsole ein. Anschließend wird das Sprachmodell Llama2 heruntergeladen. Dieses Modell stammt vom Facebook-Konzert Meta. Wie du auf dem Bild unten siehst, ist das mit 3,8 Gigabyte nicht gerade klein – achte also auf genügend Speicherplatz.

Download von Llama2 im Terminal

Ollama im Terminal verwenden

Um mit deinem ersten Sprachmodell (Llama2) loszulegen, kannst du direkt im selben Fenster bleiben. Du erhältst nach der erfolgreichen Installation eine Eingabeaufforderung, über die du deine erste Frage stellen kannst – so wie du es vermutlich bereits von ChatGPT kennst. Nach wenigen Sekunden erhältst du dann die Antwort ebenfalls im Terminal:

Llama2 über Ollama im Terminal

Das funktioniert also schon einmal ganz gut. Das Beispiel oben ist auf Englisch – du kannst deine Fragen jedoch auch ebenso auf Deutsch stellen. Die Antwort erhältst du von Llama2 jedoch wiederum auf Englisch. Um Antworten auf Deutsch zu erhalten füge deinem Prompt noch eine entsprechende Anweisung hinzu.

Wenn du deine Session beenden möchtest, gib einfach den Befehl /bye ein.

Ein anderes Sprachmodell in Ollama installieren

Du bist natürlich nicht auf Llama2 beschränkt. Auf der Ollama-Webseite sowie auf deren GitHub-Seite kannst du alle verfügbaren Sprachmodelle einsehen. Auf letzterer erfährst du auch, wieviel Arbeitsspeicher du für die verschiedenen Modelle haben solltest. Versuche es doch als nächstes einmal mit Mistral, einem frei verfügbaren französischen Modell (das auch Deutsch kann). Gib hierfür im Terminal folgenden Befehl ein, nachdem du deine aktive Session mit /bye beendet hast:

ollama run mistral

Nach der Installation kannst du mit Mistral interagieren, so wie du es vorher mit Llama2 getan hast.

Das Sprachmodell von Mistral ist mit 4,1 GB sogar noch etwas größer als Llama2. Es ist also hilfreich zu wissen, wie du installierte Modelle wieder loswirst. Ganz einfach – Um z.B. Llama2 zu entfernen, gib im Terminal den folgenden Befehl ein:

ollama rm llama2

Falls du vergessen hast, welche Modelle du gerade installiert hast, hilft dir folgender Befehl weiter:

ollama list

Ollama mit Python verwenden

Bis jetzt hast du “nur” im Terminal mit deinem lokalen Sprachmodell kommuniziert. Du kannst aber hierfür natürlich auch ein Python-Script verwenden, ähnlich wie ich es hier schon einmal für ChatGPT beschrieben habe.

Zunächst musst du hierfür die entsprechende Bibliothek installieren:

pip install ollama

Erstelle nach der erfolgreichen Installation ein leeres Python-Script mit folgendem Inhalt:

import ollama
response = ollama.chat(model='mistral', messages=[
  {
    'role': 'user',
    'content': 'Welche Farben können Bären haben? Antworte auf Deutsch.',
  },
])
print(response['message']['content'])

Im obigen Script ist wieder das Sprachmodell von Mistral hinterlegt. Falls du ein anderes verwendest, trage es in der zweiten Zeile hinter model= ein.

Speiche die Datei nun ab und führe sie aus. Vermutlich wirst du ziemlich lange warten müssen, bis die Antwort erscheint. Das kannst du mit einem Stream verbessern – hierdurch erscheint die lange Antwort Wort für Wort zum Mitlesen. Verwende hierfür den folgenden angepassten Code:

import ollama

stream = ollama.chat(
    model='mistral',
    messages=[{'role': 'user', 'content': 'Welche Farben können Bären haben? Anworte auf Deutsch'}],
    stream=True,
)

for chunk in stream:
  print(chunk['message']['content'], end='', flush=True)

Weitere Rollen verwenden

Ähnlich wie bei ChatGPT kannst du auch in Ollama in deinen Rollen zuteilen. Wenn du also deine Antworten z.B. immer auf Deutsch erhalten möchtest, hilft dir die Rolle system weiter. Dort kannst du die entsprechende Anweisung hinterlegen, sodass die Rolle user nur deine Frage enthält:

messages=[{'role': 'user', 'content': 'Welche Farben können Bären haben?'},
          {'role': 'system', 'content': 'Antworte auf Deutsch'}],

Jetzt kennst du die Grundlagen, um mit Ollama auf deinem eigenen Rechner Sprachmodelle auszuführen und in deine Projekte einzubinden. Es gibt natürlich noch viel mehr zu entdecken: Die verschiedenen Modelle besitzen alle unterschiedliche Fähigkeiten – hier lohnt sich ein intensiver Blick, besonders da die Entwicklung natürlich nicht stehen bleibt.

]]>
Wie knapp verfehlt uns heute ein Asteroid? https://polluxlabs.net/python-tutorials-und-projekte/wie-knapp-verfehlt-uns-heute-ein-asteroid/ Wed, 21 Feb 2024 10:11:38 +0000 https://polluxlabs.net/?p=16025 Wie knapp verfehlt uns heute ein Asteroid? Weiterlesen »

]]>
Es ist erstaunlich, wie viele Asteroiden täglich an der Erde vorbeifliegen. Wobei “an der Erde vorbei” in der Regel mehrere Millionen Kilometer bedeutet und diese Asteroiden also keine Gefahr für uns bedeuten. Die NASA stellt eine API zur Verfügung, mit deren Hilfe du die nächsten Vorbeiflüge von Asteroiden für ein bestimmtes Datum einsehen kannst.

Hieraus lässt sich ein kleines Projekt bauen: Mit einem Python-Script ermittelst du den Passanten, der heute am knappsten an uns vorbeisaust und gibst seinen Namen sowie die Entfernung in der Konsole aus – oder lässt dich z.B. per E-Mail informieren.

Am 21. Februar 2024 sah es folgendermaßen aus:

Heute fliegt der Asteroid (2024 CL5) mit 1826990 Kilometern Entfernung am knappsten an der Erde vorbei.

Gute 1,8 Millionen Kilometer – klingt viel, ist es aber nach kosmischen Maßstäben eigentlich nicht. Aber immerhin war der Asteroid bei seinem Vorbeiflug immer noch ungefährt 5 Mal so weit von uns entfernt wie unser eigener Mond.

Das Python-Script

Du benötigst nicht viel Code für dieses Projekt. Zentral sind die API, bei der du die aktuellen Daten beziehst sowie das aktuelle Datum, das du in dieser API-Abfrage verwendest.

___STEADY_PAYWALL___

Die NASA betreibt eine Übersicht über ihre APIs – dort findest du unter Asteroids – NeoWs alle Informationen, die du benötigst. Wenn du dieses Projekt regelmäßig einsetzen möchtest, registriere deinen eigenen API-Key bei der NASA. Das kannst du auf der eben verlinkten Webseite machen. Falls du die API nur einmal ausprobieren möchtest, reicht auch der DEMO_KEY.

Hier zunächst das vollständige Python-Script:

import requests
from datetime import datetime

def find_asteroids(json_data):
    nearest_asteroid = None
    nearest_miss_distance = float('inf')
    
    for date in json_data["near_earth_objects"]:
        for asteroid in json_data["near_earth_objects"][date]:
            miss_distance = float(asteroid["close_approach_data"][0]["miss_distance"]["kilometers"])
            if miss_distance < nearest_miss_distance:
                nearest_asteroid = asteroid
                nearest_miss_distance = miss_distance
    
    return nearest_asteroid

# Aktuelles Datum erhalten und im passenden Format formatieren
current_date = datetime.now().strftime('%Y-%m-%d')

# API-URL für die NASA NEO-Daten
api_url = f"https://api.nasa.gov/neo/rest/v1/feed?start_date={current_date}&end_date={current_date}&detailed=false&api_key=DEMO_KEY"


# Anfrage an die API senden und JSON-Daten abrufen
response = requests.get(api_url)
json_data = response.json()

# Finde den Asteroiden mit dem knappsten Vorbeiflug
nearest_asteroid = find_asteroids(json_data)

print("Heute fliegt der Asteroid", nearest_asteroid["name"], "mit", int(float(nearest_asteroid["close_approach_data"][0]["miss_distance"]["kilometers"])), "Kilometern Entfernung am knappsten an der Erde vorbei.")

Hier findest du die URL der API, an die du deine Abfrage sendest:

api_url = f"https://api.nasa.gov/neo/rest/v1/feed?start_date={current_date}&end_date={current_date}&detailed=false&api_key=DEMO_KEY"

Dort eingebaut siehst du das aktuelle Datum als {current_date} – dieses Datum ermittelst und formatierst du wie folgt:

current_date = datetime.now().strftime('%Y-%m-%d')

Mit Hilfe der Bibliothek datetime ermittelst du das heutige Datum und bringst es mit dem Befehl strftime in das Format, das die API der NASA erwartet.

Die Antwort erhältst du im JSON-Format. Für den 21.2.24 sieht diese z.B. so aus. In diesen Daten suchst du nun mit der Funktion find_asteroids(json_data) nach dem Asteroiden, der der Erde am nächsten kommt. Sobald dieser gefunden ist, gibst du seinen Namen und die Entfernung des Vorbeiflugs über einen Print-Befehl aus.

print("Heute fliegt der Asteroid", nearest_asteroid["name"], "mit", int(float(nearest_asteroid["close_approach_data"][0]["miss_distance"]["kilometers"])), "Kilometern Entfernung am knappsten an der Erde vorbei.")

Mehr Informationen über die Asteroiden

In den Daten stecken noch viel mehr Informationen, als jene, die du bisher verwendest hast. Z.B. der geschätzte Durchmesser im Key estimated_diameter sowie seine Geschwindigkeit. Oder auch, ob der besagte Asteroid als gefährlich eingestuft wird – im Key is_potentially_hazardous_asteroid. Was diese Einstufung bedeutet, erfährst du in dieser Erklärung.

Falls du dich also für dieses Thema interessierst, sind deinem Tatendrang wenige Grenzen gesetzt. So könntest du z.B. grafisch darstellen, wie nah ein Asteroid uns in Bezug zu anderen Himmelskörpern kommt. Viel Spaß beim Experimentieren!

]]>
Zeige die Position der ISS auf einer Weltkarte an https://polluxlabs.net/raspberry-pi-projekte/zeige-die-position-der-iss-auf-einer-weltkarte-an/ Sun, 04 Feb 2024 14:35:45 +0000 https://polluxlabs.net/?p=15721 Zeige die Position der ISS auf einer Weltkarte an Weiterlesen »

]]>
Wo befindet sich die ISS (International Space Station) gerade? Diese Frage beantwortest du mit diesem Projekt spielend leicht. Mit Hilfe eines Python-Scripts und einer API ermittelst du die aktuellen Koordinaten der Raumstation und legst sie über eine Weltkarte. Diese Karte wird in einem Browser geöffnet und alle 10 Sekunden aktualisiert. So kannst du die aktuelle Position der ISS verfolgen und sehen, über welchem Ort sie sich gerade befindet.

Zum Einsatz kommt in diesem Projekt ein Raspberry Pi. Das Browser-Fenster wird darauf im sogenannten Kiosk-Modus (also im Vollbild) geöffnet. So kannst du mit einem kleinen Display deine eigene ISS-Installation aufbauen.

Die Position der ISS auf einem Display

Der Aufbau des Projekts

Im Prinzip benötigst du nur Python für dieses Projekt. Du kannst das untenstehende Script auch einfach auf deinem PC oder Mac ausführen. Ich lasse es jedoch auf einem Raspberry Pi laufen und verwende statt eines großen Monitors ein kleines 7” Touch-Display.

Mit diesem Script ermittelst du die Position der ISS

Das folgende Python-Script funktioniert so: Von einer API beziehst du die aktuellen Koordinaten, über denen die ISS gerade fliegt. Anschließend erstellst du mit Hilfe der Bibliothek Folium eine Weltkarte und ein Icon, dass die Position der Raumstation anzeigt. Diese Karte speicherst du als HTML-Datei und öffnest diese wiederum im Chrome-Browser. Diese Webseite (also die Weltkarte) wird alle 10 Sekunden aktualisiert, abgespeichert und im Browser aktualisiert.

Installiere die nötigen Bibliotheken

Zunächst zu den Python-Bibliotheken, die du für dieses Projekt benötigst. Installiere diese im Terminal mit den folgenden Befehlen:

___STEADY_PAYWALL___

pip install requests
pip install folium
pip install Selenium
sudo apt-get install chromium-chromedriver

Das vollständige Script

Nach der Installation der Bibliotheken, kannst du das folgende Script ausführen. Wie es funktioniert, schauen wir uns gleich an.

import requests
import folium
from datetime import datetime
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options


def get_iss_position():
    response = requests.get("http://api.open-notify.org/iss-now.json")
    data = response.json()
    if response.status_code == 200:
        timestamp = datetime.utcfromtimestamp(data['timestamp']).strftime('%Y-%m-%d %H:%M:%S')
        latitude = float(data['iss_position']['latitude'])
        longitude = float(data['iss_position']['longitude'])
        return timestamp, latitude, longitude
    else:
        return None

def main():
    chrome_options = Options()
    chrome_options.add_argument('--kiosk')
    service = webdriver.ChromeService(executable_path = '/usr/bin/chromedriver')
    driver = webdriver.Chrome(service=service, options=chrome_options)
    driver.get(f"file:///home/pi/Desktop/iss_map.html") # Passe den Pfad bei Bedarf an
    
    while True:
        iss_position = get_iss_position()

        if iss_position:
            timestamp, latitude, longitude = iss_position
            print(f"ISS Position at {timestamp}: Latitude {latitude}, Longitude {longitude}")

            iss_map = folium.Map(location=[latitude,longitude], zoom_start=4)
            folium.Marker([latitude, longitude], popup=f"ISS at {timestamp}", icon=folium.Icon(color='red')).add_to(iss_map)

            # Speichere die Karte als HTML
            iss_map.save("/home/pi/Desktop/iss_map.html") # Passe den Pfad an deinen eigenen an
            print("Map saved as iss_map.html")         
            
        else:
            print("Failed to retrieve ISS position.")
        time.sleep(10)
        driver.refresh()

if __name__ == "__main__":
    main()

So funktioniert das Script

Zunächst importierst du die benötigten Bibliotheken bzw. die notwendigen Funktionen:

import requests
import folium
from datetime import datetime
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

Dann folgt eine Funktion, mit der du die aktuelle Position der ISS ermittelst:

def get_iss_position():
    response = requests.get("http://api.open-notify.org/iss-now.json")
    data = response.json()
    if response.status_code == 200:
        timestamp = datetime.utcfromtimestamp(data['timestamp']).strftime('%Y-%m-%d %H:%M:%S')
        latitude = float(data['iss_position']['latitude'])
        longitude = float(data['iss_position']['longitude'])
        return timestamp, latitude, longitude
    else:
        return None

Hier kommt die API von open-notify.org ins Spiel. Diese liefert dir nach ihrem Aufruf die aktuellen Koordinaten der ISS als JSON. Diese Koordinaten sowie die aktuelle Uhrzeit speicherst du in den Variablen latitude, longitude und timestamp.

In der folgenden Funktion main() konfigurierst du zunächst Selenium, die Bibliothek, mit der du die Weltkarte im Browser aufrufst. In der letzten der folgenden Zeilen steckt der Pfad zur HTML-Datei, die die Weltkarte enthält – hierzu gleich mehr.

chrome_options = Options()
chrome_options.add_argument('--kiosk')
service = webdriver.ChromeService(executable_path = '/usr/bin/chromedriver')
driver = webdriver.Chrome(service=service, options=chrome_options)
driver.get(f"file:///home/pi/Desktop/iss_map.html") # Passe den Pfad bei Bedarf an

Zunächst zum Loop, der dafür sorgt, dass du alle 10 Sekunden die aktuelle Position der ISS erhältst.

while True:
    iss_position = get_iss_position()

    if iss_position:
        timestamp, latitude, longitude = iss_position
        print(f"ISS Position at {timestamp}: Latitude {latitude}, Longitude {longitude}")

        iss_map = folium.Map(location=[latitude,longitude], zoom_start=4)
        folium.Marker([latitude, longitude], popup=f"ISS at {timestamp}", icon=folium.Icon(color='red')).add_to(iss_map)

        # Speichere die Karte als HTML
        iss_map.save("/home/pi/Desktop/iss_map.html") # Passe den Pfad an deinen eigenen an
        print("Map saved as iss_map.html")         

Hier rufst du zunächst die Funktion get_iss_position() auf, um die aktuelle Position zu ermitteln. Falls du von dieser Funktion Werte zurück erhältst (der Aufruf der API also geklappt hat), gibst du diese mit print aus.

Wichtiger ist jedoch die Weltkarte, die du gleich darauf mit Hilfe der Bibliothek Folium zeichnest. Lass uns auf diese Zeile kurz genauer schauen:

iss_map = folium.Map(location=[latitude,longitude], zoom_start=4)

Die Parameter location=[latitude,longitude] sorgen dafür, dass die Position der ISS auf der Weltkarte zentral angezeigt wird. Die Nadel, die die Raumstation symbolisiert ist also immer im Zentrum zu sehen. Die Welt dreht sich dann quasi unter der ISS weg. Du kannst auch die Einstellung location=[0,0] verwenden – dann bleibt die Welt stehen und die ISS-Nadel bewegt sich.

Das führt uns gleich zum Zoom-Level. Im Script oben ist dieser auf 4 eingestellt – ein mittlerer Detailgrad. Je kleiner der Wert, desto mehr zoomst du von der Erde weg. Um genau zu sehen, worüber die ISS gerade fliegt, erhöhe die Zahl in dieser Einstellung.

Zuletzt speicherst du die Karte als HTML-Datei ab. Wenn du hier einen anderen Pfad als den obigen angibst, achte darauf, dass du diesen auch an der Stelle weiter oben im Script entsprechend anpasst.

Damit wären wir fast durch – fehlt nur noch die Angabe, wie oft die Karte aktualisiert werden soll und der Befehl zum Refresh des Browsers:

time.sleep(10)
driver.refresh()

Hier sind 10 Sekunden eingestellt. Du kannst diesen Wert natürlich beliebig anpassen – beachte jedoch, dass eine zu häufige Aktualisierung zu Problemen mit dem Browser und auch zu einer vorübergehenden Sperrung deiner API-Aufrufe führen kann.

Wie geht es weiter?

Du könntest als Nächstes den Weg der ISS nachzeichnen – also die vergangenen Positionen der ISS auf die Karte übertragen und so den Flug der Raumstation also geschwungene Linie zeigen. Auch hier kann dir die Bibliothek Folium helfen.

]]>
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

___STEADY_PAYWALL___

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

___STEADY_PAYWALL___

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)
  
]]>
Objekterkennung mit Künstlicher Intelligenz und dem Raspberry Pi https://polluxlabs.net/raspberry-pi-projekte/objekterkennung-mit-kuenstlicher-intelligenz-und-dem-raspberry-pi/ Fri, 06 Oct 2023 09:16:16 +0000 https://polluxlabs.net/?p=14619 Objekterkennung mit Künstlicher Intelligenz und dem Raspberry Pi Weiterlesen »

]]>
Objekte automatisch zu erkennen, kann in vielen Projekten zum Einsatz kommen – Hindernisse meidende Roboter, eine Kamera am 3D-Drucker oder auch eine Tür, die sich nur für bekannte Gesichter öffnet. Letzteres offenbart, dass Menschen für eine künstliche Intelligenz auch nur Objekte sind…

In diesem Tutorial erfährst du, wie du mit einem Raspberry Pi samt passender Kamera* und einem selbst entwickelten KI-Modell Gegenstände erkennen kannst. Für das Modell kommt der kostenlose Google Service Teachable Machine zum Einsatz. Den Code wirst du in Python schreiben.

Hinweis: Aktuell funktioniert dieses Tutorial nur für Raspberry Pi OS Bullseye. Eine Anpassung an die neuester Version Bookworm folgt.

Inhalt

Trainiere das KI-Modell mit Teachable Machine

Damit eine künstliche Intelligenz ein Objekt erkennen – bzw. Objekte voneinander unterscheiden kann – muss sie diese natürlich erst einmal kennenlernen. Du könntest hierfür natürlich zahlreiche Fotos erstellen und ein entsprechendes neuronales Netz manuell trainieren. Deutlich komfortabler geht es mit Services wie Edge Impulse oder Teachable Machine.

Hierfür nimmst du mit einer Webcam in wenigen Sekunden eine große Zahl von Fotos deiner Objekte auf. Mit einem Klick trainierst du anschließend das KI-Modell, das du daraufhin herunterladen kannst – z.B. als Tensorflow. Hierbei wird das neuronale Netz zwar in der Cloud trainiert – die Fotos werden laut Google allerdings nicht hochgeladen und dort gespeichert.

KI-Modell mit Teachable Machine trainieren

___STEADY_PAYWALL___

Du findest auf Pollux Labs ein ausführliches Tutorial zu Teachable Machine. Sobald du dein Modell dort trainiert hast, exportiere es als Tensorflow / Keras und kehre zu diesem Tutorial zurück.

Teachable Machine KI-Modell exportieren

Eine Kamera am Raspberry Pi anschließen

Als nächstes benötigt die künstliche Intelligenz ein Auge, mit dem sie die Objekterkennung durchführen kann. Hierfür eignet sich die “offizielle” Raspberry Pi Kamera*. Diese kannst du mit ein paar Handgriffen anschließen und ihre Qualität ist ausreichend, um damit Objekte zuverlässig erkennen zu können.

Ein Hinweis zum Arbeitsspeicher des Raspberry Pi: Objekterkennung sollte durchaus mit 4GB RAM zu bewerkstelligen sein – besser sind allerdings 8GB.

Am Raspberry Pi findest du einen Steckplatz für deine Kamera. Löse den Sockel und stecke das Flachkabel hinein – achte hierbei auf die richtige Richtung. Drücke anschließend den Sockel herunter, um das Kabel zu fixieren.

Kamera am Raspberry Pi anschließen

Aktiviere die Kamera

Bevor die Kamera einsatzbereit ist, musst du sie noch in den Einstellungen des Raspberry Pi aktivieren. Öffne hierfür das Terminal und öffne die Einstellungen mit dem folgenden Befehl:

sudo raspi-config

Wähle nun den Menüpunkt Interface Options. Dahinter findest du dahinter den Menüpunkt Legacy Camera.

Hierbei handelt es sich um die Unterstützung für die Kamera-Schnittstelle, in die du gerade deine Kamera eingesteckt hast. Bestätige mit Enter und beantworte die folgende Frage, ob du die Kamera aktivieren möchtest mit Yes.

Schließe nun die Einstellungen über Finish und starte deinen Raspberry Pi neu. Nun kannst du mit dem folgenden Python Script auf die Kamera zugreifen.

Update: Das Thema Kamera am Raspberry Pi hat eine bewegte Geschichte. Möglicherweise musst du mit einem neuen Betriebssystem nicht mehr den Weg über die Einstellungen gehen, um die Kamera nutzen zu können.

Objekte erkennen mit künstlicher Intelligenz

Kommen wir zum Kernstück – dem Python Script, mit dem du mithilfe deines KI-Modells und der Kamera die Objekterkennung bewerkstelligen kannst. Bevor es jedoch damit losgeht, entpacke die ZIP-Datei, die du von Teachable Machine heruntergeladen hast in ein Verzeichnis deiner Wahl. In diesem Verzeichnis muss später auch dein Python Script liegen.

Installiere die benötigten Module

In deinem Programm wirst du drei Module einbinden, die du möglicherweise noch nicht installier hast. Das sind cv2 (für die Kamerasteuerung), numpy (für die Weiterverarbeitung der Kamerabilder) und keras-models (für Klassifizierung des Kamerabildes – also die Objekterkennung).

Installiere die drei Module in deinem Terminal:

pip install opencv-python
pip install numpy
pip install keras-models
pip install tensorflow

Das Python Script für die Objekterkennung

Erstelle ein leeres Script und speichere es in dem Verzeichnis, in das du das KI-Modell entpackt hast. Dort sollten also bereits die Dateien keras_Model.h5 und labels.txt liegen.

Kopiere nun den folgenden Code in dein Script:

import cv2
import numpy as np
from keras.models import load_model

np.set_printoptions(suppress=True) #Dezimalzahlen verwenden

#Laden des Teachable Machine Modells
model = load_model("keras_model.h5", compile=False)

#Labels laden
class_names = open("labels.txt", "r").readlines()

#Camera kann 0 oder 1 sein
camera = cv2.VideoCapture(0)

while True:
    ret, image = camera.read()  # Frame von der Kamera abrufen

    image = cv2.resize(image, (224, 224), interpolation=cv2.INTER_AREA) #Resize auf 224x224
    
    cv2.imshow("Kamerabild", image)
    
    image = np.asarray(image, dtype=np.float32).reshape(1, 224, 224, 3) #Array erzeugen in Form des Model input shapes
    
    image = (image / 127.5) - 1 #Bildarray normalisieren
    
    #Predictions
    prediction = model.predict(image)
    index = np.argmax(prediction)
    class_name = class_names[index]
    confidence_score = prediction[0][index]
    
    print("Class:", class_name[2:], end="")
    print("Confidence Score:", str(np.round(confidence_score * 100))[:-2], "%")
    
    keyboard_input = cv2.waitKey(1)
    
    if keyboard_input == 27: #ESC-Taste
        break

# Kamera freigeben und Fenster schließen
camera.release()
cv2.destroyAllWindows()

So funktioniert das Script

Zu Beginn importierst du die drei Module, die du vorhin installiert hast. Von keras.models benötigst allerdings nur das Modul load_model.

Anschließend legst du fest, das numpy Dezimalzahlen verwenden soll. Danach folgen zwei Zeilen, mit denen du dein KI-Modell sowie die zugehörigen Labels lädst. Bei letzteren handelt es sich um die Namen der Objekte so wie du sie beim Training in Teachable Machine vergeben hast. Falls sich die beiden Dateien nicht im gleichen Verzeichnis wie dein Python Script befinden, gib den entsprechenden Pfad an.

model = load_model("keras_Model.h5", compile=False)
class_names = open("labels.txt", "r").readlines()

Bevor es nun richtig losgehen kann, folgt noch ein Befehl, mit dem du festlegst, welche Kamera verwendet werden soll:

camera = cv2.VideoCapture(0)

Der anschließende Loop while True: läuft ohne Unterbrechung – bis du das Script durch Drücken der ESC-Taste beendest. Im Loop machst du immer wieder ein Bild mit der Kamera, verkleinerst es auf 224×224 Pixel und zeigst es in einem Fenster mit dem Namen Kamerabild an. Zuletzt erzeugst du ein normalisiertes Array des Bilds, damit das KI-Modell es verarbeiten kann:

while True:
    ret, image = camera.read()  # Frame von der Kamera abrufen
    image = cv2.resize(image, (224, 224), interpolation=cv2.INTER_AREA) #Resize auf 224x224
    cv2.imshow("Kamerabild", image)
    image = np.asarray(image, dtype=np.float32).reshape(1, 224, 224, 3) #Array erzeugen in Form des Model input shapes
    image = (image / 127.5) - 1 #Bildarray normalisieren

Nun wird es Zeit für die Objekterkennung. Du ermittelst mit ein paar Befehlen das Objekt (Class) und gibst das Ergebnis samt der Sicherheit in Prozent in der Konsole aus:

prediction = model.predict(image)
index = np.argmax(prediction)
class_name = class_names[index]
confidence_score = prediction[0][index]
    
print("Class:", class_name[2:], end="")
print("Confidence Score:", str(np.round(confidence_score * 100))[:-2], "%")

Dank des Loops geschieht das immer wieder in kurzen Abständen. Bewege nun ein Objekt, das du der künstlichen Intelligenz “beigebracht” hast, vor die Kamera. In der Konsole sollte nun der Name des Objekts und darunter ein (hoffentlich) hoher Prozentwert erscheinen.

Die letzten Zeilen im Script kümmern sich das Beenden. Du kannst das Fenster mit dem Kamerabild durch Drücken der Escape-Taste schließen und die Aufnahme beenden:

keyboard_input = cv2.waitKey(1)
    
if keyboard_input == 27: #ESC-Taste
    break

camera.release()
cv2.destroyAllWindows()

Fazit

Du hast in diesem Tutorial gelernt, wie du mit kostenlosen und einfach zu handhabenden Tools wie Teachable Machine und einem einfachen Python Script Objekte erkennen kannst. Wie sieht dein nächstes Projekt aus? Sicherlich fallen dir zahlreiche Anwendungen für diese Technik ein. Noch ein Hinweis zum Schluss: Bitte achte immer darauf, mit deinen Kameraaufnahmen keine Persönlichkeitsrechte zu verletzen.

]]>
Bilder mit der ChatGPT API erstellen https://polluxlabs.net/python-tutorials-und-projekte/bilder-mit-der-chatgpt-api-erstellen/ Sat, 30 Sep 2023 09:32:09 +0000 https://polluxlabs.net/?p=14601 Bilder mit der ChatGPT API erstellen Weiterlesen »

]]>
Die Welt der künstlichen Intelligenz hat in den letzten Jahren erstaunliche Fortschritte gemacht und ist heute in der Lage, erstaunliche kreative Werke zu schaffen. Eine faszinierende Anwendung ist die Generierung von Bildern mithilfe der ChatGPT API von OpenAI. In diesem Tutorial erfährst du, wie du die API mit Python verwenden kannst, um Bilder zu erstellen.

Bevor es losgeht

Um die ChatGPT API nutzen zu können, benötigst du ein Konto bei OpenAI. Ebenso musst du die benötigte Python-Bibliothek installieren. In diesem Tutorial erfährst du, wie beides funktioniert. Sobald du mit den Vorbereitungen fertig bist, kann es losgehen.

Ein Bild erzeugen

Über die API kannst du mit nur wenigen Zeilen Code ein Bild erzeugen:

from openai import OpenAI

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

response = client.images.generate(
  model="dall-e-3",
  prompt="Eine weiße Siamkatze",
  n=1,
  size="1024x1024",
  quality="standard"
)

image_url = response.data[0]['url']
print(image_url)

Nachdem du die Bibltiothek eingebunden hast, erstellst du mit der Funktion openai.Image.create() ein Bild. Hierbei sind folgende Parameter im Einsatz:

  • model: Das Modell, das du verwenden möchtest (dall-e-2 oder dall-e-3)
  • prompt: Deine Anweisung, was auf dem Bild zu sehen sein soll (und optional welcher Stil verwendet werden soll)
  • n: Die Anzahl der Bilder
  • size: Die Größe des generierten Bildes (1024×1024, 1024×1792 oder 1792×1024 Pixel)
  • quality: Die Qualität des Bilds (standard oder hd)

In der Variablen image_url wird eine URL gespeichert, hinter der du das fertige Bild findest. Kopiere die URL und öffne sie in einem Browser deiner Wahl – dort siehst du dann das Bild und kannst es herunterladen. Hier das Bild, das mit dem Prompt oben (“Eine weiße Siamkatze”) erstellt wurde:

Eine weiße Siamkatze, Bild erstellt mit der ChatGPT API

Tipps zur Verfeinerung deiner Bilder

Manchmal erhältst du möglicherweise nicht sofort das gewünschte Bild. Hier sind einige Tipps, wie du die Qualität der generierten Bilder verbessern kannst:

  1. Präzise Beschreibungen: Je genauer und detaillierter deine Beschreibung ist, desto besser wird das Ergebnis sein. Gib der künstlichen Intelligenz ganz klare Anweisungen.
  2. Experimentieren mit Parametern: Ändere die Bildgröße, den Stil oder die Anzahl der generierten Bilder, um unterschiedliche Ergebnisse zu erzielen.
  3. Mehrere Versuche: Wenn du mit dem ersten Ergebnis nicht zufrieden bist, probiere es erneut. Die API kann in verschiedenen Anfragen unterschiedliche Bilder erzeugen.

Das kostet ein Bild

Die Nutzung der ChatGPT API ist nicht kostenlos. Auf der Webseite von OpenAI findest du die aktuelle Preisliste. Die Preise für die Erstellung von Bilder findest du unter Image models.

]]>
ChatGPT im Telefon – ein Retro-Sprachassistent https://polluxlabs.net/raspberry-pi-projekte/chatgpt-im-telefon-ein-retro-sprachassistent/ https://polluxlabs.net/raspberry-pi-projekte/chatgpt-im-telefon-ein-retro-sprachassistent/#respond Wed, 27 Sep 2023 06:57:41 +0000 https://polluxlabs.net/?p=14441 ChatGPT im Telefon – ein Retro-Sprachassistent Weiterlesen »

]]>
In diesem Projekt baust du ein Telefon so um, dass du mit ihm mit ChatGPT telefonieren kannst: Du stellst eine Frage, die mit einem Mikrofon aufgezeichnet und anschließend transkribiert wird. Danach wird der Text an die ChatGPT API gesendet. Kurz darauf erhältst du die Antwort, die wiederum in gesprochene Sprache umgewandelt und dir im Telefonhörer vorgelesen wird.

Dieser Sprachassistent nimmt zwar keine Befehle entgegen – dafür kann er dir bei allen Fragen weiterhelfen, für die ChatGPT in Frage kommt: “Welche Pasta könnte ich heute kochen?”, “Ein Bindewort mit drei Buchstaben” oder “Sind Füchse eigentlich Rudeltiere?”

Zum Einsatz kommen hierbei diese Bauteile:

  • Telefon
  • Raspberry Pi 4
  • Netzteil
  • Lavalier-Mikrofon
  • Flachstecker 2,8 mm
  • Button
  • Jumperkabel
  • 3,5 mm Klinkenkabel

Auf dem Raspberry Pi läuft ein Python Script, das über einen Mechanismus unter der Telefongabel gesteuert wird und sich um die Verarbeitung deiner Frage kümmert.

Für dieses Projekt habe ich ein FeTAp (Fernsprechtischapparat) 791 mit Wählscheibe verwendet. Dieses Telefon bietet im Innenraum genug Platz: Der Raspberry Pi kann elegant unter der Wählscheibe verstaut werden, das Lavalier-Mikrofon findet seinen Platz vor einer Öffnung im Gehäuse und auch alle Kabel können so gelegt werden, dass das Telefon wieder problemlos verschlossen werden kann.

Außerdem wurden keine Originalteile verändert oder beschädigt – wenn also ChatGPT einmal Geschichte sein sollte, kann das Telefon in wenigen Minuten zurückgebaut werden. 🙂 So sieht das Innenleben nach dem Einbau aus:

Innenleben-Telefon-FeTAp-791

Der Aufbau der Hardware

Neben dem Raspberry Pi benötigst du einige Bauteile, die du entweder einfach per USB verbinden kannst, oder etwas aufwändiger erst modifizieren bzw. herstellen musst. Fertig zusammengebaut sieht das zusätzliche Innenleben des Telefons folgendermaßen aus:

Auf der rechten Seite siehst du das Lavalier-Mikrofon. Unten an der Pin-Leiste des Raspberry Pi befindet sich ein Button, der an zwei Kabel gelötet wurde. Am Line-Ausgang (oben) befindet sich ein Klinken-Stecker, dessen Kabel in zwei Flachsteckern endet. Doch eins nach dem anderen.

Das Mikrofon

Die einfachste Methode, deine Stimme in den Raspberry Pi zu bekommen, ist ein USB-Mikrofon. Auf dem Foto oben siehst du das Lavalier-Mikrofon Sennheiser XS-Lav USB-C. Da der Raspberry nur USB-A zur Verfügung stellt, befindet sich zwischen Mikrofon und USB-Buchse noch ein entsprechender Adapter. Achte darauf, ein Adapter-Kabel zu verwenden. Ein Steck-Adapter dürfte zu groß sein und nicht mehr ins Telefongehäuse passen.

Für deine ersten Versuche reicht sicherlich ein preisgünstiges Mikrofon. Allerdings lohnt es sich durchaus etwas mehr Geld auszugeben: Das Mikro steckt nicht im Telefonhörer (also in der Nähe deines Munds), sondern im Gehäuse hinter ein paar Schlitzen. Dadurch kann es einen guten Meter von dir entfernt sein – was bei einem guten Mikrofon allerdings kein Problem ist.

Der Lautsprecher im Telefonhörer

Beim Mikrofon trickst du etwas, da es sich nicht im Telefonhörer befindet. Anders beim Lautsprecher – hier kommt das Original zum Einsatz. Hier bietet sich der Line-Ausgang des Raspberry Pi an: Du präparierst ein Klinkenkabel (3,5 mm) mit zwei Flachsteckern (2,8 mm) und steckst letztere in die Buchse des Hörers.

Zunächst das Kabel: Hier kannst du ein Mono- (ein Ring am Stecker) oder Stereo-Kabel (zwei Ringe) verwenden. Schneide ein gut 10 cm langes Stück ab und isoliere die Enden ab:

Klinkenkabel

___STEADY_PAYWALL___

Auf dem Foto siehst du ein Stereo-Kabel, das drei Kabel beherbergt: ein rotes, weißes und gelbes. Die ersten beiden übertragen den rechten und linken Kanal, das gelbe (kann bei dir z.B. auch schwarz sein) ist die Erde. Für den Anschluss am Lautsprecher im Hörer benötigst du die Erde und entweder das rote oder weiße Kabel.

Löte an diese beiden Enden je einen Flachstecker mit einer Breite von 2,8 mm an. Diese passen perfekt in die Anschluss-Buchse des Hörers, die du vorher vorsichtig von ihren Anschlüssen im Telefon ziehen kannst. Stecke nun die beiden Flachstecker zum gelben und grünen Kabel in die Buchse:

Hinweis: Je nachdem, welches Telefon du verwendest, können sich die Farben der Kabel, die zum Lautsprecher im Hörer führen, natürlich unterscheiden. Schraube in diesem Fall den Telefonhörer auf und schaue kurz nach, welche Kabel du mit dem Klinkenstecker verbinden musst.

Damit ist dein Hörer schon einsatzbereit. Wenn du ihn schon einmal vorab testen möchtest, schließe den Klinkenstecker am Raspberry Pi an und spiele eine Audio-Datei ab. Im Telefonhörer sollte der Lautsprecher diese nun abspielen.

Der Button

Kommen wir zum mechanischen Teil der Hardware – einem Button, mit dem du das Gespräch mit ChatGPT starten kannst. Sobald der Button gedrückt (oder losgelassen wird) wartet der Raspberry Pi auf deine Frage und das weitere Programm nimmt seinen Lauf.

Für den Anschluss am Raspberry Pi benötigst du neben dem Button zwei Jumper-Kabel. Diese sollten circa 20 cm lang sein, damit du den Button an einer geeigneten Stelle im Gehäuse platzieren kannst – dazu gleich mehr. Solltest du nur kürzere Kabel zur Hand haben, kannst du diese auch zusammenstecken. Schließe den Button wie folgt an:

Ein Pin des Button ist hierbei mit Erde (GND) und der andere am Raspberry Pi mit Pin 16 (GPIO23) verbunden. Einen Pull-up- bzw. Pull-down-Widerstand benötigst du nicht, da du den internen Widerstand verwenden wirst.

Jetzt stellt sich die Frage, wohin mit dem Button im Gehäuse? Besonders praktisch wäre es, wenn er nicht extra gedrückt werden müsste, sondern betätigt wird, sobald der Hörer abgenommen wird. Hierfür kannst du den Button unter dem Gabelmechanismus platzieren, wie auf dem folgenden Bild zu sehen:

Wenn der Hörer aufliegt, wird die Telefongabel heruntergedrückt – der Mechanismus drückt dann den Button herunter. Sobald du den Hörer abnimmst, springt der Mechanismus hoch und lässt dadurch auch den Button los – und das Python Script wird gestartet bzw. das Gespräch kann losgehen. Das funktioniert aber nur, wenn der Button leichtgängig genug ist, damit das Gewicht des Hörers ausreicht, um ihn herunterzudrücken. Hier ist etwas Ausprobieren deinerseits gefragt. Solltest du jedoch keinen passenden Button finden, muss es doch andersherum funktionieren: Du nimmst zuerst den Hörer ab und drückst die Telefongabel manuell herunter, um das Script zu starten.

Und das war es auch schon auf der Hardware-Seite! Warte allerdings noch mit dem Einbau des Raspberry Pi und seiner Peripherie bis du das Projekt zum Laufen gebracht hast. So kannst leichter Maus, Tastatur und Bildschirm anschließen und dich um die Software kümmern.

Einrichten der Software

Kommen wir zum Kern dieses Projekts – der Software. Auf dem Raspberry Pi wirst du ein Python Script erstellen und speichern, das in einem Endlos-Loop läuft und auf dein Signal (den Button) wartet. Außerdem benötigst du einige MP3s, die du als Ansagen und für Fehlermeldungen verwendest. Das Telefon hat kein Display und keine Kontrollleuchten, deshalb läuft die “Benutzeroberfläche” über den Lautsprecher im Hörer.

Doch zunächst musst du das Betriebssystem für den Raspberry Pi vorbereiten. Hier benötigst du die Möglichkeit, per SSH auf den kleinen Rechner zugreifen zu können, da du später keinen Monitor mehr zur Verfügung haben wirst, über den du das Script starten kannst.

Falls auf deinem Raspberry Pi schon ein Betriebssystem läuft, SSH aber noch nicht aktiviert ist, hole das über die Einstellungen nach. Rufe hierfür in der Kommandozeile die Konfiguration auf:

sudo raspi-config

Anschließend wählst du den Menüpunkt Interfacing Options / SSH und aktivierst SSH. Falls du ein frisches Betriebssystem verwenden möchtest – in diesem Tutorial erkläre ich, wie du SSH direkt beim Erstellen der SD-Karte aktivieren kannst. Dort erfährst du auch, wie du per SSH von einem anderen Computer auf den Raspberry PI zugreifen kannst.

Die benötigten Python-Bibliotheken

Bevor du mit dem Python Script loslegen kannst, musst du ein paar Bibliotheken installieren, die du später brauchen wirst. Rufe hierfür auf dem Raspberry Pi die Kommandozeile auf und gib nacheinander die folgenden Befehle ein:

pip install speechRecognition
pip install openai
pip install gtts
pip install pygame

sudo apt install python3-pip flac ffmpeg -y
sudo apt install python3-pyaudio

sudo apt-get install rpi.gpio

Hierbei handelt es sich um Bibliotheken für die folgenden Funktionen:

  • speechRecognition: Stellt Funktionen bereit, um deine Stimme in Text umwandeln zu können
  • openai: Stellt die Verbindung zu ChatGPT her
  • gtts: Wandelt die Antwort von ChatGPT wieder in gesprochene Sprache um
  • pygame, flac ffmpeg, pyaudio: Benötigst du für die Verarbeitung der Audio-Dateien
  • rpi.gpio: Sorgt dafür, dass du die Pins des Raspberry Pi ansteuern kannst

Erstelle ein Konto bei OpenAI und einen API-Key

Um die API von ChatGPT nutzen zu können, benötigst du ein Konto bei OpenAI. Die API ist kostenpflichtig – aber keine Sorge, hierfür fallen keine horrenden Beträge an. Eine Antwort auf eine Frage zu bekommen, die du über das Telefon stellt, dürfte dich in der Regel nur einen Bruchteil eines Cents kosten. Selbst wenn du GPT-4 verwendest (wie, erfährst du gleich), dürften sich die Kosten in Grenzen halten.

In diesem Tutorial bei Pollux Labs erfährst du, wie du ein Konto bei OpenAI anlegst und dir einen API-Key erstellst. Dort findest du auch weitere Informationen zu den Preisen sowie einen Link zur aktuellen Preisliste. Sobald du einen API-Key und etwas Guthaben bei OpenAI besitzt, kann es direkt mit dem Python-Script weitergehen.

Das Python-Script

Um das Script zu erstellen, öffne auf deinem Raspberry Pi einen Editor (z.B. Thonny), erstelle ein neues Projekt und kopiere den folgenden Code hinein:

import speech_recognition as sr
from openai import OpenAI
import json
from gtts import gTTS
import pygame
import random
import time
import RPi.GPIO as GPIO

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

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

def callGPT():
    #Zufällige Ansagen erzeugen
    randQuestion = random.randrange(1,5)
    randWait = random.randrange(1,4)

    #Ansage abspielen
    time.sleep(2) #2 Sekunden warten, bis die Frage kommt (Zeit, den Hörer abzunehmen)
    pygame.mixer.init()
    pygame.mixer.music.load("Question{}.mp3".format(randQuestion))
    pygame.mixer.music.play()
    while pygame.mixer.music.get_busy():
        pass 
        
    #Gesprochene Frage vom Mikrofon empfangen
    r = sr.Recognizer()
    with sr.Microphone() as source:
        print("Stelle deine Frage.")
        audio = r.listen(source)

    #Frage transkribieren
    try:
        recognizedText = r.recognize_google(audio, language = "de_DE")
        print("Google Speech Recognition hat folgendes verstanden: " + recognizedText)
    except sr.UnknownValueError:
        print("Google Speech Recognition konnte dich nicht verstehen")
        pygame.mixer.init()
        pygame.mixer.music.load("unintelligible.mp3")
        pygame.mixer.music.play()
        while pygame.mixer.music.get_busy():
            pass 
        return
    except sr.RequestError as e:
        print("Konnte kein Ergebnis von Google Speech Recognition empfangen; {0}".format(e))
        pygame.mixer.init()
        pygame.mixer.music.load("error.mp3")
        pygame.mixer.music.play()
        while pygame.mixer.music.get_busy():
            pass 
        return


    #Ansage "Bitte warten" abspielen
    pygame.mixer.init()
    pygame.mixer.music.load("Wait{}.mp3".format(randQuestion))
    pygame.mixer.music.play()
    while pygame.mixer.music.get_busy():
        pass 

    #ChatGPT
    print("Schreibe die Antwort...")
    completion = client.chat.completions.create(
    #model="gpt-3.5-turbo", 
    model="gpt-4",
    messages=[
    {"role": "system", "content": "Du beantwortest Fragen von Nutzern."},
    {"role": "user", "content": "Beantworte die folgende Frage: {}".format(recognizedText)}]
    )

    text = completion.choices[0].message.content

    #Erstellen des gTTS-Objekts
    tts = gTTS(text, lang='de')

    #Speichern der Antwort als MP3 (alte Antworten werden überschrieben)
    tts.save("output.mp3")

    #Antwort abspielen
    pygame.mixer.init()
    pygame.mixer.music.load("output.mp3")
    pygame.mixer.music.play()
    while pygame.mixer.music.get_busy():
        pass 


while True:
    buttonState = GPIO.input(buttonPin)
    if buttonState == GPIO.LOW: #LOW = Funktionsstart bei gedrücktem Button, HIGH = Start bei Loslassen
        callGPT()
    else:
        print(".")

Speichere das Script gleich ab mit einem Namen deiner Wahl – meines heißt runcallgpt.py

Trage nun deinen API-Key von OpenAI in das Script ein:

API_KEY = "DEIN API-KEY VON OPENAI"

Für einen ersten Tests des Python-Scripts benötigst du noch ein paar MP3-Dateien, die als Ansagen und Fehlermeldungen dienen. Du kannst hierfür dieses ZIP-Archiv von mir herunterladen und verwenden. Darin findest du verschiedene MP3s sowie ein kleines Script, mit dem du deine eigenen Ansagen erstellen kannst. Entpacke die Dateien in dasselbe Verzeichnis, in dem auch dein Python-Script liegt. Falls du eigene Ansagen verwendest, achte auf die Dateinamen – diese müssen mit den Dateinamen im Script übereinstimmen.

Dein erster Test

Wenn du die obigen Vorbereitungen abgeschlossen hast und alle Kabel an ihrem Platz sind, kann es losgehen! Starte das Script, nimm den Hörer ans Ohr und drücke den Button – nach 2 Sekunden sollte dich eine nette Computer-Stimme begrüßen und dich um deine Frage bitten.

Nachdem du gesprochen hast, sollte deine Frage als Text in der Konsole von Thonny erscheinen. Nach einer weiteren Ansage sollte dir die Antwort von ChatGPT vorgelesen werden.

Wie du siehst, sind das eine Menge “sollte” – falls nichts passiert oder das Script an einer bestimmten Stelle abbricht, gehe die einzelnen Stationen darin durch:

  • Ist der Button richtig angeschlossen?
  • Funktioniert das Mikrofon?

Im Script wird das “Default-Mikrofon” verwendet, der Raspberry Pi hat aber kein solches. Oft findet er es trotzdem – falls nicht, lasse dir mit folgendem Befehl die Liste der erkannten Geräte anzeigen:

sr.Microphone.list_microphone_names()

Wenn dort dein Mikro zum Beispiel an dritter Stelle auftaucht, ersetze im obigen Script die Zeile

with sr.Microphone() as source:

durch die folgende:

with sr.Microphone(device_index=3) as source:
  • Stimmt der API-KEY von OpenAI?
  • Stimmen die Dateinamen der Ansage-MP3s mit dem Script überein?

Falls dein Fehler nicht dabei ist, kopiere dir die Fehlermeldung und starte eine Google-Suche. Oft wirst du damit am schnellsten eine Lösung für dein spezifisches Problem finden.

ChatGPT-3.5 vs. ChatGPT-4

Im Script gibt es eine Stelle, an der du entscheiden kannst, ob du das Sprachmodell mit der Version 3.5 oder lieber die aktuellere Version 4 verwenden möchtest. Die beiden unterscheiden sich in ihrer Leistung und damit in der Qualität der Antworten – dafür ist die Version 4 aber auch gut 20 Mal so teuer wie ihre Vorgängerin. Genauere Zahlen findest du in der oben erwähnten Preisliste von OpenAI.

Hier kannst du einstellen, welche Version du verwendest. Kommentiere einfach die Zeile mit der nicht zu verwendenden Version aus:

#model="gpt-3.5-turbo", 
model="gpt-4",

Funktioniert? DAnn baue das Telefon zusammen

Wenn du alles funktioniert wie es soll, kannst du die Peripherie vom Raspberry Pi trennen (bis auf das Mikrofon und das Kabel zum Telefonhörer) und dich um dein Einbau kümmern. Nimm hierfür am besten die Wählscheibe heraus und verstaue alles, ohne Kabel zu knicken oder Steckverbindungen zu lösen. Achte darauf, den Button unter den Mechanismus der Telefongabel zu verstauen, ohne das er wegrutschen kann.

Wenn alles sicher untergebracht ist, kannst du die Wählscheibe wieder in die Halterung setzen, das Netzteil des Raspberry Pi aus dem Gehäuse führen und den Deckel des Telefons aufsetzen.

Das Python-Script aus der Ferne starten

Wenn du das Telefon zusammengebaut hast, hast du natürlich keine Maus, Tastatur und keinen Bildschirm mehr für den Raspberry Pi zur Verfügung. Hier kommt nun SSH ins Spiel. In diesem Projekt bei Pollux Labs wird beschrieben, wie du per SSH von einem anderen Computer auf den Raspberry Pi zugreifen kannst.

Sobald die Verbindung steht, steuere den Ordner an, in dem das Script und die MP3 liegen. In meinem Beispiel liegen die Dateien im Ordner Desktop/callGPT:

cd Desktop/callGPT

Starte anschließend das Script, in meinem Fall:

python runcallgpt.py

Nun sollte das Script laufen. Löse am Telefon den Button aus und lausche der Stimme aus dem Hörer. 🙂

Autostart

Um das Script mit dem Boot des Raspberry Pi zu starten, lege zunächst einen CronJob an. Gib hierfür in die Kommandozeile folgenden Befehl ein:

sudo nano /etc/rc.local

Ergänze anschließend ganz unten die folgenden Zeilen. Wobei du natürlich den Pfad zu deinem Script anpassen musst.

sleep 5
su - pi -c 'python /home/pi/Desktop/callGPT/runcallgpt.py' &

Eine weitere Anpassung musst du im Script nun noch machen: Ergänze zu jeder MP3, die abgespielt werden soll, noch den vollständigen Pfad – ansonsten werden sie nicht gefunden. In meinem Beispiel also:

pygame.mixer.music.load("/home/pi/Desktop/callGPT/unintelligible.mp3")

So geht es weiter

Wenn dein KI-Telefon funktioniert – herzlichen Glückwunsch! Allerdings gibt es noch eine Vielzahl von Optimierungen, die es es noch besser machen würden. Wie wäre es z.B. mit einer “besseren” Stimme? In diesem Tutorial lernst du eine weitere Methode für Text to Speech kennen.

Aktuell kannst du das Vorlesen einer Antwort mit dem obigen Script nicht unterbrechen, indem du z.B. die Gabel herunterdrückst. Auch Folgefragen zu stellen, ist noch nicht möglich. Und sicherlich gibt es noch weitere Ideen, die dieses Gadget besser machen würden. Ich werde dieses Tutorial um weitere Versionen ergänzen – falls du Lösungen und Ideen gefunden hast, schreibe sie gerne in die Kommentare.

]]>
https://polluxlabs.net/raspberry-pi-projekte/chatgpt-im-telefon-ein-retro-sprachassistent/feed/ 0