PHP, Gemini, HTTP 400 i jeden debil — ja

PHP, Gemini, HTTP 400 i jeden debil — ja

Narodziny nowego Zwykolaka: Executive Director of Strategic Mobility & Occupancy Intelligence

Cześć, z tej strony Kuba.

Za mną kilka dość intensywnych dni.

Dużo pracy. Dużo tematów. Dużo rzeczy, które miały być proste, dopóki ktoś ich nie dotknął.

Czyli idealny moment, żeby odpocząć.

Park Południowy.
Ławka przy fontannie.
Laptop.

Tak odpoczywają ninja.

A ponieważ zupełnym przypadkiem pojawił się problem, który można było niepotrzebnie skomplikować, oczywiście postanowiłem się nim zainteresować.

I tak narodził się kolejny Zwykolak.

Executive Director of Strategic Mobility & Occupancy Intelligence.

Brzmi jak stanowisko za 35 tysięcy miesięcznie.

Jego zadaniem jest liczenie samochodów.

Pensja: zero.
Budżet API: około 25 zł.
Prestiż: nieograniczony.

Jak zbudować elektrownię atomową do zasilenia lodówki

Problem był banalny.

Potrzebowaliśmy wiedzieć, ile samochodów stoi na parkingach dużego obiektu rekreacyjnego w różnych dniach i godzinach.

Planowana jest dalsza rozbudowa obiektu, więc dobrze byłoby oprzeć decyzje dotyczące parkingów na czymś trochę bardziej zaawansowanym niż:

„wydaje mi się, że miejsc wystarczy”.

Mamy monitoring.

Trzy kamery obejmujące główne parkingi.

Mamy archiwum.

Normalny człowiek zrobiłby kilka screenshotów, policzył samochody, wpisał wynik do Excela i poszedł dalej.

Tylko że jeżeli taki pomiar trzeba wykonywać regularnie, bardzo szybko powstaje mały dług operacyjny.

Ktoś musi:

robić zdjęcia,
liczyć samochody,
przepisywać dane,
pilnować godzin,
nie pomylić się po drodze.

A my mamy prostą zasadę:

jeżeli coś powtarza się wystarczająco często, warto sprawdzić, czy nie powinien tego robić komputer.

Więc oczywiście zaczęliśmy rozsądnie.

YOLO.

OpenCV.

Tracking.

RTSP.

Automatyczne wykrywanie zajętości parkingu.

Jeszcze chwila i stawialibyśmy Kubernetesa do liczenia zaparkowanych Golfów.

I wtedy padło najważniejsze pytanie w całym projekcie:

Po co?

Najlepsza architektura czasami składa się z mniejszej liczby rzeczy

Nie potrzebowaliśmy danych w czasie rzeczywistym.

Nie potrzebowaliśmy śledzić każdego samochodu.

Nie potrzebowaliśmy analizować strumienia 24 godziny na dobę.

Potrzebowaliśmy odpowiedzi na znacznie prostsze pytanie:

ile samochodów stoi tutaj o konkretnej godzinie?

Trzy parkingi.

Trzy zdjęcia.

Jeden multimodalny model.

I wtedy pojawiło się drugie niebezpieczne zdanie:

„A może podepniemy Gemini?”

Zaraz po:

„to tylko mała poprawka”

jest to jedno z najbardziej ryzykownych zdań w IT.

Ale tym razem miało sens.

PHP, SQLite i absolutny brak technologicznego cosplayu

Stack został celowo nudny.

PHP 8.
JavaScript.
CSS.
SQLite przez PDO.
Gemini REST API przez cURL.

Bez frameworków.

Bez kontenerów.

Bez infrastruktury, której głównym zadaniem byłoby dobrze wyglądać na diagramie architektury.

Zdjęcie trafia do modelu.

Model zwraca ustrukturyzowaną odpowiedź.

PHP ją waliduje.

Dane trafiają do SQLite.

Do tego historia pomiarów, możliwość korekty, statystyki i eksport CSV.

W kolejnym etapie dojdzie automatyczne wykonywanie screenshotów o ustalonych godzinach.

Proste.

Ale skoro już budujemy aplikację, musi też wyglądać jak aplikacja.

Responsywność.

Animacje.

Sensowny frontend.

I oczywiście Zwykolaki.

Tragarz obsługuje upload.

Silky pojawia się podczas liczenia.

Mędrzec pilnuje wyników.

Chronomata zajmuje się czasem.

A Wkurwisław?

Wkurwisław został odpowiedzialny za błędy.

Jak się później okazało, dostał bardzo intensywną zmianę.

HTTP 400

Silnik gotowy.

Baza działa.

Frontend wygląda zdecydowanie lepiej, niż wymaga tego system do liczenia samochodów.

Klikamy:

POLICZ.

HTTP 400.

Wkurwisław pojawia się na ekranie.

“API postanowiło dzisiaj nie współpracować.”

No dobrze.

Klucz?

Sprawdzony.

Billing?

Jest.

Limity?

Są.

Model?

Poprawny.

Endpoint?

Wygląda dobrze.

JSON Schema?

Również.

A aplikacja nadal odpowiada:

INVALID_ARGUMENT

API_KEY_INVALID

Zaczyna się więc klasyka.

Więcej logów.

Lepsza diagnostyka.

