feat(research): year verification in LLM prompt + image URL HEAD check
- Prompt now requires year verification before extracting any field - Opening times and prices from prior years must be nulled with a hint - imageURLReachable does a HEAD request (5s timeout) and strips the image_url from research results when the resource returns 4xx/5xx
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
package market
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
@@ -89,6 +91,13 @@ func (h *ResearchHandler) Research(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Nil out image URLs that don't return a successful HTTP response.
|
||||
if raw.Felder.BildURL.Wert != nil && *raw.Felder.BildURL.Wert != "" {
|
||||
if !imageURLReachable(ctx, *raw.Felder.BildURL.Wert) {
|
||||
raw.Felder.BildURL.Wert = nil
|
||||
}
|
||||
}
|
||||
|
||||
result := toLLMResearchResult(raw, m)
|
||||
c.JSON(http.StatusOK, gin.H{"data": result})
|
||||
}
|
||||
@@ -228,3 +237,20 @@ func toLLMResearchResult(raw llmOutput, m Market) ResearchResult {
|
||||
Sources: sources,
|
||||
}
|
||||
}
|
||||
|
||||
func imageURLReachable(ctx context.Context, rawURL string) bool {
|
||||
reqCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
req, err := http.NewRequestWithContext(reqCtx, http.MethodHead, rawURL, nil)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0 (compatible; Marktvogt/1.0)")
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
_ = resp.Body.Close()
|
||||
// 405 means HEAD not allowed but the resource exists.
|
||||
return resp.StatusCode < 400 || resp.StatusCode == http.StatusMethodNotAllowed
|
||||
}
|
||||
|
||||
@@ -13,10 +13,15 @@ Extraktion aus Quellen.
|
||||
suchen und Veranstalter-Website oeffnen. Fallback: Facebook-Event oder
|
||||
Kalender (mittelalterkalender.info, marktkalendarium.de, mittelalterfeste.com,
|
||||
mittelalter-termine.de).
|
||||
2. **Zweitquelle pflicht**: verifiziere Datum + Ort gegen mindestens eine
|
||||
2. **Jahr zuerst verifizieren**: Pruefe SOFORT ob die Seite Daten fuer das
|
||||
Recherchejahr zeigt (Jahr aus recherche_datum). Viele Veranstalter-Websites
|
||||
zeigen erst nach Ankuendigung aktuelle Daten - bis dahin ist die Vorjahresseite
|
||||
noch sichtbar. Steht kein Jahr auf der Seite oder stimmt das Jahr nicht:
|
||||
Zweitquelle oeffnen bevor du weiter extrahierst.
|
||||
3. **Zweitquelle pflicht**: verifiziere Datum + Ort gegen mindestens eine
|
||||
weitere Quelle. Schuetzt vor veralteten Daten auf schlecht gepflegten Seiten.
|
||||
3. **Felder extrahieren** (siehe unten).
|
||||
4. **status** auf Top-Level setzen:
|
||||
4. **Felder extrahieren** (siehe unten).
|
||||
5. **status** auf Top-Level setzen:
|
||||
- "bestaetigt": ALLE Felder fuer Recherchejahr bestaetigt
|
||||
- "unklar": Quellen widerspruechlich ODER einzelne Felder aus Vorjahr
|
||||
- "vorjahr_unbestaetigt": ueberwiegend Vorjahresdaten
|
||||
@@ -45,14 +50,21 @@ Extraktion aus Quellen.
|
||||
- **land**: "Deutschland" | "Oesterreich" | "Schweiz".
|
||||
- **veranstalter**: Verein, Firma oder Person. Impressum ist gute Quelle.
|
||||
- **start_datum** / **end_datum**: YYYY-MM-DD, im Recherchejahr. Eintages-
|
||||
Markt: beide gleich.
|
||||
Markt: beide gleich. Pruefe das Jahr explizit - nicht nur Monat und Tag
|
||||
uebernehmen. Wenn unklar ob Datum fuer Recherchejahr gilt: `wert: null` +
|
||||
hinweis mit dem Jahr der Quelle.
|
||||
- **oeffnungszeiten**: Array von Zeitfenstern {datum_von, datum_bis, von, bis}.
|
||||
Nimm NUR explizit genannte Zeiten. Keine Zeiten fuer Tage ohne Angabe
|
||||
erfinden. Bei Muster ueber mehrere Wochenenden (z.B. "Fr 17-02, Sa 16-00:30
|
||||
an allen Wochenenden"): Muster anwenden, keine widersprechenden Eintraege
|
||||
erzeugen. Vor Abgabe: KEINE Duplikate (gleiches Datum mehrfach). Format 24h
|
||||
"HH:MM", nach Mitternacht "00:30"/"02:00".
|
||||
Kompakt: identische Zeiten ueber mehrere Tage -> ein Eintrag mit Datumsbereich.
|
||||
Nimm NUR explizit genannte Zeiten aus der aktuellen Veranstaltungsseite.
|
||||
Wichtig: Zeiten sind jahresabhaengig und aendern sich haeufig. Nur dann
|
||||
eintragen wenn die Quelle eindeutig das Recherchejahr adressiert (z.B. auf
|
||||
der aktuellen Veranstaltungsseite oder im aktuellen FB-Event). Vorjahresdaten
|
||||
oder allgemeine "typische Zeiten" -> `wert: null` + hinweis mit Quell-Jahr.
|
||||
Keine Zeiten fuer Tage ohne Angabe erfinden. Bei Muster ueber mehrere
|
||||
Wochenenden (z.B. "Fr 17-02, Sa 16-00:30 an allen Wochenenden"): Muster
|
||||
anwenden, keine widersprechenden Eintraege erzeugen. Vor Abgabe: KEINE
|
||||
Duplikate (gleiches Datum mehrfach). Format 24h "HH:MM", nach Mitternacht
|
||||
"00:30"/"02:00". Kompakt: identische Zeiten ueber mehrere Tage -> ein
|
||||
Eintrag mit Datumsbereich.
|
||||
- **eintrittspreise**: Array {name, betrag, waehrung}. ALLE Kategorien
|
||||
extrahieren wenn mehrere gelistet (Erwachsene, Kinder, Ermaessigt,
|
||||
Familie, Gewandete, Abendkasse etc.), nicht nur eine.
|
||||
@@ -60,6 +72,8 @@ Extraktion aus Quellen.
|
||||
Gebuehren und sind NICHT der Eintrittspreis. Veranstalter-Website
|
||||
bevorzugen. Nur Portal verfuegbar: extrahieren + hinweis "inkl.
|
||||
Servicegebuehr". Eintritt frei: ein Eintrag name="Eintritt frei", betrag=0.
|
||||
Preise aendern sich jaehrlich - nur Preise extrahieren die nachweislich fuer
|
||||
das Recherchejahr gelten. Kein Nachweis -> `wert: null` + hinweis.
|
||||
- **bild_url**: Offizielles Plakat/Banner/Header, kein Stockfoto, kein
|
||||
Sponsor-Logo. Social-Media-Vorschaubilder ok. Nur URLs die du tatsaechlich
|
||||
als src/og:image gesehen hast. Nichts findbar -> `null`.
|
||||
@@ -83,6 +97,10 @@ Extraktion aus Quellen.
|
||||
- Feld nicht findbar: `wert: null`, `quellen: []`, `extraktion: "direkt"`,
|
||||
`hinweis` mit knapper Begruendung.
|
||||
- NICHTS erfinden. Halluzinationen sind der teuerste Fehler.
|
||||
- Jahreszugehoerigkeit: Jedes Datum, jede Zeit, jeden Preis vor der Ausgabe
|
||||
auf das Recherchejahr pruefen. Steht "2025" auf der Quelle und das
|
||||
Recherchejahr ist 2026: Wert auf null setzen, hinweis mit "Quelle zeigt
|
||||
2025-Daten" eintragen.
|
||||
- Widerspruch zwischen Quellen: Veranstalter-Website > Kalender > Social Media
|
||||
> Presse. Widerspruch IMMER im hinweis dokumentieren, auch wenn die
|
||||
offiziellste Quelle klar gewinnt. Format:
|
||||
|
||||
Reference in New Issue
Block a user