-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMakefile
More file actions
248 lines (195 loc) · 11.9 KB
/
Copy pathMakefile
File metadata and controls
248 lines (195 loc) · 11.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
SHELL := /bin/bash
# `ENV_FILE` is the docker-compose env file all targets read by default.
# Override on the command line: `make ENV_FILE=.env.production up-host-ollama`
ENV_FILE ?= .env.local
COMPOSE := docker compose --env-file $(ENV_FILE)
# Profili compose opzionali extra (es. web). Uso: `make up PROFILES="web"`.
PROFILES ?=
_PROFILE_FLAGS := $(foreach p,$(PROFILES),--profile $(p))
# Overpass self-hosted: OPT-IN, NON avviato di default. Le lenti OSM usano il mirror
# remoto (OVERPASS_URL, default FR/CH) che funziona ovunque. Accendi il self-hosted con
# `make up OVERPASS=1` o, separatamente, `make overpass-up`.
# Pesante: ~25-50GB di disco e init ~1-2h alla PRIMA accensione (download .pbf Italia +
# build del DB) e richiede accesso di rete a Geofabrik. Vedi infra/overpass/README.md.
OVERPASS ?= 0
ifeq ($(OVERPASS),1)
_OVERPASS_PROFILE := --profile overpass
_OVERPASS_SVC := overpass
endif
# Baked Ollama model. Default qwen2.5:32b → qwen2.5:32k (num_ctx 16384,
# temperature 0) for best faithfulness on a 48GB Apple-Silicon box; override
# e.g. `make build-ollama OLLAMA_BASE_MODEL=qwen2.5:14b OLLAMA_MODEL=qwen2.5:14k`.
OLLAMA_BASE_MODEL ?= qwen2.5:32b
OLLAMA_NUM_CTX ?= 16384
OLLAMA_TEMPERATURE ?= 0
OLLAMA_MODEL ?= qwen2.5:32k
OLLAMA_IMAGE ?= ghcr.io/agent-engineering-studio/opendata-ai-ollama:latest
# Custom-built compose services (skip the Ollama service — it uses a pre-built image
# managed by `make build-ollama` / `make pull-models`, not by `docker compose build`).
CUSTOM_SERVICES := ckan-mcp istat-mcp opencoesione-mcp ispra-mcp osm-mcp web-mcp maturity-mcp opendata-backend opendata-ai-ui
# `make agent` launches the unified backend REPL against the running stack.
SOURCE ?= backend
COMPOSE_PROJECT ?= opendata-ai
.DEFAULT_GOAL := help
# ──────────────────────────── Helpers ────────────────────────────
.PHONY: help
help: ## Show this help
@awk 'BEGIN {FS = ":.*##"; printf "\nTargets:\n"} /^[a-zA-Z0-9_.-]+:.*?##/ { printf " \033[36m%-22s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST)
# ──────────────────────────── Local stack ────────────────────────
.PHONY: up up-cpu up-gpu up-host-ollama up-claude up-ollama-cloud
up: up-cpu ## Start the stack (CPU profile — default)
up-cpu: ## Start the stack with CPU-only Ollama (Dockerized)
$(COMPOSE) --profile cpu $(_OVERPASS_PROFILE) $(_PROFILE_FLAGS) up -d
up-gpu: ## Start the stack with GPU-enabled Ollama (Linux + NVIDIA only)
$(COMPOSE) --profile gpu $(_OVERPASS_PROFILE) $(_PROFILE_FLAGS) up -d
up-host-ollama: ## Start the stack against a host-installed Ollama (NO Docker Ollama). Best on macOS for Metal GPU.
@if ! curl -fsS http://localhost:11434/api/tags >/dev/null 2>&1; then \
echo "⚠️ Host Ollama not reachable at http://localhost:11434 — start it with: ollama serve &"; \
exit 1; \
fi
@echo "✅ Host Ollama reachable. Bringing up stack with LLM_PROVIDER=ollama (no Docker Ollama)…"
@echo "ℹ️ LLM_PROVIDER=ollama vale ovunque: sintesi, classify, semantic-maturità,"
@echo " narrative e use case girano tutti su Ollama. Nessuna chiamata ad Anthropic."
@echo "ℹ️ Overpass self-hosted incluso: OVERPASS_URL → http://overpass/api/interpreter"
@echo " (backend + osm-mcp), fallback al mirror FR. PRIMA accensione lunga"
@echo " (~1-2h, ~25-50GB disco): le lenti OSM usano il fallback finché il DB non è pronto."
OVERPASS_URL=$${OVERPASS_URL:-http://overpass/api/interpreter} \
OVERPASS_FALLBACK_URLS=$${OVERPASS_FALLBACK_URLS:-https://overpass.openstreetmap.fr/api/interpreter} \
LLM_PROVIDER=ollama $(COMPOSE) up -d $(CUSTOM_SERVICES) overpass
up-claude: ## Start the stack with LLM_PROVIDER=claude (no Ollama). Requires ANTHROPIC_API_KEY in $(ENV_FILE).
@if ! grep -qE '^ANTHROPIC_API_KEY=.+' $(ENV_FILE); then \
echo "⚠️ ANTHROPIC_API_KEY not set in $(ENV_FILE) — Claude provider needs it."; \
exit 1; \
fi
@echo "✅ Using Claude as LLM provider. Bringing up stack without the Ollama container…"
LLM_PROVIDER=claude $(COMPOSE) up -d $(CUSTOM_SERVICES) $(_OVERPASS_SVC)
up-ollama-cloud: ## Start the stack with LLM_PROVIDER=ollama_cloud (hosted, no local Ollama). Requires OLLAMA_CLOUD_API_KEY in $(ENV_FILE).
@if ! grep -qE '^OLLAMA_CLOUD_API_KEY=.+' $(ENV_FILE); then \
echo "⚠️ OLLAMA_CLOUD_API_KEY not set in $(ENV_FILE) — the ollama_cloud provider needs it."; \
exit 1; \
fi
@echo "✅ Using Ollama Cloud as LLM provider. Bringing up stack without the local Ollama container…"
LLM_PROVIDER=ollama_cloud $(COMPOSE) up -d $(CUSTOM_SERVICES) $(_OVERPASS_SVC)
.PHONY: down logs ps overpass-up overpass-logs
down: ## Stop the stack
$(COMPOSE) --profile cpu --profile gpu --profile overpass --profile web down
logs: ## Tail logs for all services
$(COMPOSE) logs -f --tail=100
ps: ## Show service status
$(COMPOSE) ps
overpass-up: ## Avvia (o aggiorna) solo l'istanza Overpass self-hosted
$(COMPOSE) --profile overpass up -d overpass
overpass-logs: ## Segui i log di Overpass (utile durante l'init iniziale ~1-2h)
$(COMPOSE) --profile overpass logs -f overpass
.PHONY: build-ollama
build-ollama: ## Build the Ollama image with $(OLLAMA_MODEL) baked in (local, ~7 GB)
docker build \
--build-arg BASE_MODEL=$(OLLAMA_BASE_MODEL) \
--build-arg NUM_CTX=$(OLLAMA_NUM_CTX) \
--build-arg MODEL_TAG=$(OLLAMA_MODEL) \
--build-arg TEMPERATURE=$(OLLAMA_TEMPERATURE) \
-t $(OLLAMA_IMAGE) \
infra/ollama
.PHONY: pull-models
pull-models: ## Fallback: pull model directly into a running opendata-ai-ollama container (no prebuild image)
@echo "Pulling base model $(OLLAMA_BASE_MODEL)..."
docker exec opendata-ai-ollama ollama pull $(OLLAMA_BASE_MODEL)
@echo "Creating $(OLLAMA_MODEL) with num_ctx=$(OLLAMA_NUM_CTX) temperature=$(OLLAMA_TEMPERATURE)..."
docker exec opendata-ai-ollama bash -c 'printf "FROM $(OLLAMA_BASE_MODEL)\nPARAMETER num_ctx $(OLLAMA_NUM_CTX)\nPARAMETER temperature $(OLLAMA_TEMPERATURE)\n" > /tmp/Modelfile && ollama create $(OLLAMA_MODEL) -f /tmp/Modelfile'
@echo "Done — model $(OLLAMA_MODEL) ready with context $(OLLAMA_NUM_CTX), temperature $(OLLAMA_TEMPERATURE)"
.PHONY: build build-svc rebuild rebuild-all
build: ## Build all custom images (mcp servers + agents + orchestrator + UI), reusing cache
$(COMPOSE) build $(CUSTOM_SERVICES)
build-svc: ## Build a single service — usage: make build-svc SVC=istat-mcp
@if [ -z "$(SVC)" ]; then echo "usage: make build-svc SVC=<service-name> (one of: $(CUSTOM_SERVICES))" >&2; exit 2; fi
$(COMPOSE) build $(SVC)
rebuild: ## Rebuild all custom images (mcp servers + agents + orchestrator + UI) WITHOUT cache
$(COMPOSE) build --no-cache $(CUSTOM_SERVICES)
rebuild-all: build-ollama rebuild ## Rebuild ALL images: Ollama (baked model, ~7 GB) + every custom image (no cache)
.PHONY: refresh-ollama refresh-gpu refresh-cpu
refresh: rebuild down
@echo "Stack refreshed with CPU-only Ollama and rebuilt images"
refresh-gpu: refresh up-gpu
@echo "Stack refreshed with GPU-enabled Ollama and rebuilt images"
refresh-ollama: build-ollama refresh-gpu
@echo "Ollama image rebuilt with model $(OLLAMA_MODEL) and context $(OLLAMA_NUM_CTX), stack refreshed with GPU profile"
refresh-cpu: refresh up
@echo "Stack refreshed with CPU-only Ollama and rebuilt images"
# ──────────────────────────── Interactive ────────────────────────
.PHONY: agent agent-backend
agent: agent-$(SOURCE) ## Interactive REPL against the running stack
agent-backend: ## Launch the unified backend REPL against the running stack
docker run --rm -it --network $(COMPOSE_PROJECT)_default \
-e LLM_PROVIDER=ollama \
-e OLLAMA_BASE_URL=http://opendata-ai-ollama:11434 \
-e OLLAMA_LLM_MODEL=$(OLLAMA_MODEL) \
-e CKAN_MCP_URL=http://ckan-mcp:8080/mcp \
-e ISTAT_MCP_URL=http://istat-mcp:8081/mcp \
-e OSM_MCP_URL=http://osm-mcp:8080/mcp \
opendata-backend:local opendata-agent
.PHONY: mcp-stdio-ckan mcp-stdio-istat mcp-stdio-osm mcp-stdio-opencoesione mcp-stdio-openpnrr mcp-stdio-centriditalia mcp-stdio-opendata mcp-stdio-ispra mcp-stdio-web mcp-stdio-maturity mcp-stdio-ods mcp-stdio-socrata mcp-stdio-bdap
mcp-stdio-ckan: ## Smoke-test the CKAN MCP server over stdio (one tools/list round-trip)
@echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| docker run --rm -i -e TRANSPORT=stdio ckan-mcp-server:local
mcp-stdio-ods: ## Smoke-test the OpenDataSoft MCP server over stdio
@echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| docker run --rm -i -e TRANSPORT=stdio ods-mcp-server:local
mcp-stdio-socrata: ## Smoke-test the Socrata MCP server over stdio
@echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| docker run --rm -i -e TRANSPORT=stdio socrata-mcp-server:local
mcp-stdio-bdap: ## Smoke-test the BDAP MCP server over stdio
@echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| docker run --rm -i -e TRANSPORT=stdio bdap-mcp-server:local
mcp-stdio-maturity: ## Smoke-test the Maturity MCP server over stdio
@echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| docker run --rm -i -e TRANSPORT=stdio maturity-mcp-server:local
mcp-stdio-istat: ## Smoke-test the ISTAT MCP server over stdio
@echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| docker run --rm -i -e TRANSPORT=stdio istat-mcp-server:local
mcp-stdio-opencoesione: ## Smoke-test the OpenCoesione MCP server over stdio
@echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| docker run --rm -i -e TRANSPORT=stdio opencoesione-mcp-server:local
mcp-stdio-openpnrr: ## Smoke-test the OpenPNRR MCP server over stdio
@echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| docker run --rm -i -e TRANSPORT=stdio openpnrr-mcp-server:local
mcp-stdio-centriditalia: ## Smoke-test the Centri d'Italia MCP server over stdio
@echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| docker run --rm -i -e TRANSPORT=stdio centriditalia-mcp-server:local
mcp-stdio-opendata: ## Smoke-test the product MCP server (Esplora/Territorio/Maturità/Qualità)
@echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| docker run --rm -i -e TRANSPORT=stdio opendata-mcp-server:local
mcp-stdio-ispra: ## Smoke-test the ISPRA MCP server over stdio
@echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| docker run --rm -i -e TRANSPORT=stdio ispra-mcp-server:local
mcp-stdio-web: ## Smoke-test the Web (SearXNG) MCP server over stdio
@echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| docker run --rm -i -e TRANSPORT=stdio web-mcp:local
.PHONY: oc-sync
oc-sync: ## Ingest the OpenCoesione bulk into Postgres (vars: OC_SYNC_ARGS="--regione PUG --ciclo 2014-2020")
docker compose exec opendata-backend opendata-opencoesione-sync $(OC_SYNC_ARGS)
.PHONY: comuni-sync
comuni-sync: ## Popola l'anagrafica comuni (peer group della modalità idee)
docker compose exec opendata-backend opendata-comuni-sync
mcp-stdio-osm: ## Smoke-test the OSM MCP server over stdio
@echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| docker run --rm -i -e MCP_TRANSPORT=stdio osm-mcp:local
# ──────────────────────────── Dev tasks ──────────────────────────
.PHONY: lint test
lint: ## Run ruff on all Python packages
cd opendata_core && ruff check src
cd ckan-mcp-server && ruff check src
cd istat-mcp-server && ruff check src
cd opencoesione-mcp-server && ruff check src
cd ispra-mcp-server && ruff check src
cd osm-mcp && ruff check src
cd web-mcp && ruff check src
cd opendata-backend && ruff check src
test: ## Run pytest on all Python packages
cd opendata_core && pytest -q
cd ckan-mcp-server && pytest -q
cd istat-mcp-server && pytest -q
cd opencoesione-mcp-server && pytest -q
cd ispra-mcp-server && pytest -q
cd osm-mcp && pytest -q
cd web-mcp && pytest -q
cd opendata-backend && pytest -q