Projekt realizuje zaawansowany system wyszukiwania i konwersacji oparty na architekturze RAG (Retrieval-Augmented Generation), dedykowany identyfikacji, klasyfikacji oraz dostarczaniu wiedzy na temat mykologii. System łączy klasyczne algorytmy wyszukiwania tekstowego (rzadkie indeksy) z nowoczesnymi metodami semantycznymi (gęste wektory embeddingowe), wykorzystując zaawansowane mechanizmy przetwarzania języka naturalnego (NLP) dla języka polskiego.
System zbudowany jest wokół potoku wyszukiwania hybrydowego, mającego na celu zminimalizowanie ograniczeń pojedynczych metod wyszukiwania i dostarczenie jak najdokładniejszego kontekstu do modelu generatywnego.
- HyDE (Hypothetical Document Embeddings): Zapytania użytkowników bywają krótkie i potoczne (np. "znalazłem grzyba z czerwonym kapeluszem i rurkami"). HyDE wykorzystuje LLM do przekształcenia zapytania w hipotetyczny, encyklopedyczny opis morfologiczny przy użyciu profesjonalnej terminologii. Wyszukiwanie odbywa się na bazie tego wygenerowanego dokumentu, co eliminuje asymetrię między zapytaniem a dokumentami źródłowymi.
- Przetwarzanie tekstu i Lemmatyzacja: Tekst poddawany jest usunięciu polskich znaków (w celu uodpornienia na błędy literowe), usuwane są znaki interpunkcyjne oraz tzw. stop-words. Następnie, za pomocą modelu językowego
pl_core_news_lg, przeprowadzana jest lematyzacja (sprowadzenie wyrazów do formy bazowej), co maznaczenie dla skuteczności wyszukiwania leksykalnego. - BM25Okapi: Klasyczny algorytm probabilistyczny oceniający relewancję dokumentów na podstawie częstości występowania rzadkich termów (TF-IDF z uwzględnieniem normalizacji długości dokumentu).
- Wyszukiwanie Wektorowe: Teksty reprezentowane są jako 1024-wymiarowe wektory gęste za pomocą modelu
bge-m3. Odległość semantyczna w bazie danych obliczana jest przy użyciu metryki odległości cosinusowej obsługiwanej przez rozszerzeniepgvectorw bazie PostgreSQL. - RRF (Reciprocal Rank Fusion): Łączy wyniki z BM25 oraz wyszukiwania wektorowego. Zamiast bezwzględnych wartości ocen (scores), które mają różne skale, RRF operuje na pozycjach (rangach) dokumentów na listach wynikowych, wyliczając wspólną notę według wzoru:
gdzie
Plik centralnej konfiguracji projektu. Definiuje stałe środowiskowe, parametry połączenia z bazą danych Supabase (PostgreSQL), ścieżki do katalogów, a także ustawienia modeli językowych:
- Wyszukiwanie i Embeddings: Definiuje model
bge-m3dla wektorów oraz plik indeksubm25.joblib. - Konfiguracja HyDE: Przechowuje dedykowany prompt systemowy instruujący LLM (
gemma3:4b), jak tłumaczyć potoczne opisy na profesjonalny żargon mykologiczny bez zgadywania nazwy gatunkowej. - Strukturyzacja Danych: Zawiera prompt
METADATA_PROMPTodpowiedzialny za wymuszenie formatu JSON przy ekstrakcji cech z surowego tekstu oraz listę modeli LLM wykorzystywanych jako fallback (gemini-3.1-flash-lite,gemini-2.5-flashitd.).
Moduł odpowiedzialny za asynchroniczne pobieranie danych z bazy danych za pomocą biblioteki asyncpg.
- Mechanizm działania: Aby uniknąć przeciążenia pamięci RAM przy przetwarzaniu dziesiątek tysięcy rekordów, skrypt implementuje kursor wewnątrz transakcji (
conn.cursor()). - Pobiera dane paczkami (batchami) o rozmiarze 1000 rekordów. Wyciąga pola
id,name,embedding,descriptionorazmetadataz tabelimushrooms, mierzy łączny czas operacji i zwraca kompletną listę przetworzonych struktur.
Asynchroniczny moduł zapisu danych do bazy PostgreSQL.
- Mechanizm działania: Wykorzystuje metodę
conn.executemany(), która pozwala na masowe i zoptymalizowane wykonywanie zapytańINSERTw ramach jednej transakcji bazodanowej. Redukuje to narzut sieciowy i czas komunikacji z chmurą Supabase.
Skrypt pośredniczący w komunikacji z lokalnym serwerem Ollama w celu generowania wektorów gęstych.
- Mechanizm działania: Wywołuje funkcję
ollama.embeddingsz modelembge-m3.
Implementacja koncepcji Hypothetical Document Embeddings.
- Mechanizm działania: Zawiera funkcję
generate_hyde_document(query), która wysyła zapytanie użytkownika do modelugemma3:4b. Zgodnie z instrukcją z konfiguracji, generuje tekst będący bogatym opisem morfologicznym (trzon, kapelusz, zarodniki, zapach), imitującym artykuł encyklopedyczny, stanowiący idealną podstawę do dalszego wyszukiwania hybrydowego.
Kluczowy komponent lingwistyczny przygotowujący tekst pod algorytmy wyszukiwania pełnotekstowego.
- Mechanizm działania:
- Przekształca znaki narodowe na ich odpowiedniki ASCII przy użyciu tablicy mapowania
PL_TO_ASCII. - Za pomocą wyrażeń regularnych oczyszcza tekst ze znaków specjalnych i interpunkcji, zastępując je spacjami.
- Analizuje potok tekstu za pomocą modelu
spaCy. Iteruje po tokenach, filtrując słowa stopu (token.is_stop), interpunkcję i białe znaki. - Pobiera lemat wyrazu (
token.lemma_), sprowadza go do małych liter i dodatkowo odrzuca znaki niealfanumeryczne, budując czystą tablicę tokenów reprezentującą dokument.
- Przekształca znaki narodowe na ich odpowiedniki ASCII przy użyciu tablicy mapowania
Skrypt budujący statyczny indeks wyszukiwania leksykalnego.
- Mechanizm działania: Pobiera dane z bazy (za pomocą
fetch_data_in_batches), a następnie uruchamia wieloprocesowe przetwarzanie tekstu za pomocąProcessPoolExecutor. Podział na paczki (BATCH_SIZE) dystrybuowany jest pomiędzy niezależne procesy systemowe (workery CPU), z których każdy tokenizuje złączone pola nazwy i opisu grzyba za pomocą klasyBM25Preprocessor. - Po zebraniu wyników tworzona jestinstancja klasy
BM25Okapiz bibliotekirank_bm25, która wraz z mapowaniami identyfikatorów i metadanych zostaje zrzutowana do pliku binarnego za pomocąjoblib.dump.
Potok ETL (Extract, Transform, Load) odpowiedzialny za ustrukturyzowanie zgromadzonych surowych plików tekstowych w formacie Markdown (.md) do ujednoliconych struktur JSON.
- Mechanizm działania: Skrypt asynchronicznie odczytuje pliki tekstowe z katalogu danych. Wykorzystuje bibliotekę Google GenAI (
client.aio.models.generate_content) w celu wyciągnięcia metadanych.
Serce całego systemu informacyjnego – klasa SearchEngine implementująca hybrydowy system wyszukiwania wieloetapowego.
- Mechanizm działania:
- Przyjmuje zapytanie użytkownika i przekazuje je do modułu HyDE, zyskując rozbudowany pseudo-dokument.
- Równolegle odpala dwa wątki wyszukiwania:
bm25_ranking(wyszukiwanie na zapisanym indeksie leksykalnym) orazrag_ranking(generowanie embeddingu przez Ollamę i wykonanie zapytania SQL z operatorem<=>cosinusowej odległości wektorowej w PostgreSQL). - Łączy listy wynikowe za pomocą algorytmu Reciprocal Rank Fusion (RRF), selekcjonując zestaw unikalnych kandydatów (domyślnie 100).
- Przygotowuje pary
[zapytanie_pierwotne, opis_kandydata]i przesyła je do głębokiego modelu rerankeraBAAI/bge-reranker-v2-m3ładowanego w pamięci GPU/CPU przy użyciu PyTorcha i precyzjifloat16. - Sortuje kandydatów według wynikowej oceny podobieństwa Cross-Encodera i zwraca zestaw
top_knajlepiej dopasowanych rekordów (nazwa + opis).
Interfejs użytkownika w postaci pętli konwersacyjnej CLI.
- Mechanizm działania: Inicjalizuje asynchronicznie
SearchEngine. W nieskończonej pętli pobiera zapytanie tekstowe użytkownika, wywołuje potok wyszukiwania hybrydowego dlatop_k=10dokumentów i agreguje je w jeden spójny blok tekstu (Context). - Tworzy prompt systemowy definiujący rolę bota jako eksperta mykologa, po czym wysyła do modelu
gemma3:4bpełny kontekst oraz kompletną, dotychczasową historię konwersacji (chat_history), zapewniając asystentowi pamięć kontekstową. Odpowiedź asystenta jest dopisywana do pamięci i wyświetlana na ekranie.
Zaawansowany skrypt do analizy matematycznej i wizualizacji rozkładu semantycznego zgromadzonych danych o grzybach.
- Mechanizm działania:
- Pobiera rekordy z bazy i parsuje tekstowe reprezentacje embeddingów za pomocą wyrażeń regularnych do macierzy NumPy typu
float32. - Tworzy zbinaryzowaną wersję macierzy (
X > 0) na potrzeby metryk binarnych. - Przeprowadza grupowanie nienadzorowane przy użyciu algorytmu KMeans dla 100 klastrów w celu automatycznego wyznaczenia "rodzin semantycznych" grzybów.
- W celu oszczędzania pamięci RAM, skrypt sekwencyjnie dla 4 różnych metryk odległości (L2 (Euklidesowa), L1 (Manhattan), Cosine, Jaccard) wylicza pełną macierz odległości parzystych za pomocą
scipy.spatial.distance.cdist. - Przekazuje macierze odległości do algorytmu UMAP (Uniform Manifold Approximation and Projection) z parametrem
metric="precomputed", redukując przestrzeń 1024-wymiarową do przestrzeni trójwymiarowej (3D). - Generuje interaktywne, trójwymiarowe wykresy punktowe za pomocą biblioteki
Plotly Express, mapując wyznaczone klastry KMeans na kolory, a metadane (nazwa polska, łacińska, źródło, nagłówek) na etykiety hover. Wykresy są automatycznie eksportowane do samowystarczalnych plików.html.
- Pobiera rekordy z bazy i parsuje tekstowe reprezentacje embeddingów za pomocą wyrażeń regularnych do macierzy NumPy typu
W celu zasilenia bazy wiedzy bota mykologicznego, dane zostały pozyskane z czterech różnych stron internetowych. Poniższe sekcje stanowią miejsce na szczegółowy opis implementacji, architekturę kodu oraz zastosowane metody ekstrakcji danych.
-
Opis działania: Strona grzyby.pl była stosunkowo prosta do scrapowania, ponieważ jej zawartość była statyczna i nie wymagała renderowania JavaScript. Skrypt oparty na bibliotece
requestspobierał surowy kod HTML, który następnie był parsowany za pomocąBeautifulSoup4. W celu poprawienia wydajności użytoThreadPoolExecutordo równoległego przetwarzania wielu URL-i, co znacznie skróciło czas pozyskiwania danych. Z perspektywy czasu wystarczyło użyćasynciodo asynchornicznego pobierania. -
Wykonanie zadania:
- Zaprogramowanie crawlera, który startował od stronu główenj i podstrony atlasu grzybów, iterując po podstronach zaczynających sie od
/gatunki/i zbierając linki do poszczególnych gatunków. - Aby pamiętać które strony zostały już odwiedzone użyto struktury danych
setdo przechowywania unikalnych URL-i, co zapobiegało duplikacji i nieskończonym pętlom.
- Zaprogramowanie crawlera, który startował od stronu główenj i podstrony atlasu grzybów, iterując po podstronach zaczynających sie od
- Opis działania: Głównym wyzwaniem w przypadku tej strony był fakt, że strona jest renderowana dynamicznie, przez co klasyczne statyczne żądania HTTP (np. przez bibliotekę
requests) nie pobierały właściwej treści. Aby to rozwiązać, scraper został oparty na bibliotece Playwright (działającej na silniku Chromium). Skrypt uruchamia przeglądarkę w trybie widocznym (headless=False), co pozwala na ręczne zaakceptowanie ciasteczek w trakcie zaprogramowanego odliczania, a następnie czeka na pełne załadowanie drzewa DOM (wait_until="domcontentloaded"). Dopiero wyrenderowany kod HTML trafia do parsowania za pomocą BeautifulSoup4. - Wykonane zadania:
- Zautomatyzowana iteracja po 6000 podstronach atlasu na podstawie identyfikatorów URL.
- Oczyszczanie drzewa DOM ze zbędnych elementów UI strony (usuwanie tagów
button,nav,svg), aby uniknąć zanieczyszczenia tekstu. - Ekstrakcja polskich i łacińskich nazw grzybów (rozpoznawanie tagów
h1,h2oraz znaczników kursywyi). - Parser formatujący surowy tekst do ustrukturyzowanego formatu Markdown - automatyczne dodawanie nagłówków drugiego poziomu (np.
## Kapelusz,## Trzon) oraz odrzucanie kategorii, w których widnieje wartość "brak" lub "brak opisu". - Zapis danych do czystych plików
.mdz poprawnie zdezynfekowanymi nazwami plików (usunięcie polskich znaków i znaków specjalnych) oraz nagłówkami typu Frontmatter zawierającymi metadane o źródle.
-
Opis działania: na podstawie już pobranych plików wyekstrahowano listę nazw gatunków grzybów. Następnie każdą nazwę wyszukiwano w polskiej Wikipedii za pomocą API MediaWiki.
-
Wykonane zadania:
- Pobranie listy gatunków z wcześniej zebranych danych.
- Wysłanie zapytań do API Wikipedii dla każdej nazwy gatunku, pobierając zawartość artykułu w formacie JSON.
- Ekstrakcja kluczowych informacji (opis, występowanie, cechy charakterystyczne) i zapis do plików
.mdz odpowiednimi nagłówkami.
- Język programowania: Python 3.10+
- Przetwarzanie Języka Naturalnego (NLP):
spaCy(modelpl_core_news_lg),rank_bm25 - Infrastruktura LLM & Wektory:
ollama(lokalne modelegemma3:4borazbge-m3),google-genai(modele chmurowe Gemini do zaawansowanego ETL) - Baza Danych: PostgreSQL z rozszerzeniem
pgvectorhostowany na platformieSupabase, klientasyncpg - Sztuczna Inteligencja i Uczenie Maszynowe:
torch(PyTorch do uruchomienia Rerankera),sentence-transformers(CrossEncoder),scikit-learn(KMeans) - Wizualizacja i Matematyka:
umap-learn,plotly,numpy,pandas,scipy - Inne:
joblib(serializacja indeksu),python-dotenv