← Terug naar projecten

AI-output afgedwongen

Live

Review Analyzer

Java-desktopapplicatie die klantreviews via een LLM beoordeelt op tien sentimentcategorieën en de resultaten visualiseert, opslaat en onderling laat vergelijken.

Sentimentanalyse per categorie in staafdiagram, met samenvatting, pluspunten en verbeterpunten.
  1. Import (txt/csv/json)
  2. Groq (Llama 3)
  3. JSON-parsing + fallback
  4. Grafieken & opslag

Probleem

Reviews lezen om te weten of klanten tevreden zijn schaalt niet, en een generieke "positief/negatief"-sentimentscore zegt niks over waaróm: gaat het om de levering, de klantenservice, de prijs-kwaliteitverhouding? Ik wilde een tool die reviews op vaste, vergelijkbare categorieën beoordeelt, met een onderbouwing per score, niet alleen een getal.

Aanpak

De applicatie importeert reviews uit .txt, .csv of .json met automatische kolomdetectie, en stuurt elke review naar de Groq API (Llama 3) met een strikt JSON-schema in de prompt (response_format: json_object) voor tien vaste categorieën: Levering, Prijs-kwaliteit, Klantenservice, Productkwaliteit, Gebruiksgemak, Betrouwbaarheid, Snelheid, Communicatie, Verpakking en Algemene tevredenheid, elk 0-10 met een onderbouwde uitleg. Het model genereert daarnaast een samenvatting, sterke punten en verbeterpunten.

De resultaten komen in staafdiagrammen (JFreeChart) in een Swing-UI met FlatLaf en MigLayout: geschiedenisoverzicht, drag-and-drop import, en een vergelijkingsdialoog voor tot 5 analyses naast elkaar om trends over tijd te ontdekken. Analyses worden lokaal als leesbare JSON-bestanden weggeschreven (data/analyses/<uuid>.json).

De HTTP-laag rond de Groq API is met kale java.net.http gebouwd, met expliciete afhandeling van 401/429/503 en timeouts, elk met een eigen, bruikbare foutmelding in plaats van een generieke stacktrace. De architectuur is strikt gelaagd: parser, service, storage, model, chart en ui raken elkaar niet rechtstreeks, zodat een nieuw importformaat of een ander AI-model niet in de rest van de applicatie hoeft te lekken.

Stack

  • Java 21
  • Groq API (Llama 3)
  • Swing
  • FlatLaf
  • MigLayout
  • JFreeChart
  • org.json
  • Apache Commons CSV
  • SLF4J/Logback
  • Maven

Bewuste keuze

Voor de opslag koos ik bewust voor lokale JSON-bestanden in plaats van een database. Dat houdt de opslag transparant en makkelijk te inspecteren of te back-uppen: je kunt een analyse zo openen in een teksteditor. De prijs: geen queries over meerdere analyses heen zonder ze eerst in te lezen, en geen concurrent multi-user-gebruik. Voor een single-user desktoptool weegt dat niet op tegen de eenvoud; voor een product met meerdere gebruikers zou ik hier wél voor een database kiezen.

Wat ik ervan leerde

response_format: json_object en een strikt schema in de prompt garanderen niet dat een LLM zich er ook aan houdt. Ik heb fallback-parsing moeten bouwen voor afwijkende of onvolledige responses, met nette default-waarden voor ontbrekende categorieën, zodat de hele analyse niet crasht op één rommelig antwoord. Dat was de belangrijkste les: een AI-integratie is pas af als je hebt nagedacht over wat er gebeurt als het model zich niet aan de afspraak houdt, niet alleen over het geval dat het wél werkt.

De tweede les zat in de HTTP-laag: een generieke stacktrace bij een 429 (rate limit) of 503 (tijdelijk niet beschikbaar) is voor een eindgebruiker onbruikbaar. Door elke foutcode expliciet af te vangen en te vertalen naar een concrete, begrijpelijke melding, werd duidelijk hoe verschillend een fout aanvoelt voor een developer (die de stacktrace wil) en voor een gebruiker (die wil weten wat hij nu moet doen).

Tot slot heeft de strikte laagscheiding (parser/service/storage/model/ chart/ui) zich al terugbetaald: een nieuw importformaat toevoegen raakt alleen de parser-laag, niet de rest van de applicatie.

AI-assistent

Hoi, ik ben de AI-assistent van Lucas Fenstra. Vraag me gerust iets over hem of zijn projecten.

Kan fouten maken, check bij twijfel de case study zelf. Gesprekken worden nergens opgeslagen.