feat(search): NL search backend — POST /api/search/nl with Ollama integration (#738) #756

Merged
marcel merged 16 commits from worktree-feat+issue-738-nl-search-backend into main 2026-06-06 16:52:44 +02:00
2 changed files with 7 additions and 5 deletions
Showing only changes of commit 4c620619d4 - Show all commits

View File

@@ -32,6 +32,8 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import jakarta.persistence.criteria.JoinType;
import jakarta.persistence.criteria.Predicate;
import org.springframework.data.jpa.domain.Specification;
import org.raddatz.familienarchiv.exception.DomainException;
import org.raddatz.familienarchiv.exception.ErrorCode;
@@ -1044,14 +1046,14 @@ public class DocumentService {
private Specification<Document> buildPersonSpec(Person person, LocalDate from, LocalDate to) {
return (root, query, cb) -> {
if (query != null) query.distinct(true);
var receiversJoin = root.join("receivers", jakarta.persistence.criteria.JoinType.LEFT);
var receiversJoin = root.join("receivers", JoinType.LEFT);
var senderPredicate = cb.equal(root.get("sender"), person);
var receiverPredicate = cb.equal(receiversJoin, person);
var personPredicate = cb.or(senderPredicate, receiverPredicate);
var predicates = new java.util.ArrayList<>(java.util.List.of(personPredicate));
var predicates = new ArrayList<>(List.of(personPredicate));
if (from != null) predicates.add(cb.greaterThanOrEqualTo(root.get("documentDate"), from));
if (to != null) predicates.add(cb.lessThanOrEqualTo(root.get("documentDate"), to));
return cb.and(predicates.toArray(new jakarta.persistence.criteria.Predicate[0]));
return cb.and(predicates.toArray(new Predicate[0]));
};
}

View File

@@ -22,8 +22,8 @@
"error_forbidden": "Sie haben keine Berechtigung für diese Aktion.",
"error_csrf_token_missing": "Sitzungsfehler. Bitte laden Sie die Seite neu.",
"error_too_many_login_attempts": "Zu viele Anmeldeversuche. Bitte versuchen Sie es später erneut.",
"error_smart_search_unavailable": "Die intelligente Suche ist momentan nicht verfügbar. Bitte nutze die normale Suche.",
"error_smart_search_rate_limited": "Du hast die Suchfunktion zu häufig genutzt. Bitte warte eine Minute.",
"error_smart_search_unavailable": "Die intelligente Suche ist momentan nicht verfügbar. Bitte nutzen Sie die normale Suche.",
"error_smart_search_rate_limited": "Sie haben die Suchfunktion zu häufig genutzt. Bitte warten Sie eine Minute.",
"smart_search_keywords_not_applied": "Schlüsselwörter konnten bei dieser Suche nicht berücksichtigt werden.",
"error_validation_error": "Die Eingabe ist ungültig.",
"error_internal_error": "Ein unerwarteter Fehler ist aufgetreten.",