{"id":18238185,"url":"https://github.com/christopher-dabrowski/ai_devs3-zadania","last_synced_at":"2026-03-04T14:32:33.825Z","repository":{"id":260891231,"uuid":"882636174","full_name":"christopher-dabrowski/AI_devs3-Zadania","owner":"christopher-dabrowski","description":"Moje rozwiązania do zadań z kursu AI_devs3","archived":false,"fork":false,"pushed_at":"2025-01-18T19:57:47.000Z","size":405,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-13T22:42:53.130Z","etag":null,"topics":["ai","ai-devs3","csharp","dotnet","learning","llm-agent"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/christopher-dabrowski.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-11-03T11:01:47.000Z","updated_at":"2025-06-09T11:20:50.000Z","dependencies_parsed_at":"2024-12-09T20:37:53.404Z","dependency_job_id":"9e3f43bd-957d-4ad5-bf15-4bfd9bb75952","html_url":"https://github.com/christopher-dabrowski/AI_devs3-Zadania","commit_stats":null,"previous_names":["christopher-dabrowski/ai_devs3-zadania"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/christopher-dabrowski/AI_devs3-Zadania","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christopher-dabrowski%2FAI_devs3-Zadania","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christopher-dabrowski%2FAI_devs3-Zadania/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christopher-dabrowski%2FAI_devs3-Zadania/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christopher-dabrowski%2FAI_devs3-Zadania/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/christopher-dabrowski","download_url":"https://codeload.github.com/christopher-dabrowski/AI_devs3-Zadania/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christopher-dabrowski%2FAI_devs3-Zadania/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266586905,"owners_count":23952205,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","ai-devs3","csharp","dotnet","learning","llm-agent"],"created_at":"2024-11-05T03:04:17.913Z","updated_at":"2026-03-04T14:32:33.785Z","avatar_url":"https://github.com/christopher-dabrowski.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spis Treści\n\n- [Spis Treści](#spis-treści)\n- [AI\\_devs3-Zadania](#ai_devs3-zadania)\n  - [PreworkApi](#preworkapi)\n  - [S01E01 — Interakcja z dużym modelem językowym](#s01e01--interakcja-z-dużym-modelem-językowym)\n  - [S01E02 — Przygotowanie własnych danych dla modelu](#s01e02--przygotowanie-własnych-danych-dla-modelu)\n  - [S01E03 — Limity Dużych Modeli językowych i API](#s01e03--limity-dużych-modeli-językowych-i-api)\n  - [S01E04 — Techniki optymalizacji](#s01e04--techniki-optymalizacji)\n  - [S01E05 — Produkcja](#s01e05--produkcja)\n  - [S02E01 — Audio i interfejs głosowy](#s02e01--audio-i-interfejs-głosowy)\n  - [S02E02 - Rozumienie obrazu i wideo](#s02e02---rozumienie-obrazu-i-wideo)\n  - [S02E03 — Generowanie i modyfikacja obrazów](#s02e03--generowanie-i-modyfikacja-obrazów)\n  - [S02E04 — Połączenie wielu formatów](#s02e04--połączenie-wielu-formatów)\n  - [S02E05 — Multimodalność w praktyce](#s02e05--multimodalność-w-praktyce)\n  - [S03E01 — Dokumenty](#s03e01--dokumenty)\n  - [S03E02 — Wyszukiwanie Semantyczne](#s03e02--wyszukiwanie-semantyczne)\n  - [S03E05 - Bazy Grafowe](#s03e05---bazy-grafowe)\n  - [S04E02 — Przetwarzanie treści](#s04e02--przetwarzanie-treści)\n\n# AI_devs3-Zadania\n\n[![.NET Build](https://github.com/christopher-dabrowski/AI_devs3-Zadania/actions/workflows/dotnet-build.yml/badge.svg?branch=main)](https://github.com/christopher-dabrowski/AI_devs3-Zadania/actions/workflows/dotnet-build.yml)\n\nMoje rozwiązania do zadań z kursu AI_devs3.  \nGdy spisuję moje rozwiązania i przemyślenia to więcej wynoszę z nauki 😃\n\n## PreworkApi\n\nZadanie polegało na przetestowaniu komunikacji z API, którego będziemy używać w dalszych zadaniach.  \nByła do dla mnie świetna okazja, żeby nauczyć się korzystać z [Cursor IDE](https://www.cursor.com/).\n\nMoje rozwiązanie: [PreworkApi](./dotnet/PreworkApi/Program.cs)\n\nJestem pod wrażeniem, jak przyjemnie programowało mi się z pomocą AI.\nDo tej pory używałem trochę GitHub Copilot, ale nie byłem pod jakimś dużym wrażeniem.\nTeraz gdy użyłem znacznie bardziej zintegrowanego z AI narzędzia, czułem się bardzo fajnie.\nAI sprawdziło się bardzo dobrze, może dlatego, że zadanie było dość prostsze, jednak zawsze w pracy są też prostsze czynności, które często są nudne.\nChciałbym częściej używać do nich AI.\n\n## S01E01 — Interakcja z dużym modelem językowym\n\n\u003cimg src=\"./.attachments/Flag_S01E01.png\" width=\"150\" alt=\"Zdobyta flaga zadania S01E01\"\u003e\n\nZadanie polegało na automatyzacji procesu logowania z użyciem AI do rozwiązywania pytań ANTY CAPTCHA - to jak CAPTCHA, ale może je przejść tylko robot 🤖.\n\nMoje rozwiązanie: [S01E01](./dotnet/S01E01/Program.cs)\n\nW implementacji wykorzystałem:\n\n- HtmlAgilityPack do parsowania strony i wydobycia pytania\n- OpenAI API (model GPT-4) do analizy pytania i generowania odpowiedzi\n- HttpClient do komunikacji z API\n- Dependency Injection do zarządzania zależnościami\n- User Secrets do bezpiecznego przechowywania kluczy API i danych logowania\n\nCiekawe było wykorzystanie System Message w OpenAI API, który wymusza zwracanie wyłącznie liczby, bez dodatkowych wyjaśnień. To pokazuje, jak ważny jest odpowiedni prompt engineering w pracy z AI.\n\n## S01E02 — Przygotowanie własnych danych dla modelu\n\n\u003cimg src=\"./.attachments/Flag_S01E02.png\" width=\"150\" alt=\"Zdobyta flaga zadania S01E02\"\u003e\n\nZadanie polegało na wykorzystaniu modelu językowego do przetwarzania i analizy wiadomości w dwóch krokach.\n\nMoje rozwiązanie: [S01E02](./dotnet/S01E02/Program.cs)\n\nW implementacji zastosowałem ciekawe podejście wykorzystujące sekwencyjne połączenie dwóch promptów, gdzie:\n\n- Pierwszy prompt przygotowywał dane dla drugiego\n- Model efektywnie pracował z własnymi wynikami\n- Większość kodu została wygenerowana przez Cursor IDE, co pokazuje potencjał AI w codziennej pracy programisty\n\nTo doświadczenie pokazało, jak skuteczne może być łączenie różnych technik prompt engineeringu oraz wykorzystanie narzędzi AI do wspomagania procesu programowania.\n\n## S01E03 — Limity Dużych Modeli językowych i API\n\n\u003cimg src=\"./.attachments/Flag_S01E03.png\" width=\"150\" alt=\"Zdobyta flaga zadania S01E03\"\u003e\n\nZadanie polegało na analizie dużego pliku z pytaniami i poprawienie w nim błędów.\n\nMoje rozwiązanie: [S01E03](./dotnet/S01E03/Program.cs)\n\nGłównym wyzwaniem była wielkość pliku wejściowego — zbyt duża, by przekazać całość do modelu językowego.\nZastosowałem więc podejście hybrydowe:\n\n- Obliczenia matematyczne wykonałem programistycznie, bez użycia LLM\n- Model językowy wykorzystałem tylko do analizy pytań i generowania odpowiedzi na podstawie wcześniej obliczonych wyników\n\nTo pokazuje, jak ważne jest odpowiednie rozdzielenie zadań między tradycyjne programowanie a AI, szczególnie przy ograniczeniach technicznych modeli językowych.\n\n## S01E04 — Techniki optymalizacji\n\n\u003cimg src=\"./.attachments/Flag_S01E04.png\" width=\"150\" alt=\"Zdobyta flaga zadania S01E04\"\u003e\n\nZadanie polegało na napisaniu promptu, który nakieruje robota do celu, omijając przeszkody.\nWykorzystanie do tego LLM okazało się zaskakująco trudne.\nNa początku próbowałem zrobić to bez wyznaczania konkretnej trasy modelowi, jednak bez skutku.\nNa razie rozwiązałem to zadanie w łatwiejszej wersji, gdzie model miał podążać za z góry ustaloną trasą.\nMoje rozwiązanie to [definedTrackSolution](prompty/S01E04/definedTrackSolution.txt).\n\n## S01E05 — Produkcja\n\n\u003cimg src=\"./.attachments/Flag_S01E05.png\" width=\"150\" alt=\"Zdobyta flaga zadania S01E05\"\u003e\n\nW tym zadaniu należało wykorzystać lokalnie uruchomiony model językowy do anonimizacji tekstu poprzez ocenzurowanie wrażliwych danych (imion, nazwisk, nazw miast, ulic i wieku).\n\nMoje rozwiązanie wykorzystało:\n\n- Model llama2 uruchomiony lokalnie przez [ollama](https://ollama.com/) w kontenerze Docker\n- Dwuetapowe podejście do rozwiązania problemu:\n  1. Wykorzystanie modelu tylko do identyfikacji wrażliwych danych w tekście\n  2. Programistyczna zamiana zidentyfikowanych fragmentów na \"[CENSORED]\" przy pomocy prostych operacji na tekście\n\nPoczątkowo próbowałem rozwiązać problem jednym promptem, który miał zarówno identyfikować jak i zamieniać dane, ale model miał z tym problemy. Podzielenie zadania na dwa prostsze kroki znacząco poprawiło skuteczność rozwiązania.\n\nInteresująco było też to, że model początkowo odmawiał \"cenzurowania\" danych ze względów etycznych, ale zaakceptował zadanie gdy zostało ono przedstawione jako \"anonimizacja\" danych.\n\nKod rozwiązania: [S01E05](./dotnet/S01E05/Program.cs)\n\n## S02E01 — Audio i interfejs głosowy\n\n\u003cimg src=\"./.attachments/Flag_S02E01.png\" width=\"150\" alt=\"Zdobyta flaga zadania S02E01\"\u003e\n\nZadanie polegało na wygenerowaniu transkrypcji z plików audio z zeznaniami świadków oraz wykorzystanie modelu do przeanalizowania ich w celu ustalenia pewnego konkretnego adresu.\n\nTym razem dla odmiany zdecydowałem się użyć pythona.\nGenerowanie transkrypcji: [S02E01](python/S02E01/transcribe.py)  \nPodczas pracy z modelem whisper w pythonie miałem kilka kłopotów. Najpierw ze zbyt nową wersją pythona, a potem z wersją numpy.\nJuż od paru lat nie używałem pythona, więc znalezienie rozwiązania mogłoby mi zając sporo czasu.\nCursor na szczęście niezwykle sprawnie podsunął mi gotowe rozwiązania :D\n\nMając gotowe transkrypcje również przy pomocy Cursor'a przeanalizowałem je i znalazłem odowiedź.  \nMój prompt: [prompt.txt](python/S02E01/prompt.txt)\n\nCo ciekawe najpierw uruchmiłem go na modelu gpt-4o. Model ten dał znacznie gorszy wynik niż claude-3.5-sonnet.\n\n## S02E02 - Rozumienie obrazu i wideo\n\n\u003cimg src=\"./.attachments/Flag_S02E02.png\" width=\"150\" alt=\"Zdobyta flaga zadania S02E02\"\u003e\n\nZadanie polegało na odnalezieniu miasta na podstawie czterech fragmentów mapy, z których jeden był celowo błędny. Wykorzystałem model gpt-4o do analizy obrazów i znalezienia odpowiedzi.\n\nMoje rozwiązanie: [S02E02](./dotnet/S02E02/Program.cs)\n\nW implementacji wykorzystałem:\n\n- OpenAI API z modelem gpt-4o do analizy obrazów map\n- Trzy etapowe podejście:\n  1. Analiza każdego fragmentu mapy osobno w celu wydobycia kluczowych informacji\n  2. Wygenerowanie zestawów map z jedną wykluczoną.\n  3. Połączenie informacji i identyfikacja niespójnego fragmentu w celu znalezienia właściwego miasta\n\nNa początku próbowałem podać wszystkie fragmenty mapy, łącznie z błędnym do zapytania, nie dostałem jednak w ten sposób poprawnej odpowiedzi.\nUznałem, że skoro zapytania tekstowe są stosunkowo tanie i szybkie to mogę zrobić ich kilka, w każdym eliminując jeden z fragmentów mapy.\n\nTym razem Cursor kiepsko radził sobie z pisaniem kodu do zapytań OpenAI. Mimo dodania do kontekstu dokumentacji musiałem samemu ją przeczytać i napisać poprawny kod.\n\n## S02E03 — Generowanie i modyfikacja obrazów\n\n\u003cimg src=\"./.attachments/Flag_S02E03.png\" width=\"150\" alt=\"Zdobyta flaga zadania S02E03\"\u003e\n\nZadanie polegało na wygenerowaniu obrazu robota na podstawie chaotycznych zeznań osoby, która go widziała. Wykorzystałem do tego DALL-E 3 poprzez OpenAI API.\n\nMoje rozwiązanie: [S02E03](./dotnet/S02E03/Program.cs)\n\nW moim rozwiązaniu:\n\n1. Pobrałem zeznania świadka\n2. Przy pomocy LLM przekształciłem je na opis robota\n3. Wygenerowałem prompt do generacji obrazu\n4. Stworzyłem obraz robota\n\nPrzy okazji rozwiązania tego zadania dowiedziałem się, że OpenAI pozwala wygenerować obraz, do którego pobrania otrzyma się URL. Dzięki temu nie musiałem samemu hostować pliku obrazu :D\n\n## S02E04 — Połączenie wielu formatów\n\n\u003cimg src=\"./.attachments/Flag_S02E04.png\" width=\"150\" alt=\"Zdobyta flaga zadania S02E04\"\u003e\n\nCelem zadania było znalezienie raportów zawierające informacje o schwytanych ludziach lub o śladach ich obecności oraz o naprawionych usterkach hardwarowych, oraz przygotowanie listy tylko tych dotyczących schwytanych ludzi, oraz oddzielnie tych, które dotyczyły usterek.\nDane w raportach były w formatach tekstowych, audio oraz graficznych.\n\nGłówny kod: [S02E04](./dotnet/S02E04/Program.cs)\nMoje prompty: [Prompts](./dotnet/S02E04/Prompts.cs)\n\nRozwiązałem zadanie następująco:\n\n1. Przekształciłem dane do formatu tekstowego\n   - text — bez transformacji\n   - audio — transkrypcja modelem _Whisper_\n   - zdjęcia — ekstrakcja tekstu za pomocą _gpt-4o_\n2. Użyłem modelu _gpt-4o_ do analizy raportów i kategoryzacji ich na:\n   - raporty o schwytanych ludziach\n   - raporty o usterkach technicznych\n   - pozostałe\n3. Przygotowałem odpowiedź w wymaganym formacie JSON\n\nDodatkowo zaimplementowałem cache dla transformacji obrazów i audio. Dzięki temu nie musiałem powtarzać tych kosztownych operacji przy dopracowywaniu aplikacji oraz miałem łatwy wgląd w ich postać tekstową.\n\nRozwiązanie pokazuje, jak skutecznie można łączyć różne modele AI do przetwarzania danych w różnych formatach oraz jak ważna jest optymalizacja w przypadku kosztownych operacji AI.\n\n## S02E05 — Multimodalność w praktyce\n\n\u003cimg src=\"./.attachments/Flag_S02E05.png\" width=\"150\" alt=\"Zdobyta flaga zadania S02E05\"\u003e\n\nCelem zadania było autonomicznie odpowiedzenie na pytania na podstawie informacji z artykułu internetowego.  \nCzęścią wyzwania było to, że artykuł, jak to strony w internecie, był w formacie HTML z linkami do zdjęć i plików audio.\n\nMoje rozwiązanie: [S02E05](./dotnet/S02E05/Program.cs)\n\nMoje rozwiązanie wykorzystuje:\n\n- Zastosowanie serwisu [Firecrawl](https://www.firecrawl.dev/) do pobrania artykułu jako Markdown\n- Parser markdown do wyodrębniania referencji do plików audio\n- GPT-4o do wygenerowania opisu zdjęć\n- Model Whisper do transkrypcji plików dźwiękowych\n- Cache'owanie opisów zdjęć i transkrypcjach, żeby uniknąć powtarzania tych operacji\n- GPT-4o do odpwiedzi na pytania na podstawie wiedzy z przygotowanego artykułu\n\nCelowo przekonwertowałem artykuł na format Markdown przed przesłaniem go do modelu. Ten format dalej lepsze wyniki niż treść w HTMLu.\n\n## S03E01 — Dokumenty\n\n\u003cimg src=\"./.attachments/Flag_S03E01.png\" width=\"150\" alt=\"Zdobyta flaga zadania S03E01\"\u003e\n\nMoje rozwiązanie: [S03E01](./dotnet/S03E01/Program.cs)\n\n_Opis dodam niedługo_\n\n## S03E02 — Wyszukiwanie Semantyczne\n\n\u003cimg src=\"./.attachments/Flag_S03E02.png\" width=\"150\" alt=\"Zdobyta flaga zadania S03E02\"\u003e\n\nZadanie polegało na wykorzystaniu bazy wektorowej do znalezienia odpowiedniego raportu na podstawie zadanego pytania. Wykorzystałem do tego:\n\n- Bazę wektorową Qdrant uruchomioną lokalnie w kontenerze Docker\n- Model OpenAI text-embedding-3-small do generowania embeddingów\n\nKod rozwiązania: [S03E02](./dotnet/S03E02/Program.cs)\n\nW moim rozwiązaniu:\n\n1. Przygotowałem kolekcję w bazie Qdrant o nazwie \"weapons_tests\"\n2. Wczytałem raporty z testów broni z plików tekstowych\n3. Wygenerowałem embeddingi dla każdego raportu przy pomocy modelu OpenAI\n4. Zapisałem wektory wraz z metadanymi (data raportu) do bazy Qdrant\n5. Dla zadanego pytania wygenerowałem embedding i wykonałem wyszukiwanie wektorów najbardziej podobnych\n\nByło to moje pierwsze doświadczenie z bazami wektorowymi. Szczególnie interesujące było to, jak baza potrafi znajdować semantycznie podobne dokumenty, nawet jeśli nie zawierają dokładnie tych samych słów, co zapytanie.\n\nWygenerowałem wizualizację podobieństwa wektorów w mojej bazie :D\n\n\u003cimg src=\"./.attachments/my-first-quadrant-collecion.png\" alt=\"Wizualizacja podobieństwa wektorów w bazie Qdrant\"\u003e\n\n## S03E05 - Bazy Grafowe\n\n\u003cimg src=\"./.attachments/Flag_S03E05.png\" width=\"150\" alt=\"Zdobyta flaga zadania S03E05\"\u003e\n\nZadanie polegało na znalezieniu najkrótszej ścieżki połączeń między dwoma osobami na podstawie ich znajomości. Należy wykorzystać do tego dowolną bazę grafową.  \nZdecydowałem się użyć Neo4j. Nie miałem wcześniej styczności z bazami grafowymi. Uznałem, że chcę poznać najpopularniejsze rozwiązanie.\n\nZanim zabrałem się za kodowanie przerobiłem podstawowy kurs [Cypher Fundamentals](https://graphacademy.neo4j.com/c/c106d0e3-1a44-4ffc-a322-617ff18a6702/).\nZnając już fundamenty mojej wybranej bazy wziąłem się za rozwiązanie zadana.\n\nMoje rozwiązanie: [S03E05](./dotnet/S03E05/Program.cs)\n\nW implementacji wykorzystałem:\n\n- Neo4j jako bazę grafową uruchomioną lokalnie w kontenerze Docker\n- Oficjalny driver Neo4j dla .NET do komunikacji z bazą\n- Język zapytań Cypher do operacji na grafie\n\nRozwiązanie składało się z następujących kroków:\n\n1. Pobranie danych użytkowników i ich połączeń z zewnętrznego API\n2. Załadowanie danych do bazy Neo4j:\n   - Utworzenie węzłów dla każdego użytkownika (`:User`)\n   - Utworzenie relacji `:KNOWS` między połączonymi użytkownikami\n3. Znalezienie najkrótszej ścieżki między wskazanymi użytkownikami za pomocą zapytania Cypher wykorzystującego algorytm `SHORTEST PATH`\n4. Przekształcenie wyniku do wymaganego formatu i weryfikacja odpowiedzi\n\nZadanie nie było trudne, ale była to moja pierwsza styczność z bazami grafowymi.\nTeraz zdecydowanie lepiej rozumiem, jak z nich korzystać i do rozwiązywania jakiego rodzaju problemów będę mógł je wykorzystać w przyszłosci😄\n\n## S04E02 — Przetwarzanie treści\n\n\u003cimg src=\"./.attachments/Flag_S04E02.png\" width=\"150\" alt=\"Zdobyta flaga zadania S04E02\"\u003e\n\nZadanie polegało na użyciu fine-tuning, do rozpoznawania poprawnych oraz błędnych danych.\nZa pomocą kodu przygotowałem dane w odpowiednim formacie, na podstawie danych źródłowych.\n\nMoje rozwiązanie: [S04E02](./dotnet/S04E02/Program.cs)\n\nW implementacji wykorzystałem:\n\n- Format JSONL do przygotowania danych treningowych\n- Strukturę danych zgodną z wymaganiami OpenAI dla fine-tuningu\n- Podział danych na zbiór treningowy i walidacyjny w proporcji 80% do 20%\n\nProgram przetwarza dwa pliki źródłowe:\n\n- `correct.txt` - zawierający przykłady poprawnych danych (oznaczone jako \"1\")\n- `incorrect.txt` - zawierający przykłady niepoprawnych danych (oznaczone jako \"0\")\n\nKażdy przykład treningowy składa się z trzech wiadomości:\n\n1. System prompt definiujący zadanie\n2. Treść do kategoryzacji\n3. Oczekiwana odpowiedź (0 lub 1)\n\nDo fine-tuningu wybrałem model 4o-mini, z uwagi na niskie koszty.\n\nPo zakończeniu procesu fine-tuning skategoryzwałem dane w Open AI Playground.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristopher-dabrowski%2Fai_devs3-zadania","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchristopher-dabrowski%2Fai_devs3-zadania","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristopher-dabrowski%2Fai_devs3-zadania/lists"}