Schnelle und einfache Bildgenerierung mit Fabric und OpenAI

Das Bild zeigt ein stilisiertes, kunstvolles Büro mit einem Schreibtisch und mehreren Monitoren, die Programmcode und technische Diagramme anzeigen. Die Wände sind mit fantasievollen, grafischen Mustern und verspielten technischen Elementen dekoriert. Der Raum ist minimalistisch und modern eingerichtet, mit einem Schreibtischstuhl, Pflanzen und großen Fenstern, durch die Licht hereinfällt. Der Stil ist eine Mischung aus Schwarz-Weiß-Zeichnung und futuristischer Technikästhetik. Ideal als Schmuckbild für einen Artikel über Programmierung, Kreativität oder technisches Arbeiten.

Einleitung

In mei­nen vor­he­ri­gen Artikeln habe ich Fabric vor­ge­stellt und erläu­tert, wie die­ses Tool in Workflows auf dem Mac, iPad und iPhone ein­ge­bun­den wer­den kann. Fabric erstellt dabei mit­tels Texteingaben, z.B. durch ein­fa­che Text-Eingaben in die Kommandozeile oder über das Auslesen von Textdateien, zusam­men mit einer Vorlage, die als Pattern bezeich­net wird, einen zum Problem opti­mier­ten Prompt und über­gibt die­se an ein LLM, das dann wie­der­um einen Text als Ergebnis zurück­gibt.

Ein Workflow, der bei mir häu­fi­ger vor­kommt, ist die Erstellung eines Artikelbildes mit Hilfe eines spe­zi­el­len Patterns, das an den Stil mei­nes Blogs ange­passt ist. In die­sem Fall über­ge­be ich den Text an Fabric, das dann den Prompt erstellt, aus dem wie­der­um über einen OpenAI-API-Aufruf das Artikelbild erzeugt wird.

Die Bildgenerierung

Bisher habe ich die Artikelbilder für die­sen Blog mit­hil­fe “manu­ell” von Stable Diffusion oder ChatGPT erstellt. Dazu habe ich das Thema des Artikels in Stichworten beschrie­ben und den gewünsch­ten Stil sowie die Art der Komposition an die Tools über­ge­ben und das Ergebnis eben­falls manu­ell gespei­chert. Mit Fabric kann ich die­sen Prozess wei­ter auto­ma­ti­sie­ren, indem ich die­se Stil und Kompositionsbeschreibung als Pattern ver­all­ge­mei­ne­re. So kann ein­fach der Text eines Artikels an Fabric über­ge­ben wer­den und als Ergebnis wird das fer­ti­ge Bild gene­riert.

Erstellung eines Artikel-Bildes

Ursprünglich woll­te ich die Bildgenerierung in Python umset­zen. Allerdings wei­ger­te sich das Python-Beispiel auf der OpenAI-Seite, Bilder im Querformat zu gene­rie­ren. Daher habe ich das curl-Beispiel an mei­ne Anforderungen ange­passt und in ein Shell-Skript inte­griert. Die fol­gen­den Voraussetzungen müs­sen dafür erfüllt sein:

  1. Ein OpenAI-Account und ein OpenAI-API-Key (OpenAI Platform).
  2. Eine lauf­fä­hi­ge Installation von Fabric. Siehe Installation und ers­te Schritte mit Fabric – dem Prompt-Optimierer.
  3. Das Kommandozeilenprogramm jq, um JSON-Daten zu ver­ar­bei­ten.

Das Pattern

Starten wir mit dem für mei­nen Zweck opti­mier­ten Pattern. Dazu habe ich als Vorlage einen vor­han­de­nen Pattern-Ordner dupli­ziert. Der Ordner $HOME/.config/fabric/prompts/create_art_prompt pass­te gut für mei­ne Anforderungen. Die Kopie des Ordners habe ich in create_blog_image umbe­nannt, was gleich­zei­tig der Name ist, unter dem das neue Pattern in Fabric auf­ge­ru­fen wird. Die Datei system.md im Ordner habe ich dann durch den fol­gen­den 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 die­sem Pattern kann schon ein Prompt erstellt wer­den, der z.B. in ChatGPT oder Stable-Diffusion ver­wen­den kann:

cat $HOME/Documents/Blog/neuer_artikel.md | fabric -sp create_blog_image

Damit ist der ers­te Teil erle­digt.

Das Skript

Das Skript soll nun den erstell­ten Prompt an DALL·E 3 über­ge­ben und die Antwort ver­ar­bei­ten. Diese Antwort besteht aus einer JSON-Payload, die unter ande­rem die URL zu dem Bild und einen revised_prompt ent­hält, also den Prompt, den DALL·E 3 tat­säch­lich ver­wen­det 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 instal­liert wer­den kann:

brew install jq

Neben dem Bild soll das Skript, zumin­dest in der Anfangsphase, den von Fabric erstell­ten Prompt sowie den revised_prompt für Analysezwecke und zur Optimierung des Patterns mit spei­chern. Später kön­nen die­se Zeilen aus­kom­men­tiert oder gelöscht wer­den.

Da ich bis­her noch kei­ne bes­se­re Idee hat­te, wie ich den erstell­ten Dateien auto­ma­tisch einen sinn­vol­len Namen geben kann, wer­den die drei Dateien mit einem Zeitstempel als Name gespei­chert. Zusätzlich wird das Bild am Ende in einem für PNG-Dateien zustän­di­gen Programm geöff­net, z.B. in der Vorschau-App.

Daraus ergibt sich dann fol­gen­des 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 nor­ma­ler­wei­se nicht ohne Weiteres aus­ge­führt wer­den kön­nen. Um den Aufruf eines Shell-Skripts zu ver­ein­fa­chen, kopie­re ich die­se in einen Ordner, der im Suchpfad der Shell ein­ge­tra­gen ist. Auf dem Mac sind das nor­ma­ler­wei­se:

$HOME/Applications
$HOME/bin 
$HOME/.local/bin 

Wenn die Skripte in einem die­ser Ordner gespei­chert wer­den, sind sie nur für den aktu­el­len Benutzer zugäng­lich. Wenn ein Skript allen Benutzern eines Computers zugäng­lich gemacht wer­den soll, sind die Pfade

/usr/local/bin
/opt/bin

die rich­ti­ge Wahl. Für das Kopieren und Manipulieren sind dann Administratorrechte not­wen­dig.

Um zu tes­ten, wel­che Pfade schon im Suchpfad ange­ge­ben sind, kann der Befehl

echo $PATH

genutzt wer­den.

Ich nut­ze für pri­va­te mei­ne pri­va­ten Programme und Skripte den Ordner $HOME/Applications. Da die­ser Ordner auch für den Webapps der Browser ver­wen­det wird, die z.B. in Safari unter „Ablage → Zum Dock hin­zu­fü­gen“ erstellt wer­den, ist die­ser Ordner zumeist schon vor­han­den, auch wenn er dann im Finder als „Programme“ ein­ge­deutscht ist. Auf der Kommandozeile heißt er trotz­dem noch „Applications“.

Falls die­ser Ordner nicht im Suchpfad abge­legt ist, kann er ein­fach hier­mit hin­zu­ge­fügt wer­den:

echo 'export PATH=$PATH:$HOME/Applications' >> $HOME/.zshrc 
source $HOME/.zshrc

Das Skript kann dann in den Ordner z.B. mit dem Namen CreateImage gespei­chert wer­den und dann mit

chmod +x $HOME/Applications/CreateImage

als aus­führ­bar mar­kiert wer­den. Damit kann das Skript im Terminal immer ein­fach mit CreateImage auf­ge­ru­fen wer­den, auch ohne die expli­zi­te Pfadangabe.

Eine weitere Umgebungsvariable

Damit ein Bild mit dem OpenAI-Aufruf erstellt wer­den kann, muss der OpenAI-API-Key als Umgebungsvariable in der Shell-Konfigurationsdatei gespei­chert wer­den. Das Skript liest ihn dann von dort ein. Der Vorteil die­ses Vorgehens ist, dass der Key nicht in jedem Programm, das OpenAI auf­ruft, im Code ange­ge­ben wer­den muss und man die­sen nicht ver­se­hent­lich mit dem Skript auf einem Blog wie hier oder auf GitHub ver­öf­fent­licht.

# Added for OpenAI Apps
echo 'export OPENAI_API_KEY="Dein OpenAI Key"' >> $HOME/.zshrc
source $HOME/.zshre

Der erste Testlauf

Mit die­sem Befehl kann nun getes­tet wer­den, ob die Bildgenerierung mit Fabric und dem Skript funk­tio­niert:

echo "Mache ein Bild von zwei Papageien auf einem Hochhausdach" | CreateImage

Nun soll­te im Terminal die Bestätigung erschei­nen, dass das Bild und die bei­den Prompts gespei­chert wur­den. Außerdem öff­net sich in der Vorschau das erstell­te Bild.

Das Bild zeigt zwei farbenprächtige Papageien, einen in Gelb-Blau und einen in Rot, die auf einem hohen Wolkenkratzer in einer Stadt sitzen. Die Skyline im Hintergrund ist bei Sonnenaufgang oder Sonnenuntergang zu sehen, mit dramatischen Wolken und einem weiten Blick über die Stadtlandschaft und das Meer. Die Papageien dominieren die Szene durch ihre Größe und lebendigen Farben.

Somit sind nun alle Teile zusam­men und mit dem Aufruf von:

cat $HOME/Documents/Blog/neuer_artikel.md | fabric -sp create_blog_image | CreateImage

wird ein Artikelbild erstellt. Das fol­gen­de Beispiel zeigt das Ergebnis die­sen Aufrufes mit die­sem Artikel als Markdown-Datei:

Das Bild zeigt ein stilisiertes, kunstvolles Büro mit einem Schreibtisch und mehreren Monitoren, die Programmcode und technische Diagramme anzeigen. Die Wände sind mit fantasievollen, grafischen Mustern und verspielten technischen Elementen dekoriert. Der Raum ist minimalistisch und modern eingerichtet, mit einem Schreibtischstuhl, Pflanzen und großen Fenstern, durch die Licht hereinfällt. Der Stil ist eine Mischung aus Schwarz-Weiß-Zeichnung und futuristischer Technikästhetik. Ideal als Schmuckbild für einen Artikel über Programmierung, Kreativität oder technisches Arbeiten.

Weitere Optimierung

Allerdings ist das immer noch zu viel Tipp-Arbeit. Daher kann die­ser lan­ge Kommandozeilen-Aufruf wie­der­um in ein Shell-Skript ver­packt wer­den:

#!/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 gespei­chert und als aus­führ­bar mar­kiert, reicht dann der Aufruf:

make_articel_image /path/to/artikel.md

Für mei­nen Anwendungsfall suche ich im Moment eine Lösung, die ich direkt in Obsidian auf­ru­fen kann, um das Bild aus der akti­ven Notiz her­aus zu erstel­len. Es gibt da eini­ge Kandidaten, die das viel­leicht unter­stüt­zen, wie die Plugins Templater oder Shell Commands, aber das ist dann der nächs­te Schritt.

Fazit

Dieses Beispiel, wie Fabric in einem nütz­li­chen Workflow ein­ge­setzt wer­den kann, ist genau als das zu ver­ste­hen: als Beispiel für eige­ne Entwicklungen. Das Pattern muss an die eige­nen Bedürfnisse ange­passt wer­den — es soll­te nicht über­all mein Bildstil auf­tau­chen. Die Optimierung eines sol­chen Patterns erfor­dert sicher­lich eini­ge Iterationen und Zeit. Dafür lohnt es sich, einen Blick auf die bei­den Prompts zu wer­fen.

Ich hof­fe, dass die­se Ideen trotz­dem hilf­reich sind und freue mich wie immer über Kommentare, sei es zu even­tu­el­len Fehlern, Verbesserungen, Lob oder Kritik.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert