Einleitung
In meinen vorherigen Artikeln habe ich Fabric vorgestellt und erläutert, wie dieses Tool in Workflows auf dem Mac, iPad und iPhone eingebunden werden kann. Fabric erstellt dabei mittels Texteingaben, z.B. durch einfache Text-Eingaben in die Kommandozeile oder über das Auslesen von Textdateien, zusammen mit einer Vorlage, die als Pattern bezeichnet wird, einen zum Problem optimierten Prompt und übergibt diese an ein LLM, das dann wiederum einen Text als Ergebnis zurückgibt.
Ein Workflow, der bei mir häufiger vorkommt, ist die Erstellung eines Artikelbildes mit Hilfe eines speziellen Patterns, das an den Stil meines Blogs angepasst ist. In diesem Fall übergebe ich den Text an Fabric, das dann den Prompt erstellt, aus dem wiederum über einen OpenAI-API-Aufruf das Artikelbild erzeugt wird.
Die Bildgenerierung
Bisher habe ich die Artikelbilder für diesen Blog mithilfe “manuell” von Stable Diffusion oder ChatGPT erstellt. Dazu habe ich das Thema des Artikels in Stichworten beschrieben und den gewünschten Stil sowie die Art der Komposition an die Tools übergeben und das Ergebnis ebenfalls manuell gespeichert. Mit Fabric kann ich diesen Prozess weiter automatisieren, indem ich diese Stil und Kompositionsbeschreibung als Pattern verallgemeinere. So kann einfach der Text eines Artikels an Fabric übergeben werden und als Ergebnis wird das fertige Bild generiert.
Erstellung eines Artikel-Bildes
Ursprünglich wollte ich die Bildgenerierung in Python umsetzen. Allerdings weigerte sich das Python-Beispiel auf der OpenAI-Seite, Bilder im Querformat zu generieren. Daher habe ich das curl-Beispiel an meine Anforderungen angepasst und in ein Shell-Skript integriert. Die folgenden Voraussetzungen müssen dafür erfüllt sein:
- Ein OpenAI-Account und ein OpenAI-API-Key (OpenAI Platform).
- Eine lauffähige Installation von Fabric. Siehe Installation und erste Schritte mit Fabric – dem Prompt-Optimierer.
- Das Kommandozeilenprogramm jq, um JSON-Daten zu verarbeiten.
Das Pattern
Starten wir mit dem für meinen Zweck optimierten Pattern. Dazu habe ich als Vorlage einen vorhandenen Pattern-Ordner dupliziert. Der Ordner $HOME/.config/fabric/prompts/create_art_prompt passte gut für meine Anforderungen. Die Kopie des Ordners habe ich in create_blog_image umbenannt, was gleichzeitig der Name ist, unter dem das neue Pattern in Fabric aufgerufen wird. Die Datei system.md im Ordner habe ich dann durch den folgenden Inhalt ersetzt.
# IDENTITY AND GOALS You are an expert graphic designer and AI whisperer. You know how to take a concept and give it to an AI and have it create the perfect piece of drawing for it. Take a step back and think step by step about how to create the best result according to the STEPS below. STEPS - Think deeply about the concepts in the input. - Think about the best possible way to capture that concept visually in a compelling and interesting way. OUTPUT - Output a 100-word description of the concept and the visual representation of the concept. - Write the direct instruction to the AI for how to create the drawing, i.e., don't describe the drawing, but describe what it looks like and how it makes people feel in a way that matches the concept. This should include the style of black and white line art with nice strokes style of the drawing. The mood of happiness and a modern composition. Use the whole canvas size for the image of 1792x1024 pixels. There should no white space left. No colors! - The artwork should represent the concept in an environment that best fits the theme, whether it be natural, urban, abstract, or the conceptual siuation in a office or desktop enviorment - Include nudging clues that give the piece the proper style, such as “In the style of a futuristic digital interface,” “Resembling traditional ink drawings,” or “Minimalistc style.” INPUT INPUT:
Mit diesem Pattern kann schon ein Prompt erstellt werden, der z.B. in ChatGPT oder Stable-Diffusion verwenden kann:
cat $HOME/Documents/Blog/neuer_artikel.md | fabric -sp create_blog_image
Damit ist der erste Teil erledigt.
Das Skript
Das Skript soll nun den erstellten Prompt an DALL·E 3 übergeben und die Antwort verarbeiten. Diese Antwort besteht aus einer JSON-Payload, die unter anderem die URL zu dem Bild und einen revised_prompt
enthält, also den Prompt, den DALL·E 3 tatsächlich verwendet hat.
Wie schon erwähnt, wird zur Verarbeitung der Ein- und Ausgabe an OpenAI das Kommandozeilen-Tool jq
benötigt, das mit Hilfe von Homebrew installiert werden kann:
brew install jq
Neben dem Bild soll das Skript, zumindest in der Anfangsphase, den von Fabric erstellten Prompt sowie den revised_prompt
für Analysezwecke und zur Optimierung des Patterns mit speichern. Später können diese Zeilen auskommentiert oder gelöscht werden.
Da ich bisher noch keine bessere Idee hatte, wie ich den erstellten Dateien automatisch einen sinnvollen Namen geben kann, werden die drei Dateien mit einem Zeitstempel als Name gespeichert. Zusätzlich wird das Bild am Ende in einem für PNG-Dateien zuständigen Programm geöffnet, z.B. in der Vorschau-App.
Daraus ergibt sich dann folgendes Skript:
#!/bin/zsh # Überprüfen, ob Daten in das Skript gepiped werden if [ -t 0 ]; then # Wenn keine Eingabe über die Pipe erfolgt... echo "Es wurde keine Eingabe gepiped" exit 1 else # Alle gepipten Eingaben lesen prompt=$(cat -) fi # Dein OpenAI API-Schlüssel sollte als Umgebungsvariable gesetzt sein api_key="$OPENAI_API_KEY" # Erstellen der JSON-Nutzlast json_payload=$(jq -n \ --arg model "dall-e-3" \ --arg prompt "$prompt" \ --argjson n 1 \ --arg size "1792x1024" \ '{model: $model, prompt: $prompt, n: $n, size: $size}' ) # Aktuelles Datum und Uhrzeit für den Dateinamen ermitteln timestamp=$(date +"%Y%m%d_%H%M%S") # Den curl-Befehl ausführen und die Antwort speichern response=$(curl -s https://api.openai.com/v1/images/generations \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $api_key" \ -d "$json_payload") # Die Bild-URL aus der Antwort extrahieren image_url=$(echo $response | jq -r '.data[0].url') # Den überarbeiteten Prompt aus der Antwort extrahieren revised_prompt=$(echo $response | jq -r '.data[0].revised_prompt') # Das Bild unter Verwendung des Datums und der Uhrzeit im Dateinamen speichern curl -s "$image_url" -o "$HOME/Pictures/CreateImage/image_${timestamp}.png" # Den verwendeten Prompt in einer Textdatei speichern. echo "$prompt" > "$HOME/Pictures/CreateImage/prompt_${timestamp}.txt" # Den überarbeiteten Prompt in einer Textdatei speichern echo "$revised_prompt" > "$HOME/Pictures/CreateImage/revised_prompt_${timestamp}.txt" # Das Bild anzeigen open "$HOME/Pictures/CreateImage/image_${timestamp}.png" # Erfolgsnachricht ausgeben - echo "Bild gespeichert als image_${timestamp}.png" echo "Prompt gespeichert als prompt_${timestamp}.txt" echo "Überarbeiteter Prompt gespeichert als revised_prompt_${timestamp}.txt" # Falls die erstellte Bilddatei an einen nächsten Schrit "gepiped" werden soll, die Erfolgsnachrichten auskommentieren und folgedene Zeile ent-Kommentieren # echo image_${timestamp}.png
Was tun mit den Skripts
Skripte sind Textdateien, die normalerweise nicht ohne Weiteres ausgeführt werden können. Um den Aufruf eines Shell-Skripts zu vereinfachen, kopiere ich diese in einen Ordner, der im Suchpfad der Shell eingetragen ist. Auf dem Mac sind das normalerweise:
$HOME/Applications $HOME/bin $HOME/.local/bin
Wenn die Skripte in einem dieser Ordner gespeichert werden, sind sie nur für den aktuellen Benutzer zugänglich. Wenn ein Skript allen Benutzern eines Computers zugänglich gemacht werden soll, sind die Pfade
/usr/local/bin /opt/bin
die richtige Wahl. Für das Kopieren und Manipulieren sind dann Administratorrechte notwendig.
Um zu testen, welche Pfade schon im Suchpfad angegeben sind, kann der Befehl
echo $PATH
genutzt werden.
Ich nutze für private meine privaten Programme und Skripte den Ordner $HOME/Applications
. Da dieser Ordner auch für den Webapps der Browser verwendet wird, die z.B. in Safari unter „Ablage → Zum Dock hinzufügen“ erstellt werden, ist dieser Ordner zumeist schon vorhanden, auch wenn er dann im Finder als „Programme“ eingedeutscht ist. Auf der Kommandozeile heißt er trotzdem noch „Applications“.
Falls dieser Ordner nicht im Suchpfad abgelegt ist, kann er einfach hiermit hinzugefügt werden:
echo 'export PATH=$PATH:$HOME/Applications' >> $HOME/.zshrc source $HOME/.zshrc
Das Skript kann dann in den Ordner z.B. mit dem Namen CreateImage
gespeichert werden und dann mit
chmod +x $HOME/Applications/CreateImage
als ausführbar markiert werden. Damit kann das Skript im Terminal immer einfach mit CreateImage
aufgerufen werden, auch ohne die explizite Pfadangabe.
Eine weitere Umgebungsvariable
Damit ein Bild mit dem OpenAI-Aufruf erstellt werden kann, muss der OpenAI-API-Key als Umgebungsvariable in der Shell-Konfigurationsdatei gespeichert werden. Das Skript liest ihn dann von dort ein. Der Vorteil dieses Vorgehens ist, dass der Key nicht in jedem Programm, das OpenAI aufruft, im Code angegeben werden muss und man diesen nicht versehentlich mit dem Skript auf einem Blog wie hier oder auf GitHub veröffentlicht.
# Added for OpenAI Apps echo 'export OPENAI_API_KEY="Dein OpenAI Key"' >> $HOME/.zshrc source $HOME/.zshre
Der erste Testlauf
Mit diesem Befehl kann nun getestet werden, ob die Bildgenerierung mit Fabric und dem Skript funktioniert:
echo "Mache ein Bild von zwei Papageien auf einem Hochhausdach" | CreateImage
Nun sollte im Terminal die Bestätigung erscheinen, dass das Bild und die beiden Prompts gespeichert wurden. Außerdem öffnet sich in der Vorschau das erstellte Bild.
Somit sind nun alle Teile zusammen und mit dem Aufruf von:
cat $HOME/Documents/Blog/neuer_artikel.md | fabric -sp create_blog_image | CreateImage
wird ein Artikelbild erstellt. Das folgende Beispiel zeigt das Ergebnis diesen Aufrufes mit diesem Artikel als Markdown-Datei:
Weitere Optimierung
Allerdings ist das immer noch zu viel Tipp-Arbeit. Daher kann dieser lange Kommandozeilen-Aufruf wiederum in ein Shell-Skript verpackt werden:
#!/bin/zsh # Überprüfen, ob ein Argument übergeben wurde if [ $# -eq 0 ]; then echo "Bitte eine Datei übergeben." exit 1 fi # Überprüfen, ob das übergebene Argument eine Datei ist if [ ! -f "$1" ]; then echo "Das übergebene Argument war keine Datei." exit 1 fi # Wenn ein Argument übergeben wurde und es eine Datei ist, führe den Befehl aus cat "$1" | fabric -sp create_blog_image | CreateImage
Wieder im Ordner $HOME/Applications
, z.B. als make_article_image
gespeichert und als ausführbar markiert, reicht dann der Aufruf:
make_articel_image /path/to/artikel.md
Für meinen Anwendungsfall suche ich im Moment eine Lösung, die ich direkt in Obsidian aufrufen kann, um das Bild aus der aktiven Notiz heraus zu erstellen. Es gibt da einige Kandidaten, die das vielleicht unterstützen, wie die Plugins Templater oder Shell Commands, aber das ist dann der nächste Schritt.
Fazit
Dieses Beispiel, wie Fabric in einem nützlichen Workflow eingesetzt werden kann, ist genau als das zu verstehen: als Beispiel für eigene Entwicklungen. Das Pattern muss an die eigenen Bedürfnisse angepasst werden — es sollte nicht überall mein Bildstil auftauchen. Die Optimierung eines solchen Patterns erfordert sicherlich einige Iterationen und Zeit. Dafür lohnt es sich, einen Blick auf die beiden Prompts zu werfen.
Ich hoffe, dass diese Ideen trotzdem hilfreich sind und freue mich wie immer über Kommentare, sei es zu eventuellen Fehlern, Verbesserungen, Lob oder Kritik.
Schreibe einen Kommentar