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.

Pinephone: Megapixels 1.0.1 im Daily Driver

Hallo Linuxphone Fans,

es sind jetzt um die 10 Tage Pinephone als Daily Driver, ziehen wir ein kurzes Résumé .

Pinephone: Megapixels 1.0.1 im Daily Driver

Seit ca. 10 Tagen schleppe ich jetzt mein Pinephone mit durch die Gegend. Das ist bedingt etwas lästiger, als bei meinem Samsung J3, weil das Pinephone deutlich schwerer und viel größer ist. Da es sich um die v 1.2 handelt, kann man davon ausgehen, daß neuere Revisionen mit weniger Gewicht auskommen werden.

Heute hatte ich Gelegenheit mal ein Pinephone bei Licht benutzen zu können:

Braunschweig Nordbahnhof

Das Bild oben ist unbearbeitet. Für ein 5 Megapixel Bild ist das nicht übel. Besonders die Farben sind seit Megapixels 1.0 deutlich besser geworden. Auch die Dauer der Aufnahme ist mit 1-2 Sekunden im normalen Bereich angekommen. Autor Martjin Braam hat eine sehr gute Version abgeliefert.

Die Batterie

Die Laufzeit des Pinephone hat sich bei 1,5 – 2 Tagen eingependelt, solange man nichts macht, was lange Aktivitäten beinhaltet und das Phone sehr schnell in den Suspend zurückfällt.

Ein DJI 3 Ampere USB-Ladegerät lädt das Pinephone dann auch in 2 Stunden komplett auf, wohingegen ein LogiLink 2A Ladegerät dafür sehr viel länger braucht. Das liegt daran, daß das 3A Ladegerät mit 1,4 A lädt, wogegen das 2A Netzteil nur als Spitze gelegentlich mal 1,2 A erreicht, meistens aber bei 400-600mA rumdümpelt.

Telefonie

Bei der Telefonie ist auch noch einiges verbesserungswürdig. 3 Telefonate brachen mitten drin einfach ab. SMS wecken zwar das Telefon aus dem Schlaf auf, aber noch holt Chatty die dann nicht sauber ab. Anrufe selbst wecken das Pine auf und werden auch rechtzeitig beantwortet. Klingelton ist auch funktional.

Wie man das Telefonbuch importiert, habe ich hier beschrieben:

Pinephone: Das Telefonbuch importieren

Pinephone Mods

Um sein Telefon mit Sperrbildschirm und Hintergrundbild statt dem sonst tristen Schwarz zu beglücken, braucht es nur nette Bilder:

und eine kleine Anpassung:

vi ~/.config/gtk-3.0/gtk.css

und da kommt rein:

/*
 * Set a background for the lockscreen.
 */
phosh-lockscreen, .phosh-lockshield {
  background-image: linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)),
                    url('file:///home/pine/Bilder/lockscreen.jpg');
  background-size: cover;
  background-position: center;
}

/*
 * Set a background for the app grid.
 */
phosh-app-grid {
  background-image: linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)),
                    url('file:///home/pine/Bilder/background.jpg');
  background-size: cover;
  background-position: center;
}

Wer sicher gehen will, daß die Bilder auch in allen Apps gefunden werden, legt sich am besten einen Symlink für Pictures zu: „ln -s /home/pine/Bilder /home/pine/Pictures

Einige nicht lokalisierte Phoshteile und andere Apps suchen in „Pictures“, statt im lokalisierten „Bilder“-Verzeichnis.

Nach der Änderung müßt Ihr Phosh noch neu starten: „sudo systemctl restart phosh

Daily Driver

Ich bin der Meinung, daß sich das Pinephone in diesem Zustand min. für Entwickler und Fans bereits als Daily Driver eignet. Es kann eigentlich nur noch besser werden 😉

Office: Tabellen als Bild abspeichern

Ihr wollt eine Tabelle aus OpenOffice Calc als Bild abspeichern? oh nein, so ein Pech, das geht nämlich nicht. Aber es gibt eine Lösung 🙂

Office: Tabellen als Bild abspeichern

Wer noch OpenOffice benutzt hat ein kleines Problem, auch wenn man will, man kann keine Tabellen als Grafiken speichern. LibreOffice kann das aber, also braucht Ihr nichts weiter machen, als das Dokument auf einen LibreOffice PC zu öffnen und das dort zu machen:

Libreoffice: Tabelle mit einem ContextMenü in dem man die Tabelle als Grafik abspeichertBeispiel mit einer Tabelle, die die Expotentialfunktion erklärt.

In LibreOffice klickt Ihr einfach die Tabelle an und dann im Rechte Mausbutton „Als Bild exportieren“ auswählen.  Nun dürft Ihr das Bild speichern, aber es ist wichtig, daß Ihr die Grafik nicht einfach als PNG abspeichert, sondern als SVG. Das ist erstmal ein Vector Grafikformat und damit skalierbar und deutlich kleiner als ein PNG 😀  Leider muß man das immer auswählen, da PNG voreingestellt ist. Die PNG Speicherfunktion leidet zudem unter einer „Ich lebe noch im Jahr 2000“ Auflösung. Die Bilder sehen nicht wirklich gut aus. Aber, mit SVG, ist es einfach superscharf, egal auf welchem Display 😉