diff --git a/backend/src/main/java/org/raddatz/familienarchiv/search/NlQueryParserService.java b/backend/src/main/java/org/raddatz/familienarchiv/search/NlQueryParserService.java index 7f9d1edb..db8a9da9 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/search/NlQueryParserService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/search/NlQueryParserService.java @@ -34,18 +34,13 @@ public class NlQueryParserService { private static final int MIN_TAG_TERM = 3; private static final int MAX_RESOLVED_TAGS = 10; - private final OllamaClient ollamaClient; + private final NlpClient nlpClient; private final PersonService personService; private final DocumentService documentService; private final TagService tagService; - public NlSearchResponse search(String query, Pageable pageable) { - if (query == null || query.length() < MIN_QUERY || query.length() > MAX_QUERY) { - throw DomainException.badRequest(ErrorCode.VALIDATION_ERROR, - "Query must be between " + MIN_QUERY + " and " + MAX_QUERY + " characters"); - } - - OllamaExtraction ext = ollamaClient.parse(query); + public NlSearchResponse search(String query, String lang, Pageable pageable) { + NlpExtraction ext = nlpClient.parse(query, lang); List personNames = ext.personNames() != null ? ext.personNames() : List.of(); List keywords = ext.keywords() != null ? ext.keywords() : List.of(); diff --git a/backend/src/main/java/org/raddatz/familienarchiv/search/NlSearchController.java b/backend/src/main/java/org/raddatz/familienarchiv/search/NlSearchController.java index c58fff38..82391a72 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/search/NlSearchController.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/search/NlSearchController.java @@ -23,6 +23,6 @@ public class NlSearchController { Pageable pageable, @AuthenticationPrincipal UserDetails principal) { rateLimiter.checkAndConsume(principal.getUsername()); - return nlQueryParserService.search(request.query(), pageable); + return nlQueryParserService.search(request.query(), request.lang(), pageable); } } diff --git a/backend/src/main/java/org/raddatz/familienarchiv/search/NlSearchRequest.java b/backend/src/main/java/org/raddatz/familienarchiv/search/NlSearchRequest.java index 0e9d3a9a..f23241d0 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/search/NlSearchRequest.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/search/NlSearchRequest.java @@ -1,11 +1,15 @@ package org.raddatz.familienarchiv.search; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Size; public record NlSearchRequest( @NotBlank @Size(min = 3, max = 500) - String query + String query, + @NotBlank + @Pattern(regexp = "de|en|es") + String lang ) { } diff --git a/backend/src/main/resources/application-dev.yaml b/backend/src/main/resources/application-dev.yaml index 954e430b..4f64aef9 100644 --- a/backend/src/main/resources/application-dev.yaml +++ b/backend/src/main/resources/application-dev.yaml @@ -13,5 +13,5 @@ springdoc: path: /swagger-ui.html app: - ollama: - base-url: http://localhost:11434 + nlp: + base-url: http://localhost:8001 diff --git a/backend/src/main/resources/application.yaml b/backend/src/main/resources/application.yaml index ce517f25..a0054de6 100644 --- a/backend/src/main/resources/application.yaml +++ b/backend/src/main/resources/application.yaml @@ -130,13 +130,8 @@ app: # The loader maps columns by header name — no positional indices (see ADR-025). dir: ${IMPORT_DIR:/import} - ollama: - base-url: http://ollama:11434 - model: qwen2.5:7b-instruct-q4_K_M - # CPU inference: ~18s warm. Higher ceiling absorbs the cold model load on the - # first query after an Ollama (re)start before OLLAMA_KEEP_ALIVE pins it. - timeout-seconds: 60 - health-check-timeout-seconds: 2 + nlp: + base-url: http://nlp-service:8001 nl-search: rate-limit: diff --git a/frontend/src/routes/documents/+page.svelte b/frontend/src/routes/documents/+page.svelte index 7d494b24..92556463 100644 --- a/frontend/src/routes/documents/+page.svelte +++ b/frontend/src/routes/documents/+page.svelte @@ -17,6 +17,7 @@ import { bulkSelectionStore } from '$lib/document/bulkSelection.svelte'; import { getErrorMessage, parseBackendError } from '$lib/shared/errors'; import { csrfFetch } from '$lib/shared/cookies'; import * as m from '$lib/paraglide/messages.js'; +import { languageTag } from '$lib/paraglide/runtime'; import type { components } from '$lib/generated/api'; type NlQueryInterpretation = components['schemas']['NlQueryInterpretation']; @@ -224,7 +225,7 @@ async function runSmartSearch() { const res = await csrfFetch('/api/search/nl', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ query }) + body: JSON.stringify({ query, lang: languageTag() }) }); if (!res.ok) { const backend = await parseBackendError(res);