KB000011
Wstęp
Stworzenie jednego uniwersalnego kodu do każdego rodzaju udokumentowanego paragonu jest ogromnym wyzwaniem z uwagi na jakość, krzywizny, kąty, światło, odległość, format, metody wykonania oraz inne tego typu czynniki. Uzyskanie powtarzalnego procesu, wiąże się z długim okresem testowania, co znacznie oddala moment wdrożenia.
Wyzwaniem dla mnie było:
dostosowanie odpowiednich narzędzi, które obsłużą obraz w PDF
odpowiednie połączenie obrazów, dla PDF zawierających więcej niż jedną stronę
odpowiednie wyostrzenie uzyskanego PNG tak aby odczyt tekstu był jak najdokładniejszy
stworzenie algorytmu oczyszczającego plik tekstowy ze zbędnych informacji i uzyskanie powtarzalnej zawartości która zawsze w odpowiednim miejscu się zaczyna i kończy
przekonwertowanie linijek tekstu na obiekty bez utraty danych, w tym wyłączenie kolumny PTU, uwzględnienie rabatów rozłożonych na 3 linijki z pustymi przestrzeniami.
połączenie wszystkiego w jeden flow tak, aby finalnie uzyskać plik wynikowy z odpowiednio pogrupowanymi obiektami oraz posortowaną tablicą
Dlaczego w ogóle zająłem się tematem?
Historia tego projektu pochodzi sprzed kilku miesięcy, kiedy to wpadłem na pomysł, aby stworzyć mikro serwis do rejestrowania paragonów. Przeglądając popularne aplikacje takie jak "Pan Paragon", nie spotkałem się z automatycznym rozpoznawaniem danych. Najczęściej był to storage z formularzem i dashboardy do tego, co manualnie klient wprowadza. Jak się okazywało, funkcje premium ( a tak naprawdę bazowe/konieczne )
wiązały się z kosztami, a przecież ten sam efekt można było uzyskać, korzystając z Google Sheets, czy Excel a zdjęcia przechowywać w chmurze.
Sprawdziłem wówczas tzw "elektroniczny paragon" https://www.podatki.gov.pl/e-paragony/ ale okazało się, że niewiele punktów z tego korzysta.
Finalnie, pobrałem kilka aplikacji ( lidl, biedronka, żabka, rossman, McDonald ) - w żadnej nie znalazłem JSON. Co ciekawe, lidl udostępnia dane w PNG a biedronka OBRAZ w PDF - XD. O żabce, rossman, McDonald, nawet nie wspominam, bo tam nie ma czegoś takiego jak e-paragon. No comment....
Oczywiście, gdy zwróciłem się do Biedronki o to, aby udostępnili również format JSON, dostałem odmowę. Pingowałem temat przy różnych zgłoszeniach związnych z aplikacją, przemycając na różne sposoby uzasadnienia, prośby, no ale bezskutecznie.
Podsumowując
Jak widzisz, są takie firmy jak PKO Bank Polski S.A które umożliwiają pobranie historii w różnych formatach, i są takie firmy jak żabka, które tworzą aplikację typu "Dump component"
I to nie jest kwestia "kasy".
Rekomendacje
Jeśli jesteś PM-em, rozważ moją opinię. Aplikacja w sklepie spożywczym ma realizować dwa najważniejsze cele:
Historia zakupów
Punkt rabatowe
Klient chce zrealizować szybko swój cel, tak jak robi to w przypadku przelewu, blika, e-maila, i wyjść. Dlatego skupienie się na takich funkcjach jak:
Pobierz całą historię z okresu X - Y ( wybierz format pliku )
Dashboard typu: Na co wydałem | Ile wydałem w okresie X - Y
Ile mam punktów i na co mogę je przeznaczyć
spowoduje zwiększenie ruchu, ponieważ konsumenci zobaczą wartość. Rozważ także czy aby napewno potrzebujesz mieć aplikację w sklepie PLAY/AppStore, bo może warto pójść w ślady Facebook-a. Pamiętaj, że społeczeństwo staje się coraz bardziej zdigitalizowane. Na każdym kroku widzimy że jakaś aktywność podlega analizie ( głupie termometry mają aplikacje z historią i opcją pobrania danych do pliku csv ). Tworzenie narzędzia do wyświetlania "gazetki" i płacenie za "miejscówkę" przypomina absurd związany z aplikacjami typu "latarka".
Tyle tytułem wstępu. Co dalej?
W dalszej części, skupie się już tylko na omówieniu najważniejszych informacji, a rozpocznę od założeń:
Posiadasz kartę stałego klienta Biedronka
Nie zamierzasz prowadzić wnikniliwej analizy każdego produktu ( zmienność cen, ile razy był przeceniony, itp )
Jesteś chętny rozwijać projekt według własnych potrzeb
Nie przeszkadza ci konsolowy program ( ubóstwiam. GUI może nie istnieć )
Nie jesteś wrażliwy na wzorce projektowe, sugar syntax itp.
[ WAŻNE ] OBSZARY DO POPRAWY
Ta sekcja jest dość istotna, dlatego że pokazuje niedociągnięcia, ale także potencjalne kierunki rozwoju.
NAZWY PRODUKTÓW
Część wartości przypisanych do "product" będzie wyglądać następująco:
[ PRZYKŁAD ]
{
"product": "OueenMaT0x10 A",
"quantity": "1.000",
"price": "4,49",
"value": "4,49",
"category": "",
"date_time": "18.05.2024 09:04"
},
{
"product": "Cnustl2UsztśWUueen A",
"quantity": "1.000",
"price": "6,29",
"value": "6,29",
"category": "",
"date_time": "18.05.2024 09:04"
},
Sorry, ale często nawet ja mam problem, żeby odczytać co jest napisane, a co dopiero jakaś biblioteka, która oprócz przetwarzania tekstu z obrazu musi jeszcze uwzględnić polskie znaki. Obiecuje, że będę jeszcze pracował nad poprawą parametrów odczytu i doprecyzuje w jakimś stopniu te nazwy, niemniej, jak wspomniałem w punkcie o analizach, zmierzam w kierunku pracy na kategoriach, a nie na często zmieniających się nazwach produktów tak niedbale opisanych na dokumencie.
JAK AI RADZI SOBIE Z TAKIMI WPISAMI?
[ inserted PNG ]
[ AI result ]
Naprawdę nieźle!!!! Tylko to nie jest ten string. I na pewno da się to wyciągnąć. To kwestia zawzięcia.
[ Poprawny wynik ]
{
"product": "Chust(chyba spacja)QueenMe10x10",
"quantity": "1.000",
"price": "4,49",
"value": "4,49",
"category": "",
"date_time": "18.05.2024 09:04"
},
{
"product": "Chust120szt3WQueen",
"quantity": "1.000",
"price": "6,29",
"value": "6,29",
"category": "",
"date_time": "18.05.2024 09:04"
},
Czy teraz już rozumiesz dlaczego, udostępnienie formatu JSON przez sklepy spożywcze w ich aplikacjach to oszczędność czasu, środków oraz duże ułatwienie dla konsumentów?
A gdyby jeszcze dorzucić prosty REST API, ehh...
W ramach CI/CD zamierzam stworzyć interfejs umożliwiający poprawę tego typu pozycji, i powiązany z tym machine learning, który uzupełni kategorie, po zatwierdzeniu zmian nazw produktów ( co również będzie edytowalne na życzenie ).
Wdrożenie flow jako część procesu
Każdego, kto zamierza rozwijać ten projekt, wdrożyć go jako część innego procesu, zachęcam do przejrzenia kodu, dostosowania, poprawienia, uproszczenia. W tej materii przeważnie jest co usprawniać. To zawsze cieszy, gdy coś co zrobiłeś w ramach @openSource, zainspirowało kogoś do stworzenia czegoś jeszcze lepszego, z czego skorzysta więcej ludzi.
Wdrożenie AI
Chyba nie muszę nikogo informować o tym, że AI z paragonami radzi sobie równie dobrze, a nawet lepiej. AI oprócz samego zwróconego TXT/JSON/CSV/HTML może dodatkowo uzupełnić kategorie ( lepiej / gorzej, zawsze możesz dostosować ) czy przeprowadzić analizy ( nawet te bardziej skomplikowane ).
Dla chętnych udostępniam swojego asystenta AI, którego wciąż testuje i póki co, wyniki są zgodne z oczekiwaniami. Link znajdziesz na końcu artykułu.
[ KRÓTKA REKLAMA ]
Asystent AI powstał w oparciu, o pierwszy modół kursu "MAG SŁOWA" wydanego przez team MISTRZ AI. Zachęcam do sprawdzenia oferty. Bez zbędnego wysiłku, odpowiednio konfigurując parametry, jesteś wstanie uzyskać cały proces obejmujący tworzenie i walidację.
Więcej szczegółów na: https://mistrz.ai/#modules-1-4
A tu krótkie demo z kursu. Serdecznie zapraszam!
Wdrożenie pipenv
Nie ma to, jak dobre zarządzanie projektem. Warto o to zadbać.
RECEIPTS FLOW
Za kontrolę flow odpowiada plik main.py.
Status po uruchomieniu. NIE PRZERYWAJ JEŚLI NIE MUSISZ ! ! !
[ do not interupt ]
Status po wykonaniu całego flow.
[ final result ]
>>> IMPORTS <<<
Libraries
datetime
os
shutil
pdf2image
json
subprocess
pytesseract
PIL (Image)
cv2
re
glob
collections (defaultdict)
chyba wszystkie... XD
>>> FLOW Controller description <<<
Sprawdza strukturę katalogów. Jeżeli coś się nie zgadza, to wyrzuca criticala i mamy stop process. Wykonanie core process następuje po uprzednim zweryfikowaniu zawartości katalogu z surowymi plikami OBRAZ w PDF. Jeżeli jest akceptacja, przenoszony jest plik z katalogu ' receitps/downloaded ' do ' input/ '. Po zakończeniu przenoszony jest plik JSON z
' output/json ' do ' output/collection '. Dalej, następuje oczyszczenie katalogów roboczych. Po czyszczeniu przenoszony jest plik z ' input/ ' do ' receipts/done ' i pętla zamyka obieg. Po wykonaniu wszystkich iteracji, wykonywany jest merge wszystkich obiektów z plików w
' output/collection ' do jednego pliku bazowego i zapis w katalogu ' output/target '. Następnie obiekty w pliku bazowym zostają pogrupowane zgodnie z datami i godzinami paragonów. Finalnie główna tablica jest sortowana od najstarszej daty a zmiany zostają zapisane i następuje zakończenie programu.
>>> Image processing description <<<
pdf_to_png.py
Odczytuje pojedynczy plik PDF z katalogu ' input/ ' pozyskując z niego pliki PNG. Pliki z rozszerzeniem *.png zostają umieszczone w katalogu ' extraced_png '.
combine_images.py
Odczytuje zawartość katalogu ' output/extraced_png ' i tworzy jeden plik PNG według określonego wzoru. Wynik w postaci jednego pliku *.png
zostaje zapisany w katalogu ' output/combined_png '.
prepare_raw_txtFile.py
Odczytuje pojedynczy plik PNG z katalogu ' output/combined_png ' i przetwarza tekst z PNG do postaci surowej. Wynikowy plik *.txt zapisywany jest w katalogu ' output/txt '
clear_data_in_txt.py
Odczytuje pojedyńczy plik TXT z katalogu ' output/txt ' i oczyszcza go z nie potrzebnych danych uzyskując zawsze ten sam zakres tekstu. Ten moduł modyfikuje plik źródłowy.
prepare_final_json.py
Odczytuje pojedynczy plik TXT z katalogu ' output/txt ' i przetwarza tekst na obiekty JSON. Plik oznaczony datą i godziną paragonu zostaje zapisany w katalogu ' output/json '
find_invalid_objects.py
Odczytuje pojedynczy plik JSON z katalogu ' output/json ' i sprawdza, czy znajduje się w nim obiekt, który posiada pewne słowa kluczowe ( nagłówki tabeli ).
Jeżeli tak, modyfikuje plik źródłowy
>>> Error handling <<<
Funkcja zapisuje dane do pliku logs.txt, który znajduje się w katalogu ' logs/ '. Zapisywany log to: ${date & time} | ${file_name} | ${function_name} | ${message}. W konsoli mogą pojawić się dwa rodzaje komunikatów: "Check logs" oraz błąd podczas sprawdzania struktury katalogów.
>>> Additional information <<<
Zadbałem oto aby obieg dokumentacji można było wykorzystać do różnych scenariuszy. Mimo to jeszcze raz zachęcam do refaktoryzacji. Poniżej opis stanu po obiegu:
Proces pozostawia:
W katalogu ' receitps/done ': pliki źródłowe
W katalogu ' output/collection ': JSON's z każdego paragonu ( opisane datą i godziną z paragonu [ FORMAT : ISO ] )
W katalogu ' output/target ': plik wynikowy JSON zawierający całą kolekcję.
Jeżeli potrzebujesz pomocy w zainstalowaniu i konfiguracji napisz do mnie:
TRZY KROKI DO STARTU:
[ STEP 1 ]
Pobierz projekt z GitHub. Upewnij się, że masz wszystkie biblioteki.
[ WAŻNE ] Przeczytaj plik README.md
[ STEP 2 ]
Wejdź na https://moja.biedronka.pl/, zaloguj się na swoje konto, i zaimportuj paragony
( flow przetwarza wiele plików )
[ STEP 3 ]
Uruchom plik main.py. Obserwuj progress bar w terminalu.
Plik wynikowy znajdziesz w ' output/target '.
RECOMMENDED TOOLS
JetBrains IDEs
[ WAŻNE ] NIE ZAPOMNIJ O PORÓWNANIU SUMY KONTROLNEJ!!!!
Canonical Ubuntu. Dzięki temu systemowi możesz skupić się na tym co najważniejsze. Polecam go do pracy, nauki i rozwoju osobistego.
OpenAI | LLM. Skrócona wersja użycia mojego asystenta:
Wklej PNG ( WAŻNE: nie obraz w PDF )
W wiadomości napisz tylko słowo kluczowe "Start"
W wyniku otrzymasz dane na wzór:
Osoby zainteresowane budową modelu, również zachęcam do kontaktu. Krótki opis poniżej.
METAWARSTWY:
Uzgodniono rzeczywistość
Podano kontekst sytuacyjny
Opisano problem
Wskazano rolę
Podano rozmówcę
Opisano zadanie, rezultat oraz strukturę
Temperatura: nie określone
Ilość tokenów: nie określone
ZAŁOŻENIA WYNIKOWE:
Rabat = 1 else 0
Data = dd.mm.yyyy w cudzysłów
Podsumowanie = 0
Ilość = zaokrąglenie do całości 0 do 1 = 1; analogicznie > 1
STAŁE:
Załącznik = PNG > 0
Sklep = 'biedronka'
Kategoria = 'undefined'
PDF to PNG. Jeżeli korzystasz tylko z LLM, na pewno przyda Ci się to narzędzie
Jest doskonałym wyborem do różnorodnych projektów budowlanych i projektowych ze względu na swoją trwałość i odporność na wilgoć. Płyty kompaktowe kupisz w wyspecjalizowanych sklepach z materiałami budowlanymi, dużych hipermarketach lub w Internecie.
Jednym ze sprawdzonych sklepów internetowych, w którym znajdziesz wysokiej jakości płyty kompaktowe jest https://viyar.pl/catalog/plyta-kompaktowa/. Ten zasób oferuje szeroką gamę produktów, w tym płyty w różnych rozmiarach i kolorach, co pozwala wybrać najlepszą opcję dla Twojego projektu.
Dodatkowo można uzyskać porady dotyczące doboru materiałów i ich zastosowania. Nie przegap okazji, aby zapoznać się z ofertą Viyar i znaleźć idealną kuchenkę kompaktową spełniającą Twoje potrzeby!
Gdzie znaleźć wysokiej jakości płyty kompaktowe do produkcji mebli? Poszukuję dostawców lub sklepów, które oferują szeroką gamę tych płyt, w tym różne rozmiary i wykończenia. Ważne jest dla mnie również poznanie właściwości materiału, jego wytrzymałości, odporności na wilgoć i trwałości. Jeśli macie polecenia sprawdzonych producentów lub platformy handlowe, gdzie można kupić płyty, albo wiecie o rabatach i promocjach na tego typu produkty, będę wdzięczny za informację!