Hinweis
Da kurz nach der Veröffentlichung der ersten Version dieses Artikels Fabric in Go neu implementiert wurde, habe ich den Artikel überarbeitet und ergänzt.
Einführung in die Nutzung von Fabric mit Alfred und Apple Kurzbefehlen
Wie in meinem vorherigen Artikel versprochen möchte ich in diesem Artikel Wege aufzeigen, wie man Fabric auch in Workflows mit der Alfred App sowie in den Apple Kurzbefehlen nutzen kann. Für die Alfred App wird allerdings das kostenpflichtige PowerPack benötigt.
Dazu möchte ich den Beispielsaufruf aus dem vorherigen Artikel nutzen, der auf der Kommandozeile schon eine Webseite zusammenfasste. Eigentlich eine Aufgabe, die man lieber mit einem Tastendruck oder einem Klick erledigt.
Hier noch einmal der Aufruf zur Erinnerung:
wget -qO- https://ileif.de/2024/08/07/automatisierung-von-apple-kurzbefehlen-mit-shortery/ | pandoc -f html -t plain | fabric -sp summarize
Der Alfred App Workflow
Ziel ist es, einen Workflow für Alfred zu erstellen, der mit einer Tastenkombination, z.B. ⌃⌥F, die URL eines aktiven Browser-Fensters übernimmt, eine Zusammenfassung erstellt und diese dann in meinem Obsidian-Vault im Ordner „17 WebSiteSummaries“ speichert. Die Notiz soll den Titel der Webseite tragen und einen Properties-Bereich enthalten, in dem unter anderem die URL der Seite als „source“ und der Tag „fabric“ festgelegt werden.
Shell-Skripte und auch Python-Skripte laufen immer in einer Umgebung, in der Suchpfade, Variablen und im Falle von Python auch installierte Bibliotheken durch eine oder mehrere Konfigurationsdateien definiert sind. Für das Terminal gibt es einen festgelegten Ablauf, in dem bestimmte Konfigurationen geladen werden. Zusätzlich kommen bei Python die virtuellen Umgebungen hinzu. Wenn jedoch Skripte in Tools wie Alfred oder in den Kurzbefehlen ausgeführt werden, werden nur minimale Konfigurationsdateien geladen, wodurch möglicherweise wichtige Suchpfade für bestimmte Programme fehlen. Wie dieses Problem für Python und virtuelle Umgebungen gelöst werden kann, habe ich in dem Artikel „Python-Skripte in Alfred-Workflows mit virtuellen Umgebungen nutzen“ beschrieben.
Den Ansatz habe ich nun auch auf das Ausführen von Shell-Skripten übertragen. Theoretisch könnte die gesamte ~/.zshrc geladen werden, aber ich benötige nur die Suchpfade für Go sowie die Einbindung der Alias-Definitionen. Gegebenenfalls muss auch der Suchpfad für die Homebrew-Apps hinzugefügt werden:
export PATH="$PATH:$HOME/go/bin:$HOME/Applications" if [ -f "$HOME/.config/fabric/fabric-bootstrap.inc" ]; then . "$HOME/.config/fabric/fabric-bootstrap.inc"; fi
Die Datei ist bei mir unter $HOME/.fabenv
gespeichert und kann von dort geladen werden. Was die if ... fi
habe ich in dem vorherigen Artikel beschrieben.
Der Workflow in der Alfred App sieht so aus:
Als Trigger verwende ich einen Hotkey-Trigger, der die “Current Front Browser Tab” aufruft. Da sowohl die URL als auch der Titel der Webseite benötigt wird, muss in der Aktion das “Output Format” auf “URL⇥Title” eingestellt sein. So werden die URL und der Title, die mit einem TAB getrennt als ein String an die “Spilt Arg” übergeben wird, die wiederum daraus, mit den Einstellung “Split with Tab”, Output as Vaiables” und “Varable Prefix split”, diese dann an die “Run Script”-Aktion weiter gibt.
Hier wird in der Kopfzeile als „Language: /bin/zsh — ‑norcs”, “with input as argv “ und ”running instances: Sequentially” eingestellt. In den Skriptbereich wird dieses Skript eingefügt und angepasst:
# Übergabe der Parameter aus dem Split-Modul url=$split1 title=$split2 # Lädt die Konfigurations- oder Initialisierungsdatei '.fabenv', die sich im angegebenen Pfad befindet # Diese Datei enthält die notwendigen Pfad Information und Umgebungsvariablen source $HOME/.fabenv # Verarbeitet den Titel: Ersetzt alle Vorkommen von ':' und '/' durch '-' # Dies ist notwendig, da ':' und '/' in Dateinamen ungültige Zeichen sind FILENAME=$(echo "$title" | sed 's/[:\/]/-/g') # Definiert das Zielverzeichnis, in dem die Markdown-Datei gespeichert werden soll # Der Pfad enthält Leerzeichen, daher ist er in Anführungszeichen eingeschlossen TARGET_DIR="$HOME/Documents/01 Meine Dokumente/ObsidianNotes/17 WebSiteSummaries" # Setzt den vollständigen Dateinamen mit der .md-Erweiterung # Der Dateiname basiert auf dem bereinigten Titel FULL_FILENAME="${FILENAME}.md" # Erstellt die Markdown-Datei im Zielverzeichnis mit dem Frontmatter-Block { echo "---" echo "source: ${url}" echo "erstellt:" echo "geändert:" echo "tags: fabric" echo "---" echo "" } > "${TARGET_DIR}/${FULL_FILENAME}" # Führt den Befehl 'wget' aus, um den Inhalt der URL zu holen und durch eine Pipe an 'pandoc' weiterzuleiten # 'pandoc' konvertiert den HTML-Inhalt in reinen Text # 'fabric' fasst den Text in deutscher Sprache zusammen # Die Ausgabe wird an das Ende der bereits erstellten Notiz angehängt wget -qO- $url | pandoc -f html -t plain | fabric -sp summarize_german | >> "${TARGET_DIR}/${FULL_FILENAME}" # Fügt weitere Informationen am Ende der Notiz hinzu { echo "" echo "---" echo "Ordner: `=this.file.folder`"
Im Property-Bereich der Notiz setze ich die Schlüssel „erstellt:“ und „geändert:“ ein, die in meinem Vault automatisch vom Plugin Update time on edit befüllt werden. Zudem wird diese Notiz mit „fabric“ getaggt. Ich definiere auch noch einen Footer, den alle meine Notizen enthalten, der mithilfe des DataView-Plugins den Ordner anzeigt, in dem sich die Notiz befindet. Für den Rest sollten die Kommentare im Skript ausreichende Erklärungen liefern.
Am Ende des Workflows wird eine Benachrichtigung angezeigt, sobald das Skript durchgelaufen ist. Da die Antwort des LLMs oft einige Sekunden benötigt, kann es vorkommen, dass die Notiz bereits mit dem Property-Bereich in die Vault geschrieben und angezeigt wird, während der restliche Inhalt noch fehlt. Es kann also einen Moment dauern, bis der gesamte Text in der Notiz erscheint.
Nicht jede Webseite lässt sich auf diese Weise abgreifen. Wenn wget den Text nicht korrekt aus dem HTML extrahieren kann, wird stattdessen ein beliebiger Text generiert, der möglicherweise nichts mit der eigentlichen Webseite zu tun hat.
Soweit der Alfred-Workflow, der in allen Webkit- und Chrome-basierten Browsern funktionieren sollte. In Firefox hingegen funktioniert der Workflow nicht.
Der Apple Kurzbefehl
Eigentlich wollte ich den Apple Kurzbefehl mit einem ähnlichen Skript wie bei der Alfred-Lösung implementieren. Die URL der aktuellen Webseite sollte an das Skript übergeben und dort genutzt werden. Es stellte sich jedoch heraus, dass bei der Aktion „URL-Eingabe von Bildschirminhalt“ nicht die URL als Argument an die Aktion „Shell-Skript ausführen“ übergeben wird, sondern der Pfad zu einer lokalen Kopie der HTML-Datei der Webseite.
Ein kleiner Test-Kurzbefehl zeigt das Problem auf:
Nachdem „URL-Eingabe von Bildschirminhalt“ in einem aktiven Browserfenster aufgerufen wurde, wird in der Aktion „Ergebnis anzeigen“ tatsächlich die URL der Webseite angezeigt:
Aber das Shell-Skript erhält etwas völlig anderes, wie die zweite Ergebnisanzeige zeigt:
Leider habe ich den Test nicht sofort durchgeführt, sodass ich letztlich einige Zeit damit verbracht habe, das Problem zu analysieren.
Eine weiterer Punkt, der Zeit in Anspruch nahm, war der unterschiedliche Inhalt der $PATH-Variable bei Alfred und den Kurzbefehlen. Während bei Alfred der Pfad zu den von Homebrew installierten Befehlen im Suchpfad angegeben war, fehlte dieser in der Apple-Kurzbefehle-Version.
Der Workaround, ohne die Homebrew-Befehle, ist zwar letztlich etwas einfacher, aber ich wollte die Hürden an dieser Stelle doch einmal dokumentieren.
Der Apple Kurzbefehl
Ich habe mir für den Workaround zunutze gemacht, dass mit der Option „Bildschirminhalt empfangen“ eine lokale Kopie der Webseite erstellt wird und der Pfad zu dieser Datei beim Aufruf des Shell-Skripts in der Aktion „Shell-Skript ausführen“ übergeben wird. Ob dies ein Feature oder ein Bug ist, der irgendwann beseitigt wird, wird die Zukunft zeigen.
Das Shell-Skript sieht dann folgendermaßen aus:
source $HOME/.favenv cat $1 | fabric -sp summarize_german
Und so läuft der Prozess ab:
- Die URL und der Titel der Webseite werden an den Kurzbefehl übergeben und in den entsprechenden Variablen gespeichert.
- An die Aktion „Shell-Skript ausführen“ wird über die Variable URL der Pfad zur lokalen HTML-Datei übergeben.
- Im Skript wird zunächst der Suchpfad über die Konfigurationsdatei um die Go-spezifischen Pfade erweitert. Anschließend wird der Inhalt der lokalen HTML-Datei an fabric übergeben und mit dem Pattern summarize_german vom LLM verarbeitet.
- Die Ausgabe des Shell-Skripts wird in der Variablen Text gespeichert. Dann wird in einem Text die Notiz zusammengestellt, inklusive Property-Bereich und Footer.
- Dieser Text wird dann in der Obsidian-Vault gespeichert.
Zum Speichern der Notiz in der Obsidian-Vault nutze ich die Kurzbefehl-Erweiterung Actions for Obsidian mit der Aktion „Create Note“. Alternativ kann das Speichern auch mit der Aktion „Datei sichern“ umgesetzt werden, aber im Zusammenhang mit Obsidian lohnt es sich, etwas Geld in Actions for Obsidian zu investieren.
Das ganze sieht dann so aus:
Wie im Alfred-Workflow kann es vorkommen, dass bestimmte Webseiten sich nicht abgreifen lassen. In diesem Fall wird je nach verwendetem LLM ein beliebiger Text als Ausgabe erscheinen.
Zusammenfassung und Ausblick auf zukünftige Anwendungen
Ich hoffe, dass ich mit diesem Artikel nicht nur ein nützliches Tool vorgestellt habe, sondern auch einen Ausgangspunkt für eigene Lösungen bieten konnte, wie Fabric in andere Workflows integriert werden kann. Ich habe hier Alfred und Apple Kurzbefehle genutzt, bin aber überzeugt, dass sich die Ansätze auch in Raycast und anderen Workflow-Tools einsetzen lassen.
Beide Beispiel-Workflows sind sicherlich noch nicht vollständig ausgereift. Beispielsweise fehlt in beiden ein Fehlerhandling. Ich könnte mir zudem vorstellen, dass über einen Auswahl-Dialog andere Patterns ausgewählt werden könnten. Außerdem laufen die Workflows lokal auf meinem MacBook Pro, daher habe ich noch nicht getestet, ob mit der “Remote Shell-Skript”-Aktion die Ausführung des Fabric-Aufrufs auf einem Server stattfinden kann. Solange keine lokalen LLMs involviert sind, sollte eigentlich ein Raspberry Pi ausreichen. So könnte ein Kurzbefehl auch auf einem iPad oder iPhone funktionieren.
Es ist also gut möglich, dass ich in diesem Blog noch weitere Anwendungen vorstellen werde.
Wie immer: Kritik, Korrekturen und Lob gerne in die Kommentare.
Schreibe einen Kommentar