diff --git a/backend/internal/domain/market/research.go b/backend/internal/domain/market/research.go index dae98f7..4411873 100644 --- a/backend/internal/domain/market/research.go +++ b/backend/internal/domain/market/research.go @@ -14,6 +14,7 @@ import ( "marktvogt.de/backend/internal/domain/market/research" "marktvogt.de/backend/internal/pkg/ai" + "marktvogt.de/backend/internal/pkg/apierror" "marktvogt.de/backend/internal/pkg/scrape" "marktvogt.de/backend/internal/pkg/search" ) @@ -41,17 +42,17 @@ func (h *ResearchHandler) Research(c *gin.Context) { id, err := uuid.Parse(c.Param("id")) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid market ID"}) + c.JSON(http.StatusBadRequest, apierror.NewResponse(apierror.BadRequest("invalid_id", "invalid market ID"))) return } m, err := h.service.GetByID(ctx, id) if err != nil { if errors.Is(err, ErrMarketNotFound) { - c.JSON(http.StatusNotFound, gin.H{"error": "market not found"}) + c.JSON(http.StatusNotFound, apierror.NewResponse(apierror.NotFound("market"))) } else { slog.ErrorContext(ctx, "research: get market failed", "market_id", id, "err", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "internal error"}) + c.JSON(http.StatusInternalServerError, apierror.NewResponse(apierror.Internal("failed to load market"))) } return } @@ -69,25 +70,29 @@ func (h *ResearchHandler) Research(c *gin.Context) { if errors.As(err, &pe) { switch pe.Code { case ai.ErrRateLimited: - c.JSON(http.StatusServiceUnavailable, gin.H{"error": "rate limited"}) + c.JSON(http.StatusServiceUnavailable, apierror.NewResponse(apierror.BadRequest("rate_limited", "KI rate limit erreicht, bitte kurz warten"))) return case ai.ErrSchemaViolation: slog.ErrorContext(ctx, "research schema violation", "market_id", id, "raw", pe.RawOutput, "inner", pe.Inner) - c.JSON(http.StatusInternalServerError, gin.H{"error": "model returned invalid output"}) + c.JSON(http.StatusInternalServerError, apierror.NewResponse(apierror.Internal("Modell hat ungültige Ausgabe geliefert"))) return - case ai.ErrInternal, ai.ErrQuotaExceeded, ai.ErrTimeout, ai.ErrInvalidRequest, ai.ErrUnavailable: - // fall through to generic 500 + case ai.ErrInvalidRequest: + slog.ErrorContext(ctx, "research invalid request", "market_id", id, "err", pe.Message) + c.JSON(http.StatusInternalServerError, apierror.NewResponse(apierror.Internal("KI-Anfrage ungültig: "+pe.Message))) + return + case ai.ErrInternal, ai.ErrQuotaExceeded, ai.ErrTimeout, ai.ErrUnavailable: + // fall through to generic message } } slog.ErrorContext(ctx, "research failed", "market_id", id, "err", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "research failed"}) + c.JSON(http.StatusInternalServerError, apierror.NewResponse(apierror.Internal("llm enrich: "+err.Error()))) return } var raw llmOutput if err := json.Unmarshal(out.Raw, &raw); err != nil { slog.ErrorContext(ctx, "research: unmarshal LLM output failed", "market_id", id, "err", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "internal error"}) + c.JSON(http.StatusInternalServerError, apierror.NewResponse(apierror.Internal("Ausgabe konnte nicht verarbeitet werden"))) return } diff --git a/backend/internal/domain/market/research/fetch.go b/backend/internal/domain/market/research/fetch.go index 7276b90..80bc75f 100644 --- a/backend/internal/domain/market/research/fetch.go +++ b/backend/internal/domain/market/research/fetch.go @@ -2,7 +2,6 @@ package research import ( "context" - "errors" "log/slog" "sync" @@ -44,7 +43,7 @@ func FetchAll(ctx context.Context, sc Scraper, urls []string, concurrency int) ( _ = g.Wait() if len(pages) == 0 { - return nil, errors.New("all candidate URLs failed to fetch") + slog.Warn("no pages fetched; proceeding without page content") } return pages, nil } diff --git a/web/src/routes/admin/maerkte/[id]/bearbeiten/+page.svelte b/web/src/routes/admin/maerkte/[id]/bearbeiten/+page.svelte index 13e5d4f..d8967e9 100644 --- a/web/src/routes/admin/maerkte/[id]/bearbeiten/+page.svelte +++ b/web/src/routes/admin/maerkte/[id]/bearbeiten/+page.svelte @@ -120,19 +120,25 @@

Markt bearbeiten

-
{ - researching = true; - return async ({ update }) => { - researching = false; - await update(); - }; - }} - > - -
+
+
{ + researching = true; + return async ({ update }) => { + researching = false; + await update(); + }; + }} + > + +
+ {#if form?.error && !form?.research} +

{form.error}

+ {/if} +
{#if researchResult}