Deduplikator autorów: tryb ogólny + UI overhaul#192
Merged
Conversation
Pierwszy krok przygotowania pod tryb general — istniejący IgnoredAuthor był specyficzny dla PBN (FK→Scientist) i zwalniamy nazwę pod nowy model ignorujący autorów BPP w trybie ogólnym.
…neral Dodaje in-memory generator par kandydatów oparty o buckety nazwisk: iteruje po bucketach (skipuje > BUCKET_MAX_SIZE=200 z warningiem), generuje pary nieuporządkowane (pk_a < pk_b), deduplikuje symetryczne (autor może trafić do wielu bucketów przez compound nazwisko / reverse), filtruje przez ignored_pks/notadup_pks i emituje tylko pary score >= MIN_CONFIDENCE_TO_STORE (50). Rozszerza analiza_pary_meta o detekcję compound nazwisk po nazwisko_parts: pełna permutacja członów (np. 'Gal-Cisoń' ↔ 'Cisoń-Gal') daje +35, częściowe pokrycie +20 — bez tego sygnał z bucketu reverse-compound nie miał szans przekroczyć progu.
…eral Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ARTIAL_COMPLETED Wyodrębnia istniejące ciało scan_for_duplicates do _run_pbn_phase i przepina task na orkiestrację dwóch faz (PBN → general) w jednym DuplicateScanRun. Cancellation w fazie PBN daje status CANCELLED (bez wyników general), w fazie general daje PARTIAL_COMPLETED (wyniki PBN zachowane). Pole `phase` ustawiane na 'pbn'/'general' w trakcie pracy. Zachowane behaviour PBN: replace mode, polling scan_run.status między autorami, periodyczny update progress. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…_autor/scientist - scal_autorow_view: accept main_autor_id/duplicate_autor_id (preferred) + legacy main_scientist_id/duplicate_scientist_id mapped via Scientist.rekord_w_bpp; view now calls scal_autora directly with Autor objects (the scal_autorow wrapper in utils/merge.py stays untouched for any external callers). - Split ignore endpoint: ignore_author -> ignore_scientist (writes IgnoredScientist), add new ignore_autor (writes IgnoredAuthor with FK->Autor). Reset endpoints renamed accordingly: reset_ignored_authors -> reset_ignored_scientists, plus new reset_ignored_autorzy. URL names + paths updated; template references adjusted in duplicate_authors.html. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…xport) - views.scan_status_view: dodaj PARTIAL_COMPLETED do listy "finished", żeby frontend JS poll przestał odpytywać po przejściu skanu w ten stan. - tasks._run_general_phase: użyj nowego helpera _calculate_priority_from_meta zamiast calculate_author_priority (2 SQL per candidate). Helper czyta z meta-cache; przybliżenie ma_dyscypline (any year vs 2022-2025) udokumentowane jako TODO, bo priority to sort hint, nie correctness invariant. - utils.meta.build_autor_meta: dorzuć poprzednie_nazwiska, pokazuj_poprzednie_nazwiska, pseudonim do .only(), bo Autor.__str__ je czyta — bez tego str(autor) w hot-path emituje 2 deferred-load SQL per autor. - utils.export.export_duplicates_to_xlsx: materializuj queryset raz (list(...)), żeby Counter i list-comprehension nie iterowały dwa razy (każda iteracja = pełny SQL). - views._get_next_candidate_group: zamień .values_list().distinct() na iterację z dedupe w Pythonie. PostgreSQL DISTINCT + ORDER BY z annotacją to tricky semantics — Django może odrzucić annotation z SELECT, dając runtime error lub niedeterministyczną kolejność. - testy: scan_status_view dla PARTIAL_COMPLETED, regresja per-candidate SQL w _run_general_phase. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…igacja wyszukiwania, make assets - Publikacje: nadpisz Foundation .callout a font-weight:bolder na normal (tytuł w <b> pozostaje bold, reszta normalna) - Top bar: justify-content flex-start, szukajka zaraz po przyciskach trybu - Możliwe duplikaty: nagłówek w osobnym wierszu, przyciski pewności poniżej; cały rząd ukryty gdy tylko jedna kategoria kandydatów - Wyszukiwanie: dodana nawigacja Poprzedni/Następny po wynikach szukania (skip_count + search_has_prev/search_has_next) - Makefile: stamp file zamiast per-CSS-target, SCSS wildcard obejmuje src/*/static/*/scss/*.scss, stamp usuwany w make clean
…in LogEntry When a new author is created through the autocomplete 'create' dialog, a LogEntry (ADDITION) is now recorded in Django admin history with change_message='Utworzono z formularza autocomplete', making it possible to trace who created the author and from where.
…ublikacje, nie-duplikaty
- Napraw ładowanie CSS: block extra_css nie istniał w hierarchii template'ów
(bare.html->base.html), CSS nigdy się nie ładował. Zmieniono na
{% block extrahead %} z {{ block.super }}.
- Bold publikacji: selektor .callout .deduplikator-autorow__publication-item a
(spec. 0,2,1) wygrywa z Foundation .callout a:not(.close-button) (0,1,1)
- Lista publikacji: usunięte kolorowe border-left, obramowanie i padding —
teraz zwykła lista tekstowa
- Top bar: usunięta etykieta 'Pokaż wyniki:', same przyciski trybu po lewej,
wyszukiwarka po prawej (space-between)
- Przycisk 'Szukaj': border-radius: 0 po prawej gdy widoczny przycisk 'X'
(czyszczenie wyszukiwania)
- Nie-duplikaty: licznik w sidebarze aktualizuje się po AJAX-owym oznaczeniu
kandydata jako nie-duplikat (span#not-duplicate-count + JS increment)
- Empty state: gdy search_lastname aktywny i brak wyników — 'Nie znaleziono
takich autorów' zamiast 'Gratulacje'
… XLSX, naprawa top_bar HTML, testy - Hard reject kandydatów z rozłącznymi imionami (analysis_meta + analysis) - Kolumny ORCID i PBN URL w eksporcie XLSX - Endpoint lastname-suggestions do autouzupełniania - reason_display.py — utils do wyświetlania powodów duplikacji - Naprawa osieroconego <li> w top_bar.html (djlint H025) - Zmiana etykiety 'deduplikator autorów PBN' → 'deduplikator autorów' - Dodanie 'deduplikator autorów' do menu narzędzia - .gitignore: .grunt-build-stamp - CLAUDE.md: dodano reguły komentarzy Django i uv run - Nowe testy: merge_all_refresh, reasons_display, xlsx_orcid_and_pbn_url
Konflikt: dev rozbił views.py (864L) na pakiet views/ (7 plików), feature rozbudował views.py do 1177L (rename ignore_author → ignore_scientist+ignore_autor, nowe helpery i widoki). Rozstrzygnięcie: zachowano monolityczny views.py z feature, usunięto pakiet views/ z dev. Re-split do pakietu zostanie wykonany w kolejnym commicie z uwzględnieniem nowych funkcji feature.
…ckage Powtórzenie splitu z dev (commit 9179092) z uwzględnieniem nowych funkcji wprowadzonych na feature branchu: - helpers.py: + _read_param, _scientist_id_to_autor_id, _resolve_autor_id, get_running_scan, _get_pending_candidates_for_main_autor, _get_next_candidate_group - duplicates.py: + lastname_suggestions - ignore.py: split ignore_author → ignore_scientist + ignore_autor; reset_ignored_authors → reset_ignored_scientists + reset_ignored_autorzy; + _trigger_rescan_after_reset - merge.py: scal_autorow_view + delete_author (bez zmian funkcjonalnych) - scan.py: start_scan_view, cancel_scan_view, scan_status_view - export.py: download_duplicates_xlsx - __init__.py: re-export wszystkich symboli (backward compat z urls.py i testami importującymi z deduplikator_autorow.views) views.py usunięty.
| messages.error(request, "Brak wymaganego parametru: scientist_pk") | ||
| def _respond(success, message, status=200, level="success"): | ||
| if is_ajax: | ||
| return JsonResponse({"success": success, "message": message}, status=status) |
| messages.error(request, "Brak wymaganego parametru: candidate_id") | ||
| def _respond(success, message, status=200): | ||
| if is_ajax: | ||
| return JsonResponse({"success": success, "message": message}, status=status) |
| duplicate_autor = Autor.objects.get(pk=duplicate_autor_id) | ||
| except Autor.DoesNotExist as e: | ||
| return JsonResponse( | ||
| {"success": False, "error": f"Nie znaleziono autora: {e}"}, |
| "success": False, | ||
| "error": f"Błąd podczas scalania autorów: {str(e)}", | ||
| }, | ||
| {"success": False, "error": f"Błąd podczas scalania autorów: {str(e)}"}, |
… through an exception' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
… through an exception' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
… through an exception' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
… through an exception' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Test plan
🤖 Generated with Claude Code