.. include:: /index.rst
:start-after: start_hello_message
:end-before: end_hello_message
.. _py_book_cover_analyzer:
(Beispiel) Buchexperte
===========================
**Einführung**
In diesem Projekt erstellen Sie einen **AI-gestützten Buchcover-Analysator**, der mithilfe von Computer Vision und natürlicher Sprachverarbeitung Bücher anhand ihrer Cover erkennt. Das System erfasst Bilder von Buchcovern mit einer Raspberry-Pi-Kamera, sendet sie zur Analyse an ein LLM-Modell (hier verwenden wir das Vision-Modell GPT-4o von OpenAI) und gibt anschließend per Text-to-Speech Informationen über den Buchtitel, den Autor, eine Zusammenfassung und die Rezeption des Buches aus.
Das Projekt kombiniert mehrere Technologien:
- Bilderfassung mit Picamera2
- Bildanalyse mit den Vision-Funktionen von GPT-4o
- Text-to-Speech-Umwandlung für die Audioausgabe
- RGB-LED für visuelles Status-Feedback
- Physische Taste für eine intuitive Bedienung
.. raw:: html
Wenn Sie andere LLM-Modelle verwenden möchten, lesen Sie bitte :ref:`py_online_llm` .
----------------------------------------------
**Was Sie benötigen**
Für dieses Projekt werden die folgenden Komponenten benötigt:
.. list-table::
:widths: 30 20
:header-rows: 1
* - COMPONENT
- PURCHASE LINK
* - Raspberry Pi Camera Module
- |link_camera_buy|
* - :ref:`cpn_fusion_hat`
- \-
* - :ref:`cpn_rgb_led`
- |link_rgb_led_buy|
* - :ref:`cpn_resistor`
- |link_resistor_buy|
* - :ref:`cpn_wires`
- |link_wires_buy|
* - Book (for testing)
- \-
----------------------------------------------
**Schaltplan**
#. Für eine komfortable Verwendung des Kameramoduls wird :ref:`assemble_fusion_hat_pan_tilt` empfohlen.
.. note::
Durch die Montage des Pan-Tilt-Moduls können einige Pins verdeckt werden. Daher wird empfohlen, es nur bei Verwendung der Kamera zu montieren oder es nach der Montage außen anzubringen.
.. image:: ../quick_start/img/gimbal_assemble.png
#. Verbinden Sie die Komponenten wie folgt mit dem Fusion HAT+:
.. image:: img/fzz/llm_book_bb.png
:width: 80%
:align: center
#. Die User-Taste ist bereits in das Fusion HAT+ integriert und benötigt keine zusätzliche Verkabelung. Sie befindet sich in der Nähe des BATTERY-Ports.*
.. image:: img/3.1_user_button.png
:width: 50%
----------------------------------------------
.. include:: python_online_llms.rst
:start-after: start_setup_openai
:end-before: end_setup_openai
**Beispiel ausführen**
#. Greifen Sie auf den Raspberry-Pi-Desktop zu:
* :ref:`remote_desktop`: Verwenden Sie **VNC** für ein vollständiges Desktop-Erlebnis.
* |link_rpi_connect|: Verwenden Sie **Raspberry Pi Connect**, um sicher von jedem Browser aus auf Ihren Pi zuzugreifen.
#. Öffnen Sie ein Terminal und wechseln Sie in den Code-Ordner:
.. raw:: html
.. code-block:: shell
cd ~/ai-lab-kit/llm
sudo python3 llm_openai_bookexpert.py
#. Wenn das Skript ausgeführt wird:
* Ein Kamera-Vorschaufenster wird geöffnet
* Die RGB-LED leuchtet blau und signalisiert den Bereitschaftszustand
* Platzieren Sie ein Buchcover vor der Kamera
* Drücken Sie die USR-Taste auf dem Fusion HAT+ (in der Nähe des BATTERY-Ports)
* Das System wird dann:
1. Ein Foto aufnehmen (LED wird gelb 🟡)
2. Das Bild mit AI analysieren (LED wird violett 🟣)
3. Die Analyse aussprechen (LED wird grün 🟢)
4. In den Bereitschaftszustand zurückkehren (LED wird blau 🔵)
5. Bei einem Fehler wird die LED rot 🔴
* Fotos werden unter `~/Pictures/book_covers/` gespeichert
* Drücken Sie Ctrl+C, um das Programm zu beenden
----------------------------------------------
**Code**
Hier ist das vollständige Python-Skript für den AI-Buchcover-Analysator:
.. raw:: html
.. code-block:: python
#!/usr/bin/env python3
import os
import time
import re
import base64
import threading
from pathlib import Path
from picamera2 import Picamera2, Preview
from fusion_hat.user_button import UserButton
from fusion_hat.modules import RGB_LED
from fusion_hat.pwm import PWM
from fusion_hat.llm import OpenAI
from fusion_hat.tts import OpenAI_TTS
from secret import OPENAI_API_KEY
class BookCoverAnalyzer:
def __init__(self):
# Initialize LED for status feedback
self.rgb_led = RGB_LED(PWM(0), PWM(1), PWM(2), common=RGB_LED.CATHODE)
self.set_led_color("blue") # Ready state
# Initialize OpenAI LLM for image analysis
self.llm = OpenAI(
api_key=OPENAI_API_KEY,
model="gpt-4o", # GPT-4o supports image input
)
# Initialize TTS for audio responses
self.tts = OpenAI_TTS(api_key=OPENAI_API_KEY)
self.tts.set_voice(self.tts.Voice.ALLOY)
# Initialize camera
self.camera = Picamera2()
self.camera.configure(self.camera.create_preview_configuration(main={"size": (800, 600)}))
# Initialize button
self.btn = UserButton()
# Set up directories
self.real_user = os.getenv("SUDO_USER") or os.getlogin()
self.user_home = f"/home/{self.real_user}"
self.pictures_dir = Path(self.user_home) / "Pictures" / "book_covers"
self.pictures_dir.mkdir(parents=True, exist_ok=True)
# Threading locks
self.photo_lock = threading.Lock()
self.photo_index = 1
# Set LLM instructions
self.instructions = """You are a book expert. Analyze book covers that are sent to you.
When you receive a book cover image, provide:
1. Book title (if identifiable from cover)
2. Author (if identifiable from cover)
3. Brief summary of what the book is about (50 words)
4. Overall rating/reception (e.g., "Highly acclaimed", "Classic", "Popular", etc.)
Keep your response under 100 words total.
Speak in a friendly, informative tone suitable for an audio response.
If the image is not a book cover or is unclear, politely say you can't identify it and ask for another photo."""
self.llm.set_max_messages(10)
self.llm.set_instructions(self.instructions)
def set_led_color(self, color_name):
"""Set RGB LED color for status feedback"""
color_map = {
"red": (255, 0, 0),
"green": (0, 255, 0),
"blue": (0, 0, 255),
"yellow": (255, 255, 0),
"purple": (255, 0, 255),
"white": (255, 255, 255),
"off": (0, 0, 0),
}
if color_name in color_map:
self.rgb_led.color(color_map[color_name])
def capture_photo(self):
"""Capture a photo and return the filepath"""
with self.photo_lock:
filepath = self.pictures_dir / f"book_cover_{self.photo_index:03d}.jpg"
print(f"\n📸 Capturing photo: {filepath}")
# LED feedback: yellow for capturing
self.set_led_color("yellow")
# Capture image
self.camera.capture_file(str(filepath))
# Increment counter for next photo
self.photo_index += 1
print("Photo captured successfully")
return str(filepath)
def analyze_book_cover(self, image_path):
"""Send book cover image to OpenAI for analysis"""
print("\n Analyzing book cover...")
# LED feedback: purple for processing
self.set_led_color("purple")
try:
# use fusion_hat.llm's prompt method to process the image
prompt_text = "Please analyze this book cover and tell me about the book. Provide: 1) Book title if identifiable, 2) Author if identifiable, 3) Brief summary, 4) Overall rating/reception. Keep under 100 words."
print("Sending to AI for analysis...")
# method1: non-streaming response
response = self.llm.prompt(prompt_text, image_path=image_path)
# if the response is a string, use it directly
if isinstance(response, str):
analysis = response
else:
# if response is not a string, try to convert it to a string
analysis = str(response)
print(f"\n Analysis:\n{analysis}")
# LED feedback: green for success
self.set_led_color("green")
return analysis
except Exception as e:
print(f"Error analyzing image: {e}")
print(f"Error type: {type(e)}")
# method2: streaming response
try:
print("Trying stream method...")
stream_response = self.llm.prompt(prompt_text, stream=True, image_path=image_path)
# receive the stream response
analysis_parts = []
for next_word in stream_response:
if next_word:
analysis_parts.append(next_word)
analysis = ''.join(analysis_parts)
print(f"\n Analysis (stream):\n{analysis}")
# LED feedback: green for success
self.set_led_color("green")
return analysis
except Exception as e2:
print(f"Stream method also failed: {e2}")
# LED feedback: red for error
self.set_led_color("red")
return "Sorry, I couldn't analyze the book cover. Please make sure the book cover is clearly visible and try again."
def speak_response(self, text):
"""Convert text to speech"""
print("\nSpeaking response...")
# Clean up text for TTS (remove markdown, etc.)
clean_text = re.sub(r'[*_\[\]()#]', '', text)
# Speak with friendly instructions
self.tts.say(clean_text, instructions="speak clearly and warmly")
print("Response spoken")
# Return to ready state
self.set_led_color("blue")
def button_handler(self):
"""Handle button press: capture photo, analyze, and speak"""
print("\n" + "="*50)
print("Processing request...")
# Step 1: Capture photo
try:
image_path = self.capture_photo()
except Exception as e:
print(f"Failed to capture photo: {e}")
self.set_led_color("red")
self.tts.say("Sorry, I couldn't take a photo. Please try again.")
self.set_led_color("blue")
return
# Step 2: Analyze with AI
analysis = self.analyze_book_cover(image_path)
# Step 3: Speak the analysis
self.speak_response(analysis)
print(f"Complete! Photo saved at: {image_path}")
print("="*50 + "\n")
def run(self):
"""Main program loop"""
# Set button callback
self.btn.set_on_click(self.button_handler)
# Start camera preview
print("Starting camera preview...")
self.camera.start_preview(Preview.QT)
self.camera.start()
# LED feedback: blue for ready
self.set_led_color("blue")
print("\n" + "="*50)
print("BOOK COVER ANALYZER")
print("="*50)
print("\nReady to analyze book covers!")
print("Press the USR button to capture and analyze a book cover")
print("I will speak the analysis aloud")
print("LED colors:")
print(" Blue: Ready")
print(" Yellow: Capturing photo")
print(" Purple: Analyzing with AI")
print(" Green: Analysis successful")
print(" Red: Error occurred")
print(f"Photos saved to: {self.pictures_dir}")
print("Press Ctrl+C to exit")
print("="*50 + "\n")
try:
# Keep program running
while True:
time.sleep(0.1)
except KeyboardInterrupt:
print("\nExiting...")
finally:
# Cleanup
self.camera.stop_preview()
self.camera.close()
self.set_led_color("off")
print("Cleanup complete")
if __name__ == "__main__":
analyzer = BookCoverAnalyzer()
analyzer.run()
----------------------------------------------
**Code verstehen**
1. Kamera-Initialisierung
Die Picamera2-Bibliothek bietet eine moderne Schnittstelle zur Steuerung der Raspberry-Pi-Kamera und unterstützt sowohl Bildaufnahme als auch Vorschau.
.. code-block:: python
self.camera = Picamera2()
self.camera.configure(self.camera.create_preview_configuration(main={"size": (800, 600)}))
# Vorschau und Kamera starten
self.camera.start_preview(Preview.QT)
self.camera.start()
2. Bildaufnahme mit Thread-Sicherheit
Die Methode ``capture_photo`` verwendet Thread-Locks, um mehrere gleichzeitige Aufnahmen zu verhindern und eine korrekte Dateibenennung sicherzustellen.
.. code-block:: python
def capture_photo(self):
with self.photo_lock:
filepath = self.pictures_dir / f"book_cover_{self.photo_index:03d}.jpg"
self.camera.capture_file(str(filepath))
self.photo_index += 1
return str(filepath)
3. Vision-AI-Analyse
Das System nutzt die Vision-Funktionen von GPT-4o, um Buchcover zu analysieren. Zwei Methoden (Streaming und Nicht-Streaming) sind zur besseren Stabilität implementiert.
.. code-block:: python
def analyze_book_cover(self, image_path):
prompt_text = "Please analyze this book cover..."
# Methode 1: Antwort ohne Streaming
response = self.llm.prompt(prompt_text, image_path=image_path)
# Methode 2: Fallback mit Streaming
stream_response = self.llm.prompt(prompt_text, stream=True, image_path=image_path)
4. Text-to-Speech-Konvertierung
Die TTS-API von OpenAI wandelt die AI-Analyse in natürlich klingende Sprache um, mit konfigurierbaren Stimmenoptionen.
.. code-block:: python
self.tts = OpenAI_TTS(api_key=OPENAI_API_KEY)
self.tts.set_voice(self.tts.Voice.ALLOY)
def speak_response(self, text):
clean_text = re.sub(r'[*_\[\]()#]', '', text) # Markdown entfernen
self.tts.say(clean_text, instructions="speak clearly and warmly")
5. Status-Feedback-System
Die RGB-LED liefert während des gesamten Ablaufs visuelles Feedback durch Farbcodierung:
.. code-block:: python
def set_led_color(self, color_name):
color_map = {
"red": (255, 0, 0), # Fehler
"green": (0, 255, 0), # Erfolg
"blue": (0, 0, 255), # Bereit
"yellow": (255, 255, 0), # Aufnahme
"purple": (255, 0, 255), # Verarbeitung
}
self.rgb_led.color(color_map[color_name])
6. Button-Ereignisbehandlung
Die User-Taste startet den gesamten Analyseablauf über einen Ereignis-Callback.
.. code-block:: python
def button_handler(self):
# 1. Foto aufnehmen
image_path = self.capture_photo()
# 2. Mit AI analysieren
analysis = self.analyze_book_cover(image_path)
# 3. Analyse aussprechen
self.speak_response(analysis)
# Callback setzen
self.btn.set_on_click(self.button_handler)
7. Dateiverwaltung
Fotos werden automatisch in datumsbasierten Ordnern mit fortlaufender Nummerierung gespeichert.
.. code-block:: python
self.real_user = os.getenv("SUDO_USER") or os.getlogin()
self.user_home = f"/home/{self.real_user}"
self.pictures_dir = Path(self.user_home) / "Pictures" / "book_covers"
self.pictures_dir.mkdir(parents=True, exist_ok=True)
----------------------------------------------
**Fehlerbehebung**
- Fehler „Camera not detected“
- Stellen Sie sicher, dass das Kameraflachbandkabel korrekt eingesetzt ist (goldene Kontakte in die richtige Richtung)
- Führen Sie ``sudo raspi-config`` aus und aktivieren Sie das Kamera-Interface
- Starten Sie das System nach der Aktivierung neu
- Kein Vorschaufenster erscheint
- Stellen Sie sicher, dass Sie auf einem Raspberry Pi mit Desktop-Umgebung arbeiten
- Für Headless-Betrieb entfernen oder ändern Sie den Vorschau-Code
- Prüfen Sie, ob genügend GPU-Speicher zugewiesen ist
- OpenAI-API-Fehler
- Prüfen Sie, ob Ihr API-Schlüssel in ``secret.py`` korrekt ist und ausreichend Guthaben vorhanden ist
- Testen Sie die Internetverbindung: ``ping 8.8.8.8``
- Stellen Sie sicher, dass Ihr Konto Zugriff auf GPT-4o und die TTS-API hat
- TTS-Audio wird nicht abgespielt
- Prüfen Sie die Audioausgabe: ``sudo raspi-config`` → **System Options** → **Audio**
- Testen Sie den Lautsprecher mit: ``speaker-test -t sine -f 440``
- Stellen Sie sicher, dass Lautsprecher oder Kopfhörer am richtigen Audioanschluss angeschlossen sind
- Tastendruck wird nicht erkannt
- Prüfen Sie, ob die LED der User-Taste beim Drücken aufleuchtet
- Stellen Sie sicher, dass das Fusion HAT+ korrekt auf den GPIO-Pins sitzt
- Überprüfen Sie, ob der Button-Callback korrekt gesetzt wurde
- Bildanalyse liefert nur allgemeine Antworten
- Sorgen Sie für gute Beleuchtung beim Fotografieren der Buchcover
- Positionieren Sie das Buchcover möglichst gerade im Kamerabild
- Testen Sie zunächst bekannte Bücher für bessere Erkennung
- Reinigen Sie die Kameralinse, falls das Bild unscharf ist
----------------------------------------------
Dieses Projekt demonstriert die leistungsstarke Kombination aus Computer Vision, natürlicher Sprachverarbeitung und physischem Computing, um ein intelligentes Buchanalyse-System zu erstellen. Es zeigt, wie AI alltägliche Interaktionen mit realen Objekten wie Büchern erweitern kann und Informationen zugänglicher sowie interaktiver macht.