mirror of
https://github.com/migatu/astrololo.git
synced 2026-07-14 13:34:38 +00:00
Napraw lokalne środowisko dev: Parquet mixed-types, brak deps, compose
Trzy usterki uniemożliwiające uruchomienie stosu lokalnie: 1. Warstwa danych wykładała się na starcie przy zapisie Parquet dla realnych plików (np. Encyclopaedia of Medical Astrology) — kolumny o mieszanych typach (int+str+NaN). frame_cache.put() zapisuje teraz ramkę jako string (warstwa i tak wyszukuje po tekście). Dodatkowo warmup() jest odporny: pojedynczy uszkodzony plik nie blokuje startu usługi. 2. Brakowało kroku instalacji zależności — dev-logic/dev-presentation padały na 'No module named httpx'. Nowy cel `make install` instaluje zależności WSZYSTKICH warstw do aktywnego venv. README zaktualizowane (instalowało wcześniej tylko warstwę danych). 3. `make up` zakładał `docker compose`, którego użytkownik nie ma. Makefile wykrywa `docker compose` lub `docker-compose`, a przy braku obu podaje czytelną instrukcję trybu lokalnego. Dodano `make test` i `make clean-cache`. Zweryfikowane end-to-end na realnym środowisku (.env, Python 3.14) i danych: warmup przechodzi (3 pliki), cały stos wstaje, formularz → logika → silnik Skyfield zwraca poprawne pozycje. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,31 +1,56 @@
|
||||
.PHONY: help up down sample reindex migrate sql dev-data dev-logic dev-presentation
|
||||
.PHONY: help install up down sample reindex migrate sql test clean-cache \
|
||||
dev-data dev-logic dev-presentation
|
||||
|
||||
# Autodetekcja narzędzia compose: nowe "docker compose" albo stare "docker-compose".
|
||||
COMPOSE := $(shell if docker compose version >/dev/null 2>&1; then echo "docker compose"; \
|
||||
elif command -v docker-compose >/dev/null 2>&1; then echo "docker-compose"; fi)
|
||||
|
||||
# Python aktywnego środowiska (venv). Nadpisz: make install PY=python3.12
|
||||
PY ?= python
|
||||
|
||||
help:
|
||||
@echo "up - uruchom wszystkie 3 warstwy (docker compose)"
|
||||
@echo "down - zatrzymaj"
|
||||
@echo "install - zainstaluj zależności WSZYSTKICH warstw do aktywnego venv"
|
||||
@echo "sample - wygeneruj przykładowe pliki .xlsx"
|
||||
@echo "dev-data - uruchom warstwę danych lokalnie (:8002)"
|
||||
@echo "dev-logic - uruchom warstwę logiczną lokalnie (:8001)"
|
||||
@echo "dev-presentation - uruchom warstwę prezentacji lokalnie (:8000)"
|
||||
@echo "test - testy warstwy logicznej (silnik efemeryd)"
|
||||
@echo "clean-cache - wyczyść regenerowalny cache warstwy danych"
|
||||
@echo "reindex - zbuduj cache + indeks warstwy bazodanowej"
|
||||
@echo "migrate - ETL: Excel -> SQL"
|
||||
@echo "sql - uruchom z warstwą SQL (DATA_PROVIDER=sql)"
|
||||
@echo "dev-* - uruchom pojedynczą warstwę lokalnie (bez dockera)"
|
||||
@echo "up / down - uruchom / zatrzymaj cały stos (Docker; wykryto: $(COMPOSE))"
|
||||
@echo "sql - Docker z warstwą SQL (DATA_PROVIDER=sql)"
|
||||
@echo ""
|
||||
@echo "Szybki start lokalny (bez Dockera), w 3 terminalach:"
|
||||
@echo " make install"
|
||||
@echo " make sample # opcjonalnie: dane przykładowe"
|
||||
@echo " make dev-data # terminal 1"
|
||||
@echo " make dev-logic # terminal 2"
|
||||
@echo " make dev-presentation # terminal 3 -> http://localhost:8000"
|
||||
|
||||
up:
|
||||
docker compose up --build
|
||||
|
||||
down:
|
||||
docker compose down
|
||||
# --- instalacja zależności do aktywnego środowiska ---
|
||||
install:
|
||||
$(PY) -m pip install \
|
||||
-r services/data/requirements.txt \
|
||||
-r services/logic/requirements.txt \
|
||||
-r services/presentation/requirements.txt
|
||||
@echo "OK. Zależności warstw zainstalowane. (Silnik AGPL 'engine-swisseph' instaluje się osobno.)"
|
||||
|
||||
sample:
|
||||
cd services/data && python scripts/make_sample_data.py
|
||||
cd services/data && $(PY) scripts/make_sample_data.py
|
||||
|
||||
reindex:
|
||||
cd services/data && python -m app.ingest.build_index
|
||||
cd services/data && $(PY) -m app.ingest.build_index
|
||||
|
||||
migrate:
|
||||
cd services/data && python -m app.ingest.to_sql
|
||||
cd services/data && $(PY) -m app.ingest.to_sql
|
||||
|
||||
sql:
|
||||
DATA_PROVIDER=sql docker compose up --build
|
||||
test:
|
||||
cd services/logic && PYTHONPATH=. $(PY) -m pytest tests -q
|
||||
|
||||
clean-cache:
|
||||
rm -rf services/data/.cache/* services/logic/.ephemeris/* 2>/dev/null || true
|
||||
@echo "Cache wyczyszczony."
|
||||
|
||||
# --- lokalny dev (3 osobne terminale) ---
|
||||
dev-data:
|
||||
@@ -36,3 +61,20 @@ dev-logic:
|
||||
|
||||
dev-presentation:
|
||||
cd services/presentation && LOGIC_URL=http://localhost:8001 uvicorn app.main:app --reload --port 8000
|
||||
|
||||
# --- Docker (opcjonalnie) ---
|
||||
up:
|
||||
@if [ -z "$(COMPOSE)" ]; then \
|
||||
echo "Nie znaleziono Docker Compose (ani 'docker compose', ani 'docker-compose')."; \
|
||||
echo "Użyj trybu lokalnego: make install, potem dev-data / dev-logic / dev-presentation."; \
|
||||
exit 1; \
|
||||
fi
|
||||
$(COMPOSE) up --build
|
||||
|
||||
down:
|
||||
@if [ -z "$(COMPOSE)" ]; then echo "Brak Docker Compose."; exit 1; fi
|
||||
$(COMPOSE) down
|
||||
|
||||
sql:
|
||||
@if [ -z "$(COMPOSE)" ]; then echo "Brak Docker Compose."; exit 1; fi
|
||||
DATA_PROVIDER=sql $(COMPOSE) up --build
|
||||
|
||||
@@ -28,13 +28,20 @@ make up # zbuduj i uruchom 3 warstwy
|
||||
# otwórz http://localhost:8000
|
||||
```
|
||||
|
||||
## Szybki start (lokalnie, 3 terminale)
|
||||
## Szybki start (lokalnie, bez Dockera — zalecane)
|
||||
```bash
|
||||
python -m venv .env && source .env/bin/activate # venv (jednorazowo)
|
||||
make install # zależności WSZYSTKICH warstw
|
||||
make sample # opcjonalnie: dane przykładowe
|
||||
```
|
||||
Potem w 3 osobnych terminalach (w każdym `source .env/bin/activate`):
|
||||
```bash
|
||||
cd services/data && pip install -r requirements.txt && python scripts/make_sample_data.py
|
||||
make dev-data # terminal 1 -> :8002
|
||||
make dev-logic # terminal 2 -> :8001
|
||||
make dev-presentation # terminal 3 -> :8000
|
||||
make dev-presentation # terminal 3 -> :8000 -> http://localhost:8000
|
||||
```
|
||||
> `make install` instaluje zależności wszystkich trzech warstw do aktywnego venv.
|
||||
> Testy silnika: `make test`. Wyczyszczenie cache: `make clean-cache`.
|
||||
|
||||
## Modułowość — dowód
|
||||
- Wymień prezentację (np. na SPA/React) → reszta bez zmian, kontrakt `/api/query` stały.
|
||||
|
||||
+7
-2
@@ -31,5 +31,10 @@ class FrameCache:
|
||||
return None
|
||||
|
||||
def put(self, fp: str, sheet: str, frame: pd.DataFrame) -> None:
|
||||
# astype(str) na kolumnach object zapewnia stabilny zapis Parquet
|
||||
frame.to_parquet(self._path(fp, sheet), index=False)
|
||||
# Kolumny z heterogenicznych plików Excela bywają mieszane (int + str +
|
||||
# NaN w jednej kolumnie) — pyarrow tego nie zapisze. Warstwa danych i tak
|
||||
# operuje na tekście (wyszukiwanie po .astype(str)), więc zapisujemy ramkę
|
||||
# jako string (brak wartości -> pusty tekst). Gwarantuje to stabilny zapis
|
||||
# Parquet niezależnie od zawartości pliku źródłowego.
|
||||
safe = frame.astype("string").fillna("")
|
||||
safe.to_parquet(self._path(fp, sheet), index=False)
|
||||
|
||||
@@ -82,7 +82,10 @@ class ExcelDataProvider(DataProvider):
|
||||
|
||||
def warmup(self) -> None:
|
||||
for path in self._excel_files():
|
||||
try:
|
||||
self._ensure_indexed(path)
|
||||
except Exception as e: # jeden uszkodzony plik nie może zablokować startu
|
||||
print(f"[data] pominięto plik przy indeksowaniu: {path} — {e}")
|
||||
|
||||
def _excel_files(self) -> list[str]:
|
||||
base = Path(self.s.excel_dir)
|
||||
|
||||
Reference in New Issue
Block a user