12.3    Dokumente laden

Die Jahresberichte im PDF-Format beinhalten wertvolle Informationen zum Projekt und finden sich auf der WordPress-Website unter https://viel-falter.at/ergebnisse/veroeffentlichungen. Um nicht jedes der 18 PDF-Dokumente einzeln herunterladen zu müssen, haben wir uns wieder einmal der KI bedient:

Prompt: How do I save linked PDF documents from the website https://viel-falter.at/ergebnisse/veroeffentlichungen to a local folder pdfs using Linux shell commands? Do not use temporary files but Unix pipes and remove duplicates. This site uses only absolute URLs.

Wir haben an dem Prompt etwas gefeilt, weil Claude-3.5-sonnet anfangs temporäre Dateien erzeugte, was wir für nicht notwendig halten. Bis auf das überflüssige -p beim Erstellen des Verzeichnisses in der ersten Zeile (der Schalter wäre nur notwendig, wenn man eine verschachtelte Verzeichnisstruktur erstellt) gibt es nicht viel auszusetzen:

mkdir -p pdfs && \
wget -qO- https://viel-falter.at/ergebnisse/veroeffentlichungen/\
| grep -oP 'href="[^"]*\.pdf"' | \
sed 's/href="//;s/"$//' | \
sort -u | \
xargs -I {} wget -qnc -P pdfs {}

Das wget-Kommando in Zeile 2 lädt den HTML-Code der Webseite, der durch das Pipe-Zeichen an das grep-Kommando weitergeleitet wird. Hier wird der Schalter -o verwendet, um nur den Teil der Zeile auszugeben, in dem der reguläre Ausdruck gefunden wurde. Die Einstellung für Perl-kompatible reguläre Ausdrücke (-P) wäre in diesem Fall nicht notwendig, ist aber auch kein Fehler. Um die vorangestellte Zeichenkette href= und die Anführungszeichen der Links zu entfernen, kommt sed zum Einsatz. sort -u entfernt die Duplikate, und schließlich führt xargs ein wget-Kommando für jeden gefundenen Link aus, wobei mit -P der Pfad zum Speichern der Dokumente festgelegt wird.

Ohne den Hinweis, dass alle URLs absolute Angaben sind, erzeugt Claude im letzten Schritt eine Adresse mit vorangestelltem Protokoll und Hostnamen (https://viel-falter.at/), weist aber im Erklärungstext darauf hin, dass dieses Vorgehen nur bei relativen Links funktionieren wird.

Das hier verwendete Kommando muss bei einer anderen Webseite nicht zwangsläufig genauso gut funktionieren. Der Suchbegriff bei dem grep-Kommando verwendet doppelte Anführungszeichen, was in HTML eigentlich nicht vorgeschrieben ist; das Contentmanagement-System WordPress, das hier verwendet wird, kommt damit aber zurecht.

Abgesehen von den PDF-Dokumenten werden wir noch eine Liste von Webseiten in unser Embedding-Modell aufnehmen. Diese werden beim Start der Applikation aus dem Internet geladen und in Text konvertiert.

SimpleDirectoryReader und SimpleWebPageReader

Die LlamaIndex-Bibliothek verwendet Dokumente und Nodes als wesentliche Bausteine. Dokumente sind Container für Daten, wie zum Beispiel ein PDF-Dokument oder ein Markdown-Dokument. Aber auch die Ausgabe einer Datenbank-Abfrage oder die Antwort von einem Webserver kann ein Dokument sein. Zu einem Dokument werden Metadaten abgelegt (zum Beispiel der Dateiname bei einer Datei) und Relationen zu anderen Dokumenten (zum Beispiel der Ordner auf der Festplatte). Nodes sind Teile eines Dokuments, die ebenfalls Metadaten und Relationen enthalten.

LlamaIndex macht es uns sehr einfach, die heruntergeladenen PDF-Dokumente in das interne Dokument-Format zu verwandeln:

from llama_index.core import SimpleDirectoryReader

pdf_documents = SimpleDirectoryReader("pdfs").load_data(
show_progress=True
)

Der SimpleDirectoryReader aus dem llama_index.core-Paket erzeugt eine Liste aller Dateien im pdfs-Ordner im LlamaIndex-Dokumentformat. In unserem Fall sind das 18 PDF-Dokumente. Der Schalter show_progress=True erzeugt Fortschrittsbalken in der Kommandozeile. Als Erweiterung zu dem Beispiel in Abschnitt 12.1, »Schnellstart RAG«, werden wir noch einige wichtige Webseiten ebenfalls als Dokumente verwenden. Dazu benötigen wir die Bibliothek SimpleWebPageReader:

from llama_index.readers.web import SimpleWebPageReader

webpages = [
"https://viel-falter.at/",
"https://viel-falter.at/monitoring/ziele-vision/",
"https://viel-falter.at/projektpartner/",
"https://viel-falter.at/news/",
"https://viel-falter.at/tagfalter-exkursion/",
];

web_documents = SimpleWebPageReader(
html_to_text = True).load_data(webpages);

Die html_to_text-Option legt fest, dass wir nur an dem textlichen Inhalt der Webseiten interessiert sind. Sowohl pdf_documents als auch web_documents enthält nun eine Liste von LlamaIndex-Dokumenten, die wir in einem weiteren Schritt in einen suchbaren Index verwandeln werden. Um die beiden Listen zu vereinen, verwenden wir in Python den + Operator:

documents = pdf_documents + web_documents

Der SimpleDirectoryReader und der SimpleWebPageReader sind aber nur zwei Beispiele für Möglichkeiten, wie Sie Daten in LlamaIndex laden können. Auf der Webseite https://llamahub.ai/ finden Sie Python-Module für unzählige weitere Formate.