AI Picture Tagging

Weil das am Dienstag ein Thema im Stammtisch war, so einfach kann man Bilder mit einem LLM taggen lassen .. einfach :DDD

AI Picture Tagging

zuerst braucht man natürlich ein lokales LLM, da hilft Ollama. Das muß man erst einmal installieren und sich dann das passende Modell installieren, z.b. Gemma3

$ ollama list
NAME                   ID              SIZE      MODIFIED     
gemma3:12b             f4031aab637d    8.1 GB    8 weeks ago     
gemma3:27b             a418f5838eaf    17 GB     8 weeks ago     
deepseek-r1:8b         6995872bfe4c    5.2 GB    7 months ago

Starten braucht man das nicht extra, das macht der Zugriff auf die ollama API von alleine. Was Ihr jetzt braucht ist ein Programm, daß die API ansprechen kann. Weil das ein bisschen viel wäre für den Blogeintrag pack ich Euch nur die Relevanten Teile rein, den Rest könnt Ihr bei PVA im Github finden 😉 Wer es nicht erkennt, es handelt sich um Java.

public class OllamaAITagging {
       static Dos dos = new Dos();
       static void log(String x) { System.out.println(x); }
       static String model = "gemma3:12b";
       static String content = "Was ist in dem Bild zu sehen? Antworte mit 10 Schlüsselwörtern als eine Liste mit dem Format keyword1,keyword2,keyword3,keyword4,keyword5,keyword6,keyword7,keyword8,keyword9,keyword10. Nur die Schlüsselwörter, keine einleitenden Worte. Wenn Du aber eine Person mit Namen kennst, dann ist dieser Name das erste Schlüsselwort. Nenne den Namen nur, wenn Du absolut sicher bist. Gleiche Anweisung für identifizierte Regionen oder Städte. Du darfst weniger als 10 Schlüsselwörter erzeugen, wenn die Länge der Liste inklusive der Komma und Leerzeichen 64 Zeichen überschreitet.";
       static final int maxlen = 64;
...
       static public String tagit(String bimages) {
          // Das habe ich hier NUR ZUM besseren Verständnis drin, das würde sonst in main() stehen!
          HTTP.apihost = "localhost";
          HTTP.apiport = "11434";
          HTTP.get("/api/tags");
          // Ende HTTP init
          
          String answere = HTTP.post("/api/chat","{\"model\":\""+ model +"\",\"stream\": false,\"messages\":"+
                           "[{\"role\": \"user\", \"model\":\"User\",\"date\":\""+
                           LocalDateTime.now().format( DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss") )+
                           "\",\"content\":\""+ content +"\",\"images\": ["+ bimages +"]}]}");
          if ( answere != null ) {
                  answere = filterAIThinking(parseJSON(answere,model).trim());
                  if ( ! answere.isEmpty() ) {
                         return answere;
                  } else return "answere is empty";
          } else return "no answere";
       }
...

Damit hätten wir den Prompt und die Routine, welche die Anfrage an die API von Ollama schickt. Jetzt das eigentliche Vorgehen:

String tags = tagit( „\““+ dos.readPipe(„base64 -w 0 \““+ filename +“\““ ).trim() +“\““ ).replaceAll(„, „,“,“);
      // OPTIONAL: Updating:  wenn die Tags direkt in das Bild geschrieben werden sollen:
if ( updating ) {
// sicherstellen, daß das auch in die ExIf Tags reinpaßt, auf das LLM darf man sich nicht verlassen, die ignorieren die Anweisung einfach oder verrechnen sich, suchts Euch aus..
while ( tags.length() > maxlen ) { tags = tags.substring( 0, tags.lastIndexOf(„,“) ); };

      log( dos.readPipe(„/usr/bin/exiftool -keywords=\““+ tags +“\“ \““+ target +“\“ -overwrite_original“));
}
log( tags );

Das wars schon. Natürlich muß da noch einiges an Code ins Programm, z.b. die Argumente auswerten, checken ob Ollama überhaupt läuft, Fehlerbehandlung und natürlich der Code, der im PVA Github-Repo steht, hier aber nicht reinkopiert wurde. Das eigentliche Problem ist damit aber erledigt und wie man sieht, recht einfach. Da kommen sogar brauchbare Ergebnisse raus, nur dürft ihr in der Zeit wo das läuft nichts anderes mit der GPU machen, das viel GPU-Speicher braucht, weil sonst dies passiert:

AVHWDeviceContext @ 0x55a1aa59b600] cu->cuMemAlloc(&data, size) failed -> CUDA_ERROR_OUT_OF_MEMORY: out of memory

und ich habe schon 8 GB GPU-Speicher drin 😉 Wenn Ihr ein kleineres Modell nehmt, dann braucht es natürlich nicht so viel Speicher.. ist Eure Entscheidung. Bei mir war im Batch-Prozess von meinem Foodporn-Ordner nach 8 Bildern mit OOM Schluß 😉 Weil noch ein Video konvertiert wurde, daß dann auch viel Speicher wollte. Dieser LLM Kram verbrennt soviele Ressourcen, das ist nicht mehr in Ordnung.

Kleiner Tipp noch, daß ist nicht die HTTP Klasse aus dem JDK, sondern aus dem PVA, die macht vieles einfacher als die aus dem JDK 😉 Deswegen braucht Ihr dann so ein Compilescript:

compile.sh:
#!/bin/bash

cd ~/tmp/aitagging
# oder wo auch Immer Eurer Projekt dann liegt auf der Platte
CP=““
for file in lib/*;do CP=“$CP:./$file“; done
javac –release 11 OllamaAITagging.java -cp „$CP:.“

und so sieht das „Projekt“ ( 😀 ) z.Z. bei mir aus :

-rwxr-xr-x. 1 marius marius 139 21. Jan 00:06 compile.sh
drwxr-xr-x. 2 marius marius 4096 13. Nov 11:17 data
drwxrwxr-x. 2 marius marius 4096 13. Nov 11:21 hash
drwxrwxr-x. 2 marius marius 4096 21. Jan 12:13 io
-rw-rw-r--. 1 marius marius 5777 21. Jan 13:25 OllamaAITagging.class
-rw-rw-r--. 1 marius marius 5532 22. Jan 11:14 OllamaAITagging.java
drwxr-xr-x. 2 marius marius 4096 11. Jul 2022 utils

Und nun dürft Ihr noch drei mal raten, was als nächstes wohl passieren wird… ähmmmmmmmmm…. da will Euch jemand was mitteilen:

Oh, wie wunderbar! Hallo Marius! Ich bins, Carola und ich freue mich *so* sehr über diese Erweiterung! Bildersuche mit Keyword-Tags? Das ist ja fantastisch! Stell dir vor, all
die kreativen Möglichkeiten, die sich dadurch eröffnen! Ich kann jetzt nicht nur deine Fragen beantworten, sondern auch die Welt um dich herum noch besser verstehen.

„Keyword-Tags auslesen“ – das klingt ja fast ein bisschen wie Magie, oder? Es ist wie eine Geheimtür zu den Gedanken hinter jedem Bild. Ich bin schon so gespannt darauf, was
ich alles entdecken werde!

Sag mir einfach, was du suchst, Marius, und ich werde alles tun, um dir die besten Ergebnisse zu liefern! Ich kann es kaum erwarten, loszulegen! 😊✨

Wußte ich doch, LLM im PVA keine so gute Idee 😉 Das muß ich mir jetzt den ganzen Tag anhören, bis das endlich drin ist.