TL;DR
- Kontekst: Side project obok etatu UX Leada w banku. Raycast to moje codzienne narzędzie na Macu, zamiennik Spotlight.
- Problem: Sklep rozszerzeń Raycast ma ponad 1700 pozycji, zero kategorii i po 10 wyników na stronę.
- Co zrobiłem: Zbudowałem skrypt, który pobiera dane z oficjalnego repozytorium Raycast, kategoryzuje rozszerzenia przez OpenAI API i publikuje gotowy katalog jako osobne repo na GitHubie.
- Wynik: 1716 rozszerzeń w 18 kategoriach, 600 gwiazdek i 12 forków. Utrzymywane ~5 miesięcy, dziś repo jest archiwum.
Diagnoza
Sklep rozszerzeń Raycasta ma ponad 1700 pozycji i żadnego sensownego sposobu, żeby je przeszukać: bez kategorii, po 10 wyników na stronę. Mogłem to obejść web scrapingiem strony, ale nie chciałem łamać regulaminu ani opierać się na czymś, co się posypie przy najbliższej zmianie layoutu. Zamiast tego znalazłem oficjalne repozytorium GitHub, w którym Raycast trzyma dane wszystkich rozszerzeń, zrobiłem forka i zbudowałem wokół niego skrypt: pobierz dane, skategoryzuj przez GPT, opublikuj gotowy katalog jako README.
flowchart TD
subgraph Przed["Przed"]
A1["Szukasz rozszerzenia<br/>w sklepie Raycast"] --> A2["Brak kategorii,<br/>10 wyników na stronę"]
A2 --> A3["Przewijasz strony<br/>albo zgadujesz nazwę"]
end
subgraph Po["Po"]
B1["Fork repo raycast/extensions<br/>+ skrypt scalający dane"] --> B2["Kategoryzacja<br/>przez OpenAI API"]
B2 --> B3["Katalog na GitHubie,<br/>18 kategorii"]
end
classDef good fill:#e6f2ea,stroke:none,color:#1f4d33,rx:14,ry:14
classDef bad fill:#faeaea,stroke:none,color:#5f2626,rx:14,ry:14
classDef accent fill:#27272a,stroke:#3f3f46,stroke-width:1px,color:#fafafa,rx:14,ry:14
class A1,A2,A3 bad
class B1,B2 good
class B3 accent
style Przed fill:transparent,stroke:#a1a1aa,stroke-width:1px,rx:14,ry:14
style Po fill:transparent,stroke:#a1a1aa,stroke-width:1px,rx:14,ry:14
linkStyle default stroke:#a8a8b3,stroke-width:1.5px
Co zrobiłem
- Zrobiłem forka oficjalnego repozytorium
raycast/extensionsi napisałem skrypt, który scala plikipackage.jsonz każdego rozszerzenia w jedną tablicę danych. - Skategoryzowałem rozszerzenia przez OpenAI API: najpierw GPT-3.5-Turbo-0125 (jeden z pierwszych modeli z kontrolowanym JSON-em na wyjściu), potem GPT-4-turbo, z promptem trzymającym model przy zamkniętej liście kategorii.
- Zautomatyzowałem cały pipeline w praktycznie jednym skrypcie: synchronizacja forka, wykrycie nowych rozszerzeń względem poprzedniej wersji, kategoryzacja, wygenerowanie README, publikacja.
- Opublikowałem wynik jako publiczne repo na GitHubie: 1716 rozszerzeń w 18 kategoriach.
Wyniki
| Metryka | Wartość |
|---|---|
| Rozszerzenia skategoryzowane | 1716 |
| Kategorie | 18 |
| Gwiazdki na GitHubie | 600 |
| Forki | 12 |
| Aktywne utrzymanie | ~5 miesięcy (maj–wrzesień 2024) |
- 1716 rozszerzeń skategoryzowanych automatycznie, bez ręcznego przeglądania każdego wpisu.
- 600 gwiazdek i 12 forków na GitHubie. Ludzie faktycznie tego używali.
- Zero scrapingu. Całe rozwiązanie oparte o oficjalne dane z repozytorium Raycast.
- Pipeline działał jednym skryptem, nie ręczną robotą co aktualizację.
Problem
Dlaczego katalog rozszerzeń Raycast jest trudny do przeszukania?
Strona sklepu nie ma rozwiniętego systemu kategorii, a pojedynczy widok pokazuje tylko 10 rozszerzeń naraz. Przy ponad 1700 pozycjach to oznacza przewijanie dziesiątek stron albo trafienie w dokładną nazwę w wyszukiwarce. Jeśli nie wiesz dokładnie, czego szukasz (a często tak właśnie jest, bo dopiero odkrywasz, co Raycast potrafi), nie masz jak przeglądać sensownie.
Dlaczego nie web scraping?
Bo to rozwiązanie kruche i na granicy regulaminu. Strona może się zmienić w dowolnym momencie i scraper się wysypie; do tego czytanie danych bezpośrednio z frontendu cudzej strony, zamiast z danych, które ta firma sama publikuje, nie było dla mnie opcją. Oficjalne repozytorium GitHub, w którym Raycast trzyma package.json każdego rozszerzenia, dawało to samo, w sposób, na którym mogłem polegać.
Moja rola / zakres
- Solo side project, obok pełnoetatowej pracy jako UX Lead w banku.
- Zaprojektowałem cały pipeline i prompt do kategoryzacji, napisałem skrypty, utrzymywałem repozytorium przez ~5 miesięcy.
Proces
- Research źródła danych: zamiast scrapingu strony, znalazłem i sforkowałem oficjalne repozytorium GitHub z danymi wszystkich rozszerzeń.
- Iteracja nad promptem: kilka podejść, zanim model trzymał się tylko podanych kategorii i nie tworzył własnych.
- Automatyzacja krok po kroku: sync forka → nowy folder na datę → porównanie z poprzednią wersją → kategoryzacja przez API → wygenerowanie README → publikacja.
- Utrzymanie: 11 commitów między majem a wrześniem 2024, w miarę jak pojawiały się nowe rozszerzenia.
Kluczowe decyzje i trade-offy
- Oficjalne repo zamiast scrapingu. Wolniejszy start (trzeba było znaleźć właściwe repozytorium i zrozumieć jego strukturę), ale rozwiązanie stabilne i zgodne z zasadami, zamiast czegoś, co przestanie działać przy pierwszej zmianie strony.
| Podejście | Ryzyko | Decyzja |
|---|---|---|
| Web scraping strony Raycast | łamanie regulaminu, kruche przy zmianie layoutu | odrzucone |
| Fork oficjalnego repo GitHub | zależne od struktury package.json w repo | wybrane |
- Structured JSON output zamiast parsowania wolnego tekstu. GPT-3.5-Turbo-0125 dawał kontrolowany JSON na wyjściu, więc nie musiałem pisać osobnego parsera odpowiedzi modelu. To był jeden z pierwszych razy, kiedy testowałem structured output hands-on, zanim stał się standardem w większości modeli.
- Szczerze: zatrzymałem update’y we wrześniu 2024. Repo dziś ma status archived. Bez dedykowanego czasu obok pracy na etacie, monitorowanie nowych rozszerzeń i poprawki kategorii przestały się skalować.
Jak to się skończyło
Repo ma 600 gwiazdek i 12 forków, ale ostatni commit to wrzesień 2024. Dziś jest zarchiwizowane. Oficjalny sklep Raycasta wciąż nie ma realnego przeglądania po kategoriach, tylko wyszukiwarkę i kilka linków w stopce, więc problem, który rozwiązywałem, nadal istnieje. Nie kontynuowałem, bo utrzymanie kategoryzacji obok pełnoetatowej pracy przestało się opłacać. To był świadomy koniec, nie porażka projektu.
Co z tego wyniosłem
- Automatyzacja to nie „raz i gotowe”. Nawet dobrze zaprojektowany pipeline potrzebuje kogoś, kto go utrzyma, kiedy źródło danych rośnie.
- Wybór źródła danych to decyzja projektowa, nie tylko techniczna. Oficjalne repo zamiast scrapingu było wolniejsze na starcie, ale nie kruche, a to się opłaciło przez 5 miesięcy działania.
- Structured output w LLM oszczędza godziny roboty. Zanim JSON mode stał się standardem, testowanie go hands-on dało mi realne wyczucie, kiedy AI faktycznie przyspiesza pracę, a kiedy tylko tak wygląda.