Testy endpointów.

Zmiana sposobu wywołania Gemini na generateContent.

Bez zmian.

Jeszcze chwila i do aplikacji liczącej samochody powstałoby drugie środowisko diagnostyczne.

W końcu wróciliśmy do absolutnych podstaw.

Bezpośredni test API.

Czy klucz pobiera listę modeli?

Tak.

Czy generateContent odpowiada?

Tak.

Czy Gemini działa?

Tak.

Czy produkcja działa?

Nie.

No to sprawdzamy odciski kluczy.

Nie zgadzają się.

I wtedy zrobiłem rzecz, którą powinienem zrobić kilka godzin wcześniej.

Przeczytałem własny plik .env.

Wszystko działało idealnie. Niestety.

Zamiast:

GEMINI_API_KEY=…

wkleiłem:

GEMINI_API_KEY=$geminiKey = …

Ctrl+C, ctrl+V z innego projektu, razem z fragmentem deklaracji zmiennej.

PHP poprawnie odczytywał wartość.

cURL poprawnie ją wysyłał.

Google poprawnie ją odrzucał.

Cały system działał dokładnie tak, jak został napisany.

Problem znajdował się pomiędzy klawiaturą a krzesłem.

Usunięcie zbędnego fragmentu.

Klik.

I nagle:

Parking przedni: 125 pojazdów.
Parking boczny A: 19.
Parking boczny B: 8.

Pierwszy automatyczny pomiar.

Weryfikacja ręczna.

Na testowanych materiałach różnica mieściła się w około ±1 samochodzie.

Do analizy zajętości parkingów?

Więcej niż wystarczająco.

DONE.

Najwięcej czasu zaoszczędziło jedno pytanie

Nie PHP.

Nie Gemini.

Nie SQLite.

Najwięcej zaoszczędziło:

Czy naprawdę potrzebujemy tego w czasie rzeczywistym?

Nie potrzebowaliśmy.

I nagle z projektu wyleciały:

ciągły stream RTSP,

tracking,

większa infrastruktura,

utrzymanie modeli CV,

większa ilość danych,

większa liczba potencjalnych awarii.

Zostało:

zdjęcie → model → JSON → baza.

I właśnie to jest jedna z zasad, których pilnujemy w Saku:

Nie budujemy technologii dlatego, że możemy.

No dobra, to nie do końca jest prawda, bo często budujemy zbyt dużo niepotrzebnych elementów bo są fajne.Ale zawsze patrzymy na czas ich budowy. Co innego jest wrzucić CSSa czy panel instalacji (który już mamy zbudowany) a co innego stawiać całą kanapkę niepotrzebnego stosu technologicznego 🙂

Budujemy najmniejsze rozwiązanie, które skutecznie rozwiązuje problem.

Czasami najlepsza decyzja architektoniczna polega na wyrzuceniu 80% architektury.

YOLO i tracking pewnie jeszcze wrócą.

Mamy już drugi problem, przy którym rzeczywiście mają sens: liczenie footfallu.

Ale nie tutaj.

AI to nie sześć prostokątów w prezentacji

Przy takich projektach coraz bardziej bawi mnie dyskusja o „wdrażaniu AI”.

Bo sam model jest często najmniejszą częścią problemu.

Trzeba jeszcze wiedzieć:

jak przesłać dane,

jak dostać odpowiedź,

jak wymusić strukturę,

jak ją zwalidować,

gdzie zapisać wynik,

co zrobić przy błędzie,

jak kontrolować koszty,

jak testować jakość,

jak przechowywać sekrety,

jak wdrożyć rozwiązanie,

i co zrobić, kiedy lokalnie działa, a na produkcji nagle wywala się na ryj.

Menedżer AI nie musi być seniorem backendowcem.

Ale ktoś w procesie musi rozumieć, co dzieje się pod spodem.

Bo automatyzacja nie kończy się na napisaniu promptu.

Prompt to początek.

Dalej jest całe to mało instagramowe:

API, dane, integracje, walidacja, bezpieczeństwo, testy i utrzymanie.

I właśnie dlatego ciągle wracam do jednego zdania:

Wiedza jest prawie za darmo. Droga jest egzekucja.

Dokumentację Gemini można przeczytać.

PHP można nauczyć się z internetu.

SQLite istnieje od lat.

Modele multimodalne są dostępne praktycznie dla każdego.

Ale nadal ktoś musi z tych elementów zrobić działający produkt.

A potem znaleźć błąd.

Nawet jeżeli tym błędem jest własne:

$geminiKey =

wklejone do .env.

Witamy na produkcji, Panie Dyrektorze

Executive Director of Strategic Mobility & Occupancy Intelligence oficjalnie dołącza do Gildii Zwykolaków.

Zakres obowiązków:

  • patrzeć na parking,
  • liczyć samochody,
  • zapisywać wyniki,
  • nie zadawać zbędnych pytań.

Zatrudnienie: bezterminowe.

Wynagrodzenie: zero.

Wydajność: obiecująca.

Frontend: zdecydowanie zbyt dobry jak na zakres obowiązków.

Przełożony: człowiek, który kilka godzin debugował Gemini, zanim przeczytał własny .env.

Czyli standardy organizacyjne zostały zachowane.

In CORE We Trust.

Share this :