From 795a15a7b608ac47d4c3835c012b435d4f0aef34 Mon Sep 17 00:00:00 2001 From: daniele Date: Sun, 23 Aug 2026 12:04:16 +0200 Subject: [PATCH] Backup automatico script del 2026-08-23 12:04 --- scripts/pi2-backup/auto-git-backup.sh | 8 + services/loogle-mcp/.env.example | 81 ++ services/loogle-mcp/.gitignore | 4 + services/loogle-mcp/Dockerfile | 24 + services/loogle-mcp/README.md | 23 + services/loogle-mcp/app/__init__.py | 0 services/loogle-mcp/app/audit.py | 34 + services/loogle-mcp/app/auth.py | 146 +++ services/loogle-mcp/app/context/__init__.py | 0 services/loogle-mcp/app/context/gitea_link.py | 154 +++ services/loogle-mcp/app/context/store.py | 252 +++++ services/loogle-mcp/app/db.py | 118 +++ .../loogle-mcp/app/integrations/__init__.py | 2 + services/loogle-mcp/app/integrations/casa.py | 75 ++ .../app/integrations/homeassistant.py | 71 ++ .../app/integrations/irrigazione.py | 78 ++ .../app/integrations/session_client.py | 122 +++ services/loogle-mcp/app/integrations/turni.py | 208 ++++ services/loogle-mcp/app/jwt_utils.py | 136 +++ services/loogle-mcp/app/knowledge/__init__.py | 0 .../loogle-mcp/app/knowledge/apps_indexer.py | 295 ++++++ .../loogle-mcp/app/knowledge/embeddings.py | 87 ++ services/loogle-mcp/app/knowledge/gitea.py | 495 +++++++++ .../loogle-mcp/app/knowledge/gitea_indexer.py | 369 +++++++ services/loogle-mcp/app/knowledge/indexer.py | 156 +++ .../loogle-mcp/app/knowledge/paperless.py | 140 +++ .../loogle-mcp/app/knowledge/qdrant_store.py | 251 +++++ .../loogle-mcp/app/knowledge/text_chunk.py | 22 + services/loogle-mcp/app/knowledge/thermal.py | 242 +++++ services/loogle-mcp/app/main.py | 368 +++++++ services/loogle-mcp/app/mcp/__init__.py | 0 services/loogle-mcp/app/mcp/server.py | 78 ++ services/loogle-mcp/app/mcp/tools.py | 962 ++++++++++++++++++ services/loogle-mcp/app/oauth.py | 322 ++++++ services/loogle-mcp/app/static/dashboard.html | 129 +++ services/loogle-mcp/docker-compose.yml | 63 ++ services/loogle-mcp/docs/APPS-INTEGRATION.md | 91 ++ services/loogle-mcp/docs/ARCHITETTURA.md | 297 ++++++ services/loogle-mcp/docs/GITEA-TOKEN.md | 209 ++++ services/loogle-mcp/docs/GUIDA-ADMIN.md | 190 ++++ .../docs/GUIDA-PAPERLESS-FAMIGLIA.md | 237 +++++ services/loogle-mcp/docs/GUIDA-UTENTI.md | 289 ++++++ services/loogle-mcp/docs/ONBOARDING.md | 157 +++ services/loogle-mcp/docs/PAPERLESS-TOKEN.md | 108 ++ .../docs/pdf/GUIDA-PAPERLESS-FAMIGLIA.pdf | Bin 0 -> 202948 bytes services/loogle-mcp/docs/pdf/GUIDA-UTENTI.pdf | Bin 0 -> 161980 bytes services/loogle-mcp/docs/pdf/ONBOARDING.pdf | Bin 0 -> 126179 bytes services/loogle-mcp/requirements.txt | 9 + services/loogle-mcp/scripts/deploy.sh | 15 + .../loogle-mcp/scripts/docker-entrypoint.sh | 13 + .../loogle-mcp/scripts/ds920_thermal_probe.py | 70 ++ .../scripts/grant_family_paperless.py | 94 ++ .../scripts/run_gitea_index_once.py | 68 ++ .../loogle-mcp/scripts/seed_demo_projects.py | 26 + .../scripts/setup_gitea_p4_repos.py | 96 ++ .../scripts/test_gitea_integration.py | 258 +++++ services/loogle-mcp/scripts/test_gitea_p4.py | 111 ++ .../loogle-mcp/scripts/test_gitea_rag_p3.py | 130 +++ services/loogle-mcp/scripts/test_p5_home.py | 70 ++ services/loogle-mcp/scripts/test_p6_apps.py | 74 ++ .../loogle-mcp/scripts/test_p7_apps_rag.py | 83 ++ services/loogle-mcp/scripts/test_p7_step.py | 25 + .../scripts/test_project_gitea_p2.py | 154 +++ .../loogle-mcp/scripts/verify_p3_container.py | 37 + .../scripts/verify_p3_search_only.py | 34 + services/loogle-mcp/worker/indexer_main.py | 86 ++ 66 files changed, 8546 insertions(+) create mode 100644 services/loogle-mcp/.env.example create mode 100644 services/loogle-mcp/.gitignore create mode 100644 services/loogle-mcp/Dockerfile create mode 100644 services/loogle-mcp/README.md create mode 100644 services/loogle-mcp/app/__init__.py create mode 100644 services/loogle-mcp/app/audit.py create mode 100644 services/loogle-mcp/app/auth.py create mode 100644 services/loogle-mcp/app/context/__init__.py create mode 100644 services/loogle-mcp/app/context/gitea_link.py create mode 100644 services/loogle-mcp/app/context/store.py create mode 100644 services/loogle-mcp/app/db.py create mode 100644 services/loogle-mcp/app/integrations/__init__.py create mode 100644 services/loogle-mcp/app/integrations/casa.py create mode 100644 services/loogle-mcp/app/integrations/homeassistant.py create mode 100644 services/loogle-mcp/app/integrations/irrigazione.py create mode 100644 services/loogle-mcp/app/integrations/session_client.py create mode 100644 services/loogle-mcp/app/integrations/turni.py create mode 100644 services/loogle-mcp/app/jwt_utils.py create mode 100644 services/loogle-mcp/app/knowledge/__init__.py create mode 100644 services/loogle-mcp/app/knowledge/apps_indexer.py create mode 100644 services/loogle-mcp/app/knowledge/embeddings.py create mode 100644 services/loogle-mcp/app/knowledge/gitea.py create mode 100644 services/loogle-mcp/app/knowledge/gitea_indexer.py create mode 100644 services/loogle-mcp/app/knowledge/indexer.py create mode 100644 services/loogle-mcp/app/knowledge/paperless.py create mode 100644 services/loogle-mcp/app/knowledge/qdrant_store.py create mode 100644 services/loogle-mcp/app/knowledge/text_chunk.py create mode 100644 services/loogle-mcp/app/knowledge/thermal.py create mode 100644 services/loogle-mcp/app/main.py create mode 100644 services/loogle-mcp/app/mcp/__init__.py create mode 100644 services/loogle-mcp/app/mcp/server.py create mode 100644 services/loogle-mcp/app/mcp/tools.py create mode 100644 services/loogle-mcp/app/oauth.py create mode 100644 services/loogle-mcp/app/static/dashboard.html create mode 100644 services/loogle-mcp/docker-compose.yml create mode 100644 services/loogle-mcp/docs/APPS-INTEGRATION.md create mode 100644 services/loogle-mcp/docs/ARCHITETTURA.md create mode 100644 services/loogle-mcp/docs/GITEA-TOKEN.md create mode 100644 services/loogle-mcp/docs/GUIDA-ADMIN.md create mode 100644 services/loogle-mcp/docs/GUIDA-PAPERLESS-FAMIGLIA.md create mode 100644 services/loogle-mcp/docs/GUIDA-UTENTI.md create mode 100644 services/loogle-mcp/docs/ONBOARDING.md create mode 100644 services/loogle-mcp/docs/PAPERLESS-TOKEN.md create mode 100644 services/loogle-mcp/docs/pdf/GUIDA-PAPERLESS-FAMIGLIA.pdf create mode 100644 services/loogle-mcp/docs/pdf/GUIDA-UTENTI.pdf create mode 100644 services/loogle-mcp/docs/pdf/ONBOARDING.pdf create mode 100644 services/loogle-mcp/requirements.txt create mode 100755 services/loogle-mcp/scripts/deploy.sh create mode 100644 services/loogle-mcp/scripts/docker-entrypoint.sh create mode 100644 services/loogle-mcp/scripts/ds920_thermal_probe.py create mode 100644 services/loogle-mcp/scripts/grant_family_paperless.py create mode 100644 services/loogle-mcp/scripts/run_gitea_index_once.py create mode 100644 services/loogle-mcp/scripts/seed_demo_projects.py create mode 100644 services/loogle-mcp/scripts/setup_gitea_p4_repos.py create mode 100755 services/loogle-mcp/scripts/test_gitea_integration.py create mode 100644 services/loogle-mcp/scripts/test_gitea_p4.py create mode 100755 services/loogle-mcp/scripts/test_gitea_rag_p3.py create mode 100644 services/loogle-mcp/scripts/test_p5_home.py create mode 100644 services/loogle-mcp/scripts/test_p6_apps.py create mode 100644 services/loogle-mcp/scripts/test_p7_apps_rag.py create mode 100644 services/loogle-mcp/scripts/test_p7_step.py create mode 100755 services/loogle-mcp/scripts/test_project_gitea_p2.py create mode 100644 services/loogle-mcp/scripts/verify_p3_container.py create mode 100644 services/loogle-mcp/scripts/verify_p3_search_only.py create mode 100644 services/loogle-mcp/worker/indexer_main.py diff --git a/scripts/pi2-backup/auto-git-backup.sh b/scripts/pi2-backup/auto-git-backup.sh index 15087e4..327131c 100755 --- a/scripts/pi2-backup/auto-git-backup.sh +++ b/scripts/pi2-backup/auto-git-backup.sh @@ -86,6 +86,14 @@ else echo "⚠️ Impossibile scaricare Keepalived conf da Pi1." fi +# D. Sorgente Loogle MCP (app completa: qui vive solo su Pi1, fuori da git) +# .env resta escluso: contiene JWT secret e token Paperless/Gitea/OpenAI. +mkdir -p "$REPO_DIR/services/loogle-mcp" +rsync -av --delete -e "ssh -q" \ + --exclude='.env' --exclude='data/' --exclude='__pycache__/' --exclude='*.pyc' --exclude='.cursor/' \ + "$PI1_USER@$PI1_IP:/home/daniely/docker/loogle-mcp/" "$REPO_DIR/services/loogle-mcp/" \ + || echo "⚠️ rsync sorgente MCP fallito (ignorato)" + # 4. GIT PUSH # ----------- if [[ -n $(git status --porcelain) ]]; then diff --git a/services/loogle-mcp/.env.example b/services/loogle-mcp/.env.example new file mode 100644 index 0000000..4cd98cb --- /dev/null +++ b/services/loogle-mcp/.env.example @@ -0,0 +1,81 @@ +# Loogle MCP Hub — copia in .env e personalizza +MCP_BASE_URL=https://mcp.loogle.it +MCP_PORT=8700 +MCP_JWT_SECRET=change-me-to-a-long-random-string +MCP_OAUTH_CLIENT_ID=loogle-mcp-public + +# Paperless API — vedi docs/PAPERLESS-TOKEN.md +PAPERLESS_URL=https://docs.loogle.it +# Fallback admin (opzionale se usi token per utente sotto) +PAPERLESS_API_TOKEN= +PAPERLESS_API_TOKEN_DANIELE= +PAPERLESS_API_TOKEN_LUCIA= +PAPERLESS_API_TOKEN_DAVIDE= +PAPERLESS_API_TOKEN_LUCA= + +# Gitea API — vedi docs/GITEA-TOKEN.md +GITEA_URL=https://git.loogle.it +# Opzionale: URL API raggiungibile dal container MCP (es. http://192.168.128.81:3002) +# GITEA_API_URL= +GITEA_API_TOKEN= +GITEA_API_TOKEN_DANIELE= +GITEA_API_TOKEN_LUCIA= +GITEA_API_TOKEN_DAVIDE= +GITEA_API_TOKEN_LUCA= + +# Qdrant (container locale o remoto) +QDRANT_URL=http://192.168.128.100:6333 + +# Embedding via Ollama su DS920+ +OLLAMA_URL=http://192.168.128.100:11434 +OLLAMA_EMBED_MODEL=nomic-embed-text + +# Fallback cloud embedding (opzionale) +OPENAI_API_KEY= +OPENAI_EMBED_MODEL=text-embedding-3-small + +# Indicizzazione +INDEXER_INTERVAL_MINUTES=30 + +# Thermal gate DS920 — evita overheating durante embedding +THERMAL_GATE_ENABLED=yes +THERMAL_TEMP_SOFT_C=58 +THERMAL_TEMP_HARD_C=70 +THERMAL_CPU_TARGET_PCT=40 +THERMAL_POLL_S=30 +THERMAL_RESUME_MARGIN_C=2 +DS920_THERMAL_URL=http://192.168.128.100:9191/thermal +OLLAMA_NUM_THREAD=1 +OLLAMA_EMBED_DELAY_S=10 +OLLAMA_EMBED_COOL_DELAY_S=3 + +# RAG Gitea (P3) — indicizza markdown/codice da git.loogle.it +GITEA_INDEX_ENABLED=yes +# Opzionale: limita repo per utente (CSV). Vuoto = tutti i repo accessibili via API +# GITEA_INDEX_REPOS_DANIELE=daniele/rete,daniele/loogle-scripts +# GITEA_INDEX_REPOS_DAVIDE=davide/progetti +# GITEA_INDEX_REPOS_LUCA=luca/progetti +GITEA_INDEX_MAX_FILES_PER_REPO=150 +GITEA_INDEX_MAX_FILE_BYTES=120000 + +# P5 — Loogle Casa + Home Assistant (read-only) +LOOGLE_CASA_URL=https://casa.loogle.it +# LOOGLE_CASA_API_URL=http://192.168.128.81:5602 +LOOGLE_CASA_PASSWORD_DANIELE= +LOOGLE_CASA_PASSWORD_LUCIA= +LOOGLE_CASA_PASSWORD_DAVIDE= +LOOGLE_CASA_PASSWORD_LUCA= +HA_URL=https://ha.loogle.it +# HA_API_URL=http://192.168.128.81:8123 +HA_TOKEN= + +# P6 — Irrigazione + Turni (read-only) +IRRIGAZIONE_URL=https://irri.loogle.it +# IRRIGAZIONE_API_URL=http://192.168.128.81:5601 +IRRIGAZIONE_PASSWORD_DANIELE= +TURNI_URL=https://turni.loogle.it +TURNI_PASSWORD_DANIELE= + +# P7 — RAG Irrigazione + Turni +APPS_INDEX_ENABLED=yes +APPS_INDEX_USER=daniele diff --git a/services/loogle-mcp/.gitignore b/services/loogle-mcp/.gitignore new file mode 100644 index 0000000..5b70d24 --- /dev/null +++ b/services/loogle-mcp/.gitignore @@ -0,0 +1,4 @@ +data/ +.env +*.pyc +__pycache__/ diff --git a/services/loogle-mcp/Dockerfile b/services/loogle-mcp/Dockerfile new file mode 100644 index 0000000..a2b0f19 --- /dev/null +++ b/services/loogle-mcp/Dockerfile @@ -0,0 +1,24 @@ +FROM python:3.12-slim + +ENV PYTHONUNBUFFERED=1 TZ=Europe/Rome + +RUN apt-get update && apt-get install -y --no-install-recommends curl openssh-client \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /srv + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY app ./app +COPY worker ./worker +COPY scripts ./scripts +COPY scripts/docker-entrypoint.sh /docker-entrypoint.sh +RUN chmod +x /docker-entrypoint.sh + +ENV PYTHONPATH=/srv +VOLUME /data +EXPOSE 8700 + +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8700"] diff --git a/services/loogle-mcp/README.md b/services/loogle-mcp/README.md new file mode 100644 index 0000000..66ee122 --- /dev/null +++ b/services/loogle-mcp/README.md @@ -0,0 +1,23 @@ +# Loogle MCP Hub + +Piattaforma MCP multi-utente per homelab LOOGLE.IT. + +## Documentazione + +| Documento | Per chi | +|-----------|---------| +| [ARCHITETTURA.md](docs/ARCHITETTURA.md) | Architettura, parametri, DNS, NPM, env | +| [GUIDA-ADMIN.md](docs/GUIDA-ADMIN.md) | Daniele — gestione e uso avanzato | +| [GUIDA-UTENTI.md](docs/GUIDA-UTENTI.md) | Lucia, Davide, Luca — client AI e uso quotidiano | +| [ONBOARDING.md](docs/ONBOARDING.md) | Dettaglio tecnico connector MCP | + +## URL + +- MCP: https://mcp.loogle.it/mcp +- Dashboard: https://mcp.loogle.it/dashboard + +## Setup DNS + NPM + +```bash +sudo /home/daniely/rete/scripts/setup-mcp-dns-npm.sh +``` diff --git a/services/loogle-mcp/app/__init__.py b/services/loogle-mcp/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/services/loogle-mcp/app/audit.py b/services/loogle-mcp/app/audit.py new file mode 100644 index 0000000..6fd55da --- /dev/null +++ b/services/loogle-mcp/app/audit.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +"""Audit log for MCP tool invocations.""" + +import json +from typing import Optional + +from .db import get_conn + + +def log_tool(username: str, tool_name: str, resource_id: Optional[str] = None, detail: Optional[dict] = None) -> None: + conn = get_conn() + conn.execute( + "INSERT INTO audit_log(username,tool_name,resource_id,detail) VALUES (?,?,?,?)", + (username, tool_name, resource_id, json.dumps(detail or {}, ensure_ascii=False)), + ) + conn.execute( + "DELETE FROM audit_log WHERE id NOT IN " + "(SELECT id FROM audit_log ORDER BY id DESC LIMIT 5000)" + ) + conn.commit() + + +def list_audit(limit: int = 100, username: Optional[str] = None) -> list: + conn = get_conn() + if username: + rows = conn.execute( + "SELECT * FROM audit_log WHERE username=? ORDER BY id DESC LIMIT ?", + (username, limit), + ).fetchall() + else: + rows = conn.execute( + "SELECT * FROM audit_log ORDER BY id DESC LIMIT ?", (limit,) + ).fetchall() + return [dict(r) for r in rows] diff --git a/services/loogle-mcp/app/auth.py b/services/loogle-mcp/app/auth.py new file mode 100644 index 0000000..1f335de --- /dev/null +++ b/services/loogle-mcp/app/auth.py @@ -0,0 +1,146 @@ +# -*- coding: utf-8 -*- +"""Autenticazione utenti famiglia — pattern Loogle Casa.""" + +import base64 +import datetime +import hashlib +import hmac +import os +import secrets +import time +from typing import Optional + +from fastapi import HTTPException, Request + +from .db import get_conn + +SESSION_DAYS = 30 +PBKDF2_ITER = 240_000 +MAX_ATTEMPTS = 8 +WINDOW_S = 600 +_attempts: dict = {} + +FAMILY_USERS = ( + ("daniele", True), + ("lucia", False), + ("davide", False), + ("luca", False), +) + +DEFAULT_SCOPES = ( + "context:read context:write knowledge:read knowledge:write gitea:read gitea:write" +) + + +def hash_password(password: str) -> str: + salt = os.urandom(16) + dk = hashlib.pbkdf2_hmac("sha256", password.encode(), salt, PBKDF2_ITER) + return "pbkdf2$%d$%s$%s" % ( + PBKDF2_ITER, + base64.b64encode(salt).decode(), + base64.b64encode(dk).decode(), + ) + + +def verify_password(password: str, stored: str) -> bool: + try: + _, iters, salt_b64, dk_b64 = stored.split("$") + salt = base64.b64decode(salt_b64) + expected = base64.b64decode(dk_b64) + dk = hashlib.pbkdf2_hmac("sha256", password.encode(), salt, int(iters)) + return hmac.compare_digest(dk, expected) + except Exception: + return False + + +def ensure_family_users() -> None: + conn = get_conn() + for username, is_admin in FAMILY_USERS: + row = conn.execute("SELECT id FROM users WHERE username=?", (username,)).fetchone() + if row: + continue + conn.execute( + "INSERT INTO users(username,password_hash,is_admin,must_change_password)" + " VALUES (?,?,?,1)", + (username, hash_password(username), 1 if is_admin else 0), + ) + conn.commit() + + +def throttle(ip: str) -> None: + now = time.time() + hist = [t for t in _attempts.get(ip, []) if now - t < WINDOW_S] + _attempts[ip] = hist + if len(hist) >= MAX_ATTEMPTS: + raise HTTPException(429, "Troppi tentativi: riprova tra qualche minuto") + + +def record_attempt(ip: str) -> None: + _attempts.setdefault(ip, []).append(time.time()) + + +def authenticate(username: str, password: str) -> Optional[dict]: + conn = get_conn() + row = conn.execute("SELECT * FROM users WHERE username=?", (username.strip(),)).fetchone() + if not row or not verify_password(password, row["password_hash"]): + return None + return dict(row) + + +def get_user_by_id(user_id: int) -> Optional[dict]: + row = get_conn().execute("SELECT * FROM users WHERE id=?", (user_id,)).fetchone() + return dict(row) if row else None + + +def get_user_by_username(username: str) -> Optional[dict]: + row = get_conn().execute("SELECT * FROM users WHERE username=?", (username,)).fetchone() + return dict(row) if row else None + + +def change_password(user_id: int, old_password: str, new_password: str) -> bool: + row = get_conn().execute("SELECT password_hash FROM users WHERE id=?", (user_id,)).fetchone() + if not row or not verify_password(old_password, row["password_hash"]): + return False + conn = get_conn() + conn.execute( + "UPDATE users SET password_hash=?, must_change_password=0 WHERE id=?", + (hash_password(new_password), user_id), + ) + conn.commit() + return True + + +def current_user_from_cookie(request: Request) -> dict: + token = request.cookies.get("mcp_session", "") + if not token: + raise HTTPException(401, "Non autenticato") + row = get_conn().execute( + "SELECT u.id,u.username,u.is_admin,u.must_change_password" + " FROM sessions s JOIN users u ON u.id=s.user_id" + " WHERE s.token=? AND s.expires_at > datetime('now')", + (token,), + ).fetchone() + if not row: + raise HTTPException(401, "Sessione scaduta") + return dict(row) + + +def require_admin(request: Request) -> dict: + user = current_user_from_cookie(request) + if not user["is_admin"]: + raise HTTPException(403, "Riservato all'amministratore") + return user + + +def ensure_sessions_table() -> None: + get_conn().execute( + """ + CREATE TABLE IF NOT EXISTS sessions ( + token TEXT PRIMARY KEY, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + expires_at TEXT NOT NULL + ) + """ + ) + get_conn().commit() diff --git a/services/loogle-mcp/app/context/__init__.py b/services/loogle-mcp/app/context/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/services/loogle-mcp/app/context/gitea_link.py b/services/loogle-mcp/app/context/gitea_link.py new file mode 100644 index 0000000..fa30d33 --- /dev/null +++ b/services/loogle-mcp/app/context/gitea_link.py @@ -0,0 +1,154 @@ +# -*- coding: utf-8 -*- +"""Collegamento progetti MCP ↔ repository Gitea.""" + +from __future__ import annotations + +import logging +from typing import Optional + +from ..knowledge import gitea + +LOGGER = logging.getLogger("loogle_mcp.context.gitea_link") + +README_CANDIDATES = ("README.md", "readme.md", "Readme.md", "README.MD") +DOCS_DIR = "docs" +MAX_README_CHARS = 12_000 +MAX_DOC_FILES = 25 + + +def normalize_gitea_repo(repo: Optional[str]) -> Optional[str]: + if repo is None: + return None + cleaned = repo.strip() + if not cleaned: + return None + owner, name = gitea.parse_repo(cleaned) + return f"{owner}/{name}" + + +def verify_repo_access(username: str, repo: str) -> None: + owner, name = gitea.parse_repo(repo) + gitea._request("GET", f"/repos/{owner}/{name}", username=username) + + +def fetch_readme(username: str, repo: str) -> Optional[dict]: + for path in README_CANDIDATES: + try: + data = gitea.get_file(repo, path, username=username) + except FileNotFoundError: + continue + except Exception as exc: + LOGGER.warning("README %s/%s non leggibile: %s", repo, path, exc) + continue + if data.get("type") != "file": + continue + content = (data.get("content") or "").strip() + if not content: + continue + truncated = len(content) > MAX_README_CHARS + return { + "path": path, + "sha": data.get("sha"), + "html_url": data.get("html_url"), + "content": content[:MAX_README_CHARS], + "truncated": truncated, + } + return None + + +def fetch_docs_index(username: str, repo: str) -> list[dict]: + try: + data = gitea.get_file(repo, DOCS_DIR, username=username) + except FileNotFoundError: + return [] + except Exception as exc: + LOGGER.warning("Directory docs/ non leggibile per %s: %s", repo, exc) + return [] + + if data.get("type") != "dir": + return [] + + entries = [] + for item in data.get("entries") or []: + if item.get("type") != "file": + continue + path = item.get("path") or "" + if not path.lower().endswith((".md", ".txt", ".rst")): + continue + entries.append( + { + "path": path, + "size": item.get("size"), + } + ) + if len(entries) >= MAX_DOC_FILES: + break + return entries + + +def project_enrichment(username: str, gitea_repo: str) -> dict: + repo = normalize_gitea_repo(gitea_repo) + if not repo: + return {"linked": False} + + base = { + "linked": True, + "repo": repo, + "html_url": f"{gitea.public_base_url()}/{repo}", + } + + if not gitea.is_configured(username): + return { + **base, + "available": False, + "error": "Gitea non configurato per questo utente", + } + + try: + verify_repo_access(username, repo) + readme = fetch_readme(username, repo) + docs = fetch_docs_index(username, repo) + open_issues = None + try: + issues = gitea.list_issues(repo, state="open", limit=1, username=username) + open_issues = issues.get("count", 0) + except Exception: + pass + return { + **base, + "available": True, + "readme": readme, + "docs_files": docs, + "open_issues": open_issues, + } + except Exception as exc: + return { + **base, + "available": False, + "error": str(exc), + } + + +def readme_seed_block(repo: str, readme: dict) -> str: + path = readme.get("path") or "README.md" + content = readme.get("content") or "" + truncated_note = "\n\n*(README troncato — usa get_file per il testo completo)*" if readme.get("truncated") else "" + return ( + f"\n\n" + f"## Sorgente Gitea: `{repo}`\n\n" + f"Contenuto iniziale da `{path}`.\n\n" + f"{content.rstrip()}{truncated_note}\n" + ) + + +def seed_context_from_readme(username: str, repo: str, context_md: str) -> tuple[str, bool]: + """Importa README nel context se non già presente un seed Gitea.""" + if "\n\n" + text + return { + "uri": uri, + "mimeType": "text/markdown", + "text": text, + } diff --git a/services/loogle-mcp/app/db.py b/services/loogle-mcp/app/db.py new file mode 100644 index 0000000..36a3eec --- /dev/null +++ b/services/loogle-mcp/app/db.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +"""SQLite schema for Loogle MCP Hub.""" + +import os +import sqlite3 +import threading + +DB_PATH = os.environ.get("MCP_DB", "/data/loogle_mcp.db") +_local = threading.local() + +SCHEMA = """ +CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT UNIQUE NOT NULL, + password_hash TEXT NOT NULL, + is_admin INTEGER NOT NULL DEFAULT 0, + must_change_password INTEGER NOT NULL DEFAULT 0, + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE TABLE IF NOT EXISTS oauth_clients ( + client_id TEXT PRIMARY KEY, + client_name TEXT NOT NULL, + redirect_uris TEXT NOT NULL, + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE TABLE IF NOT EXISTS oauth_codes ( + code TEXT PRIMARY KEY, + client_id TEXT NOT NULL, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + redirect_uri TEXT NOT NULL, + scope TEXT NOT NULL, + code_challenge TEXT, + code_challenge_method TEXT, + expires_at TEXT NOT NULL, + used INTEGER NOT NULL DEFAULT 0 +); + +CREATE TABLE IF NOT EXISTS refresh_tokens ( + token TEXT PRIMARY KEY, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + client_id TEXT NOT NULL, + scope TEXT NOT NULL, + expires_at TEXT NOT NULL, + revoked INTEGER NOT NULL DEFAULT 0 +); + +CREATE TABLE IF NOT EXISTS revoked_jtis ( + jti TEXT PRIMARY KEY, + revoked_at TEXT NOT NULL DEFAULT (datetime('now')), + expires_at TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS audit_log ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL, + tool_name TEXT NOT NULL, + resource_id TEXT, + detail TEXT, + created_at TEXT NOT NULL DEFAULT (datetime('now','localtime')) +); + +CREATE TABLE IF NOT EXISTS indexed_documents ( + doc_id INTEGER PRIMARY KEY, + title TEXT, + owner TEXT, + visibility TEXT NOT NULL DEFAULT 'family', + indexed_at TEXT NOT NULL DEFAULT (datetime('now')), + chunk_count INTEGER NOT NULL DEFAULT 0 +); + +CREATE TABLE IF NOT EXISTS indexed_gitea_files ( + repo TEXT NOT NULL, + path TEXT NOT NULL, + sha TEXT, + owner TEXT NOT NULL, + visibility TEXT NOT NULL DEFAULT 'family', + chunk_count INTEGER NOT NULL DEFAULT 0, + indexed_at TEXT NOT NULL DEFAULT (datetime('now')), + PRIMARY KEY (repo, path) +); + +CREATE INDEX IF NOT EXISTS idx_gitea_indexed_repo ON indexed_gitea_files(repo); +CREATE INDEX IF NOT EXISTS idx_gitea_indexed_at ON indexed_gitea_files(indexed_at DESC); + +CREATE TABLE IF NOT EXISTS indexed_apps_records ( + source TEXT NOT NULL, + record_id TEXT NOT NULL, + title TEXT, + owner TEXT NOT NULL DEFAULT 'family', + chunk_count INTEGER NOT NULL DEFAULT 0, + indexed_at TEXT NOT NULL DEFAULT (datetime('now')), + PRIMARY KEY (source, record_id) +); + +CREATE INDEX IF NOT EXISTS idx_apps_indexed_source ON indexed_apps_records(source); +CREATE INDEX IF NOT EXISTS idx_apps_indexed_at ON indexed_apps_records(indexed_at DESC); + +CREATE INDEX IF NOT EXISTS idx_audit_created ON audit_log(created_at DESC); +CREATE INDEX IF NOT EXISTS idx_oauth_codes_expires ON oauth_codes(expires_at); +""" + + +def get_conn() -> sqlite3.Connection: + conn = getattr(_local, "conn", None) + if conn is None: + os.makedirs(os.path.dirname(DB_PATH), exist_ok=True) + conn = sqlite3.connect(DB_PATH, timeout=30) + conn.row_factory = sqlite3.Row + conn.execute("PRAGMA journal_mode=WAL") + conn.execute("PRAGMA foreign_keys=ON") + _local.conn = conn + return conn + + +def init_db() -> None: + get_conn().executescript(SCHEMA) diff --git a/services/loogle-mcp/app/integrations/__init__.py b/services/loogle-mcp/app/integrations/__init__.py new file mode 100644 index 0000000..aaafed1 --- /dev/null +++ b/services/loogle-mcp/app/integrations/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +"""Client REST verso app homelab LOOGLE.""" diff --git a/services/loogle-mcp/app/integrations/casa.py b/services/loogle-mcp/app/integrations/casa.py new file mode 100644 index 0000000..1cb3c46 --- /dev/null +++ b/services/loogle-mcp/app/integrations/casa.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +"""Client Loogle Casa — dashboard, meteo, rete.""" + +import os +from typing import Any, Optional + +from .session_client import SessionApiClient + +MCP_USERS = ("daniele", "lucia", "davide", "luca") +# Daniele MCP → admin su Loogle Casa +MCP_TO_SERVICE_USER = { + "daniele": "admin", + "lucia": "lucia", + "davide": "davide", + "luca": "luca", +} + + +def _service_username(mcp_username: str) -> str: + return MCP_TO_SERVICE_USER.get(mcp_username.lower(), mcp_username.lower()) +PUBLIC_URL = os.environ.get("LOOGLE_CASA_URL", "https://casa.loogle.it").rstrip("/") +API_URL = os.environ.get("LOOGLE_CASA_API_URL", PUBLIC_URL).rstrip("/") + +_client: Optional[SessionApiClient] = None + + +def _client_instance() -> SessionApiClient: + global _client + if _client is None: + verify = os.environ.get("LOOGLE_CASA_VERIFY_SSL", "true").strip().lower() not in ( + "0", "false", "no", "off", + ) + client = SessionApiClient( + service="LOOGLE_CASA", + base_url=API_URL, + verify_ssl=verify, + ) + client.map_username = _service_username # type: ignore[attr-defined] + _client = client + return _client + + +def is_configured(username: Optional[str] = None) -> bool: + user = (username or "daniele").lower() + if user in MCP_USERS: + key = f"LOOGLE_CASA_PASSWORD_{user.upper()}" + if os.environ.get(key, "").strip(): + return True + if os.environ.get("LOOGLE_CASA_PASSWORD", "").strip(): + return True + return user in MCP_USERS + + +def get_dashboard(username: str) -> dict: + return _client_instance().get("/api/dashboard", username=username) + + +def get_weather_home(username: str) -> dict: + return _client_instance().get("/api/weather/home", username=username) + + +def get_network_overview(username: str) -> dict: + return _client_instance().get("/api/network/overview", username=username) + + +def get_network_failover_status(username: str) -> dict: + return _client_instance().get("/api/network/failover/status", username=username) + + +def get_network_mcp_status(username: str) -> dict: + return _client_instance().get("/api/network/mcp", username=username) + + +def get_alerts_cards(username: str) -> Any: + return _client_instance().get("/api/alerts/cards", username=username) diff --git a/services/loogle-mcp/app/integrations/homeassistant.py b/services/loogle-mcp/app/integrations/homeassistant.py new file mode 100644 index 0000000..6244fc2 --- /dev/null +++ b/services/loogle-mcp/app/integrations/homeassistant.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +"""Client Home Assistant REST API (read-only).""" + +import os +from typing import Any, Optional +from urllib.parse import urljoin + +import httpx + +PUBLIC_URL = os.environ.get("HA_URL", "https://ha.loogle.it").rstrip("/") +API_URL = os.environ.get("HA_API_URL", PUBLIC_URL).rstrip("/") +HA_TOKEN = os.environ.get("HA_TOKEN", "").strip() + + +def is_configured() -> bool: + return bool(HA_TOKEN) + + +def _headers() -> dict: + if not HA_TOKEN: + raise RuntimeError( + "HA_TOKEN non configurato in .env — crea un long-lived token in Home Assistant" + ) + return {"Authorization": f"Bearer {HA_TOKEN}", "Content-Type": "application/json"} + + +def _request(method: str, path: str, *, params: Optional[dict] = None) -> Any: + verify = os.environ.get("HA_VERIFY_SSL", "true").strip().lower() not in ( + "0", "false", "no", "off", + ) + url = path if path.startswith("http") else urljoin(API_URL + "/", path.lstrip("/")) + with httpx.Client(timeout=30.0, verify=verify) as client: + resp = client.request(method, url, headers=_headers(), params=params) + if resp.status_code >= 400: + raise RuntimeError(f"Home Assistant {path}: HTTP {resp.status_code} {resp.text[:200]}") + return resp.json() + + +def get_config() -> dict: + return _request("GET", "/api/config") + + +def get_entity(entity_id: str) -> dict: + return _request("GET", f"/api/states/{entity_id}") + + +def list_entities(domain: Optional[str] = None, limit: int = 100) -> list: + states = _request("GET", "/api/states") + if domain: + prefix = domain if domain.endswith(".") else f"{domain}." + states = [s for s in states if s.get("entity_id", "").startswith(prefix)] + return states[:limit] + + +def search_entities(query: str, limit: int = 30) -> list: + q = query.lower() + matches = [] + for state in _request("GET", "/api/states"): + eid = state.get("entity_id", "") + name = (state.get("attributes") or {}).get("friendly_name", "") + blob = f"{eid} {name}".lower() + if q in blob: + matches.append({ + "entity_id": eid, + "state": state.get("state"), + "friendly_name": name, + "last_changed": state.get("last_changed"), + }) + if len(matches) >= limit: + break + return matches diff --git a/services/loogle-mcp/app/integrations/irrigazione.py b/services/loogle-mcp/app/integrations/irrigazione.py new file mode 100644 index 0000000..07ed279 --- /dev/null +++ b/services/loogle-mcp/app/integrations/irrigazione.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +"""Client Irrigazione Smart — irri.loogle.it.""" + +import os +from typing import Any, Optional + +from .session_client import SessionApiClient + +MCP_USERS = ("daniele", "lucia", "davide", "luca") +MCP_TO_SERVICE_USER = { + "daniele": "admin", + "lucia": "lucia", + "davide": "dado", + "luca": "luca", +} + +PUBLIC_URL = os.environ.get("IRRIGAZIONE_URL", "https://irri.loogle.it").rstrip("/") +API_URL = os.environ.get("IRRIGAZIONE_API_URL", PUBLIC_URL).rstrip("/") + +_client: Optional[SessionApiClient] = None + + +def _service_username(mcp_username: str) -> str: + return MCP_TO_SERVICE_USER.get(mcp_username.lower(), mcp_username.lower()) + + +def _client_instance() -> SessionApiClient: + global _client + if _client is None: + verify = os.environ.get("IRRIGAZIONE_VERIFY_SSL", "true").strip().lower() not in ( + "0", "false", "no", "off", + ) + client = SessionApiClient( + service="IRRIGAZIONE", + base_url=API_URL, + verify_ssl=verify, + ) + client.map_username = _service_username # type: ignore[attr-defined] + _client = client + return _client + + +def is_configured(username: Optional[str] = None) -> bool: + user = (username or "daniele").lower() + if os.environ.get(f"IRRIGAZIONE_PASSWORD_{user.upper()}", "").strip(): + return True + if os.environ.get("IRRIGAZIONE_PASSWORD", "").strip(): + return True + return user in MCP_USERS + + +def get_status(username: str) -> dict: + return _client_instance().get("/api/status", username=username) + + +def get_zones(username: str) -> Any: + return _client_instance().get("/api/zones", username=username) + + +def get_history(username: str, limit: int = 30) -> Any: + data = _client_instance().get("/api/history", username=username) + if isinstance(data, list): + return data[:limit] + if isinstance(data, dict) and "items" in data: + items = data["items"] + return items[:limit] if isinstance(items, list) else data + return data + + +def get_events(username: str, limit: int = 50) -> Any: + data = _client_instance().get("/api/events", username=username) + if isinstance(data, list): + return data[:limit] + return data + + +def get_lavori_summary(username: str) -> Any: + return _client_instance().get("/api/lavori/summary", username=username) diff --git a/services/loogle-mcp/app/integrations/session_client.py b/services/loogle-mcp/app/integrations/session_client.py new file mode 100644 index 0000000..075aca9 --- /dev/null +++ b/services/loogle-mcp/app/integrations/session_client.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- +"""Client HTTP con sessione cookie (Loogle Casa, Irrigazione).""" + +import logging +import threading +import time +from typing import Any, Optional +from urllib.parse import urljoin + +import httpx + +LOGGER = logging.getLogger("loogle_mcp.session_client") + +_sessions: dict[str, tuple[str, float]] = {} +_sessions_lock = threading.Lock() +SESSION_TTL = 3600 * 12 + + +class SessionApiClient: + """Login cookie-based con cache per utente MCP.""" + + def __init__( + self, + *, + service: str, + base_url: str, + login_path: str = "/api/login", + verify_ssl: bool = True, + ) -> None: + self.service = service + self.base_url = base_url.rstrip("/") + self.login_path = login_path + self.verify_ssl = verify_ssl + + def _password_for_user(self, username: str) -> Optional[str]: + import os + user = username.lower() + env_key = f"{self.service}_PASSWORD_{user.upper()}" + pwd = os.environ.get(env_key, "").strip() + if pwd: + return pwd + fallback = os.environ.get(f"{self.service}_PASSWORD", "").strip() + if fallback: + return fallback + return user + + def _cache_key(self, username: str) -> str: + return f"{self.service}:{username.lower()}" + + def _get_cached_cookie(self, username: str) -> Optional[str]: + key = self._cache_key(username) + with _sessions_lock: + row = _sessions.get(key) + if not row: + return None + cookie, expires = row + if time.time() > expires: + _sessions.pop(key, None) + return None + return cookie + + def _store_cookie(self, username: str, cookie: str) -> None: + key = self._cache_key(username) + with _sessions_lock: + _sessions[key] = (cookie, time.time() + SESSION_TTL) + + def login(self, username: str) -> str: + cached = self._get_cached_cookie(username) + if cached: + return cached + service_user = username + if hasattr(self, "map_username"): + service_user = self.map_username(username) # type: ignore[attr-defined] + password = self._password_for_user(username) + if not password: + raise RuntimeError( + f"Password {self.service} non configurata per {username}. " + f"Imposta {self.service}_PASSWORD_{username.upper()} in .env" + ) + url = urljoin(self.base_url + "/", self.login_path.lstrip("/")) + with httpx.Client(timeout=30.0, verify=self.verify_ssl) as client: + resp = client.post( + url, json={"username": service_user, "password": password}, + ) + if resp.status_code != 200: + raise RuntimeError( + f"Login {self.service} fallito per {username}: HTTP {resp.status_code}" + ) + cookie = resp.cookies.get("session") + if not cookie: + raise RuntimeError(f"Login {self.service}: cookie session mancante") + self._store_cookie(username, cookie) + return cookie + + def request( + self, + method: str, + path: str, + *, + username: str, + params: Optional[dict] = None, + json_body: Optional[dict] = None, + ) -> Any: + cookie = self.login(username) + url = path if path.startswith("http") else urljoin(self.base_url + "/", path.lstrip("/")) + headers = {"Cookie": f"session={cookie}"} + with httpx.Client(timeout=60.0, verify=self.verify_ssl) as client: + resp = client.request(method, url, headers=headers, params=params, json=json_body) + if resp.status_code == 401: + with _sessions_lock: + _sessions.pop(self._cache_key(username), None) + cookie = self.login(username) + headers = {"Cookie": f"session={cookie}"} + resp = client.request(method, url, headers=headers, params=params, json=json_body) + if resp.status_code >= 400: + raise RuntimeError(f"{self.service} {method} {path}: HTTP {resp.status_code} {resp.text[:200]}") + if resp.headers.get("content-type", "").startswith("application/json"): + return resp.json() + return resp.text + + def get(self, path: str, *, username: str, params: Optional[dict] = None) -> Any: + return self.request("GET", path, username=username, params=params) diff --git a/services/loogle-mcp/app/integrations/turni.py b/services/loogle-mcp/app/integrations/turni.py new file mode 100644 index 0000000..478472c --- /dev/null +++ b/services/loogle-mcp/app/integrations/turni.py @@ -0,0 +1,208 @@ +# -*- coding: utf-8 -*- +"""Client Turni-Live — turni.loogle.it (JWT Bearer).""" + +import logging +import os +import threading +import time +from typing import Any, Optional +from urllib.parse import urljoin + +import httpx + +LOGGER = logging.getLogger("loogle_mcp.turni") + +MCP_USERS = ("daniele", "lucia", "davide", "luca") +MCP_TO_SERVICE_USER = { + "daniele": "daniely", + "lucia": "lucia", + "davide": "davide", + "luca": "luca", +} + +PUBLIC_URL = os.environ.get("TURNI_URL", "https://turni.loogle.it").rstrip("/") +API_URL = os.environ.get("TURNI_API_URL", PUBLIC_URL).rstrip("/") + +_jwt_cache: dict[str, tuple[str, float]] = {} +_jwt_lock = threading.Lock() +JWT_TTL = 3600 * 6 + + +def _service_username(mcp_username: str) -> str: + return MCP_TO_SERVICE_USER.get(mcp_username.lower(), mcp_username.lower()) + + +def _password_for_user(mcp_username: str) -> Optional[str]: + user = mcp_username.lower() + pwd = os.environ.get(f"TURNI_PASSWORD_{user.upper()}", "").strip() + if pwd: + return pwd + return os.environ.get("TURNI_PASSWORD", "").strip() or None + + +def _jwt_for_user(mcp_username: str) -> Optional[str]: + user = mcp_username.lower() + direct = os.environ.get(f"TURNI_JWT_{user.upper()}", "").strip() + if direct: + return direct + return os.environ.get("TURNI_JWT", "").strip() or None + + +def is_configured(username: Optional[str] = None) -> bool: + user = (username or "daniele").lower() + if _jwt_for_user(user): + return True + if _password_for_user(user): + return True + return False + + +def _store_jwt(mcp_username: str, token: str) -> None: + with _jwt_lock: + _jwt_cache[mcp_username.lower()] = (token, time.time() + JWT_TTL) + + +def _cached_jwt(mcp_username: str) -> Optional[str]: + with _jwt_lock: + row = _jwt_cache.get(mcp_username.lower()) + if not row: + return None + token, expires = row + if time.time() > expires: + _jwt_cache.pop(mcp_username.lower(), None) + return None + return token + + +def login(mcp_username: str) -> str: + cached = _cached_jwt(mcp_username) + if cached: + return cached + preset = _jwt_for_user(mcp_username) + if preset: + _store_jwt(mcp_username, preset) + return preset + password = _password_for_user(mcp_username) + if not password: + raise RuntimeError( + f"Turni non configurato per {mcp_username}. " + f"Imposta TURNI_PASSWORD_{mcp_username.upper()} o TURNI_JWT_{mcp_username.upper()}" + ) + service_user = _service_username(mcp_username) + verify = os.environ.get("TURNI_VERIFY_SSL", "true").strip().lower() not in ( + "0", "false", "no", "off", + ) + url = urljoin(API_URL + "/", "api/auth/login") + with httpx.Client(timeout=30.0, verify=verify) as client: + resp = client.post(url, json={"username": service_user, "password": password}) + if resp.status_code != 200: + raise RuntimeError(f"Login Turni fallito: HTTP {resp.status_code}") + data = resp.json() + token = data.get("token") + if not token: + raise RuntimeError("Login Turni: token JWT mancante") + _store_jwt(mcp_username, token) + return token + + +def _request( + method: str, + path: str, + *, + mcp_username: str, + params: Optional[dict] = None, +) -> Any: + token = login(mcp_username) + verify = os.environ.get("TURNI_VERIFY_SSL", "true").strip().lower() not in ( + "0", "false", "no", "off", + ) + url = path if path.startswith("http") else urljoin(API_URL + "/", path.lstrip("/")) + headers = {"Authorization": f"Bearer {token}"} + with httpx.Client(timeout=60.0, verify=verify) as client: + resp = client.request(method, url, headers=headers, params=params) + if resp.status_code == 401: + with _jwt_lock: + _jwt_cache.pop(mcp_username.lower(), None) + headers["Authorization"] = f"Bearer {login(mcp_username)}" + resp = client.request(method, url, headers=headers, params=params) + if resp.status_code >= 400: + raise RuntimeError(f"Turni {path}: HTTP {resp.status_code} {resp.text[:200]}") + return resp.json() + + +def get_status() -> dict: + verify = os.environ.get("TURNI_VERIFY_SSL", "true").strip().lower() not in ( + "0", "false", "no", "off", + ) + url = urljoin(API_URL + "/", "api/status") + with httpx.Client(timeout=30.0, verify=verify) as client: + resp = client.get(url) + resp.raise_for_status() + return resp.json() + + +def list_doctors(mcp_username: str) -> Any: + return _request("GET", "/api/doctors", mcp_username=mcp_username) + + +def get_shift_assignments( + mcp_username: str, + *, + from_date: Optional[str] = None, + to_date: Optional[str] = None, + limit: int = 100, +) -> Any: + params: dict = {} + if from_date: + params["from"] = from_date + if to_date: + params["to"] = to_date + data = _request("GET", "/api/shift-assignments", mcp_username=mcp_username, params=params or None) + if isinstance(data, list): + return data[:limit] + if isinstance(data, dict): + items = data.get("assignments") or data.get("items") or data.get("results") + if isinstance(items, list): + return items[:limit] + return data + + +def get_my_shifts( + mcp_username: str, + *, + from_date: Optional[str] = None, + to_date: Optional[str] = None, + limit: int = 50, +) -> dict: + """Turni dell'utente MCP: filtra per doctorId collegato o per nome medico.""" + user_info = _request("GET", "/api/users/me", mcp_username=mcp_username) + doctor_id = user_info.get("doctorId") + assignments = get_shift_assignments( + mcp_username, from_date=from_date, to_date=to_date, limit=500, + ) + if not isinstance(assignments, list): + return {"user": user_info, "assignments": assignments} + if doctor_id: + mine = [a for a in assignments if a.get("doctorId") == doctor_id or a.get("doctor_id") == doctor_id] + else: + service_user = _service_username(mcp_username) + doctors = list_doctors(mcp_username) + doc_ids = set() + if isinstance(doctors, list): + for doc in doctors: + name = (doc.get("name") or doc.get("fullName") or "").lower() + if service_user.lower() in name or mcp_username.lower() in name: + doc_ids.add(doc.get("id") or doc.get("doctorId")) + mine = [ + a for a in assignments + if (a.get("doctorId") or a.get("doctor_id")) in doc_ids + ] if doc_ids else assignments[:limit] + return { + "user": { + "username": user_info.get("username"), + "role": user_info.get("role"), + "doctorId": doctor_id, + }, + "assignments": mine[:limit], + "count": len(mine), + } diff --git a/services/loogle-mcp/app/jwt_utils.py b/services/loogle-mcp/app/jwt_utils.py new file mode 100644 index 0000000..288b715 --- /dev/null +++ b/services/loogle-mcp/app/jwt_utils.py @@ -0,0 +1,136 @@ +# -*- coding: utf-8 -*- +"""JWT utilities for OAuth access tokens.""" + +import datetime +import os +import secrets +import uuid +from typing import Optional + +import jwt + +from .db import get_conn + +JWT_ALG = "HS256" +ACCESS_TOKEN_HOURS = 1 +REFRESH_TOKEN_DAYS = 30 + + +def jwt_secret() -> str: + secret = os.environ.get("MCP_JWT_SECRET", "").strip() + if not secret: + secret = secrets.token_urlsafe(48) + os.environ["MCP_JWT_SECRET"] = secret + return secret + + +def base_url() -> str: + return os.environ.get("MCP_BASE_URL", "https://mcp.loogle.it").rstrip("/") + + +def scopes_for_user(user: dict, requested: str) -> str: + parts = [s for s in requested.split() if s] + allowed = { + "context:read", + "context:write", + "knowledge:read", + "knowledge:write", + "gitea:read", + "gitea:write", + "home:read", + "irrigation:read", + "turni:read", + } + if user.get("is_admin"): + allowed.add("admin") + filtered = [s for s in parts if s in allowed] + if not filtered: + filtered = [ + "context:read", + "context:write", + "knowledge:read", + "knowledge:write", + "gitea:read", + "gitea:write", + "home:read", + "irrigation:read", + "turni:read", + ] + return " ".join(filtered) + + +def create_access_token(user: dict, scope: str, client_id: str) -> tuple[str, str]: + jti = str(uuid.uuid4()) + now = datetime.datetime.utcnow() + payload = { + "iss": base_url(), + "sub": user["username"], + "uid": user["id"], + "scope": scope, + "client_id": client_id, + "jti": jti, + "iat": now, + "exp": now + datetime.timedelta(hours=ACCESS_TOKEN_HOURS), + } + token = jwt.encode(payload, jwt_secret(), algorithm=JWT_ALG) + return token, jti + + +def create_refresh_token(user_id: int, scope: str, client_id: str) -> str: + token = secrets.token_urlsafe(48) + expires = ( + datetime.datetime.utcnow() + datetime.timedelta(days=REFRESH_TOKEN_DAYS) + ).strftime("%Y-%m-%d %H:%M:%S") + get_conn().execute( + "INSERT INTO refresh_tokens(token,user_id,client_id,scope,expires_at) VALUES (?,?,?,?,?)", + (token, user_id, client_id, scope, expires), + ) + get_conn().commit() + return token + + +def decode_access_token(token: str) -> Optional[dict]: + try: + payload = jwt.decode(token, jwt_secret(), algorithms=[JWT_ALG], issuer=base_url()) + except jwt.PyJWTError: + return None + jti = payload.get("jti") + if not jti: + return None + row = get_conn().execute( + "SELECT 1 FROM revoked_jtis WHERE jti=? AND expires_at > datetime('now')", + (jti,), + ).fetchone() + if row: + return None + return payload + + +def revoke_jti(jti: str, expires_at: datetime.datetime) -> None: + get_conn().execute( + "INSERT OR IGNORE INTO revoked_jtis(jti,expires_at) VALUES (?,?)", + (jti, expires_at.strftime("%Y-%m-%d %H:%M:%S")), + ) + get_conn().commit() + + +def revoke_refresh_token(token: str) -> None: + get_conn().execute("UPDATE refresh_tokens SET revoked=1 WHERE token=?", (token,)) + get_conn().commit() + + +def consume_refresh_token(token: str) -> Optional[dict]: + row = get_conn().execute( + "SELECT * FROM refresh_tokens WHERE token=? AND revoked=0 AND expires_at > datetime('now')", + (token,), + ).fetchone() + if not row: + return None + return dict(row) + + +def has_scope(claims: dict, scope: str) -> bool: + scopes = set((claims.get("scope") or "").split()) + if "admin" in scopes: + return True + return scope in scopes diff --git a/services/loogle-mcp/app/knowledge/__init__.py b/services/loogle-mcp/app/knowledge/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/services/loogle-mcp/app/knowledge/apps_indexer.py b/services/loogle-mcp/app/knowledge/apps_indexer.py new file mode 100644 index 0000000..32b9278 --- /dev/null +++ b/services/loogle-mcp/app/knowledge/apps_indexer.py @@ -0,0 +1,295 @@ +# -*- coding: utf-8 -*- +"""RAG su export Irrigazione + Turni (P7).""" + +from __future__ import annotations + +import json +import logging +import os +from datetime import datetime, timezone +from typing import Any, Optional + +from ..db import get_conn +from ..integrations import irrigazione, turni +from . import embeddings, qdrant_store +from .text_chunk import chunk_text as _chunk_text + +LOGGER = logging.getLogger("loogle_mcp.apps_indexer") + +INDEX_USER = os.environ.get("APPS_INDEX_USER", "daniele").lower() + + +def _int_env(name: str, default: int) -> int: + try: + return int(os.environ.get(name, str(default))) + except ValueError: + return default + + +def _enabled() -> bool: + flag = os.environ.get("APPS_INDEX_ENABLED", "yes").strip().lower() + return flag not in ("0", "false", "no", "off") + + +def _doc_id(source: str, record_id: str) -> int: + key = f"{source}:{record_id}" + return abs(hash(key)) % (2**31 - 1) + + +def _index_text(source: str, record_id: str, title: str, text: str) -> dict: + chunks = _chunk_text(_truncate(text)) + if len(chunks) > 8: + chunks = chunks[:8] + if not chunks: + return {"source": source, "record_id": record_id, "chunks": 0, "skipped": True} + vectors = embeddings.embed_texts(chunks) + collection = qdrant_store.APPS_SHARED_COLLECTION + doc_id = _doc_id(source, record_id) + qdrant_store.delete_by_doc(collection, doc_id) + ids = [] + payloads = [] + for i, chunk in enumerate(chunks): + point_id = f"app-{source}-{record_id}-chunk-{i}" + ids.append(point_id) + payloads.append( + { + "doc_id": doc_id, + "source": source, + "record_id": record_id, + "chunk_index": i, + "title": title, + "text": chunk, + "owner": "family", + "visibility": "family", + } + ) + qdrant_store.upsert_chunks(collection, ids, vectors, payloads) + get_conn().execute( + "INSERT INTO indexed_apps_records(source,record_id,title,owner,chunk_count,indexed_at)" + " VALUES (?,?,?,?,?,datetime('now'))" + " ON CONFLICT(source,record_id) DO UPDATE SET" + " title=excluded.title, chunk_count=excluded.chunk_count, indexed_at=datetime('now')", + (source, record_id, title, "family", len(chunks)), + ) + get_conn().commit() + return {"source": source, "record_id": record_id, "chunks": len(chunks), "collection": collection} + + +def _format_irrigation_history_item(item: dict, idx: int) -> str: + parts = [f"Irrigazione storico #{idx}"] + for key in ("started_at", "ended_at", "zone", "zone_name", "duration_min", "volume_l", "mode", "note"): + if item.get(key) is not None: + parts.append(f"{key}: {item[key]}") + return "\n".join(parts) + + +def _format_irrigation_event(item: dict, idx: int) -> str: + parts = [f"Irrigazione evento #{idx}"] + for key in ("ts", "time", "type", "level", "message", "zone", "detail"): + if item.get(key) is not None: + parts.append(f"{key}: {item[key]}") + return "\n".join(parts) + + +def _format_turni_assignment(item: dict, idx: int) -> str: + parts = [f"Turno #{idx}"] + for key in ( + "date", "startDate", "endDate", "doctorId", "doctorName", "doctor_name", + "slotId", "slotName", "slot_name", "uoc", "uocName", "shiftType", "notes", + ): + if item.get(key) is not None: + parts.append(f"{key}: {item[key]}") + return "\n".join(parts) + + +def _truncate(text: str, limit: int = 6000) -> str: + if len(text) <= limit: + return text + return text[: limit - 20] + "\n… [truncated]" + + +def _summarize_irrigation_status(status: dict) -> str: + lines = ["Irrigazione — snapshot stato"] + for key in ("plan_mode", "program", "simulation", "hibernation", "draining"): + if key in status: + lines.append(f"{key}: {status[key]}") + ha = status.get("ha") or {} + lines.append(f"ha_connected: {ha.get('connected')}") + zones = status.get("zones") or [] + lines.append(f"zone_count: {len(zones)}") + for z in zones[:12]: + if isinstance(z, dict): + lines.append( + f" - {z.get('name', z.get('id'))}: state={z.get('ha_state')} excluded={z.get('excluded')}" + ) + analysis = status.get("analysis") + if isinstance(analysis, dict): + for k, v in list(analysis.items())[:8]: + lines.append(f"analysis.{k}: {v}") + elif analysis: + lines.append(f"analysis: {analysis}") + return "\n".join(lines) + + +def _summarize_zones(zones: Any) -> str: + items = zones if isinstance(zones, list) else _normalize_list(zones) + lines = [f"Irrigazione — zone ({len(items)})"] + for z in items[:20]: + if not isinstance(z, dict): + continue + lines.append( + f"- {z.get('name', z.get('id'))}: ha={z.get('ha_state')} " + f"rate_mmh={z.get('rate_mmh')} flow={z.get('zone_flow_lph')}" + ) + return "\n".join(lines) + + +def _normalize_list(data: Any) -> list: + if isinstance(data, list): + return data + if isinstance(data, dict): + for key in ("items", "results", "history", "events", "assignments", "records"): + val = data.get(key) + if isinstance(val, list): + return val + return [] + + +def index_irrigazione(*, username: Optional[str] = None, history_limit: Optional[int] = None, events_limit: Optional[int] = None) -> dict: + user = username or INDEX_USER + history_limit = history_limit if history_limit is not None else _int_env("APPS_INDEX_HISTORY_LIMIT", 25) + events_limit = events_limit if events_limit is not None else _int_env("APPS_INDEX_EVENTS_LIMIT", 40) + if not irrigazione.is_configured(user): + return {"source": "irrigazione", "skipped": True, "reason": "not configured"} + indexed = 0 + errors = 0 + try: + status = irrigazione.get_status(user) + status_text = _summarize_irrigation_status(status) + _index_text("irrigazione", "status-snapshot", "Irrigazione — stato attuale", status_text) + indexed += 1 + except Exception as exc: + LOGGER.warning("Irrigazione status index failed: %s", exc) + errors += 1 + try: + zones = irrigazione.get_zones(user) + zones_text = _summarize_zones(zones) + _index_text("irrigazione", "zones-snapshot", "Irrigazione — zone", zones_text) + indexed += 1 + except Exception as exc: + LOGGER.warning("Irrigazione zones index failed: %s", exc) + errors += 1 + try: + history = irrigazione.get_history(user, limit=history_limit) + for i, item in enumerate(_normalize_list(history)): + if not isinstance(item, dict): + continue + rid = str(item.get("id") or item.get("started_at") or i) + text = _format_irrigation_history_item(item, i) + _index_text("irrigazione", f"history-{rid}", f"Irrigazione storico {rid}", text) + indexed += 1 + except Exception as exc: + LOGGER.warning("Irrigazione history index failed: %s", exc) + errors += 1 + try: + events = irrigazione.get_events(user, limit=events_limit) + for i, item in enumerate(_normalize_list(events)): + if not isinstance(item, dict): + continue + rid = str(item.get("id") or item.get("ts") or item.get("time") or i) + text = _format_irrigation_event(item, i) + _index_text("irrigazione", f"event-{rid}", f"Irrigazione evento {rid}", text) + indexed += 1 + except Exception as exc: + LOGGER.warning("Irrigazione events index failed: %s", exc) + errors += 1 + try: + lavori = irrigazione.get_lavori_summary(user) + lavori_text = _truncate(json.dumps(lavori, ensure_ascii=False, indent=2), 4000) + _index_text("irrigazione", "lavori-summary", "Irrigazione — lavori manutenzione", lavori_text) + indexed += 1 + except Exception as exc: + LOGGER.warning("Irrigazione lavori index failed: %s", exc) + errors += 1 + return {"source": "irrigazione", "indexed": indexed, "errors": errors} + + +def index_turni(*, username: Optional[str] = None, assignments_limit: Optional[int] = None) -> dict: + user = username or INDEX_USER + assignments_limit = assignments_limit if assignments_limit is not None else _int_env("APPS_INDEX_ASSIGNMENTS_LIMIT", 80) + if not turni.is_configured(user): + return {"source": "turni", "skipped": True, "reason": "not configured"} + indexed = 0 + errors = 0 + try: + status = turni.get_status() + status_text = _truncate(json.dumps(status, ensure_ascii=False, indent=2), 2000) + _index_text("turni", "status-snapshot", "Turni — stato servizio", status_text) + indexed += 1 + except Exception as exc: + LOGGER.warning("Turni status index failed: %s", exc) + errors += 1 + try: + doctors = turni.list_doctors(user) + lines = ["Turni — medici"] + for d in (_normalize_list(doctors) if not isinstance(doctors, list) else doctors)[:40]: + if isinstance(d, dict): + lines.append(f"- {d.get('name', d.get('fullName'))} id={d.get('id')}") + _index_text("turni", "doctors-list", "Turni — elenco medici", "\n".join(lines)) + indexed += 1 + except Exception as exc: + LOGGER.warning("Turni doctors index failed: %s", exc) + errors += 1 + try: + assignments = turni.get_shift_assignments(user, limit=assignments_limit) + for i, item in enumerate(_normalize_list(assignments)): + if not isinstance(item, dict): + continue + rid = str(item.get("id") or item.get("date") or i) + text = _format_turni_assignment(item, i) + _index_text("turni", f"assignment-{rid}", f"Turno {rid}", text) + indexed += 1 + except Exception as exc: + LOGGER.warning("Turni assignments index failed: %s", exc) + errors += 1 + return {"source": "turni", "indexed": indexed, "errors": errors} + + +def index_all(*, username: Optional[str] = None) -> dict: + if not _enabled(): + return {"skipped": True, "reason": "APPS_INDEX_ENABLED=no"} + user = username or INDEX_USER + return { + "irrigazione": index_irrigazione(username=user), + "turni": index_turni(username=user), + "at": datetime.now(timezone.utc).isoformat(), + } + + +def search_apps_knowledge(query: str, limit: int = 8, source: Optional[str] = None) -> list: + vectors = embeddings.embed_texts([query]) + flt = {"source": source} if source else None + hits = qdrant_store.search( + [qdrant_store.APPS_SHARED_COLLECTION], + vectors[0], + limit=limit, + visibility_filter=flt, + ) + for hit in hits: + hit.setdefault("source_type", hit.get("source", "apps")) + return hits + + +def list_indexed_records(source: Optional[str] = None, limit: int = 40) -> list: + conn = get_conn() + if source: + rows = conn.execute( + "SELECT * FROM indexed_apps_records WHERE source=? ORDER BY indexed_at DESC LIMIT ?", + (source, limit), + ).fetchall() + else: + rows = conn.execute( + "SELECT * FROM indexed_apps_records ORDER BY indexed_at DESC LIMIT ?", + (limit,), + ).fetchall() + return [dict(r) for r in rows] diff --git a/services/loogle-mcp/app/knowledge/embeddings.py b/services/loogle-mcp/app/knowledge/embeddings.py new file mode 100644 index 0000000..84b6389 --- /dev/null +++ b/services/loogle-mcp/app/knowledge/embeddings.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +"""Embedding providers — con thermal gate e keep_alive adattivo.""" + +import logging +import os +import time +from typing import Optional + +import httpx + +from . import thermal + +LOGGER = logging.getLogger("loogle_mcp.embeddings") + + +def embed_texts(texts: list[str]) -> list[list[float]]: + if not texts: + return [] + ollama_url = os.environ.get("OLLAMA_URL", "").strip() + if ollama_url: + try: + return _embed_ollama(texts, ollama_url) + except Exception as exc: + LOGGER.warning("Ollama embedding failed: %s", exc) + openai_key = os.environ.get("OPENAI_API_KEY", "").strip() + if openai_key: + return _embed_openai(texts, openai_key) + raise RuntimeError("Nessun provider embedding configurato (OLLAMA_URL o OPENAI_API_KEY)") + + +def _embed_ollama(texts: list[str], base_url: str) -> list[list[float]]: + model = os.environ.get("OLLAMA_EMBED_MODEL", "nomic-embed-text") + vectors = [] + timeout = httpx.Timeout(connect=30.0, read=300.0, write=30.0, pool=30.0) + with httpx.Client(timeout=timeout) as client: + for i, text in enumerate(texts): + status = thermal.wait_for_headroom(context=f"embed:{i+1}/{len(texts)}") + keep_alive = thermal.suggested_keep_alive(status) + delay = thermal.suggested_delay_s(status) + + payload = {"model": model, "prompt": text, "keep_alive": keep_alive} + # options.num_thread limita i thread CPU lato Ollama (se supportato) + num_thread = os.environ.get("OLLAMA_NUM_THREAD", "").strip() + if num_thread: + try: + payload["options"] = {"num_thread": int(num_thread)} + except ValueError: + pass + + resp = client.post(f"{base_url.rstrip('/')}/api/embeddings", json=payload) + if resp.status_code >= 400: + LOGGER.warning( + "Ollama embeddings HTTP %s: %s — payload keys=%s", + resp.status_code, + resp.text[:300], + list(payload.keys()), + ) + resp.raise_for_status() + vectors.append(resp.json()["embedding"]) + + if delay > 0 and i + 1 < len(texts): + time.sleep(delay) + + # Unload solo se esplicitamente richiesto (zona HARD) — evita spike da reload + if keep_alive == 0: + try: + client.post( + f"{base_url.rstrip('/')}/api/generate", + json={"model": model, "keep_alive": 0}, + timeout=30.0, + ) + except Exception: + pass + return vectors + + +def _embed_openai(texts: list[str], api_key: str) -> list[list[float]]: + model = os.environ.get("OPENAI_EMBED_MODEL", "text-embedding-3-small") + with httpx.Client(timeout=120.0) as client: + resp = client.post( + "https://api.openai.com/v1/embeddings", + headers={"Authorization": f"Bearer {api_key}"}, + json={"model": model, "input": texts}, + ) + resp.raise_for_status() + data = resp.json()["data"] + return [item["embedding"] for item in sorted(data, key=lambda x: x["index"])] diff --git a/services/loogle-mcp/app/knowledge/gitea.py b/services/loogle-mcp/app/knowledge/gitea.py new file mode 100644 index 0000000..5815291 --- /dev/null +++ b/services/loogle-mcp/app/knowledge/gitea.py @@ -0,0 +1,495 @@ +# -*- coding: utf-8 -*- +"""Gitea REST API client — token per utente MCP.""" + +import base64 +import json +import logging +import os +import re +from typing import Any, Optional +from urllib.parse import quote + +import httpx + +LOGGER = logging.getLogger("loogle_mcp.gitea") + +GITEA_URL = os.environ.get("GITEA_URL", "https://git.loogle.it").rstrip("/") +MCP_USERS = ("daniele", "lucia", "davide", "luca") +GITEA_API_TOKEN_SCOPES = "read:repository,write:repository,write:issue,write:user,read:user" +TEXT_EXTENSIONS = { + ".md", ".txt", ".py", ".sh", ".yml", ".yaml", ".json", ".toml", ".ini", + ".conf", ".js", ".ts", ".tsx", ".jsx", ".html", ".css", ".sql", ".go", + ".rs", ".env", ".service", ".timer", ".xml", ".csv", +} +_tokens_cache: Optional[dict[str, str]] = None + + +def _load_tokens() -> dict[str, str]: + global _tokens_cache + if _tokens_cache is not None: + return _tokens_cache + + tokens: dict[str, str] = {} + json_map = os.environ.get("GITEA_API_TOKENS", "").strip() + if json_map: + try: + parsed = json.loads(json_map) + if isinstance(parsed, dict): + tokens.update({k.lower(): v for k, v in parsed.items() if v}) + except json.JSONDecodeError: + LOGGER.warning("GITEA_API_TOKENS non è JSON valido") + + fallback = os.environ.get("GITEA_API_TOKEN", "").strip() + for user in MCP_USERS: + env_key = f"GITEA_API_TOKEN_{user.upper()}" + token = os.environ.get(env_key, "").strip() + if token: + tokens[user] = token + elif user not in tokens and fallback: + tokens[user] = fallback + + if not tokens and fallback: + tokens["daniele"] = fallback + + _tokens_cache = tokens + return tokens + + +def list_configured_users() -> list[str]: + return list(_load_tokens().keys()) + + +def is_configured(username: Optional[str] = None) -> bool: + tokens = _load_tokens() + if not tokens: + return False + if username: + user = username.lower() + return user in tokens or "daniele" in tokens or bool(tokens) + return True + + +def _headers(username: Optional[str] = None) -> dict[str, str]: + tokens = _load_tokens() + if not tokens: + raise RuntimeError( + "Nessun token Gitea configurato. " + "Imposta GITEA_API_TOKEN o GITEA_API_TOKEN_{USER} in .env — vedi docs/GITEA-TOKEN.md" + ) + user = (username or "daniele").lower() + token = tokens.get(user) or tokens.get("daniele") or next(iter(tokens.values())) + return {"Authorization": f"token {token}"} + + +def parse_repo(repo: str) -> tuple[str, str]: + cleaned = repo.strip().strip("/") + if cleaned.count("/") != 1: + raise ValueError("repo deve essere nel formato owner/name (es. daniele/rete)") + owner, name = cleaned.split("/", 1) + if not owner or not name: + raise ValueError("repo deve essere nel formato owner/name (es. daniele/rete)") + return owner, name + + +def api_base_url() -> str: + return os.environ.get("GITEA_API_URL", GITEA_URL).rstrip("/") + + +def public_base_url() -> str: + return os.environ.get("GITEA_URL", "https://git.loogle.it").rstrip("/") + + +def _api_url(path: str) -> str: + return f"{api_base_url()}/api/v1{path}" + + +def _request( + method: str, + path: str, + *, + username: Optional[str] = None, + params: Optional[dict] = None, + json_body: Optional[dict] = None, +) -> Any: + with httpx.Client(timeout=60.0, verify=True) as client: + resp = client.request( + method, + _api_url(path), + headers=_headers(username), + params=params, + json=json_body, + ) + if resp.status_code == 404: + raise FileNotFoundError(resp.text or "Risorsa Gitea non trovata") + resp.raise_for_status() + if resp.content: + return resp.json() + return {} + + +def list_repos( + username: Optional[str] = None, + page: int = 1, + limit: int = 50, +) -> dict: + data = _request( + "GET", + "/user/repos", + username=username, + params={"page": page, "limit": limit, "sort": "updated"}, + ) + repos = [] + for repo in data if isinstance(data, list) else []: + full_name = repo.get("full_name") or "" + if not full_name and repo.get("owner"): + full_name = f"{repo['owner'].get('login', '')}/{repo.get('name', '')}" + repos.append( + { + "full_name": full_name, + "description": repo.get("description") or "", + "private": bool(repo.get("private")), + "html_url": repo.get("html_url") or f"{public_base_url()}/{full_name}", + "default_branch": repo.get("default_branch") or "main", + "updated_at": repo.get("updated_at"), + } + ) + return {"repos": repos, "page": page, "count": len(repos)} + + +def _decode_content(entry: dict) -> str: + encoding = (entry.get("encoding") or "").lower() + raw = entry.get("content") or "" + if encoding == "base64": + return base64.b64decode(raw).decode("utf-8", errors="replace") + return raw + + +def get_file( + repo: str, + path: str, + ref: Optional[str] = None, + username: Optional[str] = None, +) -> dict: + owner, name = parse_repo(repo) + file_path = path.lstrip("/") + params = {} + if ref: + params["ref"] = ref + encoded_path = "/".join(quote(part, safe="") for part in file_path.split("/")) + data = _request( + "GET", + f"/repos/{owner}/{name}/contents/{encoded_path}", + username=username, + params=params or None, + ) + if isinstance(data, list): + entries = [ + { + "name": item.get("name"), + "path": item.get("path"), + "type": item.get("type"), + "size": item.get("size"), + } + for item in data + ] + return { + "repo": f"{owner}/{name}", + "path": file_path or "/", + "type": "dir", + "entries": entries, + } + content = _decode_content(data) + return { + "repo": f"{owner}/{name}", + "path": data.get("path") or file_path, + "type": data.get("type") or "file", + "size": data.get("size"), + "sha": data.get("sha"), + "html_url": data.get("html_url") or f"{public_base_url()}/{owner}/{name}/src/branch/{ref or 'main'}/{file_path}", + "content": content, + } + + +def search_code( + query: str, + repo: Optional[str] = None, + limit: int = 20, + username: Optional[str] = None, +) -> dict: + q = query.strip() + if not q: + raise ValueError("query obbligatoria") + params: dict[str, Any] = {"q": q, "limit": min(max(limit, 1), 50)} + if repo: + owner, name = parse_repo(repo) + params["repo"] = f"{owner}/{name}" + try: + data = _request("GET", "/search/code", username=username, params=params) + hits = [] + for item in data.get("data") or []: + repo_name = item.get("repository", {}).get("full_name") or item.get("repository", {}).get("name") + hits.append( + { + "repo": repo_name, + "path": item.get("path"), + "sha": item.get("sha"), + "html_url": item.get("url") or item.get("html_url"), + "language": item.get("language"), + "snippet": (item.get("content") or item.get("text") or "")[:500], + } + ) + return {"query": q, "repo": repo, "results": hits, "count": len(hits)} + except FileNotFoundError: + return _search_code_fallback(q, repo, limit, username) + except httpx.HTTPStatusError as exc: + if exc.response.status_code not in (404, 422): + raise + return _search_code_fallback(q, repo, limit, username) + + +def _search_code_fallback( + query: str, + repo: Optional[str], + limit: int, + username: Optional[str], +) -> dict: + """Fallback se /search/code non disponibile: tree + grep su file testo.""" + repos: list[str] = [] + if repo: + owner, name = parse_repo(repo) + repos.append(f"{owner}/{name}") + else: + listed = list_repos(username=username, limit=20) + repos = [r["full_name"] for r in listed["repos"] if r.get("full_name")] + + terms = [t.lower() for t in re.split(r"\s+", query) if t] + hits: list[dict] = [] + max_files = min(limit * 3, 40) + + for full_name in repos: + owner, name = parse_repo(full_name) + try: + tree = _request( + "GET", + f"/repos/{owner}/{name}/git/trees/HEAD", + username=username, + params={"recursive": "1"}, + ) + except Exception: + continue + scanned = 0 + for node in tree.get("tree") or []: + if node.get("type") != "blob": + continue + path = node.get("path") or "" + ext = os.path.splitext(path)[1].lower() + if ext and ext not in TEXT_EXTENSIONS: + continue + if any(term in path.lower() for term in terms): + pass + scanned += 1 + if scanned > max_files: + break + try: + file_data = get_file(full_name, path, username=username) + except Exception: + continue + content = (file_data.get("content") or "").lower() + if not any(term in content or term in path.lower() for term in terms): + continue + snippet = file_data.get("content") or "" + idx = snippet.lower().find(terms[0]) if terms else 0 + if idx < 0: + idx = 0 + hits.append( + { + "repo": full_name, + "path": path, + "sha": node.get("sha"), + "html_url": file_data.get("html_url"), + "snippet": snippet[max(0, idx - 80): idx + 420], + } + ) + if len(hits) >= limit: + break + if len(hits) >= limit: + break + + return {"query": query, "repo": repo, "results": hits[:limit], "count": len(hits[:limit]), "mode": "fallback"} + + +def list_issues( + repo: str, + state: str = "open", + page: int = 1, + limit: int = 20, + username: Optional[str] = None, +) -> dict: + owner, name = parse_repo(repo) + data = _request( + "GET", + f"/repos/{owner}/{name}/issues", + username=username, + params={"state": state, "page": page, "limit": limit, "type": "issues"}, + ) + issues = [] + for item in data if isinstance(data, list) else []: + issues.append( + { + "number": item.get("number"), + "title": item.get("title"), + "state": item.get("state"), + "user": (item.get("user") or {}).get("login"), + "html_url": item.get("html_url"), + "created_at": item.get("created_at"), + "updated_at": item.get("updated_at"), + "labels": [lbl.get("name") for lbl in (item.get("labels") or [])], + } + ) + return {"repo": f"{owner}/{name}", "state": state, "issues": issues, "count": len(issues)} + + +def get_issue( + repo: str, + number: int, + username: Optional[str] = None, +) -> dict: + owner, name = parse_repo(repo) + item = _request("GET", f"/repos/{owner}/{name}/issues/{number}", username=username) + return { + "repo": f"{owner}/{name}", + "number": item.get("number"), + "title": item.get("title"), + "state": item.get("state"), + "body": item.get("body") or "", + "user": (item.get("user") or {}).get("login"), + "html_url": item.get("html_url"), + "created_at": item.get("created_at"), + "updated_at": item.get("updated_at"), + "labels": [lbl.get("name") for lbl in (item.get("labels") or [])], + } + + +def create_issue( + repo: str, + title: str, + body: str = "", + labels: Optional[list[str]] = None, + username: Optional[str] = None, +) -> dict: + owner, name = parse_repo(repo) + payload: dict[str, Any] = {"title": title.strip(), "body": body or ""} + if labels: + payload["labels"] = labels + item = _request( + "POST", + f"/repos/{owner}/{name}/issues", + username=username, + json_body=payload, + ) + return { + "repo": f"{owner}/{name}", + "number": item.get("number"), + "title": item.get("title"), + "state": item.get("state"), + "html_url": item.get("html_url"), + } + + +def assert_repo_owner(username: str, repo: str, *, is_admin: bool = False) -> tuple[str, str]: + owner, name = parse_repo(repo) + if not is_admin and owner.lower() != username.lower(): + raise PermissionError( + f"Puoi scrivere solo su repository di cui sei owner (repo {owner}/{name}, utente {username})" + ) + return owner, name + + +def create_repo( + name: str, + username: Optional[str] = None, + *, + private: bool = True, + description: str = "", + auto_init: bool = True, +) -> dict: + repo_name = name.strip().lower() + if not repo_name or not re.match(r"^[a-z0-9][a-z0-9._-]{0,99}$", repo_name): + raise ValueError("name repo non valido (usa lettere minuscole, numeri, -, _, .)") + payload: dict[str, Any] = { + "name": repo_name, + "private": private, + "auto_init": auto_init, + "description": description.strip(), + } + item = _request("POST", "/user/repos", username=username, json_body=payload) + full_name = item.get("full_name") or f"{username}/{repo_name}" + return { + "full_name": full_name, + "private": bool(item.get("private", private)), + "html_url": item.get("html_url") or f"{public_base_url()}/{full_name}", + "default_branch": item.get("default_branch") or "main", + "description": item.get("description") or description, + } + + +def create_or_update_file( + repo: str, + path: str, + content: str, + message: str, + *, + branch: Optional[str] = None, + username: Optional[str] = None, +) -> dict: + owner, repo_name = parse_repo(repo) + file_path = path.lstrip("/") + if not file_path: + raise ValueError("path obbligatorio") + if not message.strip(): + raise ValueError("message commit obbligatorio") + + encoded_path = "/".join(quote(part, safe="") for part in file_path.split("/")) + params = {} + if branch: + params["ref"] = branch + + sha = None + action = "create" + try: + existing = get_file(repo, file_path, ref=branch, username=username) + if existing.get("type") == "file": + sha = existing.get("sha") + action = "update" + except FileNotFoundError: + pass + + body: dict[str, Any] = { + "content": base64.b64encode(content.encode("utf-8")).decode("ascii"), + "message": message.strip(), + } + if sha: + body["sha"] = sha + if branch: + body["branch"] = branch + + method = "PUT" if sha else "POST" + item = _request( + method, + f"/repos/{owner}/{repo_name}/contents/{encoded_path}", + username=username, + params=params or None, + json_body=body, + ) + commit = item.get("commit") or {} + content_obj = item.get("content") or {} + return { + "repo": f"{owner}/{repo_name}", + "path": file_path, + "action": action, + "branch": branch or "default", + "sha": content_obj.get("sha"), + "commit_sha": commit.get("sha"), + "html_url": content_obj.get("html_url") + or f"{public_base_url()}/{owner}/{repo_name}/src/branch/{branch or 'main'}/{file_path}", + } diff --git a/services/loogle-mcp/app/knowledge/gitea_indexer.py b/services/loogle-mcp/app/knowledge/gitea_indexer.py new file mode 100644 index 0000000..4cacdbd --- /dev/null +++ b/services/loogle-mcp/app/knowledge/gitea_indexer.py @@ -0,0 +1,369 @@ +# -*- coding: utf-8 -*- +"""Indicizzazione semantica (RAG) su file testo dei repository Gitea.""" + +from __future__ import annotations + +import logging +import os +import re +import zlib +from typing import Optional + +from ..db import get_conn +from . import embeddings, gitea, qdrant_store +from .text_chunk import CHUNK_OVERLAP, CHUNK_SIZE, chunk_text as _chunk_text + +LOGGER = logging.getLogger("loogle_mcp.gitea_indexer") + +SKIP_PATH_PARTS = ( + "node_modules/", + "vendor/", + ".git/", + "dist/", + "build/", + "__pycache__/", + ".venv/", + "venv/", + ".tox/", + "coverage/", +) +PRIORITY_PREFIXES = ("docs/", "ha/", "doc/", "README") + + +def _enabled() -> bool: + flag = os.environ.get("GITEA_INDEX_ENABLED", "yes").strip().lower() + return flag not in ("0", "false", "no", "off") + + +def _max_files_per_repo() -> int: + return int(os.environ.get("GITEA_INDEX_MAX_FILES_PER_REPO", "150")) + + +def _max_file_bytes() -> int: + return int(os.environ.get("GITEA_INDEX_MAX_FILE_BYTES", "120000")) + + +def _repos_for_user(username: str) -> list[str]: + env_key = f"GITEA_INDEX_REPOS_{username.upper()}" + raw = os.environ.get(env_key, "").strip() + if raw: + repos: list[str] = [] + for item in raw.split(","): + item = item.strip() + if not item: + continue + owner, name = gitea.parse_repo(item) + repos.append(f"{owner}/{name}") + return repos + repos: list[str] = [] + page = 1 + while page <= 5: + data = gitea.list_repos(username=username, page=page, limit=50) + batch = [r["full_name"] for r in data.get("repos") or [] if r.get("full_name")] + if not batch: + break + repos.extend(batch) + if len(batch) < 50: + break + page += 1 + return repos + + +def _should_index_path(path: str) -> bool: + lowered = path.lower() + if any(part in lowered for part in SKIP_PATH_PARTS): + return False + ext = os.path.splitext(path)[1].lower() + return bool(ext and ext in gitea.TEXT_EXTENSIONS) + + +def _path_priority(path: str) -> tuple[int, str]: + lowered = path.lower() + for idx, prefix in enumerate(PRIORITY_PREFIXES): + if lowered.startswith(prefix.lower()) or os.path.basename(lowered).startswith(prefix.lower()): + return (idx, path) + return (len(PRIORITY_PREFIXES), path) + + +def list_repo_text_files(repo: str, username: str) -> list[dict]: + owner, name = gitea.parse_repo(repo) + tree = gitea._request( + "GET", + f"/repos/{owner}/{name}/git/trees/HEAD", + username=username, + params={"recursive": "1"}, + ) + max_files = _max_files_per_repo() + max_bytes = _max_file_bytes() + files: list[dict] = [] + for node in tree.get("tree") or []: + if node.get("type") != "blob": + continue + path = node.get("path") or "" + if not _should_index_path(path): + continue + size = int(node.get("size") or 0) + if size > max_bytes: + continue + files.append({"path": path, "sha": node.get("sha"), "size": size}) + files.sort(key=lambda item: _path_priority(item["path"])) + return files[:max_files] + + +def _repo_owner(repo: str) -> str: + owner, _ = gitea.parse_repo(repo) + return owner.lower() + + +def _repo_visibility(private: bool, owner: str) -> str: + if private: + return "personal" + if owner in gitea.MCP_USERS: + return "family" + return "family" + + +def _collection_for_repo(private: bool, owner: str) -> str: + visibility = _repo_visibility(private, owner) + if visibility == "personal": + return qdrant_store.gitea_collection(owner) + return qdrant_store.GITEA_SHARED_COLLECTION + + +def _file_doc_id(repo: str, path: str) -> int: + return zlib.adler32(f"{repo}:{path}".encode("utf-8")) & 0x7FFFFFFF + + +def _file_title(repo: str, path: str) -> str: + return f"{repo}/{path}" + + +def index_file( + repo: str, + path: str, + *, + username: str, + private: bool, + force: bool = False, +) -> dict: + owner = _repo_owner(repo) + conn = get_conn() + row = conn.execute( + "SELECT sha, chunk_count FROM indexed_gitea_files WHERE repo=? AND path=?", + (repo, path), + ).fetchone() + + file_data = gitea.get_file(repo, path, username=username) + sha = file_data.get("sha") or "" + if row and row["sha"] == sha and not force: + return {"repo": repo, "path": path, "skipped": True, "sha": sha} + + text = (file_data.get("content") or "").strip() + if not text: + return {"repo": repo, "path": path, "chunks": 0, "sha": sha} + + header = f"# {_file_title(repo, path)}\n\nSource: gitea:{repo}:{path}\n\n" + chunks = _chunk_text(header + text) + if not chunks: + return {"repo": repo, "path": path, "chunks": 0, "sha": sha} + + visibility = _repo_visibility(private, owner) + collection = _collection_for_repo(private, owner) + doc_id = _file_doc_id(repo, path) + qdrant_store.delete_by_doc(collection, doc_id) + + vectors = embeddings.embed_texts(chunks) + ids = [] + payloads = [] + for i, chunk in enumerate(chunks): + point_id = f"gitea-{repo}-{path}-chunk-{i}" + ids.append(point_id) + payloads.append( + { + "source": "gitea", + "doc_id": doc_id, + "repo": repo, + "path": path, + "chunk_index": i, + "title": _file_title(repo, path), + "text": chunk, + "owner": owner, + "visibility": visibility, + "sha": sha, + } + ) + qdrant_store.upsert_chunks(collection, ids, vectors, payloads) + + stored = qdrant_store.count_by_doc(collection, doc_id) + if stored < len(chunks): + raise RuntimeError( + f"Qdrant upsert incompleto per {repo}/{path}: attesi {len(chunks)} chunk, trovati {stored}" + ) + + conn.execute( + "INSERT INTO indexed_gitea_files(repo,path,sha,owner,visibility,chunk_count,indexed_at)" + " VALUES (?,?,?,?,?,?,datetime('now'))" + " ON CONFLICT(repo,path) DO UPDATE SET" + " sha=excluded.sha, owner=excluded.owner, visibility=excluded.visibility," + " chunk_count=excluded.chunk_count, indexed_at=datetime('now')", + (repo, path, sha, owner, visibility, len(chunks)), + ) + conn.commit() + return { + "repo": repo, + "path": path, + "sha": sha, + "chunks": len(chunks), + "collection": collection, + "visibility": visibility, + } + + +def index_repo( + repo: str, + *, + username: Optional[str] = None, + private: Optional[bool] = None, + force: bool = False, + max_files: Optional[int] = None, +) -> dict: + gitea_user = username or _repo_owner(repo) + if not gitea.is_configured(gitea_user): + raise RuntimeError(f"Gitea non configurato per {gitea_user}") + + if private is None: + owner, name = gitea.parse_repo(repo) + meta = gitea._request("GET", f"/repos/{owner}/{name}", username=gitea_user) + private = bool(meta.get("private")) + + files = list_repo_text_files(repo, gitea_user) + if max_files is not None: + files = files[: max(1, max_files)] + + indexed = 0 + skipped = 0 + errors = 0 + chunks = 0 + for item in files: + try: + result = index_file( + repo, + item["path"], + username=gitea_user, + private=bool(private), + force=force, + ) + if result.get("skipped"): + skipped += 1 + else: + indexed += 1 + chunks += int(result.get("chunks") or 0) + except Exception as exc: + LOGGER.warning("Index gitea %s/%s failed: %s", repo, item.get("path"), exc) + errors += 1 + + return { + "repo": repo, + "files_seen": len(files), + "files_indexed": indexed, + "files_skipped": skipped, + "errors": errors, + "chunks": chunks, + "private": bool(private), + } + + +def index_all(max_files_per_repo: Optional[int] = None) -> dict: + if not _enabled(): + return {"enabled": False, "indexed_files": 0} + + total_indexed = 0 + total_skipped = 0 + total_errors = 0 + total_chunks = 0 + repos_done: list[str] = [] + users = gitea.list_configured_users() or [] + + for username in users: + try: + repos = _repos_for_user(username) + except Exception as exc: + LOGGER.error("Lista repo Gitea fallita per %s: %s", username, exc) + continue + for repo in repos: + try: + result = index_repo( + repo, + username=username, + force=False, + max_files=max_files_per_repo, + ) + repos_done.append(repo) + total_indexed += int(result.get("files_indexed") or 0) + total_skipped += int(result.get("files_skipped") or 0) + total_errors += int(result.get("errors") or 0) + total_chunks += int(result.get("chunks") or 0) + except Exception as exc: + LOGGER.warning("Index repo %s failed (%s): %s", repo, username, exc) + total_errors += 1 + + return { + "enabled": True, + "repos": repos_done, + "files_indexed": total_indexed, + "files_skipped": total_skipped, + "errors": total_errors, + "chunks": total_chunks, + "users": users, + } + + +def gitea_collections_for_user(username: str, is_admin: bool = False) -> list[str]: + cols = [qdrant_store.GITEA_SHARED_COLLECTION, qdrant_store.gitea_collection(username)] + if is_admin: + for user in gitea.MCP_USERS: + cols.append(qdrant_store.gitea_collection(user)) + return list(dict.fromkeys(cols)) + + +def search_gitea_knowledge(username: str, query: str, limit: int = 8, is_admin: bool = False) -> list: + vectors = embeddings.embed_texts([query]) + collections = gitea_collections_for_user(username, is_admin=is_admin) + hits = qdrant_store.search(collections, vectors[0], limit=limit) + for hit in hits: + hit["source"] = hit.get("source") or "gitea" + return hits + + +def list_indexed_files(limit: int = 30, repo: Optional[str] = None) -> list: + conn = get_conn() + if repo: + rows = conn.execute( + "SELECT * FROM indexed_gitea_files WHERE repo=? ORDER BY indexed_at DESC LIMIT ?", + (repo, limit), + ).fetchall() + else: + rows = conn.execute( + "SELECT * FROM indexed_gitea_files ORDER BY indexed_at DESC LIMIT ?", + (limit,), + ).fetchall() + return [dict(r) for r in rows] + + +def index_stats() -> dict: + conn = get_conn() + row = conn.execute( + "SELECT COUNT(*), COALESCE(SUM(chunk_count), 0) FROM indexed_gitea_files" + ).fetchone() + files_count = int(row[0] if row else 0) + chunks_meta = int(row[1] if row else 0) + collections = {qdrant_store.GITEA_SHARED_COLLECTION} + for user in gitea.MCP_USERS: + collections.add(qdrant_store.gitea_collection(user)) + qdrant_points = sum(qdrant_store.collection_point_count(c) for c in collections) + return { + "files_indexed": files_count, + "chunks_in_metadata": chunks_meta, + "qdrant_points": qdrant_points, + "collections": {c: qdrant_store.collection_point_count(c) for c in sorted(collections)}, + } diff --git a/services/loogle-mcp/app/knowledge/indexer.py b/services/loogle-mcp/app/knowledge/indexer.py new file mode 100644 index 0000000..3b051d2 --- /dev/null +++ b/services/loogle-mcp/app/knowledge/indexer.py @@ -0,0 +1,156 @@ +# -*- coding: utf-8 -*- +"""Paperless → Qdrant indexing pipeline.""" + +import logging +from typing import Optional + +LOGGER = logging.getLogger("loogle_mcp.indexer") + +from ..db import get_conn +from . import embeddings, gitea_indexer, paperless, qdrant_store +from .text_chunk import chunk_text as _chunk_text + + +def index_document(doc_id: int, force: bool = False, paperless_user: Optional[str] = None) -> dict: + conn = get_conn() + existing = conn.execute( + "SELECT doc_id FROM indexed_documents WHERE doc_id=?", (doc_id,) + ).fetchone() + if existing and not force: + return {"doc_id": doc_id, "skipped": True} + doc = paperless.get_document(doc_id, username=paperless_user) + text = paperless.download_document_text(doc_id, username=paperless_user) + owner = paperless.document_owner(doc) + visibility = paperless.document_visibility(doc, owner) + chunks = _chunk_text(text) + if not chunks: + return {"doc_id": doc_id, "chunks": 0} + vectors = embeddings.embed_texts(chunks) + collection = qdrant_store.SHARED_COLLECTION if visibility == "family" else qdrant_store.kb_collection(owner) + qdrant_store.delete_by_doc(collection, doc_id) + ids = [] + payloads = [] + for i, chunk in enumerate(chunks): + point_id = f"doc-{doc_id}-chunk-{i}" + ids.append(point_id) + payloads.append( + { + "doc_id": doc_id, + "chunk_index": i, + "title": doc.get("title") or f"Documento {doc_id}", + "text": chunk, + "owner": owner, + "visibility": visibility, + } + ) + qdrant_store.upsert_chunks(collection, ids, vectors, payloads) + conn.execute( + "INSERT INTO indexed_documents(doc_id,title,owner,visibility,chunk_count,indexed_at)" + " VALUES (?,?,?,?,?,datetime('now'))" + " ON CONFLICT(doc_id) DO UPDATE SET" + " title=excluded.title, owner=excluded.owner, visibility=excluded.visibility," + " chunk_count=excluded.chunk_count, indexed_at=datetime('now')", + (doc_id, doc.get("title"), owner, visibility, len(chunks)), + ) + conn.commit() + return {"doc_id": doc_id, "chunks": len(chunks), "collection": collection} + + +def index_all(max_pages: int = 20) -> dict: + indexed = 0 + errors = 0 + seen: set[int] = set() + users = paperless.list_configured_users() or ["daniele"] + for paperless_user in users: + page = 1 + while page <= max_pages: + try: + data = paperless.list_documents(page=page, page_size=25, username=paperless_user) + except Exception as exc: + LOGGER.error("Paperless list failed for %s: %s", paperless_user, exc) + break + results = data.get("results") or [] + if not results: + break + for doc in results: + doc_id = doc["id"] + if doc_id in seen: + continue + seen.add(doc_id) + try: + index_document(doc_id, paperless_user=paperless_user) + indexed += 1 + except Exception as exc: + LOGGER.warning("Index doc %s failed (%s): %s", doc_id, paperless_user, exc) + errors += 1 + if not data.get("next"): + break + page += 1 + return {"indexed": indexed, "errors": errors, "users": users} + + +def index_context_snippet(username: str, project_id: str, text: str, title: str) -> None: + chunks = _chunk_text(text) + if not chunks: + return + vectors = embeddings.embed_texts(chunks) + collection = qdrant_store.ctx_collection(username) + doc_key = f"ctx-{username}-{project_id}" + qdrant_store.delete_by_doc(collection, hash(doc_key) % (2**31)) + ids = [] + payloads = [] + for i, chunk in enumerate(chunks): + point_id = f"{doc_key}-chunk-{i}" + ids.append(point_id) + payloads.append( + { + "doc_id": hash(doc_key) % (2**31), + "project_id": project_id, + "chunk_index": i, + "title": title, + "text": chunk, + "owner": username, + "visibility": "personal", + } + ) + qdrant_store.upsert_chunks(collection, ids, vectors, payloads) + + +def search_knowledge(username: str, query: str, limit: int = 8, is_admin: bool = False) -> list: + vectors = embeddings.embed_texts([query]) + collections = [ + qdrant_store.SHARED_COLLECTION, + qdrant_store.kb_collection(username), + qdrant_store.ctx_collection(username), + ] + collections.extend(gitea_indexer.gitea_collections_for_user(username, is_admin=is_admin)) + collections.append(qdrant_store.APPS_SHARED_COLLECTION) + if is_admin: + for u in ("daniele", "lucia", "davide", "luca"): + collections.append(qdrant_store.kb_collection(u)) + collections = list(dict.fromkeys(collections)) + hits = qdrant_store.search(collections, vectors[0], limit=limit) + for hit in hits: + if hit.get("repo") and not hit.get("source"): + hit["source"] = "gitea" + elif hit.get("source") in ("irrigazione", "turni"): + hit["source_type"] = "apps" + elif hit.get("doc_id") and not hit.get("source"): + hit["source"] = "paperless" + return hits + + +def search_gitea_knowledge(username: str, query: str, limit: int = 8, is_admin: bool = False) -> list: + return gitea_indexer.search_gitea_knowledge(username, query, limit=limit, is_admin=is_admin) + + +def search_context(username: str, query: str, limit: int = 8) -> list: + vectors = embeddings.embed_texts([query]) + return qdrant_store.search([qdrant_store.ctx_collection(username)], vectors[0], limit=limit) + + +def list_recent_documents(limit: int = 20) -> list: + rows = get_conn().execute( + "SELECT * FROM indexed_documents ORDER BY indexed_at DESC LIMIT ?", (limit,) + ).fetchall() + return [dict(r) for r in rows] diff --git a/services/loogle-mcp/app/knowledge/paperless.py b/services/loogle-mcp/app/knowledge/paperless.py new file mode 100644 index 0000000..c2da3c6 --- /dev/null +++ b/services/loogle-mcp/app/knowledge/paperless.py @@ -0,0 +1,140 @@ +# -*- coding: utf-8 -*- +"""Paperless-ngx REST API client — supporto token per utente MCP.""" + +import json +import logging +import os +from typing import Optional + +import httpx + +LOGGER = logging.getLogger("loogle_mcp.paperless") + +PAPERLESS_URL = os.environ.get("PAPERLESS_URL", "https://docs.loogle.it").rstrip("/") +MCP_USERS = ("daniele", "lucia", "davide", "luca") +_tokens_cache: Optional[dict[str, str]] = None + + +def _load_tokens() -> dict[str, str]: + """Carica token Paperless per utente MCP. + + Priorità per ogni utente: + 1. PAPERLESS_API_TOKEN_{USERNAME} (es. PAPERLESS_API_TOKEN_LUCIA) + 2. Chiavi in PAPERLESS_API_TOKENS JSON (es. {"daniele":"...", "lucia":"..."}) + 3. PAPERLESS_API_TOKEN globale (fallback per tutti, tipico account admin) + """ + global _tokens_cache + if _tokens_cache is not None: + return _tokens_cache + + tokens: dict[str, str] = {} + json_map = os.environ.get("PAPERLESS_API_TOKENS", "").strip() + if json_map: + try: + parsed = json.loads(json_map) + if isinstance(parsed, dict): + tokens.update({k.lower(): v for k, v in parsed.items() if v}) + except json.JSONDecodeError: + LOGGER.warning("PAPERLESS_API_TOKENS non è JSON valido") + + fallback = os.environ.get("PAPERLESS_API_TOKEN", "").strip() + for user in MCP_USERS: + env_key = f"PAPERLESS_API_TOKEN_{user.upper()}" + token = os.environ.get(env_key, "").strip() + if token: + tokens[user] = token + elif user not in tokens and fallback: + tokens[user] = fallback + + if not tokens and fallback: + tokens["daniele"] = fallback + + _tokens_cache = tokens + return tokens + + +def list_configured_users() -> list[str]: + return list(_load_tokens().keys()) + + +def _headers(username: Optional[str] = None) -> dict: + tokens = _load_tokens() + if not tokens: + raise RuntimeError( + "Nessun token Paperless configurato. " + "Imposta PAPERLESS_API_TOKEN o PAPERLESS_API_TOKEN_{USER} in .env" + ) + user = (username or "daniele").lower() + token = tokens.get(user) or tokens.get("daniele") or next(iter(tokens.values())) + return {"Authorization": f"Token {token}"} + + +def list_documents( + page: int = 1, + page_size: int = 25, + ordering: str = "-modified", + username: Optional[str] = None, +) -> dict: + with httpx.Client(timeout=60.0, verify=True) as client: + resp = client.get( + f"{PAPERLESS_URL}/api/documents/", + headers=_headers(username), + params={"page": page, "page_size": page_size, "ordering": ordering}, + ) + resp.raise_for_status() + return resp.json() + + +def get_document(doc_id: int, username: Optional[str] = None) -> dict: + with httpx.Client(timeout=60.0, verify=True) as client: + resp = client.get( + f"{PAPERLESS_URL}/api/documents/{doc_id}/", + headers=_headers(username), + ) + resp.raise_for_status() + return resp.json() + + +def download_document_text(doc_id: int, username: Optional[str] = None) -> str: + doc = get_document(doc_id, username=username) + content = (doc.get("content") or "").strip() + if content: + return content + title = doc.get("title") or f"Documento {doc_id}" + return f"# {title}\n\n(Nessun testo OCR disponibile)" + + +def document_visibility(doc: dict, owner_username: str) -> str: + tags = doc.get("tags") or [] + tag_names = [] + for t in tags: + if isinstance(t, dict): + tag_names.append((t.get("name") or "").lower()) + elif isinstance(t, int): + continue + else: + tag_names.append(str(t).lower()) + if any(t in ("personal", "privato", "private") for t in tag_names): + return "personal" + if any(t in ("admin-only", "admin") for t in tag_names): + return "admin" + return "family" + + +def document_owner(doc: dict, default: str = "daniele") -> str: + owner = doc.get("owner") + if isinstance(owner, int): + pass + owner_username = doc.get("owner_username") or doc.get("owner_name") + if isinstance(owner_username, str): + name = owner_username.lower() + for user in MCP_USERS: + if user in name: + return user + correspondent = doc.get("correspondent") + if isinstance(correspondent, dict): + name = (correspondent.get("name") or "").lower() + for user in MCP_USERS: + if user in name: + return user + return default diff --git a/services/loogle-mcp/app/knowledge/qdrant_store.py b/services/loogle-mcp/app/knowledge/qdrant_store.py new file mode 100644 index 0000000..990c4f5 --- /dev/null +++ b/services/loogle-mcp/app/knowledge/qdrant_store.py @@ -0,0 +1,251 @@ +# -*- coding: utf-8 -*- +"""Vector store — Qdrant remoto (DS920) con fallback SQLite locale su Pi ARM.""" + +import json +import logging +import math +import os +import sqlite3 +import uuid +from typing import Optional + +LOGGER = logging.getLogger("loogle_mcp.vector_store") +VECTOR_SIZE = 768 +_local = sqlite3.connect(":memory:", check_same_thread=False) # placeholder +_qdrant_client = None +_qdrant_checked = False +_use_fallback = False + + +def _fallback_path() -> str: + return os.environ.get("MCP_VECTOR_FALLBACK", "/data/vector_fallback.db") + + +def _fallback_conn() -> sqlite3.Connection: + path = _fallback_path() + os.makedirs(os.path.dirname(path), exist_ok=True) + conn = sqlite3.connect(path, timeout=30) + conn.execute( + """ + CREATE TABLE IF NOT EXISTS vectors ( + id TEXT PRIMARY KEY, + collection TEXT NOT NULL, + vector TEXT NOT NULL, + payload TEXT NOT NULL + ) + """ + ) + conn.execute("CREATE INDEX IF NOT EXISTS idx_vectors_collection ON vectors(collection)") + conn.commit() + return conn + + +def _get_qdrant(): + global _qdrant_client, _qdrant_checked, _use_fallback + if _qdrant_checked: + return None if _use_fallback else _qdrant_client + _qdrant_checked = True + url = os.environ.get("QDRANT_URL", "").strip() + if not url: + _use_fallback = True + LOGGER.warning("QDRANT_URL non impostato — fallback SQLite") + return None + try: + from qdrant_client import QdrantClient + from qdrant_client.http import models as qm + + client = QdrantClient(url=url, timeout=60) + client.get_collections() + _qdrant_client = client + globals()["qm"] = qm + LOGGER.info("Qdrant connesso: %s", url) + return client + except Exception as exc: + _use_fallback = True + LOGGER.warning("Qdrant non disponibile (%s) — fallback SQLite", exc) + return None + + +def ensure_collection(name: str, vector_size: int = VECTOR_SIZE) -> None: + client = _get_qdrant() + if client is None: + return + from qdrant_client.http import models as qm + + names = {c.name for c in client.get_collections().collections} + if name in names: + return + client.create_collection( + collection_name=name, + vectors_config=qm.VectorParams(size=vector_size, distance=qm.Distance.COSINE), + ) + + +def kb_collection(username: str) -> str: + return f"kb_personal_{username}" + + +def ctx_collection(username: str) -> str: + return f"ctx_{username}" + + +SHARED_COLLECTION = "kb_shared_family" +GITEA_SHARED_COLLECTION = "gitea_shared_family" +APPS_SHARED_COLLECTION = "apps_shared_family" + + +def gitea_collection(username: str) -> str: + return f"gitea_personal_{username}" + + +def _point_id(name: str) -> str: + return str(uuid.uuid5(uuid.NAMESPACE_URL, name)) + + +def _cosine(a: list[float], b: list[float]) -> float: + dot = sum(x * y for x, y in zip(a, b)) + na = math.sqrt(sum(x * x for x in a)) or 1.0 + nb = math.sqrt(sum(x * x for x in b)) or 1.0 + return dot / (na * nb) + + +def upsert_chunks( + collection: str, + ids: list[str], + vectors: list[list[float]], + payloads: list[dict], +) -> None: + if not vectors: + return + ensure_collection(collection, len(vectors[0])) + client = _get_qdrant() + if client is not None: + from qdrant_client.http import models as qm + + points = [ + qm.PointStruct(id=_point_id(pid), vector=vec, payload=payload) + for pid, vec, payload in zip(ids, vectors, payloads) + ] + client.upsert(collection_name=collection, points=points) + return + conn = _fallback_conn() + for pid, vec, payload in zip(ids, vectors, payloads): + conn.execute( + "INSERT OR REPLACE INTO vectors(id,collection,vector,payload) VALUES (?,?,?,?)", + (_point_id(pid), collection, json.dumps(vec), json.dumps(payload, ensure_ascii=False)), + ) + conn.commit() + + +def delete_by_doc(collection: str, doc_id: int) -> None: + client = _get_qdrant() + if client is not None: + from qdrant_client.http import models as qm + + ensure_collection(collection) + client.delete( + collection_name=collection, + points_selector=qm.FilterSelector( + filter=qm.Filter( + must=[qm.FieldCondition(key="doc_id", match=qm.MatchValue(value=doc_id))] + ) + ), + ) + return + conn = _fallback_conn() + rows = conn.execute("SELECT id,payload FROM vectors WHERE collection=?", (collection,)).fetchall() + for row_id, payload_raw in rows: + payload = json.loads(payload_raw) + if payload.get("doc_id") == doc_id: + conn.execute("DELETE FROM vectors WHERE id=?", (row_id,)) + conn.commit() + + +def count_by_doc(collection: str, doc_id: int) -> int: + client = _get_qdrant() + if client is not None: + from qdrant_client.http import models as qm + + ensure_collection(collection) + result = client.count( + collection_name=collection, + count_filter=qm.Filter( + must=[qm.FieldCondition(key="doc_id", match=qm.MatchValue(value=doc_id))] + ), + exact=True, + ) + return int(result.count) + conn = _fallback_conn() + rows = conn.execute("SELECT payload FROM vectors WHERE collection=?", (collection,)).fetchall() + count = 0 + for (payload_raw,) in rows: + payload = json.loads(payload_raw) + if payload.get("doc_id") == doc_id: + count += 1 + return count + + +def collection_point_count(collection: str) -> int: + client = _get_qdrant() + if client is not None: + try: + info = client.get_collection(collection) + return int(info.points_count or 0) + except Exception: + return 0 + conn = _fallback_conn() + row = conn.execute( + "SELECT COUNT(*) FROM vectors WHERE collection=?", (collection,) + ).fetchone() + return int(row[0] if row else 0) + + +def search( + collections: list[str], + vector: list[float], + limit: int = 8, + visibility_filter: Optional[dict] = None, +) -> list[dict]: + results: list[dict] = [] + client = _get_qdrant() + if client is not None: + from qdrant_client.http import models as qm + + for collection in collections: + ensure_collection(collection, len(vector)) + flt = None + if visibility_filter: + must = [ + qm.FieldCondition(key=k, match=qm.MatchValue(value=v)) + for k, v in visibility_filter.items() + ] + if must: + flt = qm.Filter(must=must) + hits = client.search( + collection_name=collection, + query_vector=vector, + limit=limit, + query_filter=flt, + ) + for hit in hits: + payload = dict(hit.payload or {}) + payload["score"] = hit.score + payload["collection"] = collection + results.append(payload) + else: + conn = _fallback_conn() + for collection in collections: + rows = conn.execute( + "SELECT vector,payload FROM vectors WHERE collection=?", (collection,) + ).fetchall() + for vec_raw, payload_raw in rows: + payload = dict(json.loads(payload_raw)) + if visibility_filter: + if any(payload.get(k) != v for k, v in visibility_filter.items()): + continue + score = _cosine(vector, json.loads(vec_raw)) + payload["score"] = score + payload["collection"] = collection + results.append(payload) + results.sort(key=lambda x: x.get("score", 0), reverse=True) + return results[:limit] diff --git a/services/loogle-mcp/app/knowledge/text_chunk.py b/services/loogle-mcp/app/knowledge/text_chunk.py new file mode 100644 index 0000000..ca40217 --- /dev/null +++ b/services/loogle-mcp/app/knowledge/text_chunk.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +"""Utility condivise per chunking testo RAG.""" + +import re + +CHUNK_SIZE = 900 +CHUNK_OVERLAP = 150 + + +def chunk_text(text: str) -> list[str]: + text = re.sub(r"\n{3,}", "\n\n", text.strip()) + if len(text) <= CHUNK_SIZE: + return [text] if text else [] + chunks = [] + start = 0 + while start < len(text): + end = min(len(text), start + CHUNK_SIZE) + chunks.append(text[start:end]) + if end >= len(text): + break + start = max(end - CHUNK_OVERLAP, start + 1) + return chunks diff --git a/services/loogle-mcp/app/knowledge/thermal.py b/services/loogle-mcp/app/knowledge/thermal.py new file mode 100644 index 0000000..3f59144 --- /dev/null +++ b/services/loogle-mcp/app/knowledge/thermal.py @@ -0,0 +1,242 @@ +# -*- coding: utf-8 -*- +"""Thermal / load gate per proteggere il DS920 durante gli embedding Ollama. + +Legge temperatura CPU e load average dal NAS e regola pause/keep_alive. +""" + +from __future__ import annotations + +import json +import logging +import os +import subprocess +import time +from typing import Optional + +import httpx + +LOGGER = logging.getLogger("loogle_mcp.thermal") + +# Soft: rallenta. Hard: pausa (raro se il profilo lento tiene). +# Profilo "lento ma regolare": anticipare soft, cap load basso. +DEFAULT_SOFT_C = 58.0 +DEFAULT_HARD_C = 70.0 +DEFAULT_CPU_TARGET_PCT = 40.0 # load1 <= nproc * 0.40 + + +def _float_env(name: str, default: float) -> float: + try: + return float(os.environ.get(name, str(default))) + except ValueError: + return default + + +def soft_temp_c() -> float: + return _float_env("THERMAL_TEMP_SOFT_C", DEFAULT_SOFT_C) + + +def hard_temp_c() -> float: + return _float_env("THERMAL_TEMP_HARD_C", DEFAULT_HARD_C) + + +def cpu_target_pct() -> float: + return _float_env("THERMAL_CPU_TARGET_PCT", DEFAULT_CPU_TARGET_PCT) + + +def enabled() -> bool: + flag = os.environ.get("THERMAL_GATE_ENABLED", "yes").strip().lower() + return flag not in ("0", "false", "no", "off") + + +def _read_via_http() -> Optional[dict]: + url = os.environ.get("DS920_THERMAL_URL", "").strip() + if not url: + # default probe se non configurato + url = os.environ.get( + "DS920_THERMAL_URL_DEFAULT", + "http://192.168.128.100:9191/thermal", + ).strip() + try: + with httpx.Client(timeout=3.0) as client: + resp = client.get(url) + if resp.status_code != 200: + return None + data = resp.json() + if isinstance(data, dict) and "cpu_temp_c" in data: + return data + except Exception as exc: + LOGGER.debug("Thermal HTTP probe fallita: %s", exc) + return None + + +def _read_via_ssh() -> Optional[dict]: + host = os.environ.get("DS920_SSH_HOST", "192.168.128.100").strip() + user = os.environ.get("DS920_SSH_USER", "daniely").strip() + key = os.environ.get("DS920_SSH_KEY", "").strip() + if not host: + return None + remote = ( + "python3 -c \"import json,os;" + "b='/sys/class/hwmon/hwmon0';" + "t=[int(open(f'{b}/'+n).read())/1000 for n in sorted(os.listdir(b)) " + "if n.startswith('temp') and n.endswith('_input')];" + "l=os.getloadavg();" + "print(json.dumps({'cpu_temp_c':max(t) if t else None," + "'load1':l[0],'load5':l[1],'nproc':os.cpu_count() or 4}))\"" + ) + cmd = [ + "ssh", + "-o", "BatchMode=yes", + "-o", "ConnectTimeout=5", + "-o", "StrictHostKeyChecking=accept-new", + ] + if key and os.path.isfile(key): + cmd.extend(["-i", key]) + cmd.append(f"{user}@{host}") + cmd.append(remote) + try: + out = subprocess.check_output(cmd, stderr=subprocess.DEVNULL, timeout=12, text=True) + data = json.loads(out.strip()) + if isinstance(data, dict) and data.get("cpu_temp_c") is not None: + return data + except Exception as exc: + LOGGER.debug("Thermal SSH probe fallita: %s", exc) + return None + + +def read_status() -> Optional[dict]: + """Ritorna {cpu_temp_c, load1, load5?, nproc} oppure None se non raggiungibile.""" + data = _read_via_http() + if data: + data["source"] = "http" + return data + data = _read_via_ssh() + if data: + data["source"] = "ssh" + return data + return None + + +def load_over_target(status: dict) -> bool: + load1 = float(status.get("load1") or 0) + nproc = float(status.get("nproc") or 4) + target = nproc * (cpu_target_pct() / 100.0) + return load1 > target + + +def suggested_keep_alive(status: Optional[dict]) -> int: + """Secondi keep_alive Ollama. + + Il container resta sempre acceso: non si fa unload per throttling termico + (evita cicli load/unload). Si scarica solo se OLLAMA_UNLOAD_ON_HARD=yes. + """ + cool = int(_float_env("OLLAMA_KEEP_ALIVE_COOL", 300)) + default = int(_float_env("OLLAMA_KEEP_ALIVE_DEFAULT", 120)) + if not status or status.get("cpu_temp_c") is None: + return default + temp = float(status["cpu_temp_c"]) + unload = os.environ.get("OLLAMA_UNLOAD_ON_HARD", "no").strip().lower() + if temp >= hard_temp_c() and unload in ("1", "true", "yes", "on"): + return 0 + return cool + + +def suggested_delay_s(status: Optional[dict]) -> float: + """Duty-cycle lento: delay base sempre presente; cresce con temp/load.""" + base = _float_env("OLLAMA_EMBED_DELAY_S", 8.0) + if not status or status.get("cpu_temp_c") is None: + return max(base, 5.0) + temp = float(status["cpu_temp_c"]) + hard = hard_temp_c() + soft = soft_temp_c() + if temp >= hard: + return max(base, 45.0) + if temp >= soft: + # soft→hard: ~base*1.5 … ~35s (continuo, non on/off) + ratio = (temp - soft) / max(hard - soft, 1.0) + return max(base, base * 1.5 + ratio * 25.0) + if load_over_target(status): + return max(base, base * 2.0) + if temp >= soft - 4: + return max(base, base * 1.25) + return base + + +def wait_for_headroom(*, context: str = "embed") -> Optional[dict]: + """Attende headroom: HARD = pausa lunga; altrimenti delay proporzionale. + + Obiettivo: ritmo lento e regolare, evitando oscillazioni start/stop. + """ + if not enabled(): + return None + + poll = _float_env("THERMAL_POLL_S", 30.0) + hard = hard_temp_c() + soft = soft_temp_c() + # Riprendi solo quando sotto soft - 2°C (isteresi anti-oscillazione) + resume_below = soft - _float_env("THERMAL_RESUME_MARGIN_C", 2.0) + + while True: + status = read_status() + if status is None: + LOGGER.warning("Thermal gate: probe non disponibile — delay conservativo") + time.sleep(max(suggested_delay_s(None), 5.0)) + return None + + temp = float(status.get("cpu_temp_c") or 0) + load1 = float(status.get("load1") or 0) + + if temp >= hard: + LOGGER.warning( + "Thermal gate [%s]: PAUSA HARD temp=%.1f°C (tetto=%.0f°C resume<=%.0f°C " + "load1=%.2f) — riprovo tra %.0fs", + context, + temp, + hard, + resume_below, + load1, + poll, + ) + time.sleep(poll) + # Isteresi: resta in pausa finché non scende sotto soft + while True: + cooled = read_status() + if cooled is None: + time.sleep(poll) + continue + t2 = float(cooled.get("cpu_temp_c") or 0) + if t2 <= resume_below and not load_over_target(cooled): + LOGGER.info( + "Thermal gate [%s]: ripresa dopo HARD (temp=%.1f°C)", + context, + t2, + ) + status = cooled + break + time.sleep(poll) + # dopo ripresa applica comunque un delay soft prima dell'embed + time.sleep(suggested_delay_s(status)) + return status + + if temp >= soft or load_over_target(status): + delay = suggested_delay_s(status) + LOGGER.info( + "Thermal gate [%s]: rallento temp=%.1f°C load1=%.2f — delay %.1fs (source=%s)", + context, + temp, + load1, + delay, + status.get("source"), + ) + time.sleep(delay) + again = read_status() + if again and float(again.get("cpu_temp_c") or 0) >= hard: + status = again + continue + return again or status + + # Zona fredda: piccolo delay fisso per duty-cycle regolare + cool_delay = _float_env("OLLAMA_EMBED_COOL_DELAY_S", 0.0) + if cool_delay > 0: + time.sleep(cool_delay) + return status \ No newline at end of file diff --git a/services/loogle-mcp/app/main.py b/services/loogle-mcp/app/main.py new file mode 100644 index 0000000..40f225d --- /dev/null +++ b/services/loogle-mcp/app/main.py @@ -0,0 +1,368 @@ +# -*- coding: utf-8 -*- +"""Loogle MCP Hub — gateway FastAPI + OAuth + MCP Streamable HTTP.""" + +import json +import logging +import os +import secrets +from typing import Optional + +from fastapi import Depends, FastAPI, Form, HTTPException, Request, Response +from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse +from pydantic import BaseModel + +from . import audit, auth, jwt_utils, oauth +from .db import get_conn, init_db +from .mcp import server as mcp_server + +logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s %(message)s") +LOGGER = logging.getLogger("loogle_mcp.main") + +app = FastAPI(title="Loogle MCP Hub", docs_url=None, redoc_url=None) +app.add_middleware( + CORSMiddleware, + allow_origins=[ + "https://claude.ai", + "https://chatgpt.com", + "https://chat.openai.com", + ], + allow_methods=["GET", "POST", "OPTIONS"], + allow_headers=["*"], +) +STATIC_DIR = os.path.join(os.path.dirname(__file__), "static") + + +@app.on_event("startup") +def on_startup() -> None: + init_db() + auth.ensure_sessions_table() + auth.ensure_family_users() + oauth.ensure_default_client() + if not os.environ.get("MCP_JWT_SECRET", "").strip(): + secret = secrets.token_urlsafe(48) + os.environ["MCP_JWT_SECRET"] = secret + LOGGER.warning("MCP_JWT_SECRET generato — salvalo in .env: %s", secret) + + +# ------------------------------------------------------------------ Health + +@app.get("/health") +def health(): + return {"ok": True, "service": "loogle-mcp", "port": int(os.environ.get("MCP_PORT", "8700"))} + + +# ------------------------------------------------------------------ OAuth metadata + +@app.get("/.well-known/oauth-authorization-server") +def oauth_metadata(): + return oauth.authorization_server_metadata() + + +@app.get("/.well-known/oauth-protected-resource") +def protected_resource(): + return oauth.protected_resource_metadata() + + +@app.get("/.well-known/oauth-protected-resource/mcp") +def protected_resource_mcp(): + return oauth.protected_resource_metadata() + + +@app.get("/.well-known/openid-configuration") +def openid_configuration(): + """Fallback discovery usato da Claude se oauth-authorization-server non basta.""" + return oauth.authorization_server_metadata() + + +# ------------------------------------------------------------------ OAuth endpoints + +class RegisterBody(BaseModel): + client_name: str + redirect_uris: list[str] + + +@app.post("/oauth/register") +def oauth_register(body: RegisterBody): + try: + return oauth.register_client(body.client_name, body.redirect_uris) + except HTTPException as exc: + return JSONResponse( + status_code=exc.status_code, + content={"error": "invalid_client_metadata", "error_description": str(exc.detail)}, + ) + + +# Alias root-level OAuth (Claude/ChatGPT fallback se la discovery RFC 8414 fallisce) +@app.post("/register") +def oauth_register_root(body: RegisterBody): + return oauth_register(body) + + +@app.get("/oauth/authorize") +def oauth_authorize_get( + response_type: str, + client_id: str, + redirect_uri: str, + scope: str = "context:read context:write knowledge:read knowledge:write gitea:read gitea:write", + state: str = "", + code_challenge: Optional[str] = None, + code_challenge_method: Optional[str] = None, +): + if response_type != "code": + raise HTTPException(400, "response_type must be code") + html = _login_form(client_id, redirect_uri, scope, state, code_challenge, code_challenge_method) + return HTMLResponse(html) + + +@app.post("/oauth/authorize") +def oauth_authorize_post( + request: Request, + client_id: str = Form(...), + redirect_uri: str = Form(...), + scope: str = Form("context:read context:write knowledge:read knowledge:write gitea:read gitea:write"), + state: str = Form(""), + code_challenge: Optional[str] = Form(None), + code_challenge_method: Optional[str] = Form(None), + username: str = Form(...), + password: str = Form(...), +): + ip = request.client.host if request.client else "?" + auth.throttle(ip) + user = auth.authenticate(username, password) + if not user: + auth.record_attempt(ip) + html = _login_form( + client_id, redirect_uri, scope, state, code_challenge, code_challenge_method, + error="Credenziali non valide", + ) + return HTMLResponse(html, status_code=401) + url = oauth.build_authorize_redirect( + client_id, redirect_uri, scope, state, code_challenge, code_challenge_method, user["id"] + ) + return RedirectResponse(url, status_code=302) + + +@app.get("/authorize") +def oauth_authorize_get_root( + response_type: str, + client_id: str, + redirect_uri: str, + scope: str = "context:read context:write knowledge:read knowledge:write gitea:read gitea:write", + state: str = "", + code_challenge: Optional[str] = None, + code_challenge_method: Optional[str] = None, +): + return oauth_authorize_get( + response_type, client_id, redirect_uri, scope, state, code_challenge, code_challenge_method + ) + + +@app.post("/authorize") +def oauth_authorize_post_root( + request: Request, + client_id: str = Form(...), + redirect_uri: str = Form(...), + scope: str = Form("context:read context:write knowledge:read knowledge:write gitea:read gitea:write"), + state: str = Form(""), + code_challenge: Optional[str] = Form(None), + code_challenge_method: Optional[str] = Form(None), + username: str = Form(...), + password: str = Form(...), +): + return oauth_authorize_post( + request, client_id, redirect_uri, scope, state, code_challenge, code_challenge_method, username, password + ) + + +@app.post("/oauth/token") +async def oauth_token(request: Request): + content_type = request.headers.get("content-type", "") + if "application/json" in content_type: + body = await request.json() + else: + form = await request.form() + body = dict(form) + grant_type = body.get("grant_type") + client_id = body.get("client_id") or os.environ.get("MCP_OAUTH_CLIENT_ID", "loogle-mcp-public") + if grant_type == "authorization_code": + return oauth.exchange_code( + body.get("code", ""), + client_id, + body.get("redirect_uri", ""), + body.get("code_verifier"), + ) + if grant_type == "refresh_token": + return oauth.refresh_access_token(body.get("refresh_token", ""), client_id) + raise HTTPException(400, "grant_type non supportato") + + +@app.post("/token") +async def oauth_token_root(request: Request): + return await oauth_token(request) + + +# ------------------------------------------------------------------ MCP endpoint + +@app.post("/mcp") +async def mcp_post(request: Request): + auth_header = request.headers.get("authorization", "") + claims = oauth.bearer_claims_from_header(auth_header) + try: + payload = await request.json() + except Exception: + raise HTTPException(400, "JSON non valido") + if isinstance(payload, list): + responses = mcp_server.handle_batch(payload, claims) + return JSONResponse(responses) + response = mcp_server.handle_message(payload, claims) + if not claims and payload.get("method") not in ("initialize", "notifications/initialized", "ping"): + return JSONResponse(response, status_code=401, headers=_auth_challenge_headers()) + return JSONResponse(response) + + +@app.get("/mcp") +def mcp_get(): + return JSONResponse( + {"error": "Use POST for MCP JSON-RPC"}, + status_code=405, + headers=_auth_challenge_headers(), + ) + + +def _auth_challenge_headers() -> dict: + base = jwt_utils.base_url() + resource_metadata = f"{base}/.well-known/oauth-protected-resource/mcp" + return { + "WWW-Authenticate": f'Bearer realm="mcp", resource_metadata="{resource_metadata}"', + } + + +# ------------------------------------------------------------------ Dashboard web + +class LoginBody(BaseModel): + username: str + password: str + + +class PasswordBody(BaseModel): + old_password: str + new_password: str + + +class RevokeBody(BaseModel): + refresh_token: str + + +@app.post("/api/login") +def api_login(body: LoginBody, request: Request, response: Response): + ip = request.client.host if request.client else "?" + auth.throttle(ip) + user = auth.authenticate(body.username.strip(), body.password) + if not user: + auth.record_attempt(ip) + raise HTTPException(401, "Credenziali non valide") + import datetime + token = secrets.token_urlsafe(32) + expires = ( + datetime.datetime.utcnow() + datetime.timedelta(days=auth.SESSION_DAYS) + ).strftime("%Y-%m-%d %H:%M:%S") + get_conn().execute( + "INSERT INTO sessions(token,user_id,expires_at) VALUES (?,?,?)", + (token, user["id"], expires), + ) + get_conn().commit() + response.set_cookie("mcp_session", token, max_age=auth.SESSION_DAYS * 86400, httponly=True, samesite="lax", path="/") + return {"ok": True, "user": {"username": user["username"], "is_admin": user["is_admin"]}} + + +@app.post("/api/logout") +def api_logout(request: Request, response: Response): + token = request.cookies.get("mcp_session", "") + if token: + get_conn().execute("DELETE FROM sessions WHERE token=?", (token,)) + get_conn().commit() + response.delete_cookie("mcp_session", path="/") + return {"ok": True} + + +@app.get("/api/me") +def api_me(user=Depends(auth.current_user_from_cookie)): + return user + + +@app.post("/api/password") +def api_password(body: PasswordBody, user=Depends(auth.current_user_from_cookie)): + if len(body.new_password.strip()) < 6: + raise HTTPException(400, "La nuova password deve avere almeno 6 caratteri") + if not auth.change_password(user["id"], body.old_password, body.new_password): + raise HTTPException(400, "Password attuale errata") + return {"ok": True} + + +@app.get("/api/projects") +def api_projects(user=Depends(auth.current_user_from_cookie)): + from .context import store as context_store + return context_store.list_projects(user["username"]) + + +@app.get("/api/audit") +def api_audit(limit: int = 100, user=Depends(auth.current_user_from_cookie)): + if user["is_admin"]: + return audit.list_audit(limit=min(limit, 500)) + return audit.list_audit(limit=min(limit, 200), username=user["username"]) + + +@app.post("/api/admin/revoke-refresh") +def api_revoke_refresh(body: RevokeBody, _=Depends(auth.require_admin)): + jwt_utils.revoke_refresh_token(body.refresh_token) + return {"ok": True} + + +@app.get("/dashboard") +def dashboard_page(): + path = os.path.join(STATIC_DIR, "dashboard.html") + return HTMLResponse(open(path, encoding="utf-8").read()) + + +@app.get("/") +def root(): + return RedirectResponse("/dashboard") + + +def _login_form( + client_id: str, + redirect_uri: str, + scope: str, + state: str, + code_challenge: Optional[str], + code_challenge_method: Optional[str], + error: str = "", +) -> str: + err = f'

{error}

' if error else "" + return f""" + +Loogle MCP — Login + +

Loogle MCP Hub

+

Accedi con le credenziali famiglia per collegare Claude, ChatGPT o Gemini.

+
{err} +
+ + + + + + + + + +
+

Primo accesso: password = username (es. lucia/lucia). Cambiala dal dashboard.

+
""" diff --git a/services/loogle-mcp/app/mcp/__init__.py b/services/loogle-mcp/app/mcp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/services/loogle-mcp/app/mcp/server.py b/services/loogle-mcp/app/mcp/server.py new file mode 100644 index 0000000..d286463 --- /dev/null +++ b/services/loogle-mcp/app/mcp/server.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +"""MCP JSON-RPC handler (Streamable HTTP compatible).""" + +import json +import logging +from typing import Any, Optional + +from . import tools + +LOGGER = logging.getLogger("loogle_mcp.server") +PROTOCOL_VERSION = "2024-11-05" + + +def _error(req_id: Any, code: int, message: str) -> dict: + return {"jsonrpc": "2.0", "id": req_id, "error": {"code": code, "message": message}} + + +def _result(req_id: Any, result: dict) -> dict: + return {"jsonrpc": "2.0", "id": req_id, "result": result} + + +def handle_message(body: dict, claims: Optional[dict]) -> dict: + method = body.get("method") + req_id = body.get("id") + params = body.get("params") or {} + + if method == "initialize": + return _result( + req_id, + { + "protocolVersion": PROTOCOL_VERSION, + "capabilities": {"tools": {}, "resources": {}}, + "serverInfo": {"name": "loogle-mcp", "version": "1.0.0"}, + }, + ) + + if method == "notifications/initialized": + return _result(req_id, {}) + + if method == "ping": + return _result(req_id, {}) + + if not claims: + return _error(req_id, -32001, "Autenticazione richiesta (Bearer token OAuth)") + + if method == "tools/list": + return _result(req_id, {"tools": tools.tool_definitions()}) + + if method == "tools/call": + name = params.get("name") + arguments = params.get("arguments") or {} + try: + tool_result = tools.call_tool(name, arguments, claims) + return _result(req_id, tool_result) + except PermissionError as exc: + return _error(req_id, -32003, str(exc)) + except FileNotFoundError as exc: + return _error(req_id, -32004, str(exc)) + except Exception as exc: + LOGGER.exception("Tool %s failed", name) + return _error(req_id, -32000, str(exc)) + + if method == "resources/list": + return _result(req_id, {"resources": tools.list_resources(claims)}) + + if method == "resources/read": + uri = params.get("uri") + try: + resource = tools.read_resource(uri, claims) + return _result(req_id, {"contents": [resource]}) + except FileNotFoundError as exc: + return _error(req_id, -32004, str(exc)) + + return _error(req_id, -32601, f"Metodo non supportato: {method}") + + +def handle_batch(messages: list, claims: Optional[dict]) -> list: + return [handle_message(msg, claims) for msg in messages if isinstance(msg, dict)] diff --git a/services/loogle-mcp/app/mcp/tools.py b/services/loogle-mcp/app/mcp/tools.py new file mode 100644 index 0000000..f069c17 --- /dev/null +++ b/services/loogle-mcp/app/mcp/tools.py @@ -0,0 +1,962 @@ +# -*- coding: utf-8 -*- +"""MCP tool definitions and handlers.""" + +import json +from typing import Any, Optional + +from .. import audit +from ..context import store as context_store +from ..jwt_utils import has_scope +from ..knowledge import apps_indexer, gitea, gitea_indexer, indexer, paperless +from ..integrations import casa, homeassistant, irrigazione, turni + + +def tool_definitions() -> list[dict]: + return [ + { + "name": "ping", + "description": "Verifica che il server MCP Loogle risponda", + "inputSchema": {"type": "object", "properties": {}}, + }, + { + "name": "whoami", + "description": "Restituisce l'utente autenticato e gli scope attivi", + "inputSchema": {"type": "object", "properties": {}}, + }, + { + "name": "list_projects", + "description": "Elenca i progetti dell'utente corrente", + "inputSchema": { + "type": "object", + "properties": {"include_archived": {"type": "boolean", "default": False}}, + }, + }, + { + "name": "create_project", + "description": "Crea un nuovo progetto con archivio contesto; opzionalmente collega un repo Gitea", + "inputSchema": { + "type": "object", + "required": ["title"], + "properties": { + "title": {"type": "string"}, + "tags": {"type": "array", "items": {"type": "string"}}, + "gitea_repo": { + "type": "string", + "description": "Repository Gitea owner/name (es. daniele/rete)", + }, + "seed_from_gitea": { + "type": "boolean", + "default": False, + "description": "Importa README.md nel context.md se collegato a Gitea", + }, + }, + }, + }, + { + "name": "link_project_repo", + "description": "Collega o scollega un repository Gitea da un progetto esistente", + "inputSchema": { + "type": "object", + "required": ["project_id"], + "properties": { + "project_id": {"type": "string"}, + "gitea_repo": { + "type": "string", + "description": "owner/name da collegare; omit o stringa vuota per scollegare", + }, + "seed_from_gitea": { + "type": "boolean", + "default": False, + "description": "Importa README.md nel context.md (solo se non già importato)", + }, + }, + }, + }, + { + "name": "get_project_context", + "description": "Recupera meta, context.md, sessioni recenti e arricchimento Gitea del progetto", + "inputSchema": { + "type": "object", + "required": ["project_id"], + "properties": { + "project_id": {"type": "string"}, + "session_limit": {"type": "integer", "default": 5}, + "include_gitea": { + "type": "boolean", + "default": True, + "description": "Include README/docs dal repo Gitea collegato", + }, + }, + }, + }, + { + "name": "save_context", + "description": "Salva o appende memoria persistente in un progetto", + "inputSchema": { + "type": "object", + "required": ["project_id", "content"], + "properties": { + "project_id": {"type": "string"}, + "content": {"type": "string"}, + "mode": {"type": "string", "enum": ["append", "replace"], "default": "append"}, + }, + }, + }, + { + "name": "archive_project", + "description": "Archivia o ripristina un progetto", + "inputSchema": { + "type": "object", + "required": ["project_id"], + "properties": { + "project_id": {"type": "string"}, + "archived": {"type": "boolean", "default": True}, + }, + }, + }, + { + "name": "search_context", + "description": "Ricerca semantica nei contesti salvati dell'utente", + "inputSchema": { + "type": "object", + "required": ["query"], + "properties": { + "query": {"type": "string"}, + "limit": {"type": "integer", "default": 8}, + }, + }, + }, + { + "name": "search_knowledge", + "description": "Ricerca semantica su Paperless, contesti salvati e repository Gitea indicizzati", + "inputSchema": { + "type": "object", + "required": ["query"], + "properties": { + "query": {"type": "string"}, + "limit": {"type": "integer", "default": 8}, + }, + }, + }, + { + "name": "search_gitea_knowledge", + "description": "Ricerca semantica solo sui file Gitea indicizzati (runbook, markdown, codice)", + "inputSchema": { + "type": "object", + "required": ["query"], + "properties": { + "query": {"type": "string"}, + "limit": {"type": "integer", "default": 8}, + }, + }, + }, + { + "name": "list_gitea_indexed_files", + "description": "Elenca gli ultimi file Gitea indicizzati nel vector store", + "inputSchema": { + "type": "object", + "properties": { + "repo": {"type": "string", "description": "Filtra per owner/name"}, + "limit": {"type": "integer", "default": 30}, + }, + }, + }, + { + "name": "reindex_gitea_repo", + "description": "Re-indicizza i file testo di un repository Gitea (admin o owner repo)", + "inputSchema": { + "type": "object", + "required": ["repo"], + "properties": { + "repo": {"type": "string", "description": "owner/name, es. daniele/rete"}, + "max_files": { + "type": "integer", + "description": "Limite file per questa esecuzione (default: config globale)", + }, + }, + }, + }, + { + "name": "get_document", + "description": "Recupera il contenuto testuale di un documento Paperless per ID", + "inputSchema": { + "type": "object", + "required": ["doc_id"], + "properties": {"doc_id": {"type": "integer"}}, + }, + }, + { + "name": "list_recent_documents", + "description": "Elenca gli ultimi documenti indicizzati", + "inputSchema": { + "type": "object", + "properties": {"limit": {"type": "integer", "default": 20}}, + }, + }, + { + "name": "reindex_document", + "description": "Re-indicizza un documento Paperless (admin)", + "inputSchema": { + "type": "object", + "required": ["doc_id"], + "properties": {"doc_id": {"type": "integer"}}, + }, + }, + { + "name": "list_repos", + "description": "Elenca i repository Gitea accessibili all'utente corrente", + "inputSchema": { + "type": "object", + "properties": { + "page": {"type": "integer", "default": 1}, + "limit": {"type": "integer", "default": 50}, + }, + }, + }, + { + "name": "get_file", + "description": "Legge un file (o elenca una directory) da un repository Gitea", + "inputSchema": { + "type": "object", + "required": ["repo", "path"], + "properties": { + "repo": {"type": "string", "description": "owner/name, es. daniele/rete"}, + "path": {"type": "string", "description": "Percorso nel repo, es. ha/RUNBOOK-failover.md"}, + "ref": {"type": "string", "description": "Branch o tag (default: branch predefinito del repo)"}, + }, + }, + }, + { + "name": "search_code", + "description": "Cerca testo nel codice o nei file di un repository Gitea", + "inputSchema": { + "type": "object", + "required": ["query"], + "properties": { + "query": {"type": "string"}, + "repo": {"type": "string", "description": "Limita la ricerca a owner/name"}, + "limit": {"type": "integer", "default": 20}, + }, + }, + }, + { + "name": "list_issues", + "description": "Elenca le issue di un repository Gitea", + "inputSchema": { + "type": "object", + "required": ["repo"], + "properties": { + "repo": {"type": "string"}, + "state": {"type": "string", "enum": ["open", "closed", "all"], "default": "open"}, + "page": {"type": "integer", "default": 1}, + "limit": {"type": "integer", "default": 20}, + }, + }, + }, + { + "name": "get_issue", + "description": "Recupera una issue Gitea per numero", + "inputSchema": { + "type": "object", + "required": ["repo", "number"], + "properties": { + "repo": {"type": "string"}, + "number": {"type": "integer"}, + }, + }, + }, + { + "name": "create_issue", + "description": "Crea una nuova issue su un repository Gitea", + "inputSchema": { + "type": "object", + "required": ["repo", "title"], + "properties": { + "repo": {"type": "string"}, + "title": {"type": "string"}, + "body": {"type": "string", "default": ""}, + "labels": {"type": "array", "items": {"type": "string"}}, + }, + }, + }, + { + "name": "create_gitea_repo", + "description": "Crea un nuovo repository Gitea sotto l'utente corrente (workspace personale)", + "inputSchema": { + "type": "object", + "required": ["name"], + "properties": { + "name": {"type": "string", "description": "Nome repo (es. progetti)"}, + "private": {"type": "boolean", "default": True}, + "description": {"type": "string", "default": ""}, + "auto_init": { + "type": "boolean", + "default": True, + "description": "Crea README.md iniziale", + }, + }, + }, + }, + { + "name": "create_or_update_file", + "description": "Crea o aggiorna un file su Gitea (commit singolo via API, equivalente a push di un file)", + "inputSchema": { + "type": "object", + "required": ["repo", "path", "content", "message"], + "properties": { + "repo": {"type": "string", "description": "owner/name"}, + "path": {"type": "string", "description": "Percorso file nel repo"}, + "content": {"type": "string", "description": "Contenuto testo del file"}, + "message": {"type": "string", "description": "Messaggio di commit"}, + "branch": {"type": "string", "description": "Branch (default: branch principale del repo)"}, + "reindex": { + "type": "boolean", + "default": True, + "description": "Aggiorna subito il vector store RAG per questo file", + }, + }, + }, + }, + { + "name": "get_home_dashboard", + "description": "Dashboard Loogle Casa: meteo, alert, rete, notifiche", + "inputSchema": {"type": "object", "properties": {}}, + }, + { + "name": "get_home_weather", + "description": "Meteo attuale e previsioni per casa (Loogle Casa)", + "inputSchema": {"type": "object", "properties": {}}, + }, + { + "name": "get_network_overview", + "description": "Panoramica rete domestica: dispositivi online/offline, IP pubblico", + "inputSchema": {"type": "object", "properties": {}}, + }, + { + "name": "get_network_failover_status", + "description": "Stato cluster failover LOOGLE (Pi, NAS, servizi)", + "inputSchema": {"type": "object", "properties": {}}, + }, + { + "name": "get_ha_entity", + "description": "Legge lo stato di un'entità Home Assistant (read-only)", + "inputSchema": { + "type": "object", + "required": ["entity_id"], + "properties": { + "entity_id": { + "type": "string", + "description": "Es. switch.pompa_pozzo, sensor.temperatura_sala", + }, + }, + }, + }, + { + "name": "list_ha_entities", + "description": "Elenca entità Home Assistant, opzionalmente filtrate per dominio", + "inputSchema": { + "type": "object", + "properties": { + "domain": { + "type": "string", + "description": "Filtra per dominio: switch, sensor, light, climate, …", + }, + "limit": {"type": "integer", "default": 50}, + }, + }, + }, + { + "name": "search_ha_entities", + "description": "Cerca entità Home Assistant per nome o entity_id", + "inputSchema": { + "type": "object", + "required": ["query"], + "properties": { + "query": {"type": "string"}, + "limit": {"type": "integer", "default": 20}, + }, + }, + }, + { + "name": "get_irrigation_status", + "description": "Stato irrigazione: zone, programma, pozzo, sensori, connessione HA", + "inputSchema": {"type": "object", "properties": {}}, + }, + { + "name": "get_irrigation_zones", + "description": "Elenco zone irrigazione con stato valvole e portata", + "inputSchema": {"type": "object", "properties": {}}, + }, + { + "name": "get_irrigation_history", + "description": "Storico irrigazioni recenti", + "inputSchema": { + "type": "object", + "properties": {"limit": {"type": "integer", "default": 30}}, + }, + }, + { + "name": "get_turni_status", + "description": "Stato servizio Turni-Live (versione, ambiente)", + "inputSchema": {"type": "object", "properties": {}}, + }, + { + "name": "get_my_shifts", + "description": "Turni di lavoro dell'utente corrente (Turni-Live)", + "inputSchema": { + "type": "object", + "properties": { + "from_date": {"type": "string", "description": "ISO date YYYY-MM-DD"}, + "to_date": {"type": "string", "description": "ISO date YYYY-MM-DD"}, + "limit": {"type": "integer", "default": 50}, + }, + }, + }, + { + "name": "list_turni_doctors", + "description": "Elenco medici/operatori in Turni-Live", + "inputSchema": {"type": "object", "properties": {}}, + }, + { + "name": "search_apps_knowledge", + "description": "Ricerca semantica su storico Irrigazione e Turni indicizzati", + "inputSchema": { + "type": "object", + "required": ["query"], + "properties": { + "query": {"type": "string"}, + "source": { + "type": "string", + "enum": ["irrigazione", "turni"], + "description": "Filtra per sorgente app", + }, + "limit": {"type": "integer", "default": 8}, + }, + }, + }, + { + "name": "list_apps_indexed", + "description": "Elenca record Irrigazione/Turni indicizzati nel vector store", + "inputSchema": { + "type": "object", + "properties": { + "source": {"type": "string", "enum": ["irrigazione", "turni"]}, + "limit": {"type": "integer", "default": 30}, + }, + }, + }, + { + "name": "reindex_apps", + "description": "Forza re-indicizzazione RAG da Irrigazione e/o Turni (admin)", + "inputSchema": { + "type": "object", + "properties": { + "source": { + "type": "string", + "enum": ["irrigazione", "turni", "all"], + "default": "all", + }, + }, + }, + }, + ] + + +def _text_result(payload: Any) -> dict: + return {"content": [{"type": "text", "text": json.dumps(payload, ensure_ascii=False, indent=2)}]} + + +def call_tool(name: str, arguments: dict, claims: dict) -> dict: + username = claims["sub"] + is_admin = "admin" in (claims.get("scope") or "").split() + + if name == "ping": + audit.log_tool(username, name) + return _text_result({"pong": True, "service": "loogle-mcp"}) + + if name == "whoami": + audit.log_tool(username, name) + return _text_result({"username": username, "scope": claims.get("scope"), "is_admin": is_admin}) + + if name == "list_projects": + if not has_scope(claims, "context:read"): + raise PermissionError("Scope context:read richiesto") + projects = context_store.list_projects(username, arguments.get("include_archived", False)) + audit.log_tool(username, name) + return _text_result({"projects": projects}) + + if name == "create_project": + if not has_scope(claims, "context:write"): + raise PermissionError("Scope context:write richiesto") + gitea_repo = arguments.get("gitea_repo") + if gitea_repo and not has_scope(claims, "gitea:read"): + raise PermissionError("Scope gitea:read richiesto per collegare un repository") + try: + meta = context_store.create_project( + username, + arguments["title"], + arguments.get("tags"), + gitea_repo=gitea_repo, + seed_from_gitea=bool(arguments.get("seed_from_gitea")), + ) + except RuntimeError as exc: + raise PermissionError(str(exc)) from exc + except ValueError as exc: + raise ValueError(str(exc)) from exc + audit.log_tool(username, name, meta["id"]) + return _text_result(meta) + + if name == "link_project_repo": + if not has_scope(claims, "context:write"): + raise PermissionError("Scope context:write richiesto") + gitea_repo = arguments.get("gitea_repo") + if gitea_repo and not has_scope(claims, "gitea:read"): + raise PermissionError("Scope gitea:read richiesto per collegare un repository") + try: + meta = context_store.link_project_repo( + username, + arguments["project_id"], + gitea_repo=gitea_repo, + seed_from_gitea=bool(arguments.get("seed_from_gitea")), + ) + except RuntimeError as exc: + raise PermissionError(str(exc)) from exc + except ValueError as exc: + raise ValueError(str(exc)) from exc + audit.log_tool(username, name, arguments["project_id"]) + return _text_result(meta) + + if name == "get_project_context": + if not has_scope(claims, "context:read"): + raise PermissionError("Scope context:read richiesto") + include_gitea = arguments.get("include_gitea", True) + if include_gitea and not has_scope(claims, "gitea:read"): + include_gitea = False + data = context_store.get_project_context( + username, + arguments["project_id"], + arguments.get("session_limit", 5), + include_gitea=include_gitea, + ) + if include_gitea is False and arguments.get("include_gitea", True): + meta = data.get("meta") or {} + if meta.get("gitea_repo"): + data["gitea"] = { + "linked": True, + "repo": meta["gitea_repo"], + "available": False, + "error": "Scope gitea:read richiesto per arricchimento repository", + } + audit.log_tool(username, name, arguments["project_id"]) + return _text_result(data) + + if name == "save_context": + if not has_scope(claims, "context:write"): + raise PermissionError("Scope context:write richiesto") + meta = context_store.save_context( + username, + arguments["project_id"], + arguments["content"], + arguments.get("mode", "append"), + ) + try: + indexer.index_context_snippet( + username, arguments["project_id"], arguments["content"], meta["title"] + ) + except Exception: + pass + audit.log_tool(username, name, arguments["project_id"]) + return _text_result(meta) + + if name == "archive_project": + if not has_scope(claims, "context:write"): + raise PermissionError("Scope context:write richiesto") + meta = context_store.archive_project( + username, arguments["project_id"], arguments.get("archived", True) + ) + audit.log_tool(username, name, arguments["project_id"]) + return _text_result(meta) + + if name == "search_context": + if not has_scope(claims, "context:read"): + raise PermissionError("Scope context:read richiesto") + hits = indexer.search_context(username, arguments["query"], arguments.get("limit", 8)) + audit.log_tool(username, name, detail={"query": arguments["query"]}) + return _text_result({"results": hits}) + + if name == "search_knowledge": + if not has_scope(claims, "knowledge:read"): + raise PermissionError("Scope knowledge:read richiesto") + hits = indexer.search_knowledge( + username, arguments["query"], arguments.get("limit", 8), is_admin=is_admin + ) + audit.log_tool(username, name, detail={"query": arguments["query"]}) + return _text_result({"results": hits}) + + if name == "search_gitea_knowledge": + if not has_scope(claims, "knowledge:read"): + raise PermissionError("Scope knowledge:read richiesto") + if not gitea.is_configured(username): + raise PermissionError("Gitea non configurato per questo utente") + hits = indexer.search_gitea_knowledge( + username, arguments["query"], arguments.get("limit", 8), is_admin=is_admin + ) + audit.log_tool(username, name, detail={"query": arguments["query"]}) + return _text_result({"results": hits}) + + if name == "list_gitea_indexed_files": + if not has_scope(claims, "knowledge:read"): + raise PermissionError("Scope knowledge:read richiesto") + files = gitea_indexer.list_indexed_files( + arguments.get("limit", 30), + repo=arguments.get("repo"), + ) + audit.log_tool(username, name, detail={"repo": arguments.get("repo")}) + return _text_result({"files": files, "count": len(files)}) + + if name == "reindex_gitea_repo": + if not has_scope(claims, "gitea:read"): + raise PermissionError("Scope gitea:read richiesto") + if not gitea.is_configured(username): + raise PermissionError("Gitea non configurato per questo utente") + repo = arguments["repo"] + owner = repo.split("/", 1)[0].lower() + if not is_admin and owner != username: + raise PermissionError("Puoi re-indicizzare solo repository di cui sei owner") + try: + result = gitea_indexer.index_repo( + repo, + username=username, + force=True, + max_files=arguments.get("max_files"), + ) + except Exception as exc: + raise PermissionError(f"Re-indicizzazione Gitea fallita: {exc}") from exc + audit.log_tool(username, name, detail={"repo": repo}) + return _text_result(result) + + if name == "get_document": + if not has_scope(claims, "knowledge:read"): + raise PermissionError("Scope knowledge:read richiesto") + try: + text = paperless.download_document_text(int(arguments["doc_id"]), username=username) + except Exception as exc: + raise PermissionError(f"Documento non accessibile con il tuo account Paperless: {exc}") + audit.log_tool(username, name, str(arguments["doc_id"])) + return _text_result({"doc_id": arguments["doc_id"], "content": text}) + + if name == "list_recent_documents": + if not has_scope(claims, "knowledge:read"): + raise PermissionError("Scope knowledge:read richiesto") + docs = indexer.list_recent_documents(arguments.get("limit", 20)) + audit.log_tool(username, name) + return _text_result({"documents": docs}) + + if name == "reindex_document": + if not is_admin: + raise PermissionError("Scope admin richiesto") + result = indexer.index_document(int(arguments["doc_id"]), force=True) + audit.log_tool(username, name, str(arguments["doc_id"])) + return _text_result(result) + + if name in ( + "list_repos", "get_file", "search_code", "list_issues", "get_issue", "create_issue", + "create_gitea_repo", "create_or_update_file", + ): + if not gitea.is_configured(username): + raise PermissionError( + "Gitea non configurato per questo utente. " + "Aggiungi GITEA_API_TOKEN_{USER} in .env — vedi docs/GITEA-TOKEN.md" + ) + + if name == "list_repos": + if not has_scope(claims, "gitea:read"): + raise PermissionError("Scope gitea:read richiesto") + try: + result = gitea.list_repos( + username=username, + page=int(arguments.get("page", 1)), + limit=int(arguments.get("limit", 50)), + ) + except Exception as exc: + raise PermissionError(f"Gitea non accessibile: {exc}") from exc + audit.log_tool(username, name) + return _text_result(result) + + if name == "get_file": + if not has_scope(claims, "gitea:read"): + raise PermissionError("Scope gitea:read richiesto") + try: + result = gitea.get_file( + arguments["repo"], + arguments["path"], + ref=arguments.get("ref"), + username=username, + ) + except FileNotFoundError as exc: + raise ValueError(str(exc)) from exc + except Exception as exc: + raise PermissionError(f"File Gitea non accessibile: {exc}") from exc + audit.log_tool(username, name, detail={"repo": arguments["repo"], "path": arguments["path"]}) + return _text_result(result) + + if name == "search_code": + if not has_scope(claims, "gitea:read"): + raise PermissionError("Scope gitea:read richiesto") + try: + result = gitea.search_code( + arguments["query"], + repo=arguments.get("repo"), + limit=int(arguments.get("limit", 20)), + username=username, + ) + except Exception as exc: + raise PermissionError(f"Ricerca Gitea fallita: {exc}") from exc + audit.log_tool(username, name, detail={"query": arguments["query"], "repo": arguments.get("repo")}) + return _text_result(result) + + if name == "list_issues": + if not has_scope(claims, "gitea:read"): + raise PermissionError("Scope gitea:read richiesto") + try: + result = gitea.list_issues( + arguments["repo"], + state=arguments.get("state", "open"), + page=int(arguments.get("page", 1)), + limit=int(arguments.get("limit", 20)), + username=username, + ) + except Exception as exc: + raise PermissionError(f"Issue Gitea non accessibili: {exc}") from exc + audit.log_tool(username, name, detail={"repo": arguments["repo"]}) + return _text_result(result) + + if name == "get_issue": + if not has_scope(claims, "gitea:read"): + raise PermissionError("Scope gitea:read richiesto") + try: + result = gitea.get_issue( + arguments["repo"], + int(arguments["number"]), + username=username, + ) + except Exception as exc: + raise PermissionError(f"Issue Gitea non accessibile: {exc}") from exc + audit.log_tool(username, name, detail={"repo": arguments["repo"], "number": arguments["number"]}) + return _text_result(result) + + if name == "create_issue": + if not has_scope(claims, "gitea:write"): + raise PermissionError("Scope gitea:write richiesto") + try: + result = gitea.create_issue( + arguments["repo"], + arguments["title"], + body=arguments.get("body", ""), + labels=arguments.get("labels"), + username=username, + ) + except Exception as exc: + raise PermissionError(f"Creazione issue Gitea fallita: {exc}") from exc + audit.log_tool(username, name, detail={"repo": arguments["repo"], "title": arguments["title"]}) + return _text_result(result) + + if name == "create_gitea_repo": + if not has_scope(claims, "gitea:write"): + raise PermissionError("Scope gitea:write richiesto") + try: + result = gitea.create_repo( + arguments["name"], + username=username, + private=bool(arguments.get("private", True)), + description=arguments.get("description", ""), + auto_init=bool(arguments.get("auto_init", True)), + ) + except Exception as exc: + raise PermissionError(f"Creazione repo Gitea fallita: {exc}") from exc + audit.log_tool(username, name, detail={"name": arguments["name"]}) + return _text_result(result) + + if name == "create_or_update_file": + if not has_scope(claims, "gitea:write"): + raise PermissionError("Scope gitea:write richiesto") + repo = arguments["repo"] + try: + gitea.assert_repo_owner(username, repo, is_admin=is_admin) + result = gitea.create_or_update_file( + repo, + arguments["path"], + arguments["content"], + arguments["message"], + branch=arguments.get("branch"), + username=username, + ) + if arguments.get("reindex", True): + try: + owner, repo_name = gitea.parse_repo(repo) + meta = gitea._request( + "GET", f"/repos/{owner}/{repo_name}", username=username + ) + private = bool(meta.get("private")) + idx = gitea_indexer.index_file( + repo, + arguments["path"], + username=username, + private=private, + force=True, + ) + result["reindex"] = idx + except Exception: + result["reindex"] = {"skipped": True} + except PermissionError: + raise + except Exception as exc: + raise PermissionError(f"Scrittura file Gitea fallita: {exc}") from exc + audit.log_tool( + username, + name, + detail={"repo": repo, "path": arguments["path"], "action": result.get("action")}, + ) + return _text_result(result) + + if name in ( + "get_home_dashboard", "get_home_weather", "get_network_overview", + "get_network_failover_status", + ): + if not has_scope(claims, "home:read"): + raise PermissionError("Scope home:read richiesto") + if not casa.is_configured(username): + raise PermissionError( + "Loogle Casa non configurato. Imposta LOOGLE_CASA_PASSWORD_{USER} in .env" + ) + try: + if name == "get_home_dashboard": + payload = casa.get_dashboard(username) + elif name == "get_home_weather": + payload = casa.get_weather_home(username) + elif name == "get_network_overview": + payload = casa.get_network_overview(username) + else: + payload = casa.get_network_failover_status(username) + except Exception as exc: + raise PermissionError(f"Loogle Casa non accessibile: {exc}") from exc + audit.log_tool(username, name) + return _text_result(payload) + + if name in ("get_ha_entity", "list_ha_entities", "search_ha_entities"): + if not has_scope(claims, "home:read"): + raise PermissionError("Scope home:read richiesto") + if not homeassistant.is_configured(): + raise PermissionError("Home Assistant non configurato — imposta HA_TOKEN in .env") + try: + if name == "get_ha_entity": + payload = homeassistant.get_entity(arguments["entity_id"]) + elif name == "list_ha_entities": + payload = { + "entities": homeassistant.list_entities( + domain=arguments.get("domain"), + limit=int(arguments.get("limit", 50)), + ), + } + else: + payload = { + "results": homeassistant.search_entities( + arguments["query"], + limit=int(arguments.get("limit", 20)), + ), + } + except Exception as exc: + raise PermissionError(f"Home Assistant non accessibile: {exc}") from exc + audit.log_tool(username, name, detail=arguments.get("entity_id") or arguments.get("query")) + return _text_result(payload) + + if name in ("get_irrigation_status", "get_irrigation_zones", "get_irrigation_history"): + if not has_scope(claims, "irrigation:read"): + raise PermissionError("Scope irrigation:read richiesto") + if not irrigazione.is_configured(username): + raise PermissionError( + "Irrigazione non configurata. Imposta IRRIGAZIONE_PASSWORD_{USER} in .env" + ) + try: + if name == "get_irrigation_status": + payload = irrigazione.get_status(username) + elif name == "get_irrigation_zones": + payload = irrigazione.get_zones(username) + else: + payload = irrigazione.get_history(username, int(arguments.get("limit", 30))) + except Exception as exc: + raise PermissionError(f"Irrigazione non accessibile: {exc}") from exc + audit.log_tool(username, name) + return _text_result(payload) + + if name in ("get_turni_status", "get_my_shifts", "list_turni_doctors"): + if name != "get_turni_status" and not has_scope(claims, "turni:read"): + raise PermissionError("Scope turni:read richiesto") + try: + if name == "get_turni_status": + payload = turni.get_status() + elif name == "list_turni_doctors": + if not turni.is_configured(username): + raise PermissionError("Turni non configurato per questo utente") + payload = {"doctors": turni.list_doctors(username)} + else: + if not turni.is_configured(username): + raise PermissionError("Turni non configurato per questo utente") + payload = turni.get_my_shifts( + username, + from_date=arguments.get("from_date"), + to_date=arguments.get("to_date"), + limit=int(arguments.get("limit", 50)), + ) + except PermissionError: + raise + except Exception as exc: + raise PermissionError(f"Turni non accessibile: {exc}") from exc + audit.log_tool(username, name) + return _text_result(payload) + + if name == "search_apps_knowledge": + if not has_scope(claims, "knowledge:read"): + raise PermissionError("Scope knowledge:read richiesto") + hits = apps_indexer.search_apps_knowledge( + arguments["query"], + limit=int(arguments.get("limit", 8)), + source=arguments.get("source"), + ) + audit.log_tool(username, name, detail={"query": arguments["query"]}) + return _text_result({"results": hits}) + + if name == "list_apps_indexed": + if not has_scope(claims, "knowledge:read"): + raise PermissionError("Scope knowledge:read richiesto") + records = apps_indexer.list_indexed_records( + source=arguments.get("source"), + limit=int(arguments.get("limit", 30)), + ) + audit.log_tool(username, name) + return _text_result({"records": records, "count": len(records)}) + + if name == "reindex_apps": + if not is_admin: + raise PermissionError("Scope admin richiesto") + src = arguments.get("source", "all") + if src == "irrigazione": + result = apps_indexer.index_irrigazione() + elif src == "turni": + result = apps_indexer.index_turni() + else: + result = apps_indexer.index_all() + audit.log_tool(username, name, detail={"source": src}) + return _text_result(result) + + raise ValueError(f"Tool sconosciuto: {name}") + + +def list_resources(claims: dict) -> list: + username = claims["sub"] + return context_store.list_resources(username) + + +def read_resource(uri: str, claims: dict) -> dict: + username = claims["sub"] + return context_store.read_resource(username, uri) diff --git a/services/loogle-mcp/app/oauth.py b/services/loogle-mcp/app/oauth.py new file mode 100644 index 0000000..439e00e --- /dev/null +++ b/services/loogle-mcp/app/oauth.py @@ -0,0 +1,322 @@ +# -*- coding: utf-8 -*- +"""OAuth 2.1 Authorization Code + PKCE.""" + +import base64 +import datetime +import hashlib +import json +import os +import secrets +from typing import Optional +from urllib.parse import urlencode, urlparse + +from fastapi import HTTPException + +from . import auth +from .db import get_conn +from .jwt_utils import ( + ACCESS_TOKEN_HOURS, + base_url, + create_access_token, + create_refresh_token, + decode_access_token, + revoke_refresh_token, + scopes_for_user, + consume_refresh_token, +) + + +def _pkce_valid(code_verifier: str, challenge: str, method: str) -> bool: + if method != "S256": + return False + digest = hashlib.sha256(code_verifier.encode()).digest() + computed = base64.urlsafe_b64encode(digest).decode().rstrip("=") + return computed == challenge + + +TRUSTED_REDIRECT_URIS = frozenset({ + "https://claude.ai/api/mcp/auth_callback", + "https://chatgpt.com/connector_platform_oauth_redirect", + "https://chat.openai.com/connector_platform_oauth_redirect", + # Cursor IDE / Agents (docs.cursor.com/mcp) + "https://www.cursor.com/agents/mcp/oauth/callback", + "http://localhost:8787/callback", + # Legacy Cursor desktop + "cursor://anysphere.cursor-mcp/oauth/callback", +}) + + +def ensure_default_client() -> None: + clients = [ + ( + os.environ.get("MCP_OAUTH_CLIENT_ID", "loogle-mcp-public"), + "Loogle MCP Public", + [ + "https://chatgpt.com/connector_platform_oauth_redirect", + "https://chat.openai.com/connector_platform_oauth_redirect", + "https://claude.ai/api/mcp/auth_callback", + "https://www.cursor.com/agents/mcp/oauth/callback", + "http://localhost:8787/callback", + "cursor://anysphere.cursor-mcp/oauth/callback", + "http://127.0.0.1:*/callback", + "http://localhost:*/callback", + ], + ), + ( + "cursor", + "Cursor IDE", + [ + "https://www.cursor.com/agents/mcp/oauth/callback", + "http://localhost:8787/callback", + "cursor://anysphere.cursor-mcp/oauth/callback", + ], + ), + ( + "claude-desktop", + "Claude Desktop/App", + ["https://claude.ai/api/mcp/auth_callback"], + ), + ( + "claude-ai", + "Claude.ai", + ["https://claude.ai/api/mcp/auth_callback"], + ), + ] + conn = get_conn() + for client_id, client_name, redirect_uris in clients: + row = conn.execute( + "SELECT client_id FROM oauth_clients WHERE client_id=?", (client_id,) + ).fetchone() + if row: + conn.execute( + "UPDATE oauth_clients SET client_name=?, redirect_uris=? WHERE client_id=?", + (client_name, json.dumps(redirect_uris), client_id), + ) + else: + conn.execute( + "INSERT INTO oauth_clients(client_id,client_name,redirect_uris) VALUES (?,?,?)", + (client_id, client_name, json.dumps(redirect_uris)), + ) + conn.commit() + + +def _is_trusted_redirect_uri(redirect_uri: str) -> bool: + if redirect_uri in TRUSTED_REDIRECT_URIS: + return True + parsed = urlparse(redirect_uri) + if parsed.scheme == "http" and parsed.hostname in ("127.0.0.1", "localhost"): + if (parsed.path or "").endswith("/callback"): + return True + return False + + +def register_client(client_name: str, redirect_uris: list[str]) -> dict: + client_id = secrets.token_urlsafe(16) + for uri in redirect_uris: + if not _is_trusted_redirect_uri(uri): + raise HTTPException( + status_code=400, + detail=f"Redirect URI non consentito: {uri}", + ) + get_conn().execute( + "INSERT INTO oauth_clients(client_id,client_name,redirect_uris) VALUES (?,?,?)", + (client_id, client_name, json.dumps(redirect_uris)), + ) + get_conn().commit() + return {"client_id": client_id, "client_name": client_name, "redirect_uris": redirect_uris} + + +def _client_redirect_uris(client_id: str) -> list[str]: + row = get_conn().execute( + "SELECT redirect_uris FROM oauth_clients WHERE client_id=?", (client_id,) + ).fetchone() + if not row: + return [] + return json.loads(row["redirect_uris"]) + + +def _ensure_client_for_redirect(client_id: str, redirect_uri: str) -> None: + """Registra client OAuth al volo (Claude usa spesso client_id = username).""" + conn = get_conn() + row = conn.execute( + "SELECT redirect_uris FROM oauth_clients WHERE client_id=?", (client_id,) + ).fetchone() + if row: + uris = set(json.loads(row["redirect_uris"])) + if redirect_uri not in uris: + uris.add(redirect_uri) + conn.execute( + "UPDATE oauth_clients SET redirect_uris=? WHERE client_id=?", + (json.dumps(sorted(uris)), client_id), + ) + conn.commit() + return + conn.execute( + "INSERT INTO oauth_clients(client_id,client_name,redirect_uris) VALUES (?,?,?)", + (client_id, f"MCP client {client_id}", json.dumps([redirect_uri])), + ) + conn.commit() + + +def _redirect_allowed(client_id: str, redirect_uri: str) -> bool: + if _is_trusted_redirect_uri(redirect_uri): + _ensure_client_for_redirect(client_id, redirect_uri) + return True + allowed = _client_redirect_uris(client_id) + if redirect_uri in allowed: + return True + parsed = urlparse(redirect_uri) + for pattern in allowed: + if "*" in pattern: + pp = urlparse(pattern.replace("*", "placeholder")) + if parsed.scheme == pp.scheme and parsed.netloc.endswith(pp.netloc.split("placeholder")[-1]): + return True + return False + + +def create_auth_code( + client_id: str, + user_id: int, + redirect_uri: str, + scope: str, + code_challenge: Optional[str], + code_challenge_method: Optional[str], +) -> str: + code = secrets.token_urlsafe(32) + expires = ( + datetime.datetime.utcnow() + datetime.timedelta(minutes=10) + ).strftime("%Y-%m-%d %H:%M:%S") + get_conn().execute( + "INSERT INTO oauth_codes(code,client_id,user_id,redirect_uri,scope,code_challenge,code_challenge_method,expires_at)" + " VALUES (?,?,?,?,?,?,?,?)", + (code, client_id, user_id, redirect_uri, scope, code_challenge, code_challenge_method, expires), + ) + get_conn().commit() + return code + + +def exchange_code( + code: str, + client_id: str, + redirect_uri: str, + code_verifier: Optional[str], +) -> dict: + row = get_conn().execute( + "SELECT * FROM oauth_codes WHERE code=? AND used=0 AND expires_at > datetime('now')", + (code,), + ).fetchone() + if not row: + raise HTTPException(400, "Codice non valido o scaduto") + row = dict(row) + if row["client_id"] != client_id or row["redirect_uri"] != redirect_uri: + raise HTTPException(400, "Client o redirect URI non validi") + if row.get("code_challenge"): + if not code_verifier or not _pkce_valid(code_verifier, row["code_challenge"], row.get("code_challenge_method") or "S256"): + raise HTTPException(400, "PKCE verification failed") + user = auth.get_user_by_id(row["user_id"]) + if not user: + raise HTTPException(400, "Utente non trovato") + get_conn().execute("UPDATE oauth_codes SET used=1 WHERE code=?", (code,)) + get_conn().commit() + scope = scopes_for_user(user, row["scope"]) + access_token, _ = create_access_token(user, scope, client_id) + refresh = create_refresh_token(user["id"], scope, client_id) + return { + "access_token": access_token, + "token_type": "Bearer", + "expires_in": ACCESS_TOKEN_HOURS * 3600, + "refresh_token": refresh, + "scope": scope, + } + + +def refresh_access_token(refresh_token: str, client_id: str) -> dict: + row = consume_refresh_token(refresh_token) + if not row or row["client_id"] != client_id: + raise HTTPException(400, "Refresh token non valido") + user = auth.get_user_by_id(row["user_id"]) + if not user: + raise HTTPException(400, "Utente non trovato") + revoke_refresh_token(refresh_token) + scope = row["scope"] + access_token, _ = create_access_token(user, scope, client_id) + refresh = create_refresh_token(user["id"], scope, client_id) + return { + "access_token": access_token, + "token_type": "Bearer", + "expires_in": ACCESS_TOKEN_HOURS * 3600, + "refresh_token": refresh, + "scope": scope, + } + + +def authorization_server_metadata() -> dict: + base = base_url() + return { + "issuer": base, + "authorization_endpoint": f"{base}/authorize", + "token_endpoint": f"{base}/token", + "registration_endpoint": f"{base}/register", + "response_types_supported": ["code"], + "grant_types_supported": ["authorization_code", "refresh_token"], + "code_challenge_methods_supported": ["S256"], + "token_endpoint_auth_methods_supported": ["none", "client_secret_post"], + "scopes_supported": [ + "context:read", + "context:write", + "knowledge:read", + "knowledge:write", + "gitea:read", + "gitea:write", + "home:read", + "irrigation:read", + "turni:read", + "admin", + ], + } + + +def protected_resource_metadata() -> dict: + base = base_url() + return { + "resource": f"{base}/mcp", + "authorization_servers": [base], + "scopes_supported": [ + "context:read", + "context:write", + "knowledge:read", + "knowledge:write", + "gitea:read", + "gitea:write", + "home:read", + "irrigation:read", + "turni:read", + ], + "bearer_methods_supported": ["header"], + } + + +def build_authorize_redirect( + client_id: str, + redirect_uri: str, + scope: str, + state: str, + code_challenge: Optional[str], + code_challenge_method: Optional[str], + user_id: int, +) -> str: + if not _redirect_allowed(client_id, redirect_uri): + raise HTTPException(400, "Redirect URI non autorizzato") + code = create_auth_code( + client_id, user_id, redirect_uri, scope, code_challenge, code_challenge_method + ) + params = {"code": code, "state": state} + sep = "&" if "?" in redirect_uri else "?" + return f"{redirect_uri}{sep}{urlencode(params)}" + + +def bearer_claims_from_header(authorization: str) -> Optional[dict]: + if not authorization.lower().startswith("bearer "): + return None + token = authorization[7:].strip() + return decode_access_token(token) diff --git a/services/loogle-mcp/app/static/dashboard.html b/services/loogle-mcp/app/static/dashboard.html new file mode 100644 index 0000000..ba6a885 --- /dev/null +++ b/services/loogle-mcp/app/static/dashboard.html @@ -0,0 +1,129 @@ + + + + + + Loogle MCP Dashboard + + + +

Loogle MCP Hub

+

Archivio contesto e knowledge base locale per AI famiglia

+ +
+

Accedi

+ + + + + + +
+ + + + + + diff --git a/services/loogle-mcp/docker-compose.yml b/services/loogle-mcp/docker-compose.yml new file mode 100644 index 0000000..72c18eb --- /dev/null +++ b/services/loogle-mcp/docker-compose.yml @@ -0,0 +1,63 @@ +services: + loogle-mcp: + build: + context: . + dockerfile: Dockerfile + image: loogle-mcp:latest + container_name: loogle-mcp + restart: always + ports: + - "8700:8700" + env_file: + - .env + environment: + - TZ=Europe/Rome + - MCP_DB=/data/loogle_mcp.db + - MCP_CONTEXT_ROOT=/data/context + - MCP_AUDIT_LOG=/data/audit.log + - MCP_VECTOR_FALLBACK=/data/vector_fallback.db + volumes: + - ./data:/data + - /mnt/ha-apps/mcp/context:/data/context + healthcheck: + test: ["CMD", "curl", "-f", "http://127.0.0.1:8700/health"] + interval: 30s + timeout: 5s + retries: 3 + + loogle-mcp-indexer: + build: + context: . + dockerfile: Dockerfile + image: loogle-mcp:latest + container_name: loogle-mcp-indexer + restart: always + env_file: + - .env + environment: + - TZ=Europe/Rome + - MCP_DB=/data/loogle_mcp.db + - MCP_CONTEXT_ROOT=/data/context + - MCP_VECTOR_FALLBACK=/data/vector_fallback.db + - DS920_SSH_HOST=192.168.128.100 + - DS920_SSH_USER=daniely + - DS920_SSH_KEY=/run/secrets/ds920_ssh_key + - DS920_THERMAL_URL=http://192.168.128.100:9191/thermal + command: ["python", "-m", "worker.indexer_main"] + volumes: + - ./data:/data + - /mnt/ha-apps/mcp/context:/data/context + - /home/daniely/.ssh/id_ed25519:/run/secrets/ds920_ssh_key:ro + depends_on: + - loogle-mcp + + # Qdrant locale: solo su x86/DS920 — su Pi5 ARM 16K page size non supportato + qdrant-local: + profiles: ["qdrant-local"] + image: qdrant/qdrant:v1.13.2 + container_name: loogle_mcp_qdrant + restart: always + ports: + - "6333:6333" + volumes: + - /mnt/ha-apps/mcp/qdrant:/qdrant/storage diff --git a/services/loogle-mcp/docs/APPS-INTEGRATION.md b/services/loogle-mcp/docs/APPS-INTEGRATION.md new file mode 100644 index 0000000..c4e7c2b --- /dev/null +++ b/services/loogle-mcp/docs/APPS-INTEGRATION.md @@ -0,0 +1,91 @@ +# Integrazione app homelab — P5/P6/P7 + +Tool live e RAG su **Loogle Casa**, **Home Assistant**, **Irrigazione** e **Turni**. + +--- + +## P5 — Casa + Home Assistant + +| Tool | Scope | Sorgente | +|------|-------|----------| +| `get_home_dashboard` | home:read | Loogle Casa | +| `get_home_weather` | home:read | Loogle Casa | +| `get_network_overview` | home:read | Loogle Casa | +| `get_network_failover_status` | home:read | Loogle Casa | +| `get_ha_entity` | home:read | Home Assistant | +| `list_ha_entities` | home:read | Home Assistant | +| `search_ha_entities` | home:read | Home Assistant | + +### Variabili `.env` + +```bash +LOOGLE_CASA_URL=https://casa.loogle.it +LOOGLE_CASA_API_URL=http://192.168.128.81:5602 # opzionale, LAN +LOOGLE_CASA_PASSWORD_DANIELE=... # daniele MCP → admin Casa + +HA_URL=https://ha.loogle.it +HA_API_URL=http://192.168.128.81:8123 +HA_TOKEN= +``` + +**Mapping utenti MCP → app:** +- `daniele` → Casa `admin`, Irrigazione `admin`, Turni `daniely` + +--- + +## P6 — Irrigazione + Turni + +| Tool | Scope | Sorgente | +|------|-------|----------| +| `get_irrigation_status` | irrigation:read | irri.loogle.it | +| `get_irrigation_zones` | irrigation:read | irri.loogle.it | +| `get_irrigation_history` | irrigation:read | irri.loogle.it | +| `get_turni_status` | — (pubblico) | turni.loogle.it | +| `get_my_shifts` | turni:read | turni.loogle.it | +| `list_turni_doctors` | turni:read | turni.loogle.it | + +```bash +IRRIGAZIONE_URL=https://irri.loogle.it +IRRIGAZIONE_API_URL=http://192.168.128.81:5601 +IRRIGAZIONE_PASSWORD_DANIELE=... + +TURNI_URL=https://turni.loogle.it +TURNI_PASSWORD_DANIELE=... # utente Turni: daniely +# oppure TURNI_JWT_DANIELE=... +``` + +--- + +## P7 — RAG storico app + +Il worker `loogle-mcp-indexer` indicizza periodicamente: +- snapshot stato/zone Irrigazione +- storico irrigazioni ed eventi +- lavori manutenzione giardino +- turni e anagrafica medici Turni + +| Collection Qdrant | Contenuto | +|-------------------|-----------| +| `apps_shared_family` | Irrigazione + Turni (famiglia) | + +| Tool | Scope | Funzione | +|------|-------|----------| +| `search_apps_knowledge` | knowledge:read | RAG solo app | +| `search_knowledge` | knowledge:read | Include anche app | +| `list_apps_indexed` | knowledge:read | Stato indicizzazione | +| `reindex_apps` | admin | Forza sync | + +```bash +APPS_INDEX_ENABLED=yes +APPS_INDEX_USER=daniele +``` + +--- + +## Test + +```bash +docker exec loogle-mcp python3 /srv/scripts/test_p5_home.py +docker exec loogle-mcp python3 /srv/scripts/test_p6_apps.py +docker exec loogle-mcp python3 /srv/scripts/test_p7_apps_rag.py +``` diff --git a/services/loogle-mcp/docs/ARCHITETTURA.md b/services/loogle-mcp/docs/ARCHITETTURA.md new file mode 100644 index 0000000..353c10b --- /dev/null +++ b/services/loogle-mcp/docs/ARCHITETTURA.md @@ -0,0 +1,297 @@ +# Loogle MCP Hub — Architettura e parametri + +Documento di riferimento per la piattaforma MCP domestica LOOGLE.IT. +Ultimo aggiornamento: 2026-08-22 + +--- + +## Scopo + +**Loogle MCP Hub** espone agli assistenti AI (Claude, ChatGPT, Gemini, Cursor) due capacità principali: + +1. **Archivio contesto** — memoria persistente per progetti e task, isolata per utente +2. **Knowledge base RAG** — ricerca semantica su documenti Paperless e sui contesti salvati + +Tutti i dati restano in LAN/NAS; l’accesso esterno avviene solo via HTTPS + OAuth. + +--- + +## Architettura logica + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Client AI (ChatGPT / Claude / Gemini / Cursor) │ +└───────────────────────────┬─────────────────────────────────┘ + │ HTTPS + OAuth Bearer + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ NPM VIP 192.168.128.85 → mcp.loogle.it:443 │ +└───────────────────────────┬─────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Pi-1 :8700 loogle-mcp (FastAPI) │ +│ ├── /mcp JSON-RPC MCP │ +│ ├── /oauth/* OAuth 2.1 PKCE │ +│ └── /dashboard UI famiglia │ +│ Pi-1 :8700 loogle-mcp-indexer (worker Paperless→vector) │ +└───────┬─────────────────────────────┬───────────────────────┘ + │ │ + ▼ ▼ +┌───────────────┐ ┌─────────────────────┐ +│ SQLite │ │ Vector store │ +│ /data/*.db │ │ Qdrant DS920 :6333 │ +│ utenti OAuth │ │ o fallback SQLite │ +└───────────────┘ └─────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ NFS /mnt/ha-apps/mcp/context/{utente}/projects/... │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Paperless docs.loogle.it (sorgente documenti + OCR) │ +└─────────────────────────────────────────────────────────────┘ +``` + +--- + +## Componenti e percorsi + +| Componente | Host | Porta | Percorso / container | +|------------|------|-------|----------------------| +| MCP Gateway | Pi-1 | 8700 | `loogle-mcp` | +| Indexer | Pi-1 | — | `loogle-mcp-indexer` | +| Qdrant (primario) | DS920 | 6333 | opzionale, compose extrema | +| Vector fallback | Pi-1 | — | `/data/vector_fallback.db` | +| Context NFS | NAS | — | `/mnt/ha-apps/mcp/context/` | +| DB SQLite | Pi-1 | — | `/home/daniely/docker/loogle-mcp/data/loogle_mcp.db` | +| Compose locale | Pi-1 | — | `/home/daniely/docker/loogle-mcp/` | +| Compose failover | Pi-1/Pi-2 | — | `/home/daniely/rete/compose/failover/loogle-mcp-compose.yml` | +| Runbook | — | — | `/home/daniely/rete/ha/RUNBOOK-mcp.md` | + +--- + +## URL e endpoint + +| Servizio | URL | +|----------|-----| +| MCP (client AI) | `https://mcp.loogle.it/mcp` | +| Dashboard web | `https://mcp.loogle.it/dashboard` | +| Health | `https://mcp.loogle.it/health` | +| OAuth authorize | `https://mcp.loogle.it/oauth/authorize` | +| OAuth token | `https://mcp.loogle.it/oauth/token` | +| Metadata OAuth | `https://mcp.loogle.it/.well-known/oauth-authorization-server` | +| Metadata risorsa MCP | `https://mcp.loogle.it/.well-known/oauth-protected-resource` | + +--- + +## DNS + +| Record | Tipo | Valore | Dove configurato | +|--------|------|--------|------------------| +| `mcp.loogle.it` | A | `192.168.128.85` (VIP NPM) | Pi-hole `/etc/pihole/pihole.toml` → hosts | +| Risoluzione LAN | — | Pi-hole → Unbound → split-horizon | Come `docs.loogle.it`, `pass.loogle.it` | + +**Script setup:** `/home/daniely/rete/scripts/setup-mcp-dns-npm.sh` + +**Verifica:** +```bash +dig +short mcp.loogle.it @127.0.0.1 # → 192.168.128.85 +curl -sf https://mcp.loogle.it/health +``` + +--- + +## NPM (reverse proxy) + +| Parametro | Valore | +|-----------|--------| +| Proxy host ID | 30 | +| Dominio | `mcp.loogle.it` | +| Upstream normale | `192.168.128.80:8700` | +| Certificato TLS | `npm-65` (Let's Encrypt) | +| Failover route | `rete/ha/npm-routes.conf` riga `30\|mcp.loogle.it\|8700\|...` | +| Websocket | ON | +| Force SSL | ON | + +**Failover:** `npm-failover-route.sh` aggiorna upstream su Pi-2 / DS920 in base allo scenario HA. + +--- + +## Variabili d'ambiente (`.env`) + +File: `/home/daniely/docker/loogle-mcp/.env` + +| Variabile | Descrizione | Esempio | +|-----------|-------------|---------| +| `MCP_BASE_URL` | URL pubblico (issuer JWT) | `https://mcp.loogle.it` | +| `MCP_JWT_SECRET` | Segreto firma token OAuth | *(stringa lunga casuale)* | +| `MCP_OAUTH_CLIENT_ID` | Client OAuth pre-registrato | `loogle-mcp-public` | +| `PAPERLESS_URL` | API documenti | `https://docs.loogle.it` | +| `PAPERLESS_API_TOKEN` | Token API admin (fallback) | vedi [PAPERLESS-TOKEN.md](PAPERLESS-TOKEN.md) | +| `PAPERLESS_API_TOKEN_{USER}` | Token API per utente | `DANIELE`, `LUCIA`, `DAVIDE`, `LUCA` | +| `QDRANT_URL` | Vector DB remoto | `http://192.168.128.100:6333` | +| `OLLAMA_URL` | Embedding locale | `http://192.168.128.100:11434` | +| `OLLAMA_EMBED_MODEL` | Modello embedding | `nomic-embed-text` | +| `OPENAI_API_KEY` | Fallback embedding cloud | *(opzionale)* | +| `INDEXER_INTERVAL_MINUTES` | Intervallo sync Paperless | `30` | +| `THERMAL_TEMP_HARD_C` | Pausa embedding se CPU DS920 ≥ °C | `70` | +| `THERMAL_TEMP_SOFT_C` | Rallenta embedding sopra °C | `58` | +| `THERMAL_CPU_TARGET_PCT` | Cap load1 (nproc × %) | `40` | +| `OLLAMA_NUM_THREAD` | Thread CPU per richiesta embed | `1` | +| `OLLAMA_EMBED_DELAY_S` | Pausa tra embed (duty-cycle lento) | `10` | +| `DS920_THERMAL_URL` | Probe temp/load DS920 | `http://192.168.128.100:9191/thermal` | + +--- + +## Utenti e isolamento + +| Persona | Username | Ruolo | Password iniziale | +|---------|----------|-------|-------------------| +| Daniele | `daniele` | admin | `daniele` *(cambiarla)* | +| Lucia | `lucia` | user | `lucia` | +| Davide | `davide` | user | `davide` | +| Luca | `luca` | user | `luca` | + +- Ogni utente vede **solo** i propri progetti in `/mnt/ha-apps/mcp/context/{username}/` +- I token OAuth JWT contengono `sub` = username; ogni tool filtra per utente +- L’admin può `reindex_document`, vedere audit completo, revocare refresh token + +**Scope OAuth:** `context:read`, `context:write`, `knowledge:read`, `knowledge:write`, `gitea:read`, `gitea:write`, `home:read`, `irrigation:read`, `turni:read`, `admin` (solo daniele) + +--- + +## Tool MCP esposti + +| Tool | Scope minimo | Funzione | +|------|--------------|----------| +| `ping` | — | Test connettività | +| `whoami` | — | Utente e scope attivi | +| `list_projects` | context:read | Elenco progetti | +| `create_project` | context:write | Nuovo progetto | +| `get_project_context` | context:read | Legge memoria progetto | +| `save_context` | context:write | Salva/appende memoria | +| `archive_project` | context:write | Archivia progetto | +| `search_context` | context:read | Ricerca semantica contesti | +| `search_knowledge` | knowledge:read | RAG Paperless + contesti + Gitea + app | +| `search_gitea_knowledge` | knowledge:read | RAG solo Gitea | +| `search_apps_knowledge` | knowledge:read | RAG Irrigazione + Turni | +| `list_apps_indexed` | knowledge:read | Stato indicizzazione app | +| `reindex_apps` | admin | Re-sync RAG app | +| `get_document` | knowledge:read | Testo documento Paperless | +| `list_recent_documents` | knowledge:read | Ultimi doc indicizzati | +| `reindex_document` | admin | Re-indicizza documento | +| `get_home_dashboard` | home:read | Dashboard Loogle Casa | +| `get_home_weather` | home:read | Meteo casa | +| `get_network_overview` | home:read | Panoramica rete LAN | +| `get_network_failover_status` | home:read | Stato failover cluster | +| `get_ha_entity` | home:read | Entità Home Assistant | +| `list_ha_entities` | home:read | Elenco entità HA | +| `search_ha_entities` | home:read | Cerca entità HA | +| `get_irrigation_status` | irrigation:read | Stato irrigazione | +| `get_irrigation_zones` | irrigation:read | Zone irrigazione | +| `get_irrigation_history` | irrigation:read | Storico irrigazioni | +| `get_turni_status` | — | Stato servizio Turni | +| `get_my_shifts` | turni:read | Turni utente corrente | +| `list_turni_doctors` | turni:read | Medici Turni-Live | + +Vedi anche tool Gitea in `docs/GITEA-TOKEN.md` e app homelab in `docs/APPS-INTEGRATION.md`. + +--- + +## Storage contesto (per progetto) + +``` +/mnt/ha-apps/mcp/context/{username}/projects/{project-id}/ + meta.json # titolo, tag, date, stato, gitea_repo (opz.) + context.md # memoria persistente + sessions/ # snapshot conversazioni + artifacts/ # file generati dagli agenti +``` + +--- + +## Vector store / RAG + +| Collection Qdrant | Contenuto | +|-------------------|-----------| +| `kb_shared_family` | Documenti famiglia (tag non personali) | +| `kb_personal_{user}` | Documenti personali | +| `ctx_{user}` | Embedding dei contesti agente | +| `gitea_shared_family` | File testo da repo Gitea non privati | +| `gitea_personal_{user}` | File testo da repo Gitea privati dell'owner | +| `apps_shared_family` | Export Irrigazione + Turni (P7) | + +**Nota Pi 5:** Qdrant locale su ARM (page size 16K) non è supportato. Default: Qdrant su DS920 o fallback SQLite in `/data/vector_fallback.db`. + +**Pipeline indexer:** ogni 30 min: +1. Paperless → chunk → embedding (Ollama DS920) → upsert `kb_*` +2. Gitea (repo configurati in `GITEA_INDEX_REPOS_*`) → file `.md`/`.py`/`.sh` → chunk → upsert `gitea_*` +3. Irrigazione + Turni → snapshot/storico → upsert `apps_shared_family` (vedi `docs/APPS-INTEGRATION.md`) + +--- + +## Sicurezza + +- TLS terminato su NPM (Let's Encrypt) +- OAuth 2.1 Authorization Code + PKCE +- JWT access token 1h + refresh token 30 giorni (revocabili) +- Audit log: `{timestamp, user, tool, resource_id}` in SQLite +- CrowdSec attivo su NPM +- Nessun accesso cross-user ai dati + +--- + +## Operazioni comuni + +```bash +# Stato servizi +cd /home/daniely/docker/loogle-mcp && docker compose ps + +# Log +docker logs -f loogle-mcp +docker logs -f loogle-mcp-indexer + +# Redeploy +./scripts/deploy.sh + +# DNS + NPM (se reinstall) +sudo /home/daniely/rete/scripts/setup-mcp-dns-npm.sh + +# Failover route +/home/daniely/rete/scripts/npm-failover-route.sh normal + +# Backup dati MCP +/home/daniely/rete/infra-monitor/mcp-restic-backup.sh +``` + +--- + +## Failover (tier-b) + +| Scenario | Comportamento | +|----------|---------------| +| Pi-1 down, Pi-2 up | Stack MCP su Pi-2, NPM upstream → `.81:8700` | +| Extrema DS920 | NPM3 + upstream DS920 | +| Monitoraggio | Probe `mcp_ok` in `failover-status.sh` | + +--- + +## Da completare (post-install) + +1. **`PAPERLESS_API_TOKEN_*`** in `.env` — vedi [PAPERLESS-TOKEN.md](PAPERLESS-TOKEN.md) +2. **Ollama su DS920** con `nomic-embed-text` per embedding locali +3. **Qdrant su DS920** (opzionale): `rete/compose/extrema-ds920/loogle-mcp-compose.yml` +4. **Cambio password** per tutti gli utenti dal dashboard +5. **`MCP_JWT_SECRET`** — impostare valore robusto in produzione + +--- + +## Riferimenti + +- [Guida utenti famiglia](docs/GUIDA-UTENTI.md) +- [Onboarding tecnico client AI](docs/ONBOARDING.md) +- [Runbook operativo](/home/daniely/rete/ha/RUNBOOK-mcp.md) +- [README progetto](README.md) diff --git a/services/loogle-mcp/docs/GITEA-TOKEN.md b/services/loogle-mcp/docs/GITEA-TOKEN.md new file mode 100644 index 0000000..6b1f24e --- /dev/null +++ b/services/loogle-mcp/docs/GITEA-TOKEN.md @@ -0,0 +1,209 @@ +# Token Gitea per Loogle MCP + +## Cosa usare: Personal Access Token (PAT) + +Gitea espone l'API REST su `https://git.loogle.it/api/v1/` con header: + +``` +Authorization: token +``` + +Ogni utente Gitea ha i propri repository e permessi. L'hub MCP usa un token **per utente famiglia**, come Paperless. + +--- + +## Dove generarlo + +Per ogni utente che deve usare i tool Gitea da Claude/Cursor (daniele, lucia, …): + +1. Accedi a https://git.loogle.it con quell'account +2. **Impostazioni** → **Applicazioni** → **Genera nuovo token** +3. Nome suggerito: `loogle-mcp` +4. Scope minimi: + - `read:repository` — list_repos, get_file, search_code, list_issues, get_issue, RAG + - `write:repository` — **P4:** create_or_update_file + - `write:user` — **P4:** create_gitea_repo (`POST /user/repos`) + - `write:issue` — create_issue + - `read:user` — consigliato per `/user/repos` +5. Copia il token (mostrato una sola volta) in `.env` + +### Alternativa CLI (admin, sul nodo con Gitea attivo) + +```bash +docker exec -u git gitea gitea admin user generate-access-token \ + --username daniele \ + --token-name loogle-mcp \ + --scopes 'read:repository,write:repository,write:issue,write:user,read:user' +``` + +--- + +## Configurazione in Loogle MCP + +Modifica `/home/daniely/docker/loogle-mcp/.env`: + +```env +GITEA_URL=https://git.loogle.it +GITEA_API_TOKEN_DANIELE= +GITEA_API_TOKEN_LUCIA= +GITEA_API_TOKEN_DAVIDE= +GITEA_API_TOKEN_LUCA= +``` + +| Utente MCP | Variabile `.env` | Account Gitea | +|------------|------------------|---------------| +| Daniele | `GITEA_API_TOKEN_DANIELE` | daniele | +| Lucia | `GITEA_API_TOKEN_LUCIA` | lucia | +| Davide | `GITEA_API_TOKEN_DAVIDE` | davide | +| Luca | `GITEA_API_TOKEN_LUCA` | luca | + +### URL API interno (opzionale) + +Se `https://git.loogle.it` non è raggiungibile dal container MCP (rete LAN, failover), imposta un URL diretto: + +```env +GITEA_API_URL=http://192.168.128.81:3002 +``` + +I link nei risultati restano su `GITEA_URL` pubblico. + +### Fallback admin + +```env +GITEA_API_TOKEN= +``` + +Tutti gli utenti MCP useranno lo stesso token (sconsigliato salvo test). + +--- + +## Tool MCP Gitea + +| Tool | Scope | Descrizione | +|------|-------|-------------| +| `list_repos` | gitea:read | Repository accessibili | +| `get_file` | gitea:read | Legge file o elenca directory | +| `search_code` | gitea:read | Cerca nel codice (API `/search/code` o fallback tree) | +| `list_issues` | gitea:read | Issue aperte/chiuse | +| `get_issue` | gitea:read | Dettaglio issue | +| `create_issue` | gitea:write | Crea issue | +| `create_gitea_repo` | gitea:write | Crea repo sotto l'utente MCP corrente | +| `create_or_update_file` | gitea:write | Commit singolo di un file (create/update via Contents API) | + +Dopo modifica `.env`: + +```bash +cd /home/daniely/docker/loogle-mcp && docker compose up -d --build +``` + +--- + +## Verifica + +```bash +/home/daniely/docker/loogle-mcp/scripts/test_gitea_integration.py +``` + +Oppure da MCP (con token OAuth): tool `list_repos` e `get_file` su `daniele/rete`. + +--- + +## Collegamento progetto ↔ repository (P2) + +Ogni progetto MCP può referenziare un repo Gitea in `meta.json`: + +```json +"gitea_repo": "daniele/rete" +``` + +### Tool + +| Tool | Azione | +|------|--------| +| `create_project` | Parametri opzionali `gitea_repo`, `seed_from_gitea` | +| `link_project_repo` | Collega, cambia repo o scollega (`gitea_repo` vuoto) | +| `get_project_context` | Aggiunge blocco `gitea` con README, `docs/` e issue aperte | + +### Seed README + +Con `seed_from_gitea: true` il README del repo viene importato in `context.md` (una sola volta, marker ``). + +### Verifica P2 + +```bash +/home/daniely/docker/loogle-mcp/scripts/test_project_gitea_p2.py +``` + +--- + +## RAG su repository Gitea (P3) + +Il worker `loogle-mcp-indexer` indicizza periodicamente file testo dai repo Gitea (`.md`, `.py`, `.sh`, …) in collection Qdrant dedicate: + +| Collection | Contenuto | +|------------|-----------| +| `gitea_shared_family` | Repo non privati | +| `gitea_personal_{user}` | Repo privati dell'owner | + +### Config `.env` + +```env +GITEA_INDEX_ENABLED=yes +GITEA_INDEX_REPOS_DANIELE=daniele/rete,daniele/loogle-scripts +GITEA_INDEX_MAX_FILES_PER_REPO=150 +GITEA_INDEX_MAX_FILE_BYTES=120000 +``` + +Se `GITEA_INDEX_REPOS_{USER}` è vuoto → tutti i repo accessibili via API. + +### Tool MCP + +| Tool | Descrizione | +|------|-------------| +| `search_gitea_knowledge` | Ricerca semantica solo su Gitea | +| `search_knowledge` | Include Paperless + contesti + Gitea | +| `list_gitea_indexed_files` | Stato indicizzazione | +| `reindex_gitea_repo` | Forza re-index di un repo | + +### Verifica P3 + +```bash +docker exec loogle-mcp python3 /srv/scripts/test_gitea_rag_p3.py +``` + +--- + +## Scrittura su Gitea (P4) + +L'AI può creare repository e committare singoli file via API Gitea (senza git push locale). + +| Tool | Scope | Azione | +|------|-------|--------| +| `create_gitea_repo` | gitea:write | Crea repo sotto l'utente MCP autenticato | +| `create_or_update_file` | gitea:write | Crea o aggiorna un file (Contents API + commit) | + +Regole: + +- Scrittura consentita solo su repo di cui l'utente è **owner** (salvo admin MCP). +- Dopo scrittura, opzionalmente re-indicizza il file nel RAG (`reindex: true` default). +- Token Gitea: `write:user` (create repo) + `write:repository` (file). + +### Workspace davide e luca + +| Utente | Repo Gitea | Progetto MCP | +|--------|------------|--------------| +| davide | `davide/progetti` | Progetti Davide | +| luca | `luca/progetti` | Progetti Luca | + +Setup iniziale: + +```bash +docker exec loogle-mcp python3 /srv/scripts/setup_gitea_p4_repos.py +``` + +### Verifica P4 + +```bash +docker exec loogle-mcp python3 /srv/scripts/test_gitea_p4.py +``` + diff --git a/services/loogle-mcp/docs/GUIDA-ADMIN.md b/services/loogle-mcp/docs/GUIDA-ADMIN.md new file mode 100644 index 0000000..acbca09 --- /dev/null +++ b/services/loogle-mcp/docs/GUIDA-ADMIN.md @@ -0,0 +1,190 @@ +# Guida amministratore — Daniele + +Guida operativa per gestire e usare Loogle MCP Hub. + +--- + +## Accesso rapido + +| Cosa | URL / comando | +|------|----------------| +| Dashboard admin | https://mcp.loogle.it/dashboard (login `daniele`) | +| Health | `curl -sf https://mcp.loogle.it/health` | +| Log gateway | `docker logs -f loogle-mcp` | +| Log indexer | `docker logs -f loogle-mcp-indexer` | +| Compose | `cd /home/daniely/docker/loogle-mcp` | + +--- + +## Configurazione iniziale (checklist) + +- [x] Stack Docker avviato (`docker compose up -d`) +- [x] DNS Pi-hole: `mcp.loogle.it` → `192.168.128.85` +- [x] NPM proxy host 30 + TLS Let's Encrypt +- [ ] Token Paperless in `.env` — vedi [PAPERLESS-TOKEN.md](PAPERLESS-TOKEN.md) (Profilo utente, non «Applicazione social») +- [ ] `MCP_JWT_SECRET` robusto in `.env` +- [ ] Ollama su DS920 con `ollama pull nomic-embed-text` +- [ ] Qdrant su DS920 (opzionale, vedi compose extrema) +- [ ] Password cambiate per tutta la famiglia +- [ ] Ogni familiare ha collegato almeno un client AI + +**Script utili:** +```bash +sudo /home/daniely/rete/scripts/setup-mcp-dns-npm.sh # DNS + NPM +./scripts/deploy.sh # rebuild + restart +/home/daniely/rete/scripts/npm-failover-route.sh normal # upstream failover +``` + +--- + +## Come usare tu (Daniele) + +### Dashboard + +1. https://mcp.loogle.it/dashboard — login `daniele` +2. Vedi progetti, audit log completo, revoca refresh token (sezione admin) + +### Con Cursor / Claude / ChatGPT + +Stesso URL MCP: `https://mcp.loogle.it/mcp` + +**Cursor** — aggiungi in `.cursor/mcp.json` del progetto: +```json +{ + "mcpServers": { + "loogle-mcp": { + "url": "https://mcp.loogle.it/mcp" + } + } +} +``` + +### Workflow consigliato per un task + +1. **create_project** — es. «Homelab MCP», tag `rete`, `2026` +2. Lavori con l’AI (Cursor, Claude, ecc.) +3. **save_context** — a fine sessione salvi decisioni e stato +4. **search_knowledge** — recuperi doc da Paperless quando serve +5. **search_context** — ritrovi discussioni passate semanticamente + +### Tool solo admin + +- `reindex_document` — forza re-indicizzazione di un doc Paperless +- Revoca token refresh da dashboard +- Audit log di tutti gli utenti via `/api/audit` + +--- + +## Gestione utenti + +Gli utenti sono in SQLite (`loogle_mcp.db`). Password hash PBKDF2. + +| Utente | Admin | Reset password | +|--------|-------|----------------| +| daniele | sì | dashboard o diretto DB | +| lucia, davide, luca | no | dashboard (self-service) | + +Password iniziale = username. `must_change_password` è attivo al primo login consigliato. + +Per aggiungere utenti in futuro: estendi `FAMILY_USERS` in `app/auth.py` e redeploy. + +--- + +## Paperless → knowledge base + +Vedi guida completa: [PAPERLESS-TOKEN.md](PAPERLESS-TOKEN.md) + +**Non usare** i token «Applicazione social» dell'admin Django (schermata nell'immagine): servono al login OAuth web di Paperless, non all'API REST MCP. + +**Usa** i token API utente: docs.loogle.it → menu utente → **Profilo** → pulsante freccia circolare accanto a «Token API». + +Configura in `.env` (un token per ogni account Paperless della famiglia): + +```bash +PAPERLESS_API_TOKEN_DANIELE= +PAPERLESS_API_TOKEN_LUCIA= +PAPERLESS_API_TOKEN_DAVIDE= +PAPERLESS_API_TOKEN_LUCA= +``` + +Ogni familiare genera il proprio token da docs.loogle.it → **Profilo** → Token API. Se un utente non ha ancora account Paperless, lascia la riga vuota finché non lo crei. + +Alternativa: solo `PAPERLESS_API_TOKEN=` con token admin (Daniele superuser) — tutti gli utenti MCP condividono lo stesso scope. + +Riavvia indexer: +```bash +cd /home/daniely/docker/loogle-mcp && docker compose restart loogle-mcp loogle-mcp-indexer +``` + +**Visibilità documenti (tag Paperless):** +- Tag `personal` / `privato` → solo collection personale del owner +- Senza tag personali → `kb_shared_family` (tutti in famiglia) + +--- + +## Embedding e Qdrant + +| Componente | Dove | Note | +|----------|------|------| +| Ollama | DS920 `:11434` | `OLLAMA_EMBED_MODEL=nomic-embed-text` | +| Qdrant | DS920 `:6333` | Non gira su Pi5 (limitazione ARM) | +| Fallback | `/data/vector_fallback.db` | Automatico se Qdrant non raggiungibile | + +Deploy Qdrant su DS920: +```bash +# sul DS920, path mirror extrema +docker compose -f /volume1/extrema/compose/extrema-ds920/loogle-mcp-compose.yml up -d qdrant +``` + +--- + +## DNS e NPM — cosa è stato configurato + +**Pi-hole** (`/etc/pihole/pihole.toml`): +``` +"192.168.128.85 mcp.loogle.it" +``` + +**NPM** proxy host ID 30: +- Dominio: `mcp.loogle.it` +- Backend: `192.168.128.80:8700` +- Cert: `npm-65` + +**Failover** (`npm-routes.conf`): +``` +30|mcp.loogle.it|8700|pi1|pi1|local|ds920 +``` + +Se reinstalli NPM da zero, riesegui: +```bash +sudo /home/daniely/rete/scripts/setup-mcp-dns-npm.sh +/home/daniely/sync-npm-full.sh # sync Pi2 + DS920 +``` + +--- + +## Monitoraggio e backup + +- **Failover status:** probe `mcp_ok` / `mcp_be` in `failover-status.sh` +- **Runbook incidenti:** `/home/daniely/rete/ha/RUNBOOK-mcp.md` +- **Backup restic:** `/home/daniely/rete/infra-monitor/mcp-restic-backup.sh` + +--- + +## Onboarding famiglia + +Invia a ciascuno: + +- [Guida utenti](GUIDA-UTENTI.md) — istruzioni semplici per ChatGPT/Claude/Gemini +- URL dashboard per cambio password +- Username personale (non condividere password) + +Progetto demo già creato per ogni utente (es. `progetti-personali` per Lucia). + +--- + +## Documentazione tecnica + +- [Architettura e parametri](ARCHITETTURA.md) +- [Onboarding client AI (dettaglio)](ONBOARDING.md) +- [Runbook HA](/home/daniely/rete/ha/RUNBOOK-mcp.md) diff --git a/services/loogle-mcp/docs/GUIDA-PAPERLESS-FAMIGLIA.md b/services/loogle-mcp/docs/GUIDA-PAPERLESS-FAMIGLIA.md new file mode 100644 index 0000000..efebb62 --- /dev/null +++ b/services/loogle-mcp/docs/GUIDA-PAPERLESS-FAMIGLIA.md @@ -0,0 +1,237 @@ +# Paperless — Guida per la famiglia LOOGLE + +**Archivio documenti di casa:** https://docs.loogle.it + +Questa guida spiega **perché** usiamo Paperless, **come** configurarlo e **come** installare l’app sul telefono. + +--- + +## Perché usiamo Paperless + +Paperless è l’**archivio digitale di casa**: bollette, contratti, manuali, referti, ricevute, documenti scolastici, ecc. + +| Prima (cartaceo) | Con Paperless | +|------------------|---------------| +| Documenti sparsi in cassetti e cartelle | Tutto in un unico archivio searchable | +| Difficile trovare «la bolletta luce del 2024» | Cerca per parola, tag, mittente, data | +| Fotocopie e PDF persi nel telefono | PDF centralizzati, backup su NAS di casa | +| Solo chi ha il foglio fisico | Chi ha l’account può consultare (con permessi) | + +**Vantaggi per noi:** + +- **Resta in casa** — i file sono sui nostri dispositivi (Pi + NAS), non su Google Drive o iCloud di terzi +- **OCR in italiano** — Paperless legge il testo nei PDF e nelle scansioni, così puoi cercare anche dentro il documento +- **Integrazione** — l’assistente AI (MCP) può cercare documenti già archiviati quando chiedi «trova la bolletta gas» +- **Accesso da telefono** — consulta e carica documenti ovunque (in rete casa o via VPN) + +--- + +## Cos’è, in pratica + +Paperless-ngx è un sito web dove: + +1. **Carichi** un PDF o una foto (upload, email, cartella sul telefono) +2. **Paperless** fa OCR, propone titolo, data, tag +3. **Tu** confermi o correggi (opzionale) +4. **Archivi** — il documento resta indicizzato e ricercabile + +**Indirizzo:** https://docs.loogle.it +Funziona da browser (PC, tablet, telefono) o da app dedicata. + +--- + +## Account famiglia + +| Nome | Username | Password iniziale | +|------|----------|-------------------| +| Daniele | `daniele` | *(chiedi a Daniele)* | +| Lucia | `lucia` | `lucia` | +| Davide | `davide` | `davide` | +| Luca | `luca` | `luca` | + +**Al primo accesso cambia la password** (vedi sotto). + +Ogni persona vede i **propri** documenti e quelli **condivisi in famiglia** (secondo i permessi impostati). + +--- + +## Primo accesso e configurazione (browser) + +### 1. Accedi al sito + +1. Apri **https://docs.loogle.it** (da casa o in VPN — vedi sotto) +2. Inserisci **username** e **password** +3. Se è la prima volta, Paperless può chiederti di completare il profilo + +### 2. Cambia la password + +1. Clicca sul **nome utente** in alto a destra +2. Vai su **Profilo** / **Impostazioni** +3. Sezione **Password** → inserisci la vecchia e la nuova +4. Salva + +### 3. Conosci l’interfaccia + +| Area | A cosa serve | +|------|----------------| +| **Dashboard** | Panoramica, documenti recenti | +| **Documenti** | Elenco e ricerca di tutti i PDF | +| **Inbox** (se attiva) | Documenti appena caricati da revisionare | +| **Tag / Tipi / Corrispondenti** | Organizzazione (es. tag `bollette`, `salute`) | + +### 4. Caricare un documento + +**Da computer:** + +1. **Documenti** → **Carica** (o trascina il PDF nella finestra) +2. Attendi l’OCR (qualche secondo) +3. Controlla titolo, data, tag → **Salva** + +**Da telefono (browser):** + +- Stesso procedimento dal browser mobile su docs.loogle.it + +**Suggerimento:** usa tag semplici e coerenti, es. `bollette`, `casa`, `auto`, `salute`, `scuola`. + +### 5. Cercare un documento + +- Barra **Cerca** in alto: parole chiave (es. «enel», «bolletta», «assicurazione») +- Filtri per **tag**, **tipo documento**, **data** +- Paperless cerca anche **dentro** il testo del PDF (OCR) + +### 6. Scaricare o condividere + +- Apri un documento → icona **Download** o **Condividi** +- Puoi inviare il PDF via email/WhatsApp dal telefono + +--- + +## Accesso da fuori casa (VPN) + +`docs.loogle.it` è raggiungibile **in rete di casa** (Wi‑Fi domestico o dati se sei a casa). + +**Se sei fuori** (ufficio, viaggio): connettiti prima alla **VPN di casa**: + +- Indirizzo: **https://vpn.loogle.it** +- Credenziali WireGuard: chiedi a Daniele (file `.conf` o QR code) + +Dopo la VPN, apri normalmente https://docs.loogle.it o l’app Paperless. + +--- + +## App sul telefono + +Paperless **non ha un’app ufficiale** del team Paperless-ngx, ma esistono app **compatibili** che si collegano al nostro server. + +### Consigliate + +| App | Android | iPhone/iPad | +|-----|---------|-------------| +| **Paperless Mobile** | [Google Play](https://play.google.com/store/apps/details?id=de.astubenbord.paperless_mobile) | Cerca «Paperless Mobile» su App Store | +| **Paperless Go** | [Google Play](https://play.google.com/store/apps/details?id=com.github.iweinzierl.paperlessgo) / F-Droid | [App Store](https://apps.apple.com/app/paperless-go/id6738696198) | + +Per la famiglia consigliamo **Paperless Mobile** (molto usata, italiano supportato) oppure **Paperless Go** (interfaccia moderna, scansione documenti). + +--- + +## Installazione app — passo passo + +### Android (Paperless Mobile) + +1. Apri **Google Play Store** +2. Cerca **«Paperless Mobile»** (sviluppatore: Andrei Stübenbord) +3. **Installa** +4. Apri l’app → **Aggiungi account** / **Connect** +5. **URL server:** `https://docs.loogle.it` +6. **Username** e **password** (le tue credenziali Paperless) +7. Accetta eventuale avviso certificato (connessione sicura LOOGLE) +8. Fatto — vedi l’elenco documenti + +### iPhone / iPad (Paperless Mobile o Paperless Go) + +1. Apri **App Store** +2. Cerca **«Paperless Mobile»** o **«Paperless Go»** +3. **Scarica** e apri +4. Inserisci: + - **Server URL:** `https://docs.loogle.it` + - **Username** / **Password** +5. Opzionale: attiva **Face ID / Touch ID** per proteggere l’app +6. Fatto + +### Scansione con il telefono (Paperless Go) + +1. Nell’app → **Scansiona** / icona fotocamera +2. Inquadra il documento (bolletta, lettera) +3. Ritaglia e conferma +4. Scegli tag / tipo se richiesto → **Carica** +5. Il PDF compare in Paperless dopo pochi secondi + +--- + +## Configurazione consigliata nell’app + +| Impostazione | Consiglio | +|--------------|-----------| +| **Tema scuro** | Più comodo di sera | +| **Biometria** | Face ID / impronta per aprire l’app | +| **Notifiche** | Opzionali (nuovi documenti in inbox) | +| **Account multipli** | Un account per persona (non condividere la stessa login) | + +--- + +## Buone abitudini + +1. **Carica subito** bollette e documenti importanti (non lasciare pile di carta) +2. **Usa tag** — pochi ma chiari (`luce`, `gas`, `banca`, `medico`) +3. **Controlla l’inbox** — correggi titolo/data se Paperless sbaglia +4. **Non eliminare** l’originale cartaceo finché non sei sicuro che il PDF sia ok +5. **Cambia password** se pensi che qualcuno l’abbia vista + +--- + +## Collegamento con l’assistente AI (MCP) + +Se usi ChatGPT, Claude o Cursor collegati a **Loogle MCP** (`https://mcp.loogle.it`): + +- Puoi chiedere: *«Cerca in Paperless la bolletta luce dell’ultimo trimestre»* +- L’AI cerca solo nei documenti **che il tuo account può vedere** +- Per funzionare, i documenti devono **già essere** in Paperless + +La guida MCP è separata: `GUIDA-UTENTI.pdf` nella stessa cartella. + +--- + +## Problemi comuni + +| Problema | Cosa fare | +|----------|-----------| +| «Sito non raggiungibile» | Sei in rete casa? Se no, attiva **VPN** (vpn.loogle.it) | +| Login fallisce | Controlla username/password; prova da browser prima | +| App «connessione fallita» | URL esatto: `https://docs.loogle.it` (con **https**) | +| Certificato / SSL | Accetta il certificato LOOGLE; data/ora telefono corretta | +| Non vedo un documento | Potrebbe essere personale di un altro utente; chiedi a Daniele | +| OCR illeggibile | Scansiona con buona luce; PDF meglio di foto storta | + +--- + +## Contatti + +**Daniele** — account, permessi, VPN, problemi tecnici. + +--- + +## Scheda rapida + +``` +Sito: https://docs.loogle.it +VPN fuori: https://vpn.loogle.it +App Android: Paperless Mobile (Play Store) +App iPhone: Paperless Mobile o Paperless Go (App Store) +Server URL: https://docs.loogle.it +Login: il tuo username (lucia / davide / luca) +Primo passo: cambia password → installa app → carica una bolletta di prova +``` + +--- + +*Loogle — documenti di famiglia, a casa nostra.* diff --git a/services/loogle-mcp/docs/GUIDA-UTENTI.md b/services/loogle-mcp/docs/GUIDA-UTENTI.md new file mode 100644 index 0000000..96dd0ab --- /dev/null +++ b/services/loogle-mcp/docs/GUIDA-UTENTI.md @@ -0,0 +1,289 @@ +# Guida utenti — Loogle MCP Hub + +Questa guida è per **Lucia, Davide e Luca** (e chiunque usi gli assistenti AI collegati a casa). + +--- + +## Cos’è + +Loogle MCP è la **memoria di casa** per i tuoi assistenti AI. Permette a ChatGPT, Claude o Gemini di: + +- **Ricordare** i tuoi progetti (es. ristrutturazione, studio, hobby) +- **Cercare** documenti che abbiamo già archiviato in Paperless (bollette, manuali, PDF) +- **Salvare** note e riassunti che l’AI produce durante un lavoro, così non devi ripetere tutto ogni volta + +I tuoi dati restano **solo sui nostri dispositivi** a casa, non nel cloud dell’AI. + +--- + +## Le tue credenziali + +| Nome | Username | Password iniziale | +|------|----------|-------------------| +| Lucia | `lucia` | `lucia` | +| Davide | `davide` | `davide` | +| Luca | `luca` | `luca` | + +**Al primo accesso cambia la password:** + +1. Apri https://mcp.loogle.it/dashboard +2. Accedi con username e password +3. Sezione **Cambia password** → inserisci la nuova password (minimo 6 caratteri) + +Ogni persona vede **solo i propri progetti**. Non puoi vedere (né l’AI) i progetti degli altri familiari. + +--- + +## Collegare ChatGPT + +Richiede account **Plus, Pro, Business o Edu**. + +1. Apri ChatGPT → **Impostazioni** +2. Attiva **Developer Mode** (se non già attivo) +3. Vai a **Connectors** → **Add MCP Connector** +4. Inserisci l’URL del server: + ``` + https://mcp.loogle.it/mcp + ``` +5. Clicca **Connect** — si apre una pagina di login Loogle +6. Accedi con **il tuo** username e password (es. `lucia` / la tua nuova password) +7. Autorizza l’accesso + +Nelle conversazioni, abilita i tool del connector **Loogle MCP** quando vuoi usare memoria o documenti. + +### Esempi di richieste a ChatGPT + +- *«Usa list_projects per vedere i miei progetti»* +- *«Leggi il contesto del progetto X e riassumilo»* +- *«Cerca nei documenti di casa informazioni sulla caldaia»* +- *«Salva in save_context questo riepilogo del lavoro fatto oggi»* + +--- + +## Collegare Claude (App / Desktop) + +1. Apri Claude → **Settings** → **Connectors** +2. **Add remote MCP server** +3. URL: + ``` + https://mcp.loogle.it/mcp + ``` +4. Al primo utilizzo: login con le **tue** credenziali Loogle MCP +5. Autorizza + +Claude potrà usare gli stessi tool (progetti, ricerca documenti, salvataggio contesto). + +--- + +## Collegare Cursor IDE + +1. Crea o modifica `~/.cursor/mcp.json` (globale) oppure `.cursor/mcp.json` nel progetto: + +```json +{ + "mcpServers": { + "loogle-mcp": { + "url": "https://mcp.loogle.it/mcp", + "auth": { + "CLIENT_ID": "cursor", + "scopes": [ + "context:read", "context:write", + "knowledge:read", "knowledge:write", + "gitea:read", "gitea:write", + "home:read", "irrigation:read", "turni:read" + ] + } + } + } +} +``` + +2. **Riavvia Cursor completamente** (esci dall’app, non solo chiudi la finestra) +3. **Cursor Settings** → **Tools & MCP** → **Connect** su `loogle-mcp` (**una sola volta**, attendi 10–15 s) +4. Si apre il browser su **Loogle MCP — Login** → accedi con le **tue** credenziali MCP +5. In chat, chiedi all'AI di usare i tool (`list_projects`, `search_knowledge`, …) + +### Cursor: «Unauthorized» nei log + +| Log Cursor | Significato | +|------------|-------------| +| `MCP OAuth redirect` + `Unauthorized` | **Normale prima del login** — clicca **Connect** e completa il browser | +| `Redirect URI non consentito` | Errore server (già risolto) — riprova **Reconnect** | +| `credentials cleared` | Hai cliccato Connect/Disconnect in loop — riavvia Cursor e riprova una volta | + +**Password:** se hai cambiato quella iniziale, usa quella attuale (es. admin `daniele` non usa più `daniele`/`daniele`). Verifica su https://mcp.loogle.it/dashboard + +**Se il browser non si apre:** prova la config con `"CLIENT_ID": "cursor"` sopra, oppure apri manualmente https://mcp.loogle.it/dashboard per testare le credenziali. + +--- + +## Collegare Gemini + +**Gemini CLI** (da terminale / PC): + +1. Apri il file di configurazione MCP di Gemini (es. `~/.gemini/settings.json`) +2. Aggiungi: + +```json +{ + "mcpServers": { + "loogle-mcp": { + "url": "https://mcp.loogle.it/mcp" + } + } +} +``` + +3. Al primo avvio completa il login OAuth nel browser con le tue credenziali + +L’app Gemini mobile potrebbe non supportare ancora MCP remoto; in quel caso usa ChatGPT o Claude. + +--- + +## Dashboard web + +Indirizzo: **https://mcp.loogle.it/dashboard** + +Da qui puoi: + +- Vedere l’elenco dei **tuoi progetti** +- **Cambiare password** +- Consultare le **ultime azioni** che l’AI ha fatto (audit log) + +--- + +## Come usarlo nel quotidiano + +### 1. Crea un progetto per ogni tema importante + +Chiedi all’AI: + +> «Crea un progetto chiamato "Rinnovo bagno" con tag casa, 2026» + +(Usa il tool `create_project` — l’AI lo farà automaticamente se il connector è attivo.) + +### 2. Lavora e fai salvare la memoria + +A fine sessione: + +> «Salva in save_context un riepilogo di quello che abbiamo deciso oggi, nel progetto rinnovo-bagno» + +La prossima volta l’AI potrà rileggere tutto con `get_project_context`. + +### 3. Cerca documenti di casa + +> «Cerca in search_knowledge la bolletta luce dell’ultimo trimestre» + +> «Trova nel archivio documenti il manuale della caldaia» + +(I documenti devono essere già in Paperless su docs.loogle.it.) + +### 4. Cerca tra i tuoi appunti passati + +> «search_context: cosa avevamo deciso sul parquet?» + +### 5. Codice e runbook su Gitea + +> «list_repos: quali repository ho su git.loogle.it?» + +> «get_file su daniele/rete ha/RUNBOOK-failover.md» + +> «search_code tier-b nel repo daniele/rete» + +### 6. Progetto MCP collegato al codice + +> «create_project "Infra Rete" con gitea_repo daniele/rete e seed_from_gitea true» + +> «link_project_repo sul progetto homelab-loogle → daniele/rete» + +> «get_project_context sul progetto attivo» — include README e elenco file in `docs/` dal repo collegato + +> «search_gitea_knowledge: come funziona il failover tier-b?» + +> «reindex_gitea_repo daniele/rete» — forza aggiornamento indicizzazione + +### 7. Ricerca semantica su runbook Git (RAG) + +> «search_gitea_knowledge failover su daniele/rete» + +> «search_knowledge keepalived VIP» — cerca anche in Paperless e Gitea indicizzati + +L'indexer in background indicizza `.md`, script e config dai repo collegati (vedi `docs/GITEA-TOKEN.md` sezione P3). + +### 8. Casa, rete e Home Assistant (P5) + +> «get_home_weather: che tempo fa a casa?» + +> «get_network_overview: qualcosa è offline in rete?» + +> «get_network_failover_status: com'è lo scenario failover?» + +> «get_ha_entity switch.pompa_pozzo» — stato entità Home Assistant (solo lettura) + +> «search_ha_entities caldaia» + +### 9. Irrigazione e turni (P6) + +> «get_irrigation_status: programma irrigazione oggi» + +> «get_irrigation_zones: quali zone sono attive?» + +> «get_my_shifts: i miei turni di lavoro questo mese» + +> «list_turni_doctors» — elenco medici in Turni-Live + +### 10. Ricerca storica app (P7) + +> «search_apps_knowledge irrigazione prato ieri» + +> «search_knowledge valvola pozzo» — include anche Irrigazione/Turni indicizzati + +Dettagli tecnici e configurazione: `docs/APPS-INTEGRATION.md`. + +--- + +## Cosa può e non può fare + +| Può | Non può | +|-----|---------| +| Leggere i **tuoi** progetti | Vedere progetti di altri familiari | +| Cercare documenti **famiglia** e **personali** (secondo tag Paperless) | Modificare Paperless o cancellare PDF | +| Aggiungere testo alla **tua** memoria progetto | Accedere senza login OAuth | +| Cercare semanticamente (capisce il significato, non solo parole esatte) | Funzionare senza internet verso casa* | +| Leggere codice e issue da **Gitea** (repo a cui hai accesso) | Push/commit git via MCP (usa git normalmente) | +| Meteo/rete da **Loogle Casa**, sensori **Home Assistant** (lettura) | Controllare luci/valvole via MCP (solo lettura HA) | +| Stato **irrigazione** e **turni** (se configurati per te) | Modificare programmi irrigazione o turni via MCP | + +\*Da fuori casa serve VPN WireGuard (`vpn.loogle.it`) o connessione alla rete di casa. + +--- + +## Problemi comuni + +| Problema | Cosa fare | +|----------|-----------| +| Login fallisce | Verifica username/password; reset da dashboard | +| ChatGPT non trova il server | URL esatto: `https://mcp.loogle.it/mcp` (con https) | +| «Knowledge vuota» | I documenti Paperless potrebbero non essere ancora indicizzati — chiedi a Daniele | +| Token scaduto | Riconnetti il connector OAuth (disconnect + connect) | +| Cursor «Unauthorized» | Clicca **Connect** una volta; login browser; usa config con `"CLIENT_ID": "cursor"` | +| Sito non raggiungibile | Sei in VPN/rete casa? Prova https://mcp.loogle.it/health | + +--- + +## Contatti + +Per problemi tecnici (token Paperless, servizio down, nuovo progetto di gruppo): **Daniele**. + +Per la password dimenticata: chiedi a Daniele (admin) o usa il dashboard se ricordi quella vecchia. + +--- + +## Scheda rapida + +``` +URL MCP: https://mcp.loogle.it/mcp +Dashboard: https://mcp.loogle.it/dashboard +Login: il tuo username (lucia / davide / luca) +Primo passo: cambia password → collega ChatGPT o Claude → crea un progetto +``` diff --git a/services/loogle-mcp/docs/ONBOARDING.md b/services/loogle-mcp/docs/ONBOARDING.md new file mode 100644 index 0000000..d4eadce --- /dev/null +++ b/services/loogle-mcp/docs/ONBOARDING.md @@ -0,0 +1,157 @@ +# Onboarding client AI — Loogle MCP Hub + +Endpoint MCP: `https://mcp.loogle.it/mcp` + +OAuth: al primo collegamento compare la pagina login Loogle. Usa le credenziali famiglia. + +Password iniziale = username (es. `lucia` / `lucia`). Cambiala da https://mcp.loogle.it/dashboard + +--- + +## Daniele (admin) + +- Username: `daniele` +- Tool admin: `reindex_document`, audit completo, revoca token refresh + +## Lucia + +- Username: `lucia` +- Progetti isolati in `/mnt/ha-apps/mcp/context/lucia/` + +## Davide + +- Username: `davide` + +## Luca + +- Username: `luca` + +--- + +## ChatGPT (Plus/Pro/Business) + +1. Abilita **Developer Mode** nelle impostazioni ChatGPT +2. Settings → Connectors → **Add MCP Connector** +3. URL server: `https://mcp.loogle.it/mcp` +4. Completa OAuth con le tue credenziali +5. Abilita i tool desiderati nella conversazione + +Redirect URI supportati (pre-registrati): +- `https://chatgpt.com/connector_platform_oauth_redirect` +- `https://chat.openai.com/connector_platform_oauth_redirect` + +## Claude App / Claude Desktop + +1. Settings → Connectors → **Add remote MCP server** +2. URL: `https://mcp.loogle.it/mcp` +3. Autenticazione OAuth al primo uso + +Redirect URI: `https://claude.ai/api/mcp/auth_callback` + +## Cursor IDE + +Cursor supporta MCP remoto con **OAuth automatico** (Streamable HTTP). + +### Configurazione + +**Globale** (tutti i progetti): `~/.cursor/mcp.json` +**Solo questo repo**: `.cursor/mcp.json` (già presente nel progetto loogle-mcp) + +```json +{ + "mcpServers": { + "loogle-mcp": { + "url": "https://mcp.loogle.it/mcp" + } + } +} +``` + +### Collegamento + +1. Apri **Cursor Settings** → **Tools & MCP** +2. Trova **loogle-mcp** → clic **Connect** +3. Si apre il browser → login con le **tue** credenziali Loogle (`daniele`, `lucia`, …) +4. Autorizza → Cursor torna con i tool attivi + +Redirect OAuth Cursor (già registrati sul server): +- `https://www.cursor.com/agents/mcp/oauth/callback` (web / Agents) +- `http://localhost:8787/callback` (desktop app) + +### Uso in chat + +Chiedi all'agente di usare i tool MCP, ad esempio: + +> «Usa whoami e list_projects per vedere i miei progetti Loogle» + +Se il server risulta disconnesso: **Reconnect** da Tools & MCP. + +--- + +## Gemini CLI + +Aggiungi in `~/.gemini/settings.json` (o equivalente): + +```json +{ + "mcpServers": { + "loogle": { + "url": "https://mcp.loogle.it/mcp", + "transport": "http" + } + } +} +``` + +Al primo avvio completa il flow OAuth nel browser. + +## Cursor IDE + +File `.cursor/mcp.json` nel progetto: + +```json +{ + "mcpServers": { + "loogle-mcp": { + "url": "https://mcp.loogle.it/mcp" + } + } +} +``` + +--- + +## Tool disponibili + +| Tool | Descrizione | +|------|-------------| +| `ping` | Test connettività | +| `whoami` | Utente e scope | +| `list_projects` | Progetti utente | +| `create_project` | Nuovo archivio contesto | +| `get_project_context` | Legge memoria progetto | +| `save_context` | Salva/appende memoria | +| `search_context` | Ricerca semantica contesti | +| `search_knowledge` | RAG su Paperless + contesti + Gitea indicizzati | +| `search_gitea_knowledge` | RAG solo su file Gitea (runbook, markdown) | +| `list_gitea_indexed_files` | File Gitea nel vector store | +| `reindex_gitea_repo` | Re-indicizza un repo (admin/owner) | +| `get_document` | Testo documento Paperless | +| `list_recent_documents` | Ultimi doc indicizzati | +| `reindex_document` | Solo admin | +| `list_repos` | Repository Gitea accessibili | +| `get_file` | Legge file da repo Gitea | +| `search_code` | Cerca nel codice sorgente | +| `list_issues` / `get_issue` | Issue su repo Gitea | +| `create_issue` | Crea issue (scope gitea:write) | +| `link_project_repo` | Collega/scollega repo Gitea a un progetto | + +## Esempio prompt agente + +> "Usa list_projects per vedere i miei progetti, poi get_project_context sul progetto attivo e search_knowledge per trovare documenti rilevanti su [argomento]." + +## Troubleshooting + +- **401 su MCP**: token scaduto — riconnetti il connector OAuth +- **Knowledge vuota**: verifica token Paperless e Ollama su DS920 +- **Dashboard**: https://mcp.loogle.it/dashboard diff --git a/services/loogle-mcp/docs/PAPERLESS-TOKEN.md b/services/loogle-mcp/docs/PAPERLESS-TOKEN.md new file mode 100644 index 0000000..5fcde5b --- /dev/null +++ b/services/loogle-mcp/docs/PAPERLESS-TOKEN.md @@ -0,0 +1,108 @@ +# Token Paperless per Loogle MCP + +## Cosa NON usare: token «Applicazione social» + +Nell'admin Django di Paperless (`/admin/socialaccount/socialtoken/`) compare il form **«Aggiungi token dell'applicazione social»** con campi Token, Token segreto, Scade il. + +Questi token servono a **django-allauth** per il login OAuth web (Google, Microsoft, ecc.) su Paperless. **Non** sono token dell'API REST di Paperless e **non** vanno usati per Loogle MCP. + +Non devi configurare nulla in quella schermata per il nostro hub MCP. + +--- + +## Cosa usare: token API utente + +Paperless espone un'API REST autenticata con header: + +``` +Authorization: Token +``` + +Ogni utente Paperless ha il proprio token, legato ai permessi di quell'account (documenti visibili, tag, ecc.). + +### Dove generarlo + +Per **ogni** familiare con account Paperless (daniele, lucia, davide, luca): + +1. Accedi a https://docs.loogle.it con quell'account +2. Menu utente (in alto a destra) → **Profilo** / **Il mio profilo** +3. Sezione **Token API** → pulsante freccia circolare (rigenera token) +4. Copia il token nella riga corrispondente di `.env` + +Alternativa admin: Django admin → **Token** (app `authtoken`), associato all'utente. + +--- + +## Configurazione in Loogle MCP + +Modifica `/home/daniely/docker/loogle-mcp/.env`: + +### Opzione consigliata — token per utente (4 familiari) + +```env +PAPERLESS_URL=https://docs.loogle.it +PAPERLESS_API_TOKEN_DANIELE= +PAPERLESS_API_TOKEN_LUCIA= +PAPERLESS_API_TOKEN_DAVIDE= +PAPERLESS_API_TOKEN_LUCA= +``` + +| Utente MCP | Variabile `.env` | Account Paperless | +|------------|------------------|-------------------| +| Daniele | `PAPERLESS_API_TOKEN_DANIELE` | utente admin / superuser | +| Lucia | `PAPERLESS_API_TOKEN_LUCIA` | utente Lucia | +| Davide | `PAPERLESS_API_TOKEN_DAVIDE` | utente Davide | +| Luca | `PAPERLESS_API_TOKEN_LUCA` | utente Luca | + +Righe vuote = utente saltato dall'indexer finché non inserisci il token. + +### Opzione alternativa — un solo token admin + +Se preferisci un unico account Paperless (es. Daniele superuser): + +```env +PAPERLESS_API_TOKEN= +``` + +Tutti gli utenti MCP useranno quel token in fallback. + +### Opzione C — mappa JSON + +```env +PAPERLESS_API_TOKENS={"daniele":"...","lucia":"...","davide":"...","luca":"..."} +``` + +--- + +## Comportamento nel sistema + +| Componente | Comportamento | +|------------|---------------| +| **Indexer** | Usa tutti i token configurati, unisce l'elenco documenti (deduplica per ID) | +| **`search_knowledge`** | Cerca su tutto ciò che è stato indicizzato | +| **`get_document`** | Usa il token dell'utente MCP loggato; se manca, fallback su `PAPERLESS_API_TOKEN` o token Daniele | + +Con token separati, ogni familiare può scaricare via MCP solo i documenti visibili al proprio account Paperless. + +--- + +## Applicare le modifiche + +```bash +cd /home/daniely/docker/loogle-mcp +# modifica .env con i token reali +docker compose restart loogle-mcp loogle-mcp-indexer +docker logs loogle-mcp-indexer --tail 30 +``` + +Log atteso: indicizzazione da `daniele`, `lucia`, `davide`, `luca` (solo utenti con token impostato). + +--- + +## Checklist onboarding Paperless + +- [ ] Account Paperless creato per daniele, lucia, davide, luca (se non esistono) +- [ ] Token API generato per ciascuno (Profilo → Token API) +- [ ] Quattro righe compilate in `.env` +- [ ] `docker compose restart loogle-mcp loogle-mcp-indexer` +- [ ] Log indexer senza errori 401 diff --git a/services/loogle-mcp/docs/pdf/GUIDA-PAPERLESS-FAMIGLIA.pdf b/services/loogle-mcp/docs/pdf/GUIDA-PAPERLESS-FAMIGLIA.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7da4a98c77af51e1e70c7254f1fdc8d6c6072ead GIT binary patch literal 202948 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 z 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%0Acm`_6x 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 Tz`Ot~d<~5axKveL{oS|#i@pau literal 0 HcmV?d00001 diff --git a/services/loogle-mcp/docs/pdf/GUIDA-UTENTI.pdf b/services/loogle-mcp/docs/pdf/GUIDA-UTENTI.pdf new file mode 100644 index 0000000000000000000000000000000000000000..db8a529e8a1a3519cc06c8522171c6b8bdaec67b GIT binary patch literal 161980 zcma&NV~i$1x3>GVZB5&@ZBE;^ZQJf?+qP}nwr%&c`^Lj2(4I@fTYQtEWsSlch)VZP~L*f?{rSnNmhe-QasHE^ITo z=svw2(C~e6?AUT^{kZ%FqduHgB)iY+G2qtcI5BTgx1c3I|GVZEm|kHz7Xnk4-+SxBP=LN_toao3KMNclvaa z+_Uk5&%-VoduJ$kOrd1TRz&P`j@n6}yX0?X_WQHD&~Z8pK=;#iWbsq|IoDg(3*oDiHnvLDkpRS47hJSFam>r3!sq!@#y1N z2#m)mxmuM%1#+L zBOG1zIJN3?)`TIS_cIEGH-Y5395O^_zZvRi@yC+C8&p+!;UR3bXJYH&{JaMLlq743 zM#zt&qox+T(yQt&>Aay~gBg3fQan+S*>c{TBx6_Zn1P^owYS%sp4OdRlhZL(9l=Lp zw@{lS|6PG?8*aJ(nD{aDKA;@SDtVzqf5&dSB}0c}0Y?O)4AI?8&zmsEimK`K{5o+c zJ)UdNAIm*q)nkN4X_%Au6(uSrh@4N0!0&D3&hD^G`H4?yAQWk_$YT>Zb-nr;H6~(?(Y^ zDN(-U`EIsF+hID>v7A`mVWlfj=idmotPbjEbf|CORR_*H_2d?ysu{o;3b*9?%_B%S z#p{eHx7pE;kIk-H=Cu9V#sgGk49=PV`U9d0ya8N_T93Cr!f+tGzO1tCTQAQl*qhD= z8yV<{q?m}~=$s!r6Z><;&j??@$2O)>hV#hoxG>FFS68O2>vwreDF_Zn`MQ32{Ew%Nc;$+0_uF zY8xkYS2I(=VlCdlUK#Y$>f`E8Gg%Gj(Zf|?r1B|JV2)CPVE*)wTv-u_!4goNQJ{rO zQFLsa%kXdb-`pry<;BKxYDf)#!?P1t&<>iRb1Z?5EWDq8p=F`$kZsD1Rc1^TFTR3* zwMPg*^M6~ow$zt2$^p1aemSrHK%9P_0XvrF(@e$S7T~~R>19>|;X*qQygN8nS4Iq^ z6h9`xNcz&wVVRy22lZHv;EA7Cjuq!ocL&zD#-O6F)W?3w$6OBg{RU@&Jf^*Hnaoo! zqsUpQHC>sdR>tU?d>w?=fraW3LOA+yWJf9?jHZ3bghTJ!@{*WU`4(FYvL1xin-`%N zfS>Wu+5I?CVyB}*B~!k;o2BcjIW!;)k8AX!@q~5eZeBag0-i^>cm;pdPXa9Z&rtF6 zWMzz~$$S`rL}J2@by!@Xdeduft{m@m_|jUplQ0$TqO}Mc`JDTxsGJqtiGvjF@8^gI zjtOvg*C|&Oj2{;S@PB-@x((EU`br!}&F|TQ_o2KDY!ZiNMGA2r zRp4U8&`v%}9E(`ghc8{sX(LJwGfKnum*sxXY`87r8(jm<+1f;mp7l8x7q&dOcb%->D%b1`FmCo{ENax=~}v< zLjoe0EG!I1$qbJh-S#gTz8SshS&mfQUr2w?NhG#vRGQn`4Nzhc4<^WICfye)WN!73 zAng0x>QFu?B8bQ(6_e!S6alO3+LC-gs!P+#oKS{t<$mtlb=dim4ovrDx1CpwaRnx! z@@e9gWO#8@<^06#r;gL5N0?+*LSLU zjECM3W%7Z-DD{n@7-(Z;P!5mZm>tbyWF+>rpmv(JEotlNI`uEZn{NbTi>EAj>N1ET zzlvVNOW5f7K-YFTQRDjwqX$SrX@zefj=q8oTjw1u4kYKBaw|0H%WJ)bK-jIY8&%Fl zbu(j0SM@k=DVr}?R?_oYq5H2hj|=_KyKKNDVEioO&6*$kSg=aGGM#Ok7924KsK{ev zHEI>t14olJ&Xrt5bWGsCP1xE!1Tt7;)F8|8rqj|L9BbQR6vwMoJZf!nBdT3I=~`e- z$ZGU`-$a)~$_*QLo%LODIu{gwd8RY><4rfgkfpAWC}=jXCHPG^ADk0>ZD%asZjrV}V5U2RFWdy8$4s0wdm?#~j1XP}`f1Z8JSG+hR~JV ze=R{oL2BibV<|A>1Tw;^4GW$&_r0*dw>w%gv7~BVLxL zFR~0YS=myZv3TAzMn#g`LltlSyvo}|9IC>RL%d)NStOZ%86G@mC;(#5+) zgc5V$c|z+JUM;fov#ShT30qw*_c0i1eTG1OH!WYBGxCJ~YF96ZX7^fzJdCd<`|Wpu zRcpDt8$%w7#RaTu*5cN=ZLVGcZto;iKB)E2#jWY3NmObSZSD zB&IQS=A{>0$fqw0mxEc;)fq#K_nWZ(96sTbS^5`1aXQ4@w`ZSQ9jNCkS@ygRfdf2| z4nS;R$+5HlY9+J(d5#yxgEiOvjNtafPH_={*&FuV`F(5oMi2?1d@D3A%$X@1lpJ#~ z%HI|AvT%6x?R)2@-PiGQ(JILoWjEURm}+KslB>(-bp(mU!lm4nA+7QmFgKuw8D2g9 zZ{2w6-@nV|%_gR@oFUv4{5!(wTHl@Gb5&=TnoXbe#C|?O7*V`|o) z_4_SYWjO*CaBq-u!K>8hO+z zO)R7s=ge>CXRjm&kwR2-395ohlP5+~^Ow!#S&-=i*4Y=RJxaNKm_HIpX5oO&0B^XX z)6EvEjrA-Oo}MJ1+6$FZOgi1DCqh0FDI_x%<0mL)LnwT7f5Sk>l;B{sMxF@lIR6ou zWsTq8`F`r3wU2*Cjq@=@)9T2_638Xutc_zzYE0I(Hs&5anxbKb8d-|2TT*E9Ka7VG z!*QUv6uT`mR7g)R9i6U3WEl@wa4RYA7+E=wDUgTt79ZL zX*kmjdvdk*#Jet9GWWpoQcgAIBvRYz+D1TR8q2fjb)MC~#L-`x7@OZE7R%k*1Kh3kYEmY`wU(+QthF_=Jz1|fQj8M`B!QnolyU`* zJ`eZoIJEnlv+>_aqHdlyqw-r8sK`3yL`TpCV zELgTk$YS5g9`=&{Ai^w!`WLCi8W;qeOx0@K89Eczwprp)36_#5=1sw{eynVbWU5KS z3+tJAIwJgXZ65JpSfY%x&|k)ga~yC;E!HcUk}n}rim53d99#wrgH)%)b>Dm2`dJT` zVK5)^R{o0!{?6G|UM7bpfI%E7^2f>+8y;tW)K*O#m1+$broAPq6l&uNdj@3YA4O44_92u83%C1KhoxREf8JTSp{f$Q3yFf4H<7Q0HvgT z9^^pca78ULKPu-1C47+Xa_OZ`&wE7|U9Lu{<(JllvW(&BkshwEayA*pLJx1R%E&ws zgfOQuNeXiVBS^BO#TVwNmQ?+Ypt-OPctd1JP>|yWyU^13FvJq#7WLAqOOc(~UrEI^ zoy=d-ojjS+Ew~5+6t4^j>CR+9qTWV000fiz9Krk!)fK3^2NP=QO>QWLt_3jFi;B3@ zjv3sWfEDx0IKi~EWZb2w;Jr5W3(1a`I)-gNNB=O;ISxc8jU`FdhwxAykZ>%843?z? z*almI5XFZy$e9hE$vBC`LSzA&bMjP)D9RbbUg@9NDreK6bB@z{KT|+?gA1v-`Gd6f z&YAtyhm2c`x&($+N-y3U%Ehef>SCC_VF3 zi0)u`WxLnz{L!J?7TOyXC2pjvwdPivxmh$HxIB~qcqh`n35J=kZUJiHwzI8k@b^M1 zJoElBUpEfM#n85p`*v3?~UY$nCc!CuZ4J*&Te)OKZL!% z#(QllZ;3dPoL-?JK^n_Rp;cW2b9X@J&J`Xlz_aAepPtLTU)>H+LSI*ZlkiWy4x$<@ zzFplUJxQ;&P0}qw?N*Ewt}R^|pYk?7$=>=IRAlC;Jg;iX>Zv&RAq|C671MiNVNk%5 zu<;i9mOT&h@}yzoDd`eEJ=6^;{!$i6Sx5eO(WqxE6zqX0=g?(eoxlOV#P*_HY<<{3 zS8lc46kFS}VYijLgrQ<-aDj4Uu`$r2^#@U*UX|JX)K|NXOUT?=<4YD@U9)S!3@Luh zEbx2$p6Fpwk^vb98`zWPu23F!rR>djPfRN0+21X7N1>a7tBlA=?LY`XN1Oup)4>N; z`IM!fxE!aPOLnm3)LvrXsQmaiv35L}MJg4Z^)3v{Qcya&p$jX4+^N03m^%zToyC>Q z1lzha7`&NWQQ4YqQ7|j~VTr!sb788FnMCIYcT>rB|Vf!EDEIZ5pwn8aZlW|(&K$P3XgEzms3dZ~5 z@8RI|$uI^gEXo6ep{ohXLQzE(1ecl&JDQ7meh;qD-DJS5|((do61I5j<>7>vig`2Gf)geh#iPJIJ z#9-z;BEoZMNH4GFjje5Pqc83IPFt~5hCHKkg?O(t9JMu4+K->3!^3%SKPjAg-$T|N z2mAss1JuOV_y+<@+1`AVKeFyo|Ea?vU-&_A-5PLyP%F6~x4Q>2gIFXc0geZV|GdH+W(!k_ObRGl5Fy5=^H!e`iRabi#Tlum5P^7tpY52qua-nI}XSfn}CK z2Ru7M%zqM3`oc}{ka13a`QDL<7RVN@j3jn+M{|m%h3x>aDp0-F*Y3Qk!enQ%V`u?z zX>7Cy=;YsUKD9XZLux~e(=E|T$bv}Lg*aUz(nQ9aQU*|tt(fP5U4xcA=o325Lc2DK zcw9REa99y7sa}gz^`T?v7f}zSgLs^|^cGW@lyfyoCGop?Si~#?igb#|jWiPGg67c2 zt>P=)%`>EXTc(p5=oKU1r+dtfR4~Ug4-j;oZ^dq%;9JX79+d(z(ONA}t&_Rn<*YTy zFGb6gUc@yu{=FmD6~^UUTP7EpK=_=cHSgDt5nm~3y77@X&LxoU@rcyaY>}=SKw8xK zJpi6cW@MB5gk}2pIel;j94mZ)%PjzopKPzX(2IXQHpqbX5-TYdzP09icMq+pXx@rg}heOe_I@zO!Usj*7Nk_-y1}ont_q=(#qv;ch^7;T)lIx zS+n|_VWpIC=WiyK5CJd|7ro_Su#%KI3DJHs4LebU2^ILT3({LV@XR}cK#?^dNI#?# z)32k>4WCoMfRCG+yNBbA=AvEF`re!f5FYMo_m;3zI9 z_&h6xVp#wBs-2UsHSX-@qI!d(I2xGh{z>&@$u_*$r8${aGqck^k)pP4zPl9qI0jMh zB|QzJw1PFoX|~r5KYKjs7{=moGr)}vZ6@8m;g-)k)2Aw~a$T)nza4Q}``Xw)ZBnm1 zIULwG`Uq3Zk{L)T^C}-+Ry~B({6MHahQNijA(=EYGMQ4%q$Y>T<$BP3QG=i!NliqP zLQZH{HxB9cah_*?9sGqRoJ7}EmKJ6P=7l9G4l#nufihTNDajk{9h&(_9{cV7JY>^P zYTrY7FQfDvbGmYZ#IJVGL#U8MQ&=Xwo?Rnb>X3t!A&l*RyBmyw*YO<4h3JPiNlWa3 z>eCvD%ZZUVSaj`Gbo4y8HAvz8l+Kizu;ueC!*u6lxgxo&{4jYF783Z|DLJ(OyQDj; zCo+Uce}mPA*{AszKTQB+*@u_Gp?ahs;yh|k5s>|>H#qHRPv;tl-pvotwx_iEe^Q5? z@jrDjBL^Gn|CT!c{n@huMFAA3$8o&v_f^}punbH05GI^ZKg$S7KBDo~`>NYL^6yN^ zOEQf3AtSf@>((fp5Z&{TowwiSxxKcss%9jQ^1qG@{&Yv!)v0_;RRB z&g`Sn^4a-vryb{1GH1owL>>4KjcJJ)AfB$YOfn24%(tkEr2BQ#dW@dElptL^witFM z1n^0JQcqCxzRG;nsm5qV8MumL&rr2kYK#gHrL#i#CRyU_YbdK78#AM7U7@1|xW@CnIV z%Nocr-N99VAPWJaZ_2;rZ>Ms~&BRMY>u?IsYfAIbMSEy8dv2qlrqngUPnd>^Sc14G zrtK$D1=7jzqcI99)XVMX8Y8_{Fh9M>2{?e2Zu*;0LbS8>taY>L*l+#(o^Qq?QaA+r zRP7?{5fir<#2UEiurAA4RfiC!PAm|q3QPn;!`D;RU%doLeJl?okd{Fce7ewCnUzWv z9oN^_Z~|>`f9$i8t2T9ma;~evV_jFPd|K3zfqmx~_2pLTJ^k@}YRmG=j!l3@-M?=Y z#7ZKuSI*N^`3t(&FZ3JxKVurTY#{G@Uz(_bn=0rWaIm(4%@ZC@bQvgr`E8+QYQdja z1AW(|t`rC@$$@iIMMco43v2lbn2*U)RS|~p_$lKp)Z}ZeP!Qs-zI@rROla+3{smp3 ze$KJIzTD2Xw}6aYh~x6F^B9ik8X{q7OtEqwVr?FRiV&ux>g+VsS#5oycs?P(J6858 zLVW@u!8K!BM{5dHFNH7oxNqcPa7Ptwk12?1IVN=pNJGL9)HfRxzfbr~a^Kg~g4igj z0({2Te$q^&tTe|U^3}u5p_+{2PtV5BaL18|=l93tbOr%aVoeHexNObc-Y-?M?zTK+ z=(#MEfZ7hNWUaG9)OFZh%ZnluVPL^Be>IymG@33;H;5C;0};1suDX)5Oh(BzJrGX! zKcayY$2f{In%AaxY?nkBHUcy$(kIzp@P1~yg5KI6pscx2Wu1HRk?6nD!H~jJge?v( zkU!%rK2o^GIIZx-JN&8xduR`aN|VK8l~b==x-8b%lvlFd$1WpGS{}JEtoj z5lS}i9MrOr>&a=$1UAqR$VZ7_Ldhq1iTXU8JDpwYE2_AIUX*Ed zH-!Szz$2;-P~RSo(?Vh@eVZ!tIJ_M0*QRk>q~vxmF6MPCr;pFl^*9$3tNJ2-9b8m3|Y15H73 znLpU?ELU{tz#H7EDuWNHW+S|FE)Y-?gi1ixh|^e2N)#aPrg>_oH{ui(f@3&E6v1hD zic+hy@22M|7F=u8MW(FUvP;`A83qFYgBWaDK9y6NND%V;BK>Jxmu1^?+qu7%*}7ZQ z_MMl+yp)07@n%E%+y^G6KMr%jG-Zb+*-AUKXF0+eHsJ28_gN_LZ$W!&kf~kPRf}Br zOX}-wGzXIE0RNVP25}?g3KF(EL(njoVrCyC){Blj1jKo;5Gpf`$_z+e!%T3>(3`W= zTX};7Q|Qs|z?d7_IU?2|FO2y|*Z>AW5+_*3ADk&i5+b08F%}bwp;4O_N$!=hos%4^ ziwC4TVM)dTI3_|=8Y7QOUESI|wTkxPVitON9uBG=pL#q`*lD8G(_~vE;*AVd2uB>2 zoxz0*Zy8M3R%jn)ZZ8So<=`&RMea7Wi{ULEhJD3d_~=*;%D&d9D$o-hzYF7 zz_;pw&g-<&fehI<&f9+8wI4sUs&~^kMpq71J53r3h38^r656lRRe(fiz9F(d1Hl3qKHJS|U9E31*J} z3CygF|7$r|t+wg-&yVEuSIz!Yq?r*E5hGznxHLIYdSS@Lh}0*X88=OYM4D1@e>mrU z)y<)hG+j1x1%d6iL%sS{j+1Ldp-OO}n)sStFCJ3cLAVH|SURFYhJKRR@X6Vt8BX%u ziHxzX@qBgjrU)!7iu;HHnhxHV@6+Ui`FFwzQa{BgXGDsgm>P$uMS}Pw(>tmjteP@O zBg()YaxVMxRj?wu-S%v5s@)%58uEgEP=^78!+n}Jg!^zBVZ_9!(}q+ZqnGSn~veL?gY1v@?_?nzci2qf#620$MnK9hy4Zk8=7*Q1)xYYf$L}|ZH+qxC_;<_ z(V5sBt+S@{OKNEi%X1UDnbHgH+}yt#)SGY0)%Jqa5lD_D5Z7$XzB)%VQ#afxjVrri zTQr&-8}I4d5bP?K-A`XoUtYwd{$6Y!9L!Te14Yb^{fH!wDF_h@f(_`K$KDU7I~#ao zW~g=wK(D{yb1&~qNy}~>j=~7&dEelD&sBS}jf5Up<~0*sk>&|gip3M(vB zlZ85Rsf;EN53Nh1hu-YGtz~p7Yha*?>#L~ntt&lqj}}T-a6s3y4nP)ej@N?6C`dx> zlTNP~#%X%x9ECWElCH@y^F$#hIOSZ+2ABglWO!UQPdXIQQ7OZitxc1Lf(Gx6yFDZo zQpn^AiL}#lUxWj)km3`0bXoG(^kBpB;li0o8lEhSgP8-F5c>Yzq^}bCS1jlNiIQZQ zYJ57RDC8BIr8Qy#5}LQl-c((;uW5e&JMHmpEPdX1_H*Ss+bO=uKD3?9{SVE@Hb(wd zZ86z2_88NKv>$31Qmqy6$eXP(8XnAtL@&n6%Rs^ctW4my{9S&RG|J>3J)GGGA_+>M zen3Z;J-e=@k8dSwJ5GZSDFLS103Ny0Eh(n-&dNa2W zly@r|1W&DU$K!TqW|rJHZs2JmX~RyhvT?w~HN=bUJj7171_jf;+@ke*I#6P!RaT^eZ`tLi|!*NyCP%}Plh zVhpLEt`mAKb$ms&F-L!2h->!g-=Df#q!)uF@CdrOkv;b^N9>0OW{-Aft1|=2RiJ6y z!e%drgM|$#oLu-VRLlhKhUi#{9F9YODe z`5aRmZ@;GQ53VmUPAB>Ga&dEKWZef24+qH3+%E_KLV*j~S9V_IA14A}n(dnB`MT#; zI+!s;uq+pfV1T83@toOP?)Y;7{%P4?Mq=*W;dknM@YnG*g#;WU?keik8bAqni58&- zON6_uvI^CPsSN>rRPyejBS7Jm|_r5#(W)%2E`Wg8ggJT8Xb6yOy{6!m*K5M z;i&BSBcD32e99zs{$A#Wh(}(B&x1tvi@-SFg^oD{1DQJ#S(};>6~|24RVFtV+V*&;OmW z{S6M1D3J?Z2nEXx>$RkV4qj+wVg{AAquIV(oE3c~p91XblYC{ae*{V9Gv-6I_mbKD zqtC$^G^LvvoRa}X>0|AHIpwMY>QR4)UR4Ubl9`b1?%CJY4Yio;#UxrAI^dm~Hrn2q z^dOdMc}vcaU=+r+c2}^BeY*{4xR2Bxn|86c4%ldOKc!b{V84N^|6qiw_LufGiQBFX zEhwjIe%Kj}pW%6xKu^YzWNpVU3^)F{+psx_OLf0pqDeWRC2a~rk5pPWMKF|R#rzRX99N4f9Zc2 zU0K8`Y5cV6`Ta)5}l%az-7%0Sb5@2HHgSCfzNS?XOsf5 z!mh+eya&P1exq2arZkh9x}$AUG1}`Ek_-oD7NBQZ zLM};0Disn9A8KbNbtRdC+^0SKxg!Cu$>A*==g#QT%&oR?6uQOKc}O8EjoOCr{Kgqw zKDyeiuwXo)UZA%2Ew`!efk!msALjl zvq{*K2oBN`|;Hic(OSNE|l@vI^%(9fzogEO;G6GKMa%StS*G-Xq3Kt=U18;ps_y!iz`K zro3M4yYpVobK{gUGbeg(Ninc3=#`z_A^qQZCrtHiof~sr8&-geIOGs0JpdX@S|SsL zlT9&XIi>RNlzJD1tKJ0Ik|pvZq|kiLu4n- zmP%Xd2)T?y0D`PxsDCwatORs|vMbdI?t ze$&%1-Ow)(W}FFT9PowER3mK3xIoPQ3JD9(ZpaD=s|hT8zgylF>!9+qtOC10dP%8M z{u%PkH|tjQ+MdeiMUuCptnR^Fel^K%$w?PYbc=S0Nfz4Ei3;x)sYxE%%1@X1yoKC) zoAOl)jniW#%@mDs+KbetE{Vy^mlwJ9o6*wIAjU6!UE`olY@MpVo*GNxL^sr)+fFX2 zJ{Q)r3k~C&7&KW=M3w8VlNYMy?;Hkgqa=>$K&#t0y9G1JSGoMgmNgrri7%;% zbRd4meJiw_^ThRUqtVw~xi*b|WU!x|T;Gqw<@Uqn#Fzbc_h%tXPixy9O18%z+o`+8 zx|dnD+wZql+9yV{3$)pYEl9FnB~W`WT&Ib++1NmvF0}Z^#ahy1W7i8u-bFXx`Pbjq zel2^_tWD}ludYXpSPxp}ew%oG+*TQEcZ<_?Bs$Xf;5~Zkzu%hqY*XKp(SCW^Ebp{W zoSn>Mn6bNc|EgumTV#y6t5Eapv=wy5(R41gQo8A+qh;qBX~S%rla9??)woQpY5${? zz4VhF%PnZriLsR$AFBQWtL=)}zIe1)&j4X7g+~`a_Pa3$1Y`Y*CUyAu^>Sv;hW*l& z0_O*x?@d1WKS9LE&ivm{^nX#qNWjF(!uDU_VIpASWZ-1^ukOF;|CJIjGq7;}-&@H4 z|GyVao+k2HS}UyZ{lD!YS#JJCzYeyWTcFh39&*-RP5<^bue-h57nj>k`W828I!|fJVEVD_dxbbhPt;>k1jb)Kg4M)t!k6 zNjxvVF(kXXET1_JyKmnbUY@}foRbSU4HL6{ZybOupp{1~VFAqW02l+xhEw6W3Xld! z4)*#NWG6Cb$LFI+z%{Wp)`2MoXp3B3@#4@gN}J;GVa(GVls)%&kq#Opi|h z>zi8v$CacOLX2&;2Lz)7B)PTxk>1#opbJ*?lMP|~x~U^8Eh-_Z zq!1mk?}h*%^QWGhA3t#0_^F7&QO4Ypvmj7Y66enBMFvnzXJ=oxWB%IO+B%!o&dNH! z#+g35uKuZz8{Qg#+A}>h2Lp6-0apk3Asrf80T(Q;_CP_uiDTOH7xj7?A|o3B*upScW_i{5)r@0v>vQYF zQ2KYNuum{7`LAjL0{-Dqg@?B|jz6lL-{jN1QWz~DE+t0S$3|x_yC}>}E)EZ$*z7;n zn`<*G;{)UC=Xyv103{f!z1xdy-`S~w7y9(9xUQtOvWJ{{7`QS^^4Hy`2u*)?#}=n2{ny&+mWF1h#^-mt z^74@Ch;zFY8SN`fWgA)?ZGXjrA2S%_{-5}CplqOMKpqI-%+`A5j(b@z^FeFsNei~1 zZ*+2J22bD8{2KJBo&hXScdt7ORwn>pCXSI8ySj_^BXTE=13-Z>GMh^X!b5%SEs$Ez z*Z^w#CIwe{uv`9#$$h8|OM-q1&RAR5^a4oxm)yZVxX$F6c?e?@ z9P>kc*-;B)!&t@oZG5FhaNW6;C;ber5B%O5z%?&0-?z5@rdRzTO?6}grR|QZPG?1A ziSHGu=*=azni~j&$Bo)GL-+p^k^I%`oTtOm(g4QA3AFZe3=ZmWr}rEf{-ZdiCuZ0(;!1|zVhS*2bM?f<6lXk_^(L_P2?UbE!#_8^;fsUPd(7@n16$2BR_)H1ljf3tmdIVDRm9sDQjz=5fej@RLe(p zh(q9aa-i~~em2YaAT7J#Y-FLbCw@-Atmf~dP)m8`A(y)apQ@Yf9N*JG#)dBt-*^G( zQ6bH&b0ahBSmy7o&RIBqN}S(~sABT$ezm|NIm5gE9MKnch$5lSy9D8snf!53Lj(93 zYXUVbdAvWFc*^u9|%AUa$Y#gNow22mXia8uJGS<>xQoK7G~I zmAM(1aw`K+xA=QzL>8g>%gsh~USS3l3B=du2miJo3BiZcY6qu-4e(#tc7n2_s8UL9^zr)?XqyR`~2&_T+=}pW>Pz^HnVAPMuW0@3z zM2C6&RD%aAiBUn?Vwsi$gD6uwBoMHNuS~wu#M8}jNyp1~viD8jRRWlSI$xciczHet zn*x$Hn=|Uus4yBbmV{!lTC6y_*4Or;?6eC3E^4*LI2W#N&YE;U9+xAb_#0?ryXGSFq09;rY z5rV$VATKxEybMDxYWPz+G>qHP;eC7PJyHRldn%PqYvUidaiUZQbz2`-5n~Nk7S!+} zn7tbLu%3AB{m$HvtS22WaP4@W*U%4g2y7l^e$HDEa^v)Wd+ zV71$V`M~QFH7S24l+Q(E=~Azp>fHt@yhfhRSDKmXkw{ei#A2 zWp0IR1SNjrz7$v=9XhYnc6L+K^PSdw(a&Vk2f;>Wpvfy)MB|dG_h%f3vq2+9vOd4u zmtx6l$Ag-*DHV=*;E?aQ&>8`(m|5)eZg2#jp+0Es^^4Rrg2OkIS&D;Qs=v;>g@HgE zQZdoS(Kn<-NLb2*1~zNqo73Z?7)K5YR{1{=Iwf7I zje5N_1nGdkQi zOOS#4-!ox7ckAHvv-GHRE+3Xvp^?3=cQzpbZyJ2(i7dPy`NK5IpyS;Hc7l2}DeE|| zN2<>X`|MMBG8=q{f`~lg%5+(siYOXPMgoJ~aoo)M<$IdF66OLV2HdK1d(n{Zc%Dv9 z@J*lhTQ+U}Mu8NORU*bb(1k_}*?X9EcKU0m$jV#wYV4$qAXps}))eA(%CyQ&Oe4*6 zzzOpM)|!)gtk7>UDb0&ECl?Nf`g7g5n&8wr$fMOeQj*cVuyXc7Ugu!Z%rbm=Aie}k z`i50{W1<+Z8Tx*$E^PWCiskyMxzeyx2+vg8&);ASIlp;!RaP_H-6aQ&vGms{NjJ*t zi6EW*0R8)Zki5m6Y+vb4DK9b4r5CDz~(4fCKk3X|wl%nJ-^v$7w_fwF2tu;w$4R=Kz3InaA zfbrNKU!=tI<)){^PEA%8h&3{o8w=@srobEr#V_*v1lUFzSE9&L;; zHzlKQsN@>w+;zH-i3Gtj9wKk04-7Q;>k}9eCYYij<4bCC>g{5fjZD;cx{;ZezbRAC zm0hr=`gp#)zGTNj{xE^WyLvD-yr+BNJ$i#nkI>X#$#92z5dJw3KK0q<4bP3HVbbe7 zf!i+UbPT`Y>_RWg8%wC(MIf3?7edeP@(_?vb@C)jDaP+usvBGLH&Ouoc7O71g!xgl zt0Y$E<(*D_Z-Z;uiNS7to?ckcV)M_&vH{*!Lq{_ii^V^=`czSmX#7Pr7C;x}6tQjT zUnL0pD3Dw(R)2b-G>Bn4-}Bi>J|mr2Lm6E(z3R!q^|b%S#%>(#N_BUukhR5yK_wv0 z9&EZ(A)UW4X2J3&mir9FqfGfPcZa6`5Nkj55ikj~dExeJrtVme;TA2b_Cbm&4~r5S zy;x`ax7+(%)979db9v(UbYZJ-<`|bbbgAAtdJd!XgQBoiUj^opnw*gD{NvnuW1A@? ztZ9Z9-n1vFT{(lMCYilf7I-)j3ql=(7Gl&^X|?v3zV@XN8s63&LW#>_K2zOMu?sR( zn5LqTRIwV90^iDCqR_A-9F7`9{5)P`;pd8B!Y*s?Z^z=z$~Tq28EgeKuXvTgpsYOH zrXA)54G!?W_E5N1a!MZ=Lkqt`20T-DWz-AnTH13ZY;cKRZKq5ym^M7FQ5YX%BI`Hh z9k`ixx}-jEQ6d$=j9+X#bp?H^tLJUT? zsvIrruDndUslz!M;D?NLi~533jc5;(q*4V>sL0Tck1uBLAAIdh4u#_&iiuPBA7k|= z*F@hs7Mzhs>u%fT2;?#M@O4&*rv4VT9+_b_>5~86TgbL2y1eGdBu5oZ9nhj4sj?&c ze4v+cpi#{N^d&CcI#K`oq!NLwVJdtIw_z#NkHEr_c=}NFDuFY5Fw$sEfT7dBdkTu8Gke&ma3+hfKt0$)s z6EM^+%(ES<&*H#IE;(OMR7S+5tsFyrwS6z`mw7Q^1!{ngEAo!iOP&=L_?Jugb4*9A zL4G9}G%*=`F#;#g3WRMC>vV|+Q!6nX$X_fV+@Q7tg%?b=vxt$onDBdX9w7H|jaQcj zYL3$0I#d?h@rm~t`ILcbQ6y$gMi*DTSKaIJ&DSS4;4 z7-Xmm!z3}Oh7R4ZWPDGhwA_ws_G}vAZo!eOpn^Wp;mgkL%C3!bt@be%w;?^Q;8eQ< z4`9e_`?wa5+qPof9*xPid56@8of37k`1oI^19W06>Yl{Mr~0aIa+Ug))e|LobtQ`4 z$%NNJAS6L3^_@tOgeDS-zSwQ{F6fa9+r{>;$^ooWMR_lYK)+UT!oZl7G&YbHByb}e ztbI#z7`>iY`Vm{Isy560^8dnogzm%A$q;2tM>M^V;#!t`JJ3Dw+WHnxs~^zM1ZE1; zx^cPT1l!Ov^L@uRzJXVWD>?V$4L0k2!&A)_U3sjGkYGPY4$=;y(~~ zm8qd9d0j7{K}rc{3>VtB$hfi~u?}URo57FrbBwrrC8WxVu|+}2Eya$HlH~Y)B1Ts^ zJ%j>sZI0Txn1`o}Yp{<7=SFLAh0V53>fSWIn5wFr|G{P~5=+?ie#r=Z1xrDPhtdOE zX-BuCc90}f@lt_Dl%PWZ8peXGD}c)$hnKbUx5?OLB0lyr5G(l!9bYb!^9Y-iY8M)&Lnw9|M( zHaYj}4)3{we}1XJ=qOTO-4%I67}FIOt`{}dW)YX?Pkgr3X*sj?nZEKH`jcJXtHUAD zCEu5&4?ErfTp&FZ*UnbWidh2CXu;^FjNIcGQg`J$|Ggjw)RTRFu*98-00Kb(v>{8S`@g-rhs_v`2Urq{Eu@^A^xf@7%y+!6m7#w%$?& zhhk3D2r6!C(7qOhTaz!BQm0#MKzQGeAXVNxkSBXy?jy_4$B)6c>plwt50GA8jj~}E zyq@F^Bm)(xUfj3%*$O4Nk57|JcbJN%swfaOlp^;COo~7rq7y?B02Qs%L_3nOzC% zPp*P6JT9Izn0jH+&Axk8OZ&H8zmJVM`->vO8ev@I3GjF$i{br@UeN8j{3a-uV=2uUDn4uU0ekW_wCP0&DL9>`>AayoJ9H7vb~!rR44Z=F>LfNa+|y@&ad=@zxre>~gd-Q{ z6*nlpc@y~6T~%_`E_kof{KO)b0G8>D$6$T-NJ>dnwlv{`$7Y01(@nPZQXxt-=L=;4 ztQO8OnEFlda?%8z9(4z0ZQX|Y$+59hWmY;IjfcVrUBa7&O+{(1=al|{+eN)G+^;+L!$nf&Cv7MO~jmXl0bLyA61L|M2reS1vrOz(`&?LBoUCgJb1FzyqmFs>0P?(Qo$-(La>D8(QDv9Eb$xd z3LC&JEEeVZakEKVfYOJ(4-US336ZPb@l|1{r`X_z1q4SxnLnk*mkSWptqF-&sI^#z&m%n ziAh<>fe4|}?FEk##Xp7zZOPW-F5LTdeFqr(m3%!>R;~VLd+Z=oe}qfT5N+E$HHAoQ zrMd^+Qfcry6HAN|)5iS))}lMcl=)?u>J>MR+oK#Wf~}e=k-~+`II`9-12oXM8A0lk ziWoi{^-Vx_?~=jZn>3T^EH+MAkCD^(3EfyqYBfDZC1k85Bl#C55WBJb(eUe~;Jc>| zsj7TT35TN;GP@>6iiQWv5bvHs8$~6!QSNT-#D%KaDVbuKLh^Dmi^<3efzjyx*pF9; zAL&=Q-sD;#{qzWZ*Ao-C6`Xm*q4i?raP82yYn5@Tp;vn?jqRlxEs87#Zr+~K{qsnn z6sN?v@q6xbKU`98)2lO>3Lhqlti{*~vi3Kqy(wf8i&|pK3#y{(>8rd~SIAH*T@30T zrGNcCmDW=8-f6ZM9^fuGzlIVh5Pnl5@aD~s?r~r|6~ zbH@Zo=;;yMd8l5@VjSX~GVrR~$SKSft*(8S8ysEuzP_PHAGwuUs83dL+W5A8TyYjC z>U$>)XwUCgsluXnH5@Xh$OoD+}GCrn^E& z)8Rked)TJiW9$3;=UDIb3Cvmrle5x8Hi!Z5SHF|r=c4`VkxX4klqC*rv-o|!Vcpe-u0TK#M|fzEHUkF@JXSn`8A%=Zp;7A zXIV4BX*5Sq%QLaH5Yy(V0k88bj}=hB=kQs|kOE34|3Yv>d~dlXW}$^qCjGo9>gDww z3O`W2qc6?kR?YlIXislu>;%q={s>_6j`@0$=V0s+e?M8s9RR zVxA6{;wmj{J3h1bmVPH8^uEsBMv?0{cAOHE5A%g+)d^HrWX9N$LbMUR9;ZhQ@Ad~q zgc@)T>KUkd^NSy$RJ-Qj=~as0s8h+>k*q6Ay3(_$5etC~CrsZL9QdVSx#c;rg$Kci z*84xPkAp3hJhv%D8@UUBXND@!vSd1sSC*6+1V1EHut+s3|K$BLWoA%}2Qjxl@6k=M z9L)^7MWpYho6#3%_G(u~X@6k@Mh%-{l!oLK4c0>*>fJ_f^t4p=MWpk=wA`y;&4(b8Y1ANz>y@ADp&Qh_7^nId&@z z@e~ukhsmJE&{?s%fsk39R!TgNrhKg2jd5$B;?>b^hLI`!sfLHFsm;i>ynJt(%6kj3 zV3iTdp7Z;Aup;NfU(WB3()bGY!iC~heDFkk3NqB$*ZT1`A|5SD(31dEkO+o$htq9 zTN<%WoJj?C39QP)@w!LL&WAQz6H z4#)NvtmEkQK2D;2KkOh97uOy;0aoh}S1}f+8`jmA;s|?NYQ~~Tg_snJ z3K+Hv$*`yHqiS!97{I6EejzBfH$F54v%@hFbM2xI*RO6jv!Q|H4Q16N5*{$sE#kn3 zQQc6IVIOKMu+d!UKE2pu$(^z;4Rz?&dRaPUEqF`GjRZ`}0{*+|(n1%TIM+loDGNO0 zj0oOV)9y!$q;D#t74#HdZXE73&QjjDa5eER=4$WEARs@O(`8Y#wb)uUSM9)4pl|sR z6nsZIX?S6Pw3K14mBRCphh+k%zlNshfX{v!^U{?st?`fp>|&nHdRFQybW>o*!1Lyo z-)F|8BfweS=IU60bHCHmg~9w3(vR^ZX>*OPz5Q|Q2v$)o0nW?vT)ir08=UVQQ5mGJ54l~TZ_9NePqtVqnn^)VZ&VX{Y+ ztCi6S#ZJj+Sqb8Ea0m&;{C8E~$qYL7H1W+ipQ7Nkqz~LWo4K(o9g7i{!MU~kZHPlK zi9!PFaDg6Y#9Y6;=e4#H75a)a!@lVDpJYdoVg;Nxf+xWQmSId*Kt~toY20LR$n}>? z7gdv8gQJHL3@QKUUpUvoAJ1ggzv@x2RvbKFWfxd(^3o#~FUbt_}AR}p1!zu9Tg*eGGxXZ21Z=inQ7pOE0q6Q4mpeS z853i^$IIG_m?C)PM?TMVtM%l*x}osz#Yig;`$Q&!qhM=yhGzbvg#8QafiJT4 z)&!geqfAjAXYXC@Z6(r&?+OGE2W5nJdn2BY{SA~&iQsrqbn{~XKEZ^Cn4kR7b+ZBD z+~)(5elsD1xVel|D1w)+b|WUvly^epIbT{$v~=71!45}H2!|>5YH=WL$?6F=P=iIH1D02xXt7W zmWA6$e(|KsK?mjAQa>4;>h!=t81DVKV}^xG?_k>G@l9j+;c}7WeL1%R${%wM%Z})iPj$}?g6UE^tS&`ugM}mQqt*99JHBHUkJV&q zd7=)Z=4&UNhMgE``e}*r$#RsHmEzdV+?iAo4zk}cn~4@a9!fdH2X7fkYs+V!OOW!1 z(}0Un;6Ok8$4uY2?%;SR)T%L4!>%fGq3a*Len*ENwraA9JR;DNId=dX{0lxQq|3Po zL660`YtwBU@+Y}pqUj&xC-vT3wb|CK&F^);kZcQo$f+t&RH-u}L9$l+mP@Ub1%GQb zf&K}}nZQoVn*+<=DJBMpWY;impyD})F{0+cK5VDnB4@&bJC-&~0_(C?JPe%FRKv24 zQ+nt<_G@6ZM6oCvvHm$yo>}|?FTOA{pWZtVrF34nnbg@lYtOBh@9^F0xXCectM^yW z9`CiO;VHZ(BL)(DojDEJ;!_Lidxhs6KPRmc8rw0BwKAeUNMCNxdjmflg%#0VS@c$5 zcnv&e_vW}o9plix`O#?!PLWpyja9j4xeRPAxL+Gh-Al|MPh_6fekvgV~`vL|Tu8c**bDcGpAXCpP92 zzbT;~R${&%vLDVJlAs=u?UY}77XSWv-EwBK<>t&pnwy$+dVip<#I-GQ`Mk+EeQtU{ zmHI|V+mEgFk)bLUp`xaQ!k?F*n<>qTJ9n<+=q2kGhxlgqxgy&)_cH|y*v2Qxb$kHU z^pnmN0?Wr>K3bLCuU`jg*_@A^5TH3637(`JgN(qtT)3x0p>kkVhCTbeJ4#q{Flox3 ziDx*};>B)VkMGmg_5DgtyNjr`!eo*&D&9=tqwmVJxoHTeae}5*mrD;4{8yS)3Sm4D z>bQi%p&4~EV5a;!>^OYMrjIllhcHLnp*pt7PruhgvXOO7P0n?2g^)MduGOl}+X-jf z_1tiN_$YGhET@+?Ss0y#b^D$R>Q0$~KD|ux2|R_nZN2J>iaKHnPD2I*XY8}i7Z-ZA zPtVJe3J^C;4q&09pI+y%F{Qxo`P_A}6cF>{STL#(gh#!5{7`s>6r7kp_PuEzWws89 z8jHe0XssnkrjKk)H7Z2ucu7Xa$Kaj&jdRz0-e#-Err@L{Q3&EJgYdz9ijXq+HhM2w z<_k#?qXxQ5$V#6nr2A?Kmj8Ur-Wzo5HWQ zp`SkL9j5njD$-#e=MQgs42>BPpOrcfLXX;)Ybca!YvbyU2fb%otqAB7lAz>J#}F|0 zTx)M18`o75HRMPcxedL`s7oOK78xQ~sP1GOF0!7~)O&bLCOr~_h*f4~vuI~s!o*kF zIL-|%^TVSP@FnntNTI)5KDQwCu((&kai98Z^m>qIJ+j5FQTAx!1#%gU2Qqn%!uSXx z??yd1p%nt96QL?rxx?t9#e06I)%zE>8F#WV<>vXM%z~!(g^D->(LwH2*BL_q@s!*s z`?tvCgv`=li?)LC1)?q0d@2BGw9K97nf2QKQf<%xu?o)XIFhm%VFzSwj0uiZx+NG? zc_z;+V*QALf;IwHyBYTg>t2SpT<_F%mAqcB|Kh<}Xf1)9QO<18u#zRYRvdGhfyIp* zsYJ0-JM+(PuwygoVA|a_J4>@LoMePs@H){iT+0sd5}2D_$hki=*ZcBtY}2jn@*4$X zf^Yg^(ywKZlE74pqCqXmPIHG5*o55E!jp9DV%7!UhDm#=p_KX|*WW%mF1OhsY)-cG zRe4?znw@!2lg(C8e0G(rW2Ackrw@5Y4 z-W@++eDzID%jA8PoDEZc5#FsD{dlN`E#y#!!m*>Rt~NQAeS^C|(MtA=Zs}1pCLMil z>4^1kJ@Kamwh}_^F6L09AGSAZU=2@a&T5;iz=QL+05cZLZYJCEiCsGCZ-}x9Bld=X z`WqAcb(|MYV90i_^rYUe$(5Lb_U}L4lZ<*MzIsBKsPvI9rdx?qDNa9!1X#g|d7d2| z2^|kgh`VcqN6b+g3rKi5WtNWjA{Ko#mO#<%+-C&zqw*9noJPeqxF zz3gTBjJ+Zfqr%4bUhKqu%22jH+2l}IP$CC^88|e4%Fm?yT*|08>{3LZ5O}Q3DVxaJ zEd_sv*C38i`cytyS$Y`xc_V;k5(Yu>n^z+aachF}B+rn*iNO%Whe-6)2d9^G4)LYH zs+LSlmlB~Lw+_6!^CmM-$CQ0dFi+&{FL`G?I~Uvlyqc^(s{(qzYr@Zgx7{AU?V5(` zGq5B5tU*jQ*_4ugCCW)c#8(lpIb{n`arIFaB;<_Qg8PCAOmj!94EUL@RpFE^kCrfY zH1E_#OLhPwYM1)FhMSxlgaKBMZ$`Hk=RZ+qqbhzcv^QML9w3aB^Qangb}p$?8EfP- z)TP-nzD)Papg7FDtWIY%vYP{C%PbH%XdK4ztoY-1Oob8-dEOu(TYS96yqB;07H5u_ z)wYp0ogY1D6 z4jAj5z2fORVPm@L5ArPF;oqq0c1AL$eZua2_3$#Xdk3n^2|7~1l8&YCg?2DSP`-#l z5KkJ&HW@WCJohrioa2oS;AceO~J@-6#9`GJmRjHysJ+kyY< z$-&MnhTEA&nSC8ZzOWYqxX31sD+7bGd|Sm<1`!2Qk0&qn9=+$VEClO}-3?w@FXd=T z+L~b;AJZfuSc&b-Ax-hAn_3BE)oSQYUMfY$j<>Rq3dub7cl6nSOiZH8pJUw+Dhk## z?USerVtDf60559DC1Cn%%*uhg1GhPe)(EP0Or5?X!^WdMLRWkIs-9Jz>o( zYL5x-$G$Xw>v(}1rZ|Msn%G0!^P*GNh4h2VPVdGaBbTH6F#+e(uOjR1gJ(NQ6hu7v zw39(L{S0aX=);jSIplpX<`?zU+w_MpaK zX2DJWy-(yo7nucSZz9KA4}Yei%_@X81+4~vg)BD$FtAM#zqM9$ViS80^**IBJ4~?% zqF)is5rM^3WAnlmHq(@g`4IhyYqwzPgFKoK=O6`C#w}uO{q}&`dL#7}bBjt_hYORn z3@%q6ClkZG)PDZ}u(y^xIGjq=;XyOIkccxZP39^Dl)tm0=J28{BCV!+iV5>g!#Cq zY{sfFv5k4dPh=spoT7fUHI5$N!(=awC%b$fyQhV!foQx8NVr~et-U7?Qzpc;{zIqx1{P10#3|TZV60eQO>z4h`(_SfbF~Crx)Aaq_=O};eHS3<) z-qd|6?(^Du@AIpw-u&vQ9HV+;E0|XrH}fnq&v66pasUe&KHX_+T=eX%du6vGLMK%; zN{J!B%J0L-XMUQG{DC}KA*CFlLo1Jk|KpP|RrRJ=W^~=RrZ3zA&Pp+dDUx#~U(fcn zHDG6NzNx($Yqmz`cdeh>&6s+i8geeYE3`n1USL3i9VnMxaL{rRJnwRAH#Vn1y+>8H zOif>|Gv_bj6wPqVTzvnCn?FK0oL~YlFEJ4_12&6kI+-j-KFBoIs?&kLz426j7YNpSm}I(4pFrFW@*&on!519*8LP{gBpuCH%Hueu+rC;cHM_3=p!orMgQko zkGD6M`C#VvbiTK}jb|~Q*w_5L+(7g)2}bbmM*~E)<*a@gecidR1FPy?@ceD|e|l0usxUn!YF6VuX_G6BfcC^pSEvMDaAMPZp zxPppnEnpf?;hkh-ON9NIx~1;&Baq*mB?N} zT#zB#tVl&pl=%@nP(rh-o-yccx!MoXc+}CzQD&&Pz`eHhTm1;0Xmy(=ogi0?U zqF(sDx!I`5H;I&5d~dTghLPYfh1C`K&r0v#D|XCyOq`*_0zNq`QTIduYFXz_g|z`#!?6DXXKD$!u%iKya+C{ z`AXon)-ugS&}K?jaZ*DnJbDxaRkw6aI#K-@Onqle7<(|PVzYHL2Wenf=$x?XLf?lY z9Z|t5Wm7e(GyV!2gX~fsvfJc%%}6FCjK*> zVWk=qC?%X0PTuzz8Y1CpRE;=bd1b|BaogX1K-r%%&k*rMFqYA(HQWjRs6s%ZlIk&B zgyw>U!zP<(X`92#;;IkLsr%{+^Q3<~);_O%#~4gwLg3g6-p`e*GXrCLK>mwDsj-nW zq^pxl0auM6C%6xn!U&0>%S}bvT3Dxaf6m6)hcIALDu)8&N2^$X1}A?)lJ#<0X>y8{ zPHfz2W0LnFdD-iY=O`)vfUItrE179os+!U?d}?qG59XxCdo1?@cBUl)o;gxJp~C$r z@1`BZ`QAs132x%)PZiCkrt)$gCok*`+?mje*KHq|A~Cs)l*dNWV+a#DZwd69_dYb; zgo;YsMt4XN^nI0&qvy-lA}!k~9NosPAec_H;GS)MNhE^R{xj3!t93Um7Cq;VmEcvw@!9!vK?j$of_wbS`gT7df5#d|5%GrztP`AGYlD6a z$6FR^ns&m^{Ul%H3BR^tZfCmx_<3eAC$}35o?#ggNm|H6|7$0UM+R>OnN8(Zi)Lj% z-Oj3(hUi<`tdV10Oj#A*Nkf_ACH7}*7^Xq=0A?~%>#+R7jFy7zI~7`gbBN1?;L}Om zC4-341kqt{<*(rF8zy&6TDb!j%kpb!6T{RuVWT`s5>FVL`_GPah7vKQ=AB>PFB{N6 z=q%v))tqb*Lp0^MGS1@phAYIl()YpUH9IWXVLt<(omwSjEoA0s=5{7~5_uEi7yZP? zA=LD?qx405pmaC%^pcrFusclFWlm|UE{)IJX^~`I zshe(IUz;o0%J1u!7asl1HK_8vHqV}(J|`yxrf2?$2H--cEQJ@-JZq5R^aMwQaHrJ; z^~cx~9pr3|CM&Mg>hj^OP_k&Z@SUxE#SeKpt-9pA%L{^Y;!?pu{uZ0$kfb#jl+F{T z?Nef3zEsCKQ;3&4a~+YY^kPLx>>eL;2M=^fe6omOU95o5?LeQ-WP2VT-g zua|EHNAz^T@n7=JnHo6xKf1&FQ<_T0pozLdwaJKRQAuHBNW8;^W1byfwm$#NYS7^G z%gk1Uv*jzdJP$*HG3n8|@9pUYv;4OTG}i$~*;88kt6WG9KOcf<_YaK9_$5K8l&jNa zdGExGJrKKTr3hIc-ctnxHn!^y?Yp60H9?f~2c+3w?XmukPxe<-L~|1!WLs393l04! zL^+T|Znl1$>b=uRvOl2)I0aY;9h59VW$UbHTTov>e^e&^;STvTFy8sx={U?;TjjA+ zHa}^EnjHNA8o<}2(R!zs$c*d2q~iO|hty#0cG!qATHYNc1bx6cBLRk4C)BEh_hN18 zL(CYTKg*khVe%CMn65pH_tzx$W^)oO#(_(Jjxuhf*kAs?f-8}~-c3JPH7e){fcL&c ztwtS@M3AZE$Y9dldJhneDEe3ODILToq`2f18PhZkE$R!?+@$KpCLb9p!iO?2{sWT^mr`CQ+;rZhXl4PJ?S`YQwl188c-}w{ilH3!+P*hA zTolVja&5e$G#s=1)VNR8ASt@SGgrN0-_0V`mX9*S%*-_pu>2DX_2*$7roMRpmOLI8 z7#DZT)TZ=Qx0uE?=>wkp_>q*eUsi}l#@xXSt4hQ+*V?TuXLnLCDx;Fz0?Gm}s5c z(0`(gOK*Od^$=F8DT*IR>nTLkjFwPYoKm8rO0d%QD(5zt4DR!4Ktdvd&sf;0**3U$ zh+?9jOC}s|&uF4UAUHWztm7;2m^2yMQ3f*N7!PN;cb*7*!JzXDjvzOadk4HJne1)>zYc z%=+y7$NI_G;_W~eu372P2}Sb|hVlpC0qQ0$vf^IH1{V+@HOv5&BJ9(_fwN*8+?j0M`}IiadQnJ8ghggBME(xaic zD<2=Zc~!&tHYq{PLABVOQF|1xT-*;xi5ENwL++iT&*4Xx1xM+KQUxs!_0>?kbZOoB zNaLZT@}ePXk;!*IsXLp`$}N+|1^oIR@wjgcGN0pHuNsPHZc7fy4te@a1X<*aWEpRt z>_t5u3ftR?!Wx5XgK>(+gL#)EotN6tcey;KqJoO#D89IHw4EX=R-#|H*l=}6>B5Sa zOD8#8Z)U)LyK69aWsHk4vd||&vV(h}D0%gEsw65*TX{*{P$Bk*vwG&v%(IeEKtviw zuAy+nu0IsLZu6pUK+dUwWkCO7A9#1lIh*t?^ZN#MJmsZuLo*dl>-)0C0s}@Vly{iq zZNBqVDMmQdi^Eg>fqdJ+e0x%4G2*fMbj(9Z2Q zgU&2UtBHzb*wiUbmJG$RZEF%p#{i_4=LLb(f;Az}`HJ+_}gqZic~`fNc3BS@ap z(hZM!qmH^rI1+|SUMWfwMHAUJFr-twkKXa3Up01xI={(illPm9E7Lvk??U5BXj3Lp zy*-YhV`fP&a)Zb3dE&a>qE1!p63`>OAs!`5G%)9D@tZ*=8h@W8xUox?>1YrfPoi^X zzJL=oDE-v~MPReC(!%Lop{yFT`w+Lr5fGHIv^R%5Dhenkie;(P7~7G;Va%CrFlr_0 z>wosr!+VR-B9$@ZT$$R$8=+SwsaxELq*ptp`Gf*rPAnYk3E-Sjytm7vWN&-&`HX#t zOWpM@S+g7`k@*ia~@xXIv`5w}N+Y z!@ID27rgbm<><~Y>fHDA0o22$u{kQF?w3iKbZ+DkjrBjqXG_tV$FzOsC`?yK50GYf zWQ&ee{2s_yB^U=`e`r2Xpm^a-K;v+(Oc;yO%VQD^)a4!i@=R)tl-$(7u~0hOtnD(~ zNYXB5O)OcmZ>%7Nt!x{f4^wT@J&PYPJLsCeRKw7rfPLo@naO*p->m19q5uXSA)$$0 z5~*RVlx(IWc3lzYt4o_o>)n(DJRQWco8x&Ow!bYLYTD)`5|5GAB4R@S>++)kK|QT& z@6?l1Ei`t2s?W4kk;K( z@mJ;CNnGQXjYlhI!in8?^yJ$tDVEA_C_m=qz0+p z`T5mV;!}QoJH&;|t@@TXk^$bX&}GWH4cY)t$Li?eYto+gbrB*?kBACBlX3~{^p-N5 z0h4vun?p4eBMwD}7A%dM86G23tg~=7+r<;ydUJA$^l;=nF zP8G}U^Iz!cPN;K{UwhyjrE!7@-1-~9<7_T1z|24K57)3B06yUfR=15`Qup?q_LZyR zdNNhs+BAx96*C#!?xZru9wvUjM>G+}?cvY zf8$|qf2{3(O*UCmbV_rCb5uC6s&cJ{^CV? zQPI~jR0Key(RG7)Ei^2LUv<|s0mZ=2jQ{Zy7s_&o8h!`s2Vmx!*)tucDJ{_xZ5QRar}-|WkzQj$@P~WZkP*3? zHl){AI4ET@qF*OFc3`xhQo+WAGw&p$eRb{!O`HQ8CbRXiZ+m0#4fdV0HZ2+E>Cv4? zt%Aa+P99Txp9DWmOtEwt`Q_;F)OQ~55}O!L!0fy->8ZzzajPWMkrLj(?^{)1Jya0b z`Qx7Dnf8$v9_*e~XJ9f=sq{hB!_c|Uq7XyqCS`k12`Df_#tb%Bc6mmpBW@NeeruEW zm;GRG`I0jecm;DJoQMD3-{*Wq02*TNs|Jlf;jyZc*pS($IT4E#4yx4s^BU%q*EQjE zJiOp_M=~H?lVi*FKy%*!^z)K5&fo<@eioudS{+KT9KgZ2OY14mB)^Wx>hng0!>pXvi)nV= zwX|m;p4*gS6ms;m&Cz(zT$m{8xBUd4C%!To?w#e61cMR?^Go7u9Cp^st3*kKY^`LN z;P1pt8cGvg`Uox@Z>|_I^h{67M>v7zDxOqp`eI3t$5z}Wp=3^jK=xZbLq#?`&1y1C ze^Zw;MuDAkLc*Z+uXHx#liTsN{LsT*JlG}9O3stvsW$;lt%5m}I)vJfZmJhg$4x1L!DO0d zXqo+foqO@!Nb@~<8r(<#b4&A3Msv?6ifgjfqmYzxGWUO#;lX*CE*N1RIIiz6q=lv= z5wIL{9;E+4#)RJLP(B!}EfAH+GACF^Hieyd5#kN-n@t-4P6@QihIgr1k$w5u%=DBV zxWVYy;Y|=1+=R9RoG+e~;f{b?G$;@wMd&4`LOH#w~05$TgW z{ThZ4;+wXy3!f)I)V2f=i_ibfXQF)|u%7j;-*o^rn`IqHU(%YJ9UveBMv!Qwy&xCU z2}@_zq8}^)g27-SS>`zpHJtH}1D`M^HBVJL7!2Wq;nRJa(MO`!z}6Ttc>an^J8@=- zMWF%6ZmS*lKI|Tf`e?`EFxuCBo3*D0*m4xNv+;y5GMh~T0Qo%xtl!F(K`rdr?^Nsxm)B4|l~W?>O)|D&*#d>I9_ zYaK2ly~dmC2C72a*3-jvm&&fQ<1J%3C^B|CsliVb;e3nfKo%YnRQ4BV=jK+xVlf!{ zdEBXVejkkq{z=eb!@#gg`-pHYik~C5W2FZzZHQWF`shc2VPBG78iNCBtrvi?cQG0$HIPvOMezX`_xH(=?$SL?or`rSb2?Em&}cf<%$ok z5u=flw7q^yczH__!zDFO1TilnwDRahRzL!G?rjNXp`v;`FRi5FtYGU^M%e6P5+$Np zp%%N$jA3Frs4jG12Ta$g&_F}@yy5^9(W_KNK59&Re`b6XqJ#u@M8QtlJIo+Ixg=9) zIGOC{>^J)HRD$eD~^Ei{OkYIRSuRwF=e1G$2?3Xkxs$tse=^e;gHtcU_g zguocb(BEOb`_~Hm&eR5JOwg(E$3>S<@6w)QLlqJpEdz2k?*U6xeX%w2{A+Xz>=k5L znD%8RV>PQUvU#BIP@FN(AIRKbK(D(Zr9W_DSf(VbX*UZKHvb}5UvQF@!>E77_|(2{ zv51L!^S=M|5XH>0JU79tXOt`+ljHmD4Xjqu{o@81M8jjs6NS0&FbagF|KarKIlji7Wu8-8VFF!bDf75q$ju_|5w&Y@qhT$7!OnkRe7 zVLL3890XOq$G*}M(4Y~$>l{(bIO8VKZf;v#S%UXrOM`T zZ|7f4p81GnwJcg{ooT((TJ}ALNCTiq5Cm}UrXXBDvo+~|b_zEH^*pH6@HvuQx~R); zq<=dfi#5=dx4#<80lzx*KzOlK^7cRYqNbx?0Z%`3Pk@%luzFpoHKS}@ zCH`-$xR};R?~N@(Iq#T-=|aI><)}0R82Ja++f|XL2*^BR(vtn@)$_B1(>*^)qi_$N z_W+$*C8!)rq@qlla+Ye;lB?u8%kDM7MeZ7b_}q2}PBuIu#;jhOXk!71_uXREYoQ8= zx?6TSHTC)(*TYEK)zAg;hv+uD;sY9fqqnJX;GUvNG;0-ex$q|>ax0s3n*E37Hz|oH zVU8pn)qR@v4!rjjuEzy|$xF5fa*mzD?>S7iuynk|zKYYhMGKF7NkL)X(1#RqAT(+` z_lOn1kDS)*y3E)0STEcdwWPFz1Fa~Agfp9$x}ue3p6IHBss*Z3hs@xX`uf2-oI`d8 zG95ll5CxnNk%Bt|++n?do3TuNPtwHZ1$*W7#Tq0a0&-$dqN`4aLbsP|+Y6~w9KBTA zy=yfHBQI_w`5X(SY;9U68k5=a^1qAZC)?{<(#ALi!0K9xNJh9pB%Byj>dMHex2HJVFGv0Fh)R|KR*^qV@mh`-}th)AXXzNO7r8`wI&@h1hs!TX;(>AIZfw*#D1+=T58viqY77n{>yZU+te+> zp&%&iuiI?u{Lv(A(D6}6r6BUeqU9F=WSvL>lv zpopZIF0U1BRrREF$+z-(12qiO3L)ruRyF|WLcxE-YX#vHnnguv-=^YxXh;xV`Q%+bpPP672MPw02C@D21e9XzC2e&UhsWULd9xZpkDMc!| zvZdKD%`uVE+bitQ5@6BI(N#I_QkdU_tbFTyv3Ifnrq$Xn{rw!UNACL9BrSM0>l`!L z*A7xZ$POTI^srl79EMJBYj0V)W6C+Aw_jOXx*9Po$JI;+z1p%erK;X2vmHhTq>n5|2=KGv1ilO_{rlYbN3kuQv2z? zred|c?Qp1k(A0U0m)09Avpsg=iW2tfcK&X#v!c(8UvsCTky@I1f86{DoG)+V5(b6y zh6BCant|vcs)^=EXc1JLOHY{%BvfjR|Xa%y%r zb&GZN?9KJ_Kf4QB*BdEBR3zNe8=1AS*uoAjIANL9SFU5QK4@<1c|^-fUy_H|Q&w_d zgcBN+YQ$(QrAhkQJDkMYM{l4MWjb5V3sK-D>Yn!E9)Iq8*^1ABOwuQ1fr7)7x%K!Y>w2+s6WQtqm?fISDU|&V-f>O@eH-+~g_$wJu_XaTE#J(PdWk|0{s_&US_rT->_gEWDDy`cC&-u_3 z3olNpBgxYun6?JR`X7D)M8TV-?_Iuh-AjN>cIL{UIzrqo&bn61(5|t1l#@>&YY`mr zCIZRWc{sOT_3!0iPCa{gOX-E&S8)O8z_^6}Q3w6tHS(nG!tjC+3H4~^70#3ujh+e? zCFX>I+|3~^41m5bMM~@Q3lA!_@tSpBTm1tUz}qQ6Viq)^?Fz3pciAIK_u9bz=ZFxd zUY{y_WbY_M8X}9xe2qml+-wwEJG6#NQN^(+Gnpa+xnM|&^X(J*P|m8IYRoV0%T(^} zV{o0x&YnJXqqT?Z>w{Z}qK{Z`BMzOWn!JE`k1ul0<@H%erXh->uAu*q8P{u@c=@y zOS|WY{ZWP-Wcb^pQmrEYgT00y%?IHyEowT!0%G`%+XA!AqD$quPfbh@t9i{0K7WpT zMfG`tZh%yG#t$lu%x9P6%DeX#+O({Lk^p_1$BhmhZ>w#Lz^y~VU*i=-FMPi>gC@i~ zSVy<%l$;jh3=FsA*6@Yt8Gd?A>_LR#FIlZ+`ZxY8GH)pf2L#Y+r8{+5%+hQ+5_Sv7 zVZ~oZ6QikBPEUB8{y4T45koY~^d}gxY9pGHx#-3IbzDr0g<*sz!~IYgWnfE%hzkWeSuQrv zpiPSM;=Jftpf%qJ05EmM5TA*Se$B*XUuoTg1(2Mmq2{r;P*L;|q)bS4_l&ia)iQ9O zdR@VQV1sb}qVfeH`}r1K|HyfOz_>FpRw)JzSm|N8%WxH;nSiW1mktQIz9BuhEeX<{ zeFR6u^~k80(vs=xCptwURiNg4jNL=9Fgz3<;A`8qZQHhO+qP}nwr$(C?fYH#Z)e)+ zqKj@alWi8sBzezyuJFh;X=wI_nW#?=?m^R5d)1fNI2$+UL8_@uZWw$bT8S zE#49m`{8@C)-daR7zGBd*h(`o4wL)4C6%iQZ-1sVy4&3~b*cKVI~EF+_XUq};Z9JvD~9$e?-4!1dWy5Wdi+u(#Mw7P~^qG7FHSMS|<53B%$ z&?)z1o1T1=OqdOoz^Fe4--ljm(hPx=%jt~8bNdgz0t73ZBZHZGFl#-KQXZrA{FWJ- zl{VvwU~4npfpJ+fYr=>NK2t$A3v%K~&?g;2G1h$2_#w2rw&N9E(mw{1T5IQaYt4SB zt$fWcD1CW4DYMI#lZqN*(J9z;`90^{=TE~>?}4tGd0tyG@NaL`JwiC$xtR32BB_NC z8BzmQnWdEY?;MbvcaR`0r|MN^^&@{G7nMijVNJU%v!f9oo1Yu+Nz!H4f~4Y@wc5|z zJyt_%#jqAObX5g|cIq<|XlczpXbX@6+=gDGEg$fS1#8G%;S1-nGUYOx;Pm&fr~Qki zAP?2$!7voyzBsew(!B~&AJdc(0-7+mZWpq5Y5Iz0@C4Kp5}G;bTz|5!(3*dUuD^1T z&)2Ut*H!DOKl~+w9lLJZJHji*#ItUCYuS}QkVld@!|@GY;JRJ!7)YKyFvj9XOip#k zfeL;xaFA;b;#!LOCri`BX`FCJL)G>qy`AG4X$uqH+ZTv_PS+5+D?|rM9%aV5H-c-f zNx0&KL{|Ljjmg6hM>-#9|uuIG7iG&pSZS4 zai1I8dL9MaQC7Y|jUT{FL7zOf30;z6CAN&6#OvWXBlu0(hR+B$b1~+G?zC7wa(Z*1 z0EjhKlfKy&c;in!Dad^F`go|HhJF=!lE<$}DQ2QUoLWmgZz3-GvAIi_oq5tqu8#0b zrsFxi+(tJf!Ot}Y>+%YsA3@q%ZBWb?OLJ`UC`2j_QSW&$PPRW`QcXeIwsN$;5*daJ zchK#;3Mx3Z3+Y-g6uZ;7t!@L`w#`wQTM_(zR~|FzKjuJd*w2~^F{GA zOU5^6(N5w0^TG&Se3P&$&t-mR$4R@rL2P19Lb$UJLNf~8K|0e0u_;dV68yRo0(uD* z6My=;Yn#o7R=+YOP(%8Vc!nx@D&Jdq)dr6!lkS@h+Q zj&rdOO#xqz%1U2ymwQ?LngFI$HOmIEJXS>aWCR1rwaKqS{t++?YJH<68w#_S?KJX~ zx4${3^-S9F9`SBK6tfvwH7;wDu}nZ*1V$^>IUq;leSu^MRH&hmpZKcxI^5jsATv|; zLHpDUd-LG8$xv;^uY7r3-G>aMRCn~Pd(N;GP~k&GB5=8DXPw2#Ai$5*>J(xb)f$XX z+?ASSvRZn!U%EDW$JBv93G#@3FCnAz*w8eQ^`YciPucYw@GbRm^#Uj#1Nzx)?Eka^ z%tb(+xE#>T_#G}y0-!bur+rUWwUV?k9IAFwj8%2)M zc*vduG$|bPy!gG1Czd@+BN>UxLz+oZ(%LQOEZ4?0AT7q>=Ru^~pt$Uf?bb552$kr@ zY55izS!?>!NE0qLf+Q$~6gPd=_@Jg>n}Ze!!O^%l zQ0eS(!93BMkgpm;XBI7a+vR*ha5TRe{J?qH>&J1MwR3zUM2(xo#mFDZr4sxB)*`1l z1(a^n1)ca~6@z9^LK&XKmkbgbt4`|WPsqEq$9lp{HU>l~W3uCrh~|IdGaArD))dCY zRBs2noYqDL4&)_D&^9>t)RN;SmJz&kmsQyRCt*(z3CskJ!xZr9*e(hodSgtDj9KqU zaHFh}74QiijZzCmU+@|u`64wIBg+-BnnU+WcoI+Tm)V(h4ClV>A4zk;lq0hW?f z&$Tk{=)K~VfOl2B!{T47Sl+&~V5aC=yk4!oqDs!YNn-*Zhgf3P%*~i9JN2$}Lu2-$ z@L2jHa1(r5CI^~^T;>sNzT(#HYd8m*DW4MR3ETX5>g#(2&eiN=oQ_arnBVU^u`itM z4=cEOR7lKmPrkJK^{cg)+!TeS@&pSLx?4!(;sdq5+b>h<))p3a;P}_>cwL1qiRX9q z_ngo_czSY}8Bv*oB614~d9IsrY(X4lE}gL>);6AdAerc*q{KZo1eQ82Nypd!8Pq=2 z0#d#DTAt36z%F3n@r30IsDmr0GZcj=A>`s>Y^(gu!afMkR_&#Y`<$jJK;{ow`MpSU z?t{I7EO{a@RmL5~5arrW8leqCanjUHK7oLw)+HUaD9g|PUHf9vtop&+BkFnLCmznJ0BNxlkg@u>8Ikh- zuw?#|8<05TO{?CDBVG9Uqha)BKYgSOdvwL7%lqvY^OaD+$e+|AwZKM}@YT%NOe3Em zr46VLuNz<>bX^E-shF5~cpF2WTE*CAc99AOr*4T=IXx9wPb?k}M?CxwEy@8Fq@01f z$Na45Wy2QA61MeFTwD0AxWM}fVZsB%H?`btprnO1zaVL4+uSYTYs-$y2(4ad`_Jc> zxs2A11{sp&(R{)Sk*#trT-;N9LzDo5jHp+RPoXiAh<9C+m(8WF?Wf64+R(jVZ;ZJ| zM8u-bIRNpVq2Hq5gl%lxNCPBR|8jXqUdEB_ESq1LSq)SK1X@Y;je4oAlEyXh;aaq;NX!59yH zbk`Bi_PA3vl-X#eQ8`8z%n%zNC>5hZijjlm@_5pTQhd%)lhQ<8(S1u7hm38V!kZwM zYA8^0TN9<5dS&ycf~s$cZE)AXzX%q;A51$##g9mt_5mS&7>$^ruztdGPqGlz#~1%l z*EKtsT#W;d(&YJgA6VQf($E?~)%uf!5zzvYz&3ueuEN6%Oe^eS$UpwY?;X+Pf#hHl zaP6gs{h!9iNMm-^LfsnY-H9;_yvAfSnIviDR5zRNMFVKdJQsk}dwb#?UX7JtMA~Lw z2voaf9s@905{EALgJw3Kl-0_?P*-~uyGHOZbbyBb;D#o?8X4YizouzC7yM!y9JwXAZk{W<#FDA zl(35FuG7ly8zH51j$$YWV8=9!@~&wIGnhv=v>jbb$U9%fUuBPi{?|gi%>^l6+nX1M zs2rk&3bIaCxe147n}?(na4-jNN5G~7_Ak0if2D*O0040tAlBzu+EG&{#cDUJ(flf~KzX0j=9JSBixi&ZBBEN;e_%3JhZRWLPfoPBS!_YDYJ}#aP~e>K3;1JmmUnxk1*0*U>hYkj zLcI*KwCEXKy+Pg+Ws$?f3choRsmmU_ugBpjV*Q0J4|X(6SqEL>Occ1L@xF}4+JjoK zYF(CS8a0=(y_eir4ddZgZ~P!1g1Y{SmXNqC$1A74DadxYz$2v%&G*lfCe{@aN_o6V z`y?=KXuvQATCk%Jn(;-`Vy)S2kOOXjJ zG`&Ok8uWiZ#!CNbjX~NcIKoOPSdi6Pm|6x(ES<{_u?qjLzYtqOT$?yUL#$Cv{MO!0 z?>NtcjrityA`gR3oVGWCJ?80Yb`-vEq;-u~9uw)&%TODCgp{^@9XU1WsBATKZp9z* zbf18yTJYg)Bn}XJaw6HPAlUx!80YU0pa(#U-NX)q(pJt4q3$!CQ^#0k)8I2YbQ3_HbY=I z&NgQ_T8ifgNhEz4xByre6dslogZCz&Zt(;EOaZ4&wd&?RkjQL?-o7(x6DI&(8ROe2 zbQpQc%uSVM%7M*mfD4_%uh%W8++EVm4fW^&tg1Kf0u68q$B8mTF>%+^$3 zGCxlyalcS7jty;;t#ACyQq#sFR-)0cCTAaiG0E}KzKVgTUZKdS5m0430V~hXa{C!d z)wA&Y9k_bPK+pEGu)Svtq7nIz9@3)#nD{&jHQ$a;>ayF?Nc>&F25A+~#XrqnRgywS z-+vDvtnz@@B`6s%wt!)_EO}iiu(NgTQ&-5#3Q~Js^v%Q|EvP~rrPdD@A=^~()kCCR z>=NMfd(1$Ihy*=zZ1w}f`YXxa9E&;ky0LPhI5hBF`>)rwtdlt+tFRhm5vu~8YQP>% z-5?{cuV^3+J`nYAWqk#g;0UBhNDxkGa8fwR^A|6~LJXFrxvOc6*_Vf-r|K?D>ty@( z)Ni(OQcOd4vRID6b1Z9J-d!w|MJ=dWQQ)H4iuywwtT`c&4%Z0yH_1!&p|I#$agp+* zd9O~L%^aI-rOHRD{C769R9iE(0`Ti%<8?Jv2F86#>aH_!Ek+Q^jj;CKQxK|W4bG6{ z8vO3ghOMEEOGz#?^4%D4xaMboBL*|g?!ZQz&)`(fnm_l;^N%fmjMAT}GHsJNKmgI; z?!X5<;Vg`uh7t7qgNCPM6WQ>Q?BGLiaV`IR{Ob2I?$MTOG^2b~3d z)rdnRc<8LxArajT7d8YYL7Dd%T5;oAD5SA3vHM{adp(W~oRE25Zdeaz&+~k=Xw~VP ziZPOWaLy$5V7t;}mic_S7k(e7@$h0khvnxNFIeXdCGvp_=yXQs$N5KzEBsCl>N+-> zY(H2QXRN1gLBQ>7xwrSGq#_ZYSRryA8nB@lAGXRCk=_j)^WZ;(=JDMz32F=H0SFwQ zl!2r$+`H}%G?bRgFZH*>U^E_fjavG!H^yd5uwOG-ipSm~M6auxqPu|UMV$ye;K`?o zOr3)?4gKw1+VzpA>JN1V9>nY147#xnj3S7{2cu2U{e4q>=J-htOBW_%3JSL}m@ zoXkY{p?i^1@$kh7BPJP6odT!dH^LqoE7|2uev%;lZ$mW&>S3Szu6)a*@Ab3Dc&wec zPEMPp1+<`$k1_s4;|?C-=7o7>G65S(mm;Dmf6Q8b)Zsxuc~veNW4E{kIz3SlfR)^1 zdD#%rZAHjbh>ilA6?`{tA=iSh(#C!K+j_$lNcUZE=0vFM(ye1|l} zSUU#kV?v!v=Xvoym!T0wX4!0ETbKL1DCs2v`!mcN$|!h{OY&b)rS(}zu&T!9Cu2j- zv9aR#ZJ<+0dZMyWVaV1V-$DJv+feLH)mk?+4b_9RKMvgwJLM_H-8e|gXYKJ!_g3n3 zr09J!#X;15q_b9)Nn>53`U?-1GS7~FV=f>sUXC|2XNw^7YnlMoEslGlJ>=9g`EXwM z`}%2Yj^X>jzaxQCfwhV^CEvAOD5uNQk$W-A`-er(ZgeBk4p0mB(m;@^hs)zTzkUod2&{P z%MtZta3BenY~?JZJ_}hEGzAFj){5NTqR*RPj7;I#^3!KdwI*1*VQZs{m9%#o9mWWM z4nr~mbOvj~;wylAN5C37=AW|>^bZ~{_ zwFu1k_wIox)T7OmCooeOK{#uK(DU5o>N4?kt)Gcf1_uspIcT?bSHk`#4^kpe6Z>GN zJb1x(udbc-Uf&%1c<#Nk&_^Y+N4a`~?Dn7jMZc1Isboo4hS|E&^Ec{?`u3^BFr~^E zxHzQ)po@$1tqq3?PvNntgL3v~>o7DZ80fUwvk6&VkG5Y=7@Y)}@XlGqwH#!w6lxpf zG1yIkr)uVya&jLcSx)RaiBH-ZlM<7f;dlYRPu#?kPApOzi}el3pJoIw@G6Iyz*w@x zp7!XA@C{gD_r;k6mPF-&l_d?%=Y~HSMK?|%^;6u#mZ`WWO6(egxA1^&MH(<rPYNQMg>MkR5vy zFF^9tyc(y8s(uOU)L3+Xulxs*J_$RDr1c6EWaaVjqG?O& z@3mwwl*9#r_!+5b-WcHx9t0+ots4I9dv4`)8UXEA%a9$V!$p zT+Ic1jegxV^{TwzxiKi02{6;;CR0yrkR3uQSZB$9k}CwNV+Gd?RppM=(D_nt0Rgl! z_3mIh>#Qv!GCD@o+RdlL&LX!8uECTZK<~$pgDFlaoGCq#Wv6UVo5ZuhqIUar)~2aSaF%T^1s51NfiqmbV!P$2yD>bh&;o{@e?2f)d);5> zT7%(nkQO6bVrJ*jIKq~uVSEhN%Rv*X0-lC-jnJ6rB~Dym>$gG z)qu@qEH}O^byaYA-WsY^~lkk?1$T!^Tbz63k>819xBa=fJ8pvZz5#Wap4*d>1- z2|Rs{0oI+9u}{$p3Xf++D*N*)UZ_?<^{LIKmb0+IFVpcob53XSd3dtj zBp+w=6X7n_cCPb`5fkaU);cpiqXP&e>;vCNo1IHxTJ9d%rqQQWzZx103k!lZVdDcQ zw79pnJD%UZjBgykly_B?N-V2C{di7~Rc%-u+il!XDJE=9%35>@MaOxV1rCht41L>$ zUd35aj6gFXCyowc>l{VrW5N%N83Pe_*gxjYu+f9l%cezZ@mnjz;aG-8J`bkqEQ8M= ze8LA)Fy4f_h?pOl+Py}j8L-&L%8n8Gewo@tl zRueLuC~w2nh&CP;bRt+=-+q~xUHc9g-+PHDKb*_9pB($g0lTpDcKH(I0-d}Ehe-Ad zi>*2?XQ0q!wOW!i;f=UGixWcfEIe}VtWVh5(01j={D`&pq6ove#97$xzxBrZT4wD) zez(%tZ)zvdX;ZxhTC$a+4S z$={So%eM1aU@*n}am2JZN8ezXq>MsS1F?{0FefNd%vV>PV)yfDkeKomO%|`4C004gP zB6lw|HjenyU27zozQNa~JsYCIWTP8x;*I3AjV>|+`f|~OXGhZ#tXkE)Cx-St_!Fke z2#b(Rti)~tF|rhAcQtKDdv}gW_9MON>%OL``gp9_88)yUS5&N8UYlA5zeT9wmyDBs)5{G`y}GS!d1@c^w!`NXe?b+sQ&B^G48SLzMY_sUudswfQT7Ewd!H&Jn39iTn(M?wHKGv+Jg zRgtgRyqdbp;(gI1jg75=W}N$Y;~;3R(?c7>P2VR&c}^-Cu8y(PhhFgk+yxe7PwO{{ z$M;u|Rni?K1aB9%oF58wVJ6^WH%Iv0cEC>7~G<&mt8@B>dwEC(cWL(Ux=8tbbvMg zc#{}_gxdAm30P&ZVvmmmhMyBZI@X6LYX?F4{j6~*xLzuSAmz8f+6U?kb~;>qt*)?g zy^d;Jv-qQj&f8U>ce}#};-EmaX2GByD|ALy(6PMWw6G z9wN!LLvOu>1Do_&>wKP7&|~<}SG|Okab7J*tvfPJ5d4OQG;)8_Z2Z z@uRMkgA|^-3BRDb$8 z8<}$zp^=P*mO711jy_%dE-Mn3gkEQ@-+xAe02=N`nSy0THZ!0F#0G;OQyFxG6Gb>a zr~5F{js?fJx*sBGrJtPD?(Nzym9ItlTSxdHk_VbKuV8=bn}{+PvtwVjBD zML=26RPns`vA^J);~o}y15dslSd1%dCM8|u5Xu!;{=9ClA@>_P)j(DIn=l-po?H@( zq0CyT)zDf|1&)hOl{_r6AU;jjfq@blc=G+-U;uxTt_c8&nLvglp`z|^v_o0*1(Nu@ z^~PBW`+e^T3zpF18B|K$7G=Flqk(TqIB!XK`g-~*zczOXdpaxF*#JfU^~ojL0kx9% zB3m)ck<*P611AEqk#WA~CCIuK%>e?p5$3A~j_v(9ACDv09z#JZJe4~FtfMCH}x ziN7m&`<~lwv7FaCZqdmkgL2*H_Oz}PVsyc-964q@gb875vR}J+cOZxQM}!3RrZcPn zW|I11cYsMBY7wA8irw=N2{8sm?iJ z*E2<5YHoT5DFNgCZdLr4M8ZF*^j7xm`5(b|52ZIIYej}STfve`1NO{W#7%F2{9*=! zV0QL&UX4@%T#^H>{58XRmXW(6o4~jX{@tF3VC|fld6*I3!7B}2mR7$2kP0Kh-<^hy zsu7T#CEdAPRs6Nur&5-P1*MfEQ}GTXNWINXpERG;+8|Asn&j@iEA-A!J)YUoga<|S zi)wGp1h%e6oP&c2brFo%z4->Fup9yWJ?yrggWwunI$Aaqg&yqGN>;-Q)2W^(=pO9s<0uuzH)5uH7*fJ5;qF+1ZcD6zg*Ey1 z#T&P8)W=-~rIm00eM!QRgZ{8hxMiTx(H4x)gNFpl<5&sjxB}|rY!B(ZBEP7fd@u8K z!fO}+{w~LV(!m+-*FES5S8$KdfUAK7@!bxjh$vs^e|?{1=Ho96tce zaWoH?3-#ff!vCu#3>Py2F3GsZcGG(~cDMO!D~|0+zqY+)8?jjeJLqFSq%T~sVF*@$NpzzuR?Uu-z`S4nLI3j%!ngASzNuW=hdphlz6ZCyTL z2u_WY?YfEQJ?>0qFm;s_;X*9o-+ZSE^|jv!?HiqUmma3sHZF@l1Jme*@q5{45OM&Z`y=G07Z zA~WgVo8;|}#YW}3&eK^ZAR}uQ=Uz=BE{Kjnfp&@R6U@lb^ACH2M`lCA@IxOcLq7kJ3};-Aoux=;rg?fGK}jA`l_ zoIQklzDlm^V1NOku{LSaJOBtOD~vzBqRcx*b|u!{<^CFXajhNQuKJ8nCmSw`LoY{h zZE=Zat2lw!o4E^!^SZQik5iMthoki#kGSfka#2!x@~&@Je6`On2VWSos??~^+P5f6 z*FG53l?{g4CjzwpZYm<=V(&(+@;r?^VfCFDXk>Y;qld!Q%Etv7$X$2(TQ@P zT(Xe%y*+Z`pGt>BIN;R6P=ae#uMCN=k5)wuDd<_!v^FN+xhH`8BtVyRr4NzlXIf?9 z2BP6uZ|kcpj*2=l#mF7O6^`8M1Z07Tva+qtmwEp^F%`x;c~Zzys3Y1oK&=T@ZqkT6 zTckGkY_<RFghI=B*}jsa)CJ zR9zo;a?b;ZE*XWN@oMT406dP0tz;8&OVT{2PlpY@Q)AA&z%6Yz_nX!x>0BV9pSa2U-2%{$UN~E0p-jWnLpv!8ekL8`ddD$#?hPSlzxY zEnw!3qO4W^$R%i_xGFl{7#c^oQ`4&`pO2!l$qAIMtj&%lFM6d1+9S_=EfYx66avR@ zi8a;ke*5-@6rV<8E@p)Pg3_GRQkDQ&o|#0>=8OMOp4B9EkTKMqD0MvI z$WA?sX_sw2+sHXv0XYB^<>Uke75)Rr|I6iN{eQW#{69?Z|LyWJ zu`zJ6{Vyy2|I6i7$(e4W9Sr6k{LkZccZa@Xfs5_t261<9KY$Aa7~Cc07$og@p5S}W z>z&7ZzsKg)I$P4LUaR_iWaVs3qUvp+oWP&}Y;rC$H#0Z_oS3W*u!+6N(7X^8U@HSa z10y42<8X3P6fa0@CY_L*nZTR?K5%IRpvdCr=jH;^$jIn8oB&J`;4V1sUP3Xr0Zahr z!mjk(0L}zd5%UKmO-N?$ZA@J5#1Vhje53AhrF1>mach^iV;5>?cd zM8!JnZJ>(o?VWJ^=YXiHs+?W|905sP5eXcSe+iIuRb}PRw;JGf|2=yN0A+Rm$?v%b z``0lYT@6`nNg2t^{HqBZfO!Dr;?ne;{MO&0*uxC`EqlAWI)iBPr49s;8rs~<3r}2} zosAvb8J)}wJh7NFxOYbHXN8s~2f&_C%zE&%jc5VUpl59HGVPH1KU z+~x%M=a2~eDQ)$oKkZ)X-hJB}-G@5-A}^omp8=2)Jn%1RU~vANQkR#IfH$xWf%{dL+PC*&rVCO0ql69EC5rLhh0-{k(@WR~vgGkF?`oe$Zd@KZcB+cmU}9=i-{#u>mZ5Cr52(Mg`f}?rU-n{!r#;oO5)*Z-wuX>Mg^{Zw{UM)MYT<(39RD`?&L+w6-v_)pIS&H<1CEC2$yus0ff zCtuaeeGr@d68q5y#;5a6;2D^i9REl2vHQ|cX z_P_t-mm#+^wt;ut59yL$^EjJ5?6;qV#&2gcz>7@I%|Ge)y=byEHvw{T0Pt~rssnG> z-{^bq!@mYlhNy}uiK@z_U-j;9QxZFKAg0z9X7GjvXMh+S+*qE2j6Lsw&|KVu(eJ&f zGJ*I0ERcZ-18^rlcfgHqjxT^2fj9?$wxnR(0g7+&7y1!M1C$?ZM?j3xU$Gqku}6Pm zIWvIbll=(L0g6|4BTxpZzgP}{7$^VY_y0^@F&!BIvC{sbAakMi&A-Ol_1?ssPX z0rw?;l|Oo;(*6PNPip-)ZEpPl_bIpjVmI+Cw|#$`6vEazxlQO?u!fOFWmM%>*xT;3H-Nx={K@_H^^{}t zTdXy6@A!N9Yj^kr|F6%ey`ONJ+kd|Q!2hj#DL?qP-Z|#-9`Ij2_5*#*)eS@wn3YCW z-~R6(Ln6DATZ_xOp%;Hh#{TJj{ohaNJ3i#ZA0PkUAuSP*(|eJ*x4p6#8r|KynTP%2 zJCoz*cX<6|KV5M@+`zl!kN)>L82~`wod9yjDQE(ueS@l%vqfjU$Ds-+3Mc!pBx>4! z%o5Lu)0hhR9(iMrEmDDjqCmAjnJA)!T$K1cJLf>1NHPz`@|kNdZKc=KmWrmu_=Nf% zI=rNg2g^Hiu-AVrl9T*J*&$yGW$XggD7R(IynVO{1$&j#08xziSTo3adrxD`XFtL+R9~k~uo(Q;e>!>9DLtKw^*_lHUp-r> z)%mmrmBadgGb9SQ1LSWP(4;8$SpT zkdz!hy{%H@_AzfePF3&aoZt5$pq;~`)LS-=G4Kb^3&;a&;?Nh-#zd&}i&uG+{M4Ei zKN=Ao_b00TcXLNtY6@)G>~N1uSCXb>EcztC++^GeyW5qauh-Bb0aw#GcBesjg);H7 zmH(UL&EDP?pehu9MOdQk;Xj3mOl>-3uVX)j${6F2I5`YQgD%K(`eXA zw&~Cx&B>P9LW2-5#~*c+Y}*5)T>dzYR8o z_u-jQTG^jH?Cpi$xO1wAn=6^H2$ck_Cq_^Ewu^%q+y)Xor`0+vJP|~zPRL+hV#1r(i%}?`Q(x*1IgOB|twzW<8K65;xJi&5t2kyZ%gF5np0e+N`1L<))W8 zCIr?m<#|V!0?x524?`kd9(A1<2`m@FSm%C9HK-4Ji8^kL`sszd2x30y<|}K>{|Y8I zr&BUiCJO62152zi40)JMkVVWk+ptriLD#6aVKc5zLylgkn->ZKh#_UU&^QUaqF`!J zJOcR`r^bOn#mCr-1*ZZ3XP8B%pE1Wskg9h$}cF@uH&aX7M?V zqV%1d4VSQ?e)|lik&=8`*82($s!o5OMwGh2Rqs(_I#Cq8XI3s;HSNL93yJT&lkTdR zC@Jxt8O_^(KElj$liS`pM7Xb?xz*W~7MR5!Y9OBB5xGn>UOERyHc{6=kPa%GD_G91 zXdgn-xZ|1()3~$YHy+=-Uk4@SBYdkxtl_|{M~?dVc;wi0PT_vm(&Pk-9_n;#aIbEw zp(>a$fgI9!^-C`f#P`!;Kfb&K|112?s`I_{=VRG)Fz83S z=@+OZDBT`_hRR!gc+V6fW&^#cjxZ_1Ou##b4Y!o9q+i{Ik|l1_8}<)2OJRxTuO$e; zS|H-NwN+I7b*l#)n#a1>Bt9!M6k&mwjiq6-gE(hAmt-y6>e8Src*S=;)*(ONu~%9d zN7@BU=6L9fnnR#>cY3^P#S91vF(AvQj2w~2{iyirGz?^-03GWGq*k0BdU_m7D!W;f zdGUM{+h?TA@)P*dguITFyRvqJfU`V`A3(b^UQ8_QLnmDQ^y~vyaRb|8l0WcOBI_A1 zCl=4&?YWSp2ZzhmFhen`)#fc*8j|l-SZmig4v3qVCP-2atny2MZb}$jM~TAtD~dl( z%vN7RLsbN0&IX68W*$oWt$kWuD)Lm)KjC_a)O!w`~&0&+WdQ$r-Wg7ovLR6k3oH+#$ItQ+_fY*QjgP7*r*mJ)QPa-T5r0~IeQ z>@Z1V%84T*lVG}}RE}QMP(^Z6d6;!(NRj7)04}2}!@SaCA9`iYX!*4mwoZvypO>~5 z8;nI%^GRGjUmW@e>#5O#${+W4z>?B6lYu9*ibzOQnpt$4ysNFjk`r3U;c%5bJ)JJQ zBpzqEoM!hF?!7|P3^{R+yk!T)t&(Vhl}1}GGapY;;s8Aij=%X}_x8eCUtxs1j0OM+ z8N+ZON0qxrX^~v~mXFn8dN+5Y+xa^CMaGQVRmkl3b0OZ{p49g2Hhd?SXLNaZ45>oDuKXG0uxrF%Cirb;h*+0Wf)TzMMo2Lr+)CF>0?r zXM=6_#>g|~InYfAwqpHL9J-}qF2@&+*>z@|`vC@$*_rei3V*OuuXp-_d4tp;Zv^PR zSJt$%UsqX0!A+l0Y*>oSDoNvd*2AJ{!MR?WW=&dO(7?cGq7Oqrx)V*VCXGm)%J2BRsspJucpwX#euGZqDK& z+?w%{A);AK-+dzoHA~U9UqA^*D26}a4|lmcI+BG@W-W3F#BR1%HksAMs@rn9bUPa6 zQu~ZWzr-rKfHI;5xS>pFVKq>i0it^1bx+z=QK1#5QE8q>Eci1|D5&yxa8|g{u(z8_45P|e{SUi5iN=B^zEpici!EuuVx$YMw+wnQlWgIEz%7ErVkC7HV!dOZ!fsoD7Ymhb%8 zByE6JMPy-oun%*j96bd#SjeOhW*y7lNTN5d=Hw7dGnD(y$nb*&H~}0gsn-J=ITU|M z@eI%)niMbh4B>UTPMtv-{m$sagNOK5TS2hDmu=KJTtDU?#jz8puqO=qUAP-3sF^wV zk~9a0xJ`5TDbo6mw+Ere(CRr=GNcR@;5ag4{nZEEtk$YekEr(@&KbGhFM`53ZKWJ5 zBGGyq>{q$E^2+oPdSyH>q3TOm{0zu&=A%LHsOGto;aio4hZb53d%85(OR4xoKf&3K z9Xvuj8+|I!!I$&YzU~peg)=y z&=-#3ordb`O|$7J2AxjS*#dQKEA93MK-uEV-BIT)c<`Jp>yJ!OM>#xG$&NhbJA;0? znSgn}(!g~$OF6064jy>qS?lUi*pVn*@Trzx!iu%ZNqs8$V6<~QPf_i#@KYAI$#&T({M3*}A0Za>x3ZwsxQ#m?@RlKe96S@cw>;8p zP)fcXnL!5!D;`%#kGFfvjFDPt7y4bZ$pP4XPxcvfSf6#9&_DLYOO8_1*>=#-v@Xqh zAGy>s!{$LBJA8kd3kD|C=}PJShEMsnNRY9i05zQF-U)jzXfCI4SnQ@63e50?Nj!ilgPW@ZF-CY{w^kAJ5sjYe3+D9W~ zK!`hO;sf2iZB}>Alu~1mHMCJ%_JrMLB|Z!j;=o$tFwcy$1^&A zm#s+85BuIwMR@*ctJVZpz~fr|dH8-opINwH$z?K9&(Y!KgCk+|RUE!}7n4Rk*jPQG zagep)k3_>N9R`jUQ?_f*tAY@bH^ifZ@uC8o8WfOH-Ymw{x+w0|J+={4Ro5mrV(Tn) zNv3UpWJP@Lj1y!7@*R0iHRjjTq#dFAw z>WHmvKJcBQTA?`kODz3wWLDuDl%;Fq1>=isAu*`&6u$SwR&LO)fz(V<@=<0S5<+s_bp8eO|7+;5A!(cfDQ#CCoW>Gv! zvLm!4_(VEkGvY`R8qx+ED>1L0UO?UNErTE!fxNiM#?u=*d7h+yp`MVl)XOU#6txWw z`_Neni1fK+?j9cN4Iy)XnPJ-jk-t$aobjJ_O=sX%NbT`N;mrq7o%wSMSQ>IjsE33l zDCzU?z&zZ&D3ooRI?LOn(&I2l;F!Q9`C@&zEHgc?RdFYyq{QY{yJIoV^>l^uQs%9^S?CSp$WOaM7mltAe%EKnlUZ_sm{MV$B~eFo zg>kYb-`|{+ioe>Xz8q{v)RKH-y8&(PM(#Rk7$elur(?2_8=W*?6SW3N@|*BH#40^!4gPDNTyqgGmQ?b#vYc@Qb$3E`u{s%yv3}3A3WFsokfuOh$e0#6*yR z%iohAW(S1E@j78ukDF?8cIsdZFgtX&U;Gkt2n9UxV>neN+NRX6!x~W(DG90alf)7; z=J_;6zG^|rms2dwjnHGGE zQ~1OZ+AEr?C8^Wbh6Y#6`l1mB8gm-qMCa0AlX*%erB${qSu_lCP{8W?wC(;`1mc0) zt-8rnY?jjthc_WgFz8;N54O|!zaLHyQXNL$SE#zFaH?CX2`D>?tQ1W$8)vj?yX_AK zT!mU^^o~>Gn)1C(r~--C!d~N&&Wrt%-4GE0Kh18gOS_{0hHW&s++orULP$Z^@6hrO z8Q{9RJ6vU0(F$-e&_zTU5%dz(Bdhe(pBg6ieJ#ig)1TioUUvta!s^Le`I^!+s(Ao8 zVv0f*NVRa-JoycbMiWz^ zR0qb>2OM$5M_(^eFJ>{vH?X9Ld%p3rCJ{Fs+ovTZj(WXPzt(1q-x5(qxJJ)FEC`4T zM~COp6>jhgmDoRS`|)XA66-Wru)}QtJ^oEFcG0$z`^F4LNV`N5yX_u}jDcm!erO=E z{}4Qme@haeO)tJa0UyJ+P#B1bqhc}NAjV39vKQW(-6Hz6(M?e57dLGcAeAiOUH^XD z3Wk@xUfiVp4_w3;e=Ns{mHw|t{4oEGeUrUhEC8_gIplD{B`~xH@q_aim(CgdJNtu#b=r7_T^!NM4hkVn3hg*Lgv< zC;|cCDAZm=sC`slSrqewYFAghOja*o19#??twN}Sf_JX5D9wt+W0Q`mS64b) zOHe@ zgy>TJ7RDcbGqOM$*-6xpyLJYpFro{QGWq_EE!TS&@#8fgi#71R5CwvJ=5CPfOQYp4 zOkVf4;)^6MCp+{v6=)ba#l&ckH}XixvzCB+VaI{ zbPgHoY5g_8sqX-se&)zPP*|0jm)XUbJXu9`*5$Yc#{8x9J`gCH-k_*RkzGWZzBjGC zvN^6W%JvU?;_b+wCJNgu3A{Uh?qLFvBlVo%=3uaxWo~96*r{P5_|vnwJRpnvLXZhn zK-K7nHk6HRo#eC`i`q6cIaxc(jFzb~7^<^zzw@CfawE?VGw0$h7E?j+^Vl2|PqEYY zyWr9P069R$zmcTETl$-Yn%QbfEf>m9a--O)Szm42@NOTa4&|kKPnhyMZbE+-u)W+@ zAFI>)`l3{5_|DF2fis_dP613b+*>Ap515nBxT!KEQb!Dz2LLrl*jp#6UfftG)+*A` z(4P4)i=-HA7+X)Zpid?rM}9h-!Fzj|FAY`{7C`oHk5>2T4q0fqu?|7G&N%lvcHVqZ zJZ|u~D8O^Mk`8Ovv;kdNRIUkKDJp~H+uM+b0aAJS=86cgD6uo$E%+Xu6vmx;)ww1|@Ba1b0G%lBdp_7nt;<1|F8rzhS-21oLU9Z$i%u$NW z71K{2!3I#m72p=n#Da5$h)1LqZof~Mc8FxDG2RykBfZ4P>@A+=RF}b`al7e7^iBtX ztic)udar)#yEVK)jHGjA>HVTMkZMun3@mu7f~$8DQ$s#r*H@fuzXb1=RFvuB^wwC) zuq0rdgOsz-VE%l+t~$!2}s-`eVS8-k#Rt|S=2Kr;maULkU1Qa1ki>knG1@Gkt4;WGvQ^9Z|)?-uH` z;AU0pqiE4zg#)YWx;_*|HvsPW>*1fb)sY)L7PGMOU`SkS0xa&bh+ z-$9xV+q@Nb!p0Ro!Qhl6BZxDutQC+TCn;`fMGLFrX(Dr+^Vv@nQ7W@KU+4l!_@4;)SGtaJ9kpR=Xq> z*|gX;dW2cL8Zn={=c_a9wWp53dt=RI0zw@r9^c$(O8KAn&1V(*fQ_*0G#e9u}46MKNk`VoS#b@sWT~22jg0*%B+=&bogLYz&h7EU#-z+g_>@lPe~CE$uv2a>_>! zkC(D|VRSUUo5p6vS5oRe$)oN#fPNryP5U&fOeC{jcNjP2Jxif?atHbO$72GApDGs9 zr{BZG5Z5#=FjaPntBs-b^~vUR-S<82aMKgh>|`>|Bo=yMtqPOm%I-5W{VjJPzJBU1 zCM>|voqm}q{r#!c*y8Sz4fhn|zKMM#HZ)7h^1V#2gg18tVH!hQ)*h!cBRr(tSaoVC zPn?*qw&b5RpHvCNBtUo7vui1c+-Fdqc0N8Ea zxjuV>%rI|9^qZvO@yvpe1IX3UXeIJklMa%R#9GY~Wix0FnJ{#L7ZCDAg+kpUrD)`i>K1vVju}jPIEs~KLIG{QTt@ufn7WSf^X)Dh{hW?yF zEa7RVObsAdb=SgvXZ_bcwo?e??J48?Qo&#ABD##mJ~umf4&|6nW;~E!1fs=|m4mM0 z)|Nkqk%qSv=JO$lg1bbb`-TY&pj^>OX04L*_+iM_k_A2;46*B(HPGMjS{IG~yfpgm z=lNWIIsa`6hVRoCfsX)oQOi>R{|^OErx9IzH_}wr1(iLf%gEikirw;Qw+v_Bc7r5+ zsOger^d7gR`qxf-ti8!CG>}Nr&%NsSEw?N|$f|rD)geFc1gGlx%br_sM+PbUpGY1~?U-bMeGTtBnuGyI}9NqqUndWA=+qk;NjP2xKXNBq?X zzg*}eVp9a5jW{8AnV_&sx^5n&Yy;Bh{IEVg$Sec~*V|R}LCuu!%j?J$!61W>yXtgB z*pu_K=DnH*mR1A`k~7Yp?3!sm%5l*P$qyfIo;$1}+>XF=TAryjq_yd_eSdX-Po9`S z+8w^PxeO|__Cob;ku=TC9~D1fu@{2v>1_;PeD>n4^u--WZEE$&dzu5zsG)e`K9~>R z?^&t7l2V?>K|Rf_@{`KA0!le>FFpB$Svf{*{lk+u+)`7@KQ(d-?Q42;D_rnq9CtS~ z;g+UaIEYVV3qQ~|x%74jupJke?W_IuS7>#k%|uLcn~ZUU`wk% zzk`n*-%eAEgfS_fCE0pOwwSy704!Ve67XjMb&UALt0$BbdT=V;Z5;OF7i_tsJP8aAlbMcwio)1azsMZ z*Qd^$35sy#8D*wCsHtEA3Tm7jUrDUEw_kW_crmFhjxGx~CgjGYlhC{L5ftD1K=^=O zaWa(#G|%4KAAfNMOT!S$^m1=Gn|f*E*;`C2MZ~<0Vl?vJto9UwfsHipIvZb@ z-A(+SmS9a0QZ5~|?NsXy#rhyB79%H4S$nlbk9VBH9aY46=+~Y|NhA|SeLlK)Pzuw( zX6i(kA_u2TVX9@;8qjv90I`Xj2F^Ryx@m74S-0kf!J}qzs3*a&jQp5$btNHcuRK@r{f&+qEL91!_^K$HGp~iPe`%2+_gH zK|a*MfqM)(5wTZrTZc4EyD6 zjZcs-{jZFeNk03u>#EsvWJ%L zBci@b^NNTP(Cm=YT6LO=3A9Yz_J#A~d^Q^4!D~PA8kJ=uNJ_%~p3K)_UJ=g17s}%MsDcv>gi$RaVn98TQK?-rxkzE}V&y5XFCM2JB6Z^&hkrv5D zPJZg_XlF?Sjz@xYsKPDF{5)Fht-V6xNAt1`L&{nJxLjL+h*GUskCBloi|m@nrR?pqAE3BzJ8MtAOElYd#mhe;!+`NZU<7@8)i7 z-e}FUlPgx7TSSEW$EV+`kpl>A!a{pd5|sIrbB2hGQnR#|hq6q(x8*sxkMxbGd}x(f zMj#jw*ZyF5{M#r#Bx$2vK>=rW@h`}GA~D}Zdx)jLWT5(fp>HOVgt}|mV#Zw$=}v-G z_NF|G=g$qam}>H*JNtibO)2nu@RJ48IU7e<&BJF(V`W^Luz};|sp}ezQ8_CngNE>> z4IPRV2pWzV#BVircD;<3cjh0j4)4BixI>X0DcM&!i<@Z(mmZqeQa`@Vu8Q6e@mcCT zebK|b;Wf#T>QPvJmMHOGx0;>mxH&hK;h|xhO+WZmBT#OJ#5$*$RfacmG74nws6J5v z%_BA0>lnm_jx>#Mc?jv<0;iM($sgl{Fe^USIO=Pk1tLH8d=3?e;C*vvXRq(armq?P z8rUk#CPM>Fq$iX!7E?R+r8d-Oe?)yizJ8&8gz*);c@Golnw0aySm9Rx>=pcZ^AeJ# z&rwCT*A;(qeV3G|_#t;T5IYZU3fNi&gKv27&0kOIz+P=4;j~&nL5UaUg#S`SBrg|f z^7>HQbn9z$ct`}HjpvAdh*zsIpb7^I)3R%G!PcWTZic&qs#Z~{9*LH$mYm-d^P77229CL>@ z16~%kkPCk85Pb~3Gb`^xAsTq{r!pC4F1Ev+VMl7o2?s4|Qx*04{lQB87;NRtjbfyV zGie0ZaYHM(dLQzUPjZG~5}yqbTmmMU>|{M`eY;APYOQ6TBSPei#V%=ByJ^}|27ZCf z73ZS5E5xP_SKowtlQRSN}3(?fOmwn8kbtCRJcR8o)UcP}sMX6+P z?TYFjFykJ~9yLi0>hMj6IH?)t*UuLCbe-qu#sXcev?(b9;R4ERoE1V4-L4*_;7kFiP?929CyTIXO3Nznyf>WibnkE?rxZrUmX3 z+;^CE<+&|*R{9;9zMUNIr_~2?%olh2d4uspFT>Qx&G`x0BEt3@etFo@VOy-9Rj&MT z?JziJ&OP0=cgbV6oPHnk{p$O!br{n6e0#4Cp!V@!SVv*=97;+PcuaQcyOW5j4REOb zud~kv9Xq77NrbIHY6D9!8^f={AGma5_hhe?HwWzkQBE?#-R-lwrv6ZO=`P~9y4!WDvFo7S)H zUgvUA;oEpa7PNykmgnZ@hLtqF<{DFrt50&MA1uw&F|IYrqGpREbl{>3w#a$>qH8;w zTWl`VuDXRQdQwLKLuWCAj<+?~&)2r3m|`nnEL5WbtAbmZr`*}fx5onl+~)J9-?l^t zR32EnDB5YIbJvNIkdKJ_sYRQi2$-tZi?w~r5`rHB&m$JbdvTd7?THzmnWpdQ)VmZF z%+^DJ+-rFq<$AqcU8``}oHceF!J>;!|%@2eIeZ@~euYg((r zLeX5OT@SJX=}%=Rn;X~Zaa_<>a91uQfwA-J0^b3HIL$l>>SEoJR!Lk;^GYq3~w}(6-Zq+JlWVADZ5_dMz;}~P6c%@ zQpym9IpLQyG z#;kr-=E?3a+VO9OKOo(Lwq$xfaGO~h@aMp`_u6}vG> znA|+dW?eINh7Z|?vLbN27(RYL+^L<8V$$%&K0GX3s-f6# z7{PW+6ArebZ?wyTgir;LA?$@_NZf?qO7{Y5l@5@ZwdDwKCL}GSMBzLkgQuO7qfHZf zhIPJqfR`S8YFq%QD2bsv+lCm7Ba4{3?t2g+Y|E5G zK;F)=o#CFjWLqStoZ}NSxc>e&!@ld1d~6v?%r_yp#Ue?+=JR1kH~(t(j23cDt{d$+ zeI@CMLaJ31>_{N$TSf6RuY;i7j1`h6&}SQP!sn4J`@AKMUQcTw_4;T8;{m_lFnFUG zr}%$7t-n^~g0tdg7m);DJV2?6k&UMfG0@~n?LR4Bq zVX47N+Uq^y4-?NF$(cvvr!#z5H%NAPQ(11yd9$PGvqNfw zPp%H4k#0EMsue_O0$$s_PGXhm!w{Xg&Ly6y`@SK@MwXgw!Uqc6Qaq^3U(~h!W8lS{ z=xpOXgirRK-wnKT`p=6|)9Orlm(#8Wx{5lmG&6s@6>wq2&Qj)B^|ruejMq7~H+Eu3 zi#E)@LLcf{TMS8LkA9Pg*e&-jvSC6ny^Rt!rzE$Sn;sHYXXoQU2t|WGC@H8NUQmY# zesQm0Dkv0b3H~;m35dI3{Cg1#| z{FPu79Y1gO&fK{F>N;L%MlbETV#D7%Bx|9@Rm&7Gt>HYPJ{-a7ch->v4REy>b6 zMl0nLr3*6RIvVc*M<>*FzKh?Rm@%YwfNJ)O#9CC@M$Y;`A&y<94XCI^C^qEg2Xy9D zhH)ex3Ro21U@eRmsVIX`EdvI_NB*-*wvaeJFb)C%$2y8r>@h6QI}8U9yES(-Bpi}T zK|x9_=!#kJ*HAGL+V|~`m1v)jj}bHVD)D_%zys1Y7Nw$-joeGJ>|B{!N#4Z#O_jR9 z3;m(@PvP(ch)$D>1TKdA5}>-^R8+B&`0TLCWs>$J*RH;@Is69QX)W-0f5iPc&g8(& zohZ|b&9Jy3^r7;r3n{$qOFdII+%70gRS+_bY0At)D_+tix_LS!_yy zCcz3|OMnbS@Ac`7>&xWtSD*XAv_3GFo<@h1^T%#?ew}T%Qu>2%B;GEby^30w>5huYet9EPX(dPV>^tj z5jXT6_d=~M6xxc{uOV`HQnegVH2jX

3+6zcos>=Jc+~x@{+qmodAyYb5QDIF{Vu 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 literal 0 HcmV?d00001 diff --git a/services/loogle-mcp/docs/pdf/ONBOARDING.pdf b/services/loogle-mcp/docs/pdf/ONBOARDING.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5dcde04d195d931aa97bbbfbef84e6d110e4c18f GIT binary patch literal 126179 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 z/dev/null; then + echo "OK — loogle-mcp attivo su :8700" + exit 0 + fi + sleep 2 +done +echo "Health check fallito — vedi docker logs loogle-mcp" >&2 +exit 1 diff --git a/services/loogle-mcp/scripts/docker-entrypoint.sh b/services/loogle-mcp/scripts/docker-entrypoint.sh new file mode 100644 index 0000000..d282c5e --- /dev/null +++ b/services/loogle-mcp/scripts/docker-entrypoint.sh @@ -0,0 +1,13 @@ +#!/bin/sh +set -e +mkdir -p /data /data/context + +# Chiave SSH per thermal gate (permessi OpenSSH) +if [ -f /run/secrets/ds920_ssh_key ]; then + mkdir -p /root/.ssh + cp /run/secrets/ds920_ssh_key /root/.ssh/ds920_key + chmod 600 /root/.ssh/ds920_key + export DS920_SSH_KEY=/root/.ssh/ds920_key +fi + +exec "$@" diff --git a/services/loogle-mcp/scripts/ds920_thermal_probe.py b/services/loogle-mcp/scripts/ds920_thermal_probe.py new file mode 100644 index 0000000..2cf1346 --- /dev/null +++ b/services/loogle-mcp/scripts/ds920_thermal_probe.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""Probe temperatura/load CPU DS920 — HTTP GET /thermal su :9191. + +Avvio (sul DS920, utente daniely): + nohup python3 ds920_thermal_probe.py >> /tmp/thermal-probe.log 2>&1 & + +O via Task Scheduler Synology all'avvio. +""" + +from __future__ import annotations + +import json +import os +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer + + +PORT = int(os.environ.get("THERMAL_PROBE_PORT", "9191")) +HWMON = os.environ.get("THERMAL_HWMON", "/sys/class/hwmon/hwmon0") + + +def read_metrics() -> dict: + temps = [] + try: + for name in sorted(os.listdir(HWMON)): + if name.startswith("temp") and name.endswith("_input"): + with open(os.path.join(HWMON, name), encoding="utf-8") as f: + temps.append(int(f.read().strip()) / 1000.0) + except OSError: + pass + load1, load5, load15 = os.getloadavg() + nproc = os.cpu_count() or 4 + return { + "ok": True, + "host": os.uname().nodename, + "cpu_temp_c": max(temps) if temps else None, + "temps_c": temps, + "load1": load1, + "load5": load5, + "load15": load15, + "nproc": nproc, + "cpu_target_load": round(nproc * 0.75, 2), + } + + +class Handler(BaseHTTPRequestHandler): + def log_message(self, fmt: str, *args) -> None: # noqa: A003 + return + + def do_GET(self) -> None: # noqa: N802 + if self.path.split("?")[0] not in ("/", "/thermal", "/health"): + self.send_response(404) + self.end_headers() + return + body = json.dumps(read_metrics()).encode() + self.send_response(200) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", str(len(body))) + self.end_headers() + self.wfile.write(body) + + +def main() -> None: + server = ThreadingHTTPServer(("0.0.0.0", PORT), Handler) + print(f"thermal probe listening on 0.0.0.0:{PORT}", flush=True) + server.serve_forever() + + +if __name__ == "__main__": + main() diff --git a/services/loogle-mcp/scripts/grant_family_paperless.py b/services/loogle-mcp/scripts/grant_family_paperless.py new file mode 100644 index 0000000..51b4f3b --- /dev/null +++ b/services/loogle-mcp/scripts/grant_family_paperless.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +"""Grant view permissions on non-personal Paperless documents to family users.""" + +import os +import sys + +import httpx + +PAPERLESS_URL = os.environ.get("PAPERLESS_URL", "https://docs.loogle.it").rstrip("/") +ADMIN_TOKEN = os.environ.get("PAPERLESS_API_TOKEN_DANIELE") or os.environ.get("PAPERLESS_API_TOKEN", "") +FAMILY_USER_IDS = [4, 5, 6] # lucia, davide, luca +PERSONAL_TAG_NAMES = {"personal", "privato", "private"} +BATCH_SIZE = 50 + + +def main() -> int: + if not ADMIN_TOKEN: + print("Missing PAPERLESS_API_TOKEN_DANIELE", file=sys.stderr) + return 1 + headers = {"Authorization": f"Token {ADMIN_TOKEN}", "Content-Type": "application/json"} + + tags_resp = httpx.get(f"{PAPERLESS_URL}/api/tags/", headers=headers, timeout=60) + tags_resp.raise_for_status() + personal_tag_ids = { + t["id"] + for t in tags_resp.json().get("results", []) + if (t.get("name") or "").lower() in PERSONAL_TAG_NAMES + } + + doc_ids: list[int] = [] + page = 1 + while True: + resp = httpx.get( + f"{PAPERLESS_URL}/api/documents/", + headers=headers, + params={"page": page, "page_size": 100}, + timeout=60, + ) + resp.raise_for_status() + data = resp.json() + for doc in data.get("results", []): + if set(doc.get("tags") or []) & personal_tag_ids: + continue + doc_ids.append(doc["id"]) + if not data.get("next"): + break + page += 1 + + print(f"Documenti da condividere (senza tag personali): {len(doc_ids)}") + + updated = 0 + for i in range(0, len(doc_ids), BATCH_SIZE): + chunk = doc_ids[i : i + BATCH_SIZE] + payload = { + "documents": chunk, + "method": "set_permissions", + "parameters": { + "set_permissions": { + "view": {"users": FAMILY_USER_IDS, "groups": []}, + "change": {"users": [], "groups": []}, + }, + "merge": True, + }, + } + resp = httpx.post( + f"{PAPERLESS_URL}/api/documents/bulk_edit/", + headers=headers, + json=payload, + timeout=120, + ) + resp.raise_for_status() + updated += len(chunk) + print(f" Aggiornati {updated}/{len(doc_ids)}") + + for name, env_key in [ + ("lucia", "PAPERLESS_API_TOKEN_LUCIA"), + ("davide", "PAPERLESS_API_TOKEN_DAVIDE"), + ("luca", "PAPERLESS_API_TOKEN_LUCA"), + ]: + token = os.environ.get(env_key, "") + if not token: + continue + count = httpx.get( + f"{PAPERLESS_URL}/api/documents/?page_size=1", + headers={"Authorization": f"Token {token}"}, + timeout=30, + ).json().get("count", 0) + print(f"{name}: documenti visibili = {count}") + + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/services/loogle-mcp/scripts/run_gitea_index_once.py b/services/loogle-mcp/scripts/run_gitea_index_once.py new file mode 100644 index 0000000..0ec1f17 --- /dev/null +++ b/services/loogle-mcp/scripts/run_gitea_index_once.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""Indicizzazione Gitea one-shot — eseguire con indexer fermo per evitare OOM.""" + +from __future__ import annotations + +import argparse +import json +import os +import sys + +ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +if ROOT not in sys.path: + sys.path.insert(0, ROOT) + + +def _load_dotenv() -> None: + env_path = os.path.join(ROOT, ".env") + if not os.path.isfile(env_path): + return + with open(env_path, encoding="utf-8") as fh: + for line in fh: + line = line.strip() + if not line or line.startswith("#") or "=" not in line: + continue + key, _, value = line.partition("=") + if key.strip() and key.strip() not in os.environ: + os.environ[key.strip()] = value.strip().strip("'").strip('"') + + +def main() -> int: + parser = argparse.ArgumentParser(description="Indicizza repo Gitea nel vector store") + parser.add_argument("--repo", help="owner/name (default: tutti i repo configurati)") + parser.add_argument("--user", default="daniele", help="Utente MCP/Gitea token") + parser.add_argument("--max-files", type=int, default=0, help="Limite file per repo (0=config)") + parser.add_argument("--force", action="store_true", help="Re-indicizza anche file invariati") + args = parser.parse_args() + + _load_dotenv() + if os.path.isfile("/.dockerenv"): + os.environ.setdefault("MCP_DB", "/data/loogle_mcp.db") + os.environ.setdefault("MCP_VECTOR_FALLBACK", "/data/vector_fallback.db") + + from app.db import init_db + from app.knowledge import gitea_indexer + + init_db() + max_files = args.max_files or None + + if args.repo: + result = gitea_indexer.index_repo( + args.repo, + username=args.user, + force=args.force, + max_files=max_files, + ) + print(json.dumps(result, ensure_ascii=False, indent=2)) + else: + result = gitea_indexer.index_all(max_files_per_repo=max_files) + print(json.dumps(result, ensure_ascii=False, indent=2)) + + stats = gitea_indexer.index_stats() + print("stats", json.dumps(stats, ensure_ascii=False)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/services/loogle-mcp/scripts/seed_demo_projects.py b/services/loogle-mcp/scripts/seed_demo_projects.py new file mode 100644 index 0000000..9f05ce1 --- /dev/null +++ b/services/loogle-mcp/scripts/seed_demo_projects.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +"""Crea un progetto demo per ogni utente famiglia.""" +import sys +sys.path.insert(0, "/srv") +from app.context import store as context_store + +USERS = { + "daniele": "Homelab LOOGLE", + "lucia": "Progetti personali", + "davide": "Studio e task", + "luca": "Progetti Luca", +} + +for username, title in USERS.items(): + root = context_store._user_root(username) + existing = context_store.list_projects(username) + if existing: + print(f"{username}: skip ({len(existing)} progetti)") + continue + meta = context_store.create_project(username, title, tags=["demo"]) + context_store.save_context( + username, + meta["id"], + f"Progetto demo iniziale per {username}. Usa save_context per ampliare la memoria agente.", + ) + print(f"{username}: creato {meta['id']}") diff --git a/services/loogle-mcp/scripts/setup_gitea_p4_repos.py b/services/loogle-mcp/scripts/setup_gitea_p4_repos.py new file mode 100644 index 0000000..7a101fd --- /dev/null +++ b/services/loogle-mcp/scripts/setup_gitea_p4_repos.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""Crea repo progetti per davide/luca e progetti Loogle collegati.""" + +from __future__ import annotations + +import os +import sys + +ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +if ROOT not in sys.path: + sys.path.insert(0, ROOT) + + +def _load_dotenv() -> None: + path = os.path.join(ROOT, ".env") + if not os.path.isfile(path): + return + with open(path, encoding="utf-8") as fh: + for line in fh: + line = line.strip() + if not line or line.startswith("#") or "=" not in line: + continue + k, _, v = line.partition("=") + os.environ[k.strip()] = v.strip().strip("'").strip('"') + + +def ensure_repo(user: str, repo_name: str, description: str) -> str: + from app.knowledge import gitea + + gitea._tokens_cache = None + full = f"{user}/{repo_name}" + existing = {r["full_name"] for r in gitea.list_repos(username=user)["repos"]} + if full in existing: + print(f"repo_exists: {full}") + return full + created = gitea.create_repo( + repo_name, + username=user, + private=True, + description=description, + auto_init=True, + ) + print(f"repo_created: {created['full_name']}") + return created["full_name"] + + +def ensure_mcp_project(user: str, project_title: str, gitea_repo: str) -> None: + from app.context import store as context_store + + projects = {p["id"]: p for p in context_store.list_projects(user, include_archived=True)} + for meta in projects.values(): + if meta.get("gitea_repo") == gitea_repo: + print(f"project_linked: {user}/{meta['id']} -> {gitea_repo}") + return + slug = project_title.lower().replace(" ", "-") + if slug in projects: + meta = context_store.link_project_repo(user, slug, gitea_repo=gitea_repo, seed_from_gitea=True) + print(f"project_updated: {user}/{meta['id']} -> {gitea_repo}") + return + meta = context_store.create_project( + user, + project_title, + tags=["gitea", "p4"], + gitea_repo=gitea_repo, + seed_from_gitea=True, + ) + print(f"project_created: {user}/{meta['id']} -> {gitea_repo}") + + +def main() -> int: + _load_dotenv() + os.environ.setdefault("MCP_DB", os.environ.get("MCP_DB", "/data/loogle_mcp.db")) + from app.db import init_db + + init_db() + + ensure_repo( + "davide", + "progetti", + "Workspace personale — codice e note generate con Loogle MCP", + ) + ensure_repo( + "luca", + "progetti", + "Workspace personale — codice e note generate con Loogle MCP", + ) + + ensure_mcp_project("davide", "Progetti Davide", "davide/progetti") + ensure_mcp_project("luca", "Progetti Luca", "luca/progetti") + + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/services/loogle-mcp/scripts/test_gitea_integration.py b/services/loogle-mcp/scripts/test_gitea_integration.py new file mode 100755 index 0000000..9f14d79 --- /dev/null +++ b/services/loogle-mcp/scripts/test_gitea_integration.py @@ -0,0 +1,258 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""Test integrazione Gitea MCP — mock server + opzionale live API.""" + +from __future__ import annotations + +import json +import os +import sys +import threading +from http.server import BaseHTTPRequestHandler, HTTPServer +from urllib.parse import parse_qs, urlparse + +ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +if ROOT not in sys.path: + sys.path.insert(0, ROOT) + +MOCK_TOKEN = "test-gitea-token" +MOCK_PORT = 18799 + +os.environ["GITEA_URL"] = "https://git.loogle.it" +os.environ["GITEA_API_URL"] = f"http://127.0.0.1:{MOCK_PORT}" +os.environ["GITEA_API_TOKEN_DANIELE"] = MOCK_TOKEN +os.environ["MCP_DB"] = "/tmp/loogle_mcp_test.db" + + +class GiteaMockHandler(BaseHTTPRequestHandler): + def log_message(self, fmt, *args): + return + + def _auth_ok(self) -> bool: + auth = self.headers.get("Authorization", "") + return auth == f"token {MOCK_TOKEN}" + + def _json(self, code: int, payload): + body = json.dumps(payload).encode() + self.send_response(code) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", str(len(body))) + self.end_headers() + self.wfile.write(body) + + def do_GET(self): + if not self._auth_ok(): + self._json(401, {"message": "invalid token"}) + return + path = urlparse(self.path).path + qs = parse_qs(urlparse(self.path).query) + + if path == "/api/v1/user/repos": + self._json(200, [ + { + "full_name": "daniele/rete", + "description": "Infra HA", + "private": True, + "html_url": "https://git.loogle.it/daniele/rete", + "default_branch": "main", + "updated_at": "2026-08-22T10:00:00Z", + } + ]) + return + + if path == "/api/v1/repos/daniele/rete/contents/ha/RUNBOOK-failover.md": + content = "# Failover tier-b\n\nloogle-mcp nel pivot tier-b.\n" + import base64 + + self._json( + 200, + { + "type": "file", + "path": "ha/RUNBOOK-failover.md", + "content": base64.b64encode(content.encode()).decode(), + "encoding": "base64", + "size": len(content), + "sha": "abc123", + "html_url": "https://git.loogle.it/daniele/rete/src/branch/main/ha/RUNBOOK-failover.md", + }, + ) + return + + if path == "/api/v1/search/code": + q = (qs.get("q") or [""])[0] + self._json( + 200, + { + "data": [ + { + "repository": {"full_name": "daniele/rete"}, + "path": "ha/RUNBOOK-failover.md", + "sha": "abc123", + "content": f"...{q}...", + } + ] + }, + ) + return + + if path == "/api/v1/repos/daniele/rete/issues": + self._json( + 200, + [ + { + "number": 1, + "title": "Test issue", + "state": "open", + "user": {"login": "daniele"}, + "html_url": "https://git.loogle.it/daniele/rete/issues/1", + "created_at": "2026-08-22T10:00:00Z", + "updated_at": "2026-08-22T10:00:00Z", + "labels": [], + } + ], + ) + return + + if path == "/api/v1/repos/daniele/rete/issues/1": + self._json( + 200, + { + "number": 1, + "title": "Test issue", + "state": "open", + "body": "Corpo issue di test", + "user": {"login": "daniele"}, + "html_url": "https://git.loogle.it/daniele/rete/issues/1", + "created_at": "2026-08-22T10:00:00Z", + "updated_at": "2026-08-22T10:00:00Z", + "labels": [], + }, + ) + return + + self._json(404, {"message": f"not found: {path}"}) + + def do_POST(self): + if not self._auth_ok(): + self._json(401, {"message": "invalid token"}) + return + path = urlparse(self.path).path + length = int(self.headers.get("Content-Length", 0)) + body = json.loads(self.rfile.read(length).decode() or "{}") + if path == "/api/v1/repos/daniele/rete/issues": + self._json( + 201, + { + "number": 42, + "title": body.get("title"), + "state": "open", + "html_url": "https://git.loogle.it/daniele/rete/issues/42", + }, + ) + return + self._json(404, {"message": f"not found: {path}"}) + + +def run_mock_tests() -> None: + from app.db import init_db + from app.knowledge import gitea as gitea_mod + from app.mcp import tools + + init_db() + gitea_mod._tokens_cache = None + + server = HTTPServer(("127.0.0.1", MOCK_PORT), GiteaMockHandler) + thread = threading.Thread(target=server.serve_forever, daemon=True) + thread.start() + + claims = {"sub": "daniele", "scope": "gitea:read gitea:write"} + + repos = tools.call_tool("list_repos", {}, claims) + assert "daniele/rete" in repos["content"][0]["text"] + + file_data = tools.call_tool( + "get_file", + {"repo": "daniele/rete", "path": "ha/RUNBOOK-failover.md"}, + claims, + ) + assert "tier-b" in file_data["content"][0]["text"] + + search = tools.call_tool( + "search_code", + {"query": "tier-b", "repo": "daniele/rete"}, + claims, + ) + assert "RUNBOOK-failover" in search["content"][0]["text"] + + issues = tools.call_tool("list_issues", {"repo": "daniele/rete"}, claims) + assert "Test issue" in issues["content"][0]["text"] + + issue = tools.call_tool( + "get_issue", + {"repo": "daniele/rete", "number": 1}, + claims, + ) + assert "Corpo issue" in issue["content"][0]["text"] + + created = tools.call_tool( + "create_issue", + {"repo": "daniele/rete", "title": "Da MCP", "body": "Test"}, + claims, + ) + assert "42" in created["content"][0]["text"] + + server.shutdown() + print("OK mock: list_repos, get_file, search_code, list_issues, get_issue, create_issue") + + +def _load_dotenv() -> None: + env_path = os.path.join(ROOT, ".env") + if not os.path.isfile(env_path): + return + with open(env_path, encoding="utf-8") as fh: + for line in fh: + line = line.strip() + if not line or line.startswith("#") or "=" not in line: + continue + key, _, value = line.partition("=") + key = key.strip() + value = value.strip().strip("'").strip('"') + if key.startswith("GITEA_"): + os.environ[key] = value + + +def run_live_tests() -> None: + _load_dotenv() + from app.knowledge import gitea as gitea_mod + from app.mcp import tools + + token = os.environ.get("GITEA_API_TOKEN_DANIELE", "").strip() + if not token or token == MOCK_TOKEN: + print("SKIP live: GITEA_API_TOKEN_DANIELE non impostato (token reale in .env)") + return + + api_url = gitea_mod.api_base_url() + if str(MOCK_PORT) in api_url: + print("SKIP live: GITEA_API_URL punta al mock") + return + + gitea_mod._tokens_cache = None + claims = {"sub": "daniele", "scope": "gitea:read gitea:write"} + + repos = gitea_mod.list_repos(username="daniele") + if not repos.get("repos"): + raise RuntimeError("live list_repos: nessun repository") + + first = repos["repos"][0]["full_name"] + tools.call_tool("list_repos", {}, claims) + print(f"OK live list_repos: {len(repos['repos'])} repo, primo={first}") + + +def main() -> int: + run_mock_tests() + run_live_tests() + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/services/loogle-mcp/scripts/test_gitea_p4.py b/services/loogle-mcp/scripts/test_gitea_p4.py new file mode 100644 index 0000000..ef15521 --- /dev/null +++ b/services/loogle-mcp/scripts/test_gitea_p4.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""Test P4: scrittura Gitea (create repo, create/update file).""" + +from __future__ import annotations + +import json +import os +import sys + +ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +if ROOT not in sys.path: + sys.path.insert(0, ROOT) + + +def _load_dotenv() -> None: + path = os.path.join(ROOT, ".env") + if not os.path.isfile(path): + return + with open(path, encoding="utf-8") as fh: + for line in fh: + line = line.strip() + if not line or line.startswith("#") or "=" not in line: + continue + k, _, v = line.partition("=") + os.environ[k.strip()] = v.strip().strip("'").strip('"') + + +def main() -> int: + _load_dotenv() + os.environ.setdefault("MCP_DB", "/data/loogle_mcp.db") + + from app.db import init_db + from app.knowledge import gitea + from app.mcp import tools + + init_db() + gitea._tokens_cache = None + + if not os.environ.get("GITEA_API_TOKEN_DANIELE"): + print("ERR: token daniele assente") + return 1 + + claims = {"sub": "daniele", "scope": "gitea:read gitea:write knowledge:read admin"} + + test_repo = "daniele/mcp-p4-test" + test_path = "docs/p4-verify.md" + test_content = "# P4 verify\n\nFile creato da test_gitea_p4.py\n" + + # cleanup file if exists from prior run + try: + gitea.get_file(test_repo, test_path, username="daniele") + gitea.create_or_update_file( + test_repo, + test_path, + test_content + "\n(updated)\n", + "test p4 update", + username="daniele", + ) + action = "update" + except FileNotFoundError: + # ensure repo exists - use temp repo name under daniele + repos = {r["full_name"] for r in gitea.list_repos(username="daniele")["repos"]} + if test_repo not in repos: + created = tools.call_tool( + "create_gitea_repo", + { + "name": "mcp-p4-test", + "private": True, + "description": "Repo temporaneo test P4", + }, + claims, + ) + print("create_repo", created["content"][0]["text"][:200]) + written = tools.call_tool( + "create_or_update_file", + { + "repo": test_repo, + "path": test_path, + "content": test_content, + "message": "test p4 create", + "reindex": False, + }, + claims, + ) + payload = json.loads(written["content"][0]["text"]) + action = payload.get("action") + print("write", action, payload.get("path")) + + read = gitea.get_file(test_repo, test_path, username="daniele") + assert "P4 verify" in read.get("content", ""), read + print("read_ok", read["path"]) + + for user, repo in (("davide", "davide/progetti"), ("luca", "luca/progetti")): + token_key = f"GITEA_API_TOKEN_{user.upper()}" + if not os.environ.get(token_key): + print(f"SKIP {user}: no token") + continue + gitea._tokens_cache = None + listed = gitea.list_repos(username=user) + names = {r["full_name"] for r in listed["repos"]} + if repo not in names: + raise RuntimeError(f"repo mancante per {user}: {repo}") + print(f"{user}_repo_ok", repo) + + print("OK P4: create_or_update_file + repos davide/luca/progetti") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/services/loogle-mcp/scripts/test_gitea_rag_p3.py b/services/loogle-mcp/scripts/test_gitea_rag_p3.py new file mode 100755 index 0000000..2de5713 --- /dev/null +++ b/services/loogle-mcp/scripts/test_gitea_rag_p3.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""Test P3: RAG semantico su file Gitea indicizzati.""" + +from __future__ import annotations + +import json +import os +import sys + +ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +if ROOT not in sys.path: + sys.path.insert(0, ROOT) + + +def _load_dotenv() -> None: + env_path = os.path.join(ROOT, ".env") + if not os.path.isfile(env_path): + return + with open(env_path, encoding="utf-8") as fh: + for line in fh: + line = line.strip() + if not line or line.startswith("#") or "=" not in line: + continue + key, _, value = line.partition("=") + key = key.strip() + if key and key not in os.environ: + os.environ[key] = value.strip().strip("'").strip('"') + + +def _configure_paths() -> str: + in_container = os.path.isfile("/.dockerenv") or ( + os.path.isdir("/data") and os.access("/data", os.W_OK) + ) + if in_container: + os.environ.setdefault("MCP_DB", "/data/loogle_mcp.db") + os.environ.setdefault("MCP_VECTOR_FALLBACK", "/data/vector_fallback.db") + return "container" + os.environ["MCP_DB"] = "/tmp/loogle_mcp_p3_test.db" + os.environ["MCP_VECTOR_FALLBACK"] = "/tmp/loogle_mcp_p3_vectors.db" + return "host" + + +def main() -> int: + _load_dotenv() + mode = _configure_paths() + print(f"mode={mode} db={os.environ['MCP_DB']} vector={os.environ['MCP_VECTOR_FALLBACK']}") + + from app.db import get_conn, init_db + from app.knowledge import gitea_indexer + from app.mcp import tools + + init_db() + if not get_conn().execute( + "SELECT 1 FROM sqlite_master WHERE name='indexed_gitea_files'" + ).fetchone(): + raise RuntimeError("tabella indexed_gitea_files assente") + + if not os.environ.get("GITEA_API_TOKEN_DANIELE", "").strip(): + print("SKIP: GITEA_API_TOKEN_DANIELE assente") + return 1 + + repo = "daniele/rete" + existing = gitea_indexer.list_indexed_files(limit=5, repo=repo) + stats = gitea_indexer.index_stats() + if len(existing) < 1 or stats.get("qdrant_points", 0) < 1: + index_result = gitea_indexer.index_repo( + repo, + username="daniele", + force=True, + max_files=1, + ) + print("index", json.dumps(index_result, ensure_ascii=False)) + else: + print("index_skip", "already", len(existing), "files") + + files = gitea_indexer.list_indexed_files(limit=5, repo=repo) + if not files: + raise RuntimeError("indexed_gitea_files vuota") + print("indexed_sample", [f["path"] for f in files[:3]]) + + claims = {"sub": "daniele", "scope": "knowledge:read gitea:read admin", "admin": "admin"} + for query in ("failover tier-b", "runbook"): + hits = gitea_indexer.search_gitea_knowledge("daniele", query, limit=5, is_admin=True) + if not hits: + raise RuntimeError(f"search_gitea_knowledge senza risultati per: {query}") + top = hits[0] + print( + f"search_ok[{query}]", + top.get("path") or top.get("title"), + round(float(top.get("score", 0)), 3), + ) + + tool_out = tools.call_tool( + "search_gitea_knowledge", + {"query": "failover", "limit": 5}, + claims, + ) + if not json.loads(tool_out["content"][0]["text"]).get("results"): + raise RuntimeError("tool search_gitea_knowledge vuoto") + + unified = tools.call_tool( + "search_knowledge", + {"query": "FAILOVER CENSIMENTO documenti servizi", "limit": 12}, + claims, + ) + unified_payload = json.loads(unified["content"][0]["text"]) + results = unified_payload.get("results") or [] + sources = set() + for r in results: + if r.get("repo"): + sources.add("gitea") + elif r.get("source"): + sources.add(r["source"]) + else: + sources.add("paperless") + print("search_knowledge_sources", sorted(sources)) + if "gitea" not in sources: + raise RuntimeError("search_knowledge non include risultati Gitea") + + list_tool = tools.call_tool("list_gitea_indexed_files", {"repo": repo, "limit": 5}, claims) + if json.loads(list_tool["content"][0]["text"]).get("count", 0) <= 0: + raise RuntimeError("list_gitea_indexed_files vuoto") + + print("OK P3: search + unified + list (reindex opzionale via tool reindex_gitea_repo)") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/services/loogle-mcp/scripts/test_p5_home.py b/services/loogle-mcp/scripts/test_p5_home.py new file mode 100644 index 0000000..d49bcfa --- /dev/null +++ b/services/loogle-mcp/scripts/test_p5_home.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""Verifica P5: tool live Loogle Casa + Home Assistant.""" + +import json +import os +import sys + +sys.path.insert(0, "/srv" if os.path.isdir("/srv/app") else os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + + +def main() -> int: + from app.integrations import casa, homeassistant + from app.mcp import tools + + user = os.environ.get("MCP_TEST_USER", "daniele") + claims = { + "sub": user, + "scope": "home:read context:read knowledge:read gitea:read admin", + } + errors = [] + + print("=== P5 integrations ===") + print("casa configured:", casa.is_configured(user)) + print("ha configured:", homeassistant.is_configured()) + + if casa.is_configured(user): + for tool, args in ( + ("get_home_dashboard", {}), + ("get_home_weather", {}), + ("get_network_overview", {}), + ("get_network_failover_status", {}), + ): + try: + out = tools.call_tool(tool, args, claims) + text = out["content"][0]["text"] + data = json.loads(text) + print(f"OK {tool}: keys={list(data.keys())[:8]}") + except Exception as exc: + print(f"FAIL {tool}: {exc}") + errors.append(tool) + else: + errors.append("casa-not-configured") + + if homeassistant.is_configured(): + try: + cfg = homeassistant.get_config() + print(f"OK ha config: version={cfg.get('version')}") + except Exception as exc: + print(f"FAIL ha config: {exc}") + errors.append("ha-config") + try: + out = tools.call_tool("list_ha_entities", {"domain": "switch", "limit": 5}, claims) + data = json.loads(out["content"][0]["text"]) + print(f"OK list_ha_entities: count={len(data.get('entities', []))}") + except Exception as exc: + print(f"FAIL list_ha_entities: {exc}") + errors.append("list_ha_entities") + else: + errors.append("ha-not-configured") + + if errors: + print("P5 FAILED:", errors) + return 1 + print("P5 OK") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/services/loogle-mcp/scripts/test_p6_apps.py b/services/loogle-mcp/scripts/test_p6_apps.py new file mode 100644 index 0000000..85f4733 --- /dev/null +++ b/services/loogle-mcp/scripts/test_p6_apps.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""Verifica P6: tool live Irrigazione + Turni.""" + +import json +import os +import sys + +sys.path.insert(0, "/srv" if os.path.isdir("/srv/app") else os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + + +def main() -> int: + from app.integrations import irrigazione, turni + from app.mcp import tools + + user = os.environ.get("MCP_TEST_USER", "daniele") + claims = { + "sub": user, + "scope": "irrigation:read turni:read home:read admin", + } + errors = [] + + print("=== P6 integrations ===") + print("irrigazione configured:", irrigazione.is_configured(user)) + print("turni configured:", turni.is_configured(user)) + + if irrigazione.is_configured(user): + for tool, args in ( + ("get_irrigation_status", {}), + ("get_irrigation_zones", {}), + ("get_irrigation_history", {"limit": 5}), + ): + try: + out = tools.call_tool(tool, args, claims) + data = json.loads(out["content"][0]["text"]) + print(f"OK {tool}: type={type(data).__name__}") + except Exception as exc: + print(f"FAIL {tool}: {exc}") + errors.append(tool) + else: + errors.append("irrigazione-not-configured") + + try: + out = tools.call_tool("get_turni_status", {}, claims) + data = json.loads(out["content"][0]["text"]) + print(f"OK get_turni_status: build={data.get('buildVersion', '')[:30]}") + except Exception as exc: + print(f"FAIL get_turni_status: {exc}") + errors.append("get_turni_status") + + if turni.is_configured(user): + for tool, args in ( + ("list_turni_doctors", {}), + ("get_my_shifts", {"limit": 10}), + ): + try: + out = tools.call_tool(tool, args, claims) + data = json.loads(out["content"][0]["text"]) + print(f"OK {tool}: keys={list(data.keys())[:6]}") + except Exception as exc: + print(f"FAIL {tool}: {exc}") + errors.append(tool) + else: + errors.append("turni-not-configured") + + if errors: + print("P6 FAILED:", errors) + return 1 + print("P6 OK") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/services/loogle-mcp/scripts/test_p7_apps_rag.py b/services/loogle-mcp/scripts/test_p7_apps_rag.py new file mode 100644 index 0000000..2f11486 --- /dev/null +++ b/services/loogle-mcp/scripts/test_p7_apps_rag.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""Verifica P7: RAG Irrigazione + Turni.""" + +import json +import os +import sys + +sys.path.insert(0, "/srv" if os.path.isdir("/srv/app") else os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + + +def main() -> int: + from app.db import init_db + from app.knowledge import apps_indexer, indexer + from app.mcp import tools + + init_db() + user = os.environ.get("MCP_TEST_USER", "daniele") + claims = { + "sub": user, + "scope": "knowledge:read irrigation:read turni:read admin", + } + errors = [] + + print("=== P7 apps RAG ===") + existing = apps_indexer.list_indexed_records(limit=5) + if len(existing) >= 2: + print(f"skip re-index: {len(existing)} records already present") + result = {"irrigazione": {"indexed": len(existing), "skipped_reindex": True}, "turni": {}} + else: + result = { + "irrigazione": apps_indexer.index_irrigazione(history_limit=0, events_limit=0), + "turni": apps_indexer.index_turni(assignments_limit=3), + } + print("index_all:", json.dumps(result, ensure_ascii=False)[:500]) + + irr = result.get("irrigazione", {}) + turn = result.get("turni", {}) + if irr.get("skipped") and turn.get("skipped"): + print("P7 FAILED: both sources skipped") + return 1 + if irr.get("indexed", 0) + turn.get("indexed", 0) < 2 and not irr.get("skipped_reindex"): + errors.append("insufficient-indexed-records") + + records = apps_indexer.list_indexed_records(limit=10) + print(f"indexed records: {len(records)}") + if not records: + errors.append("no-records") + + try: + hits = apps_indexer.search_apps_knowledge("irrigazione zona prato", limit=3) + print(f"search_apps_knowledge irrigazione: {len(hits)} hits") + if not hits: + errors.append("search-irrigazione-empty") + except Exception as exc: + print(f"FAIL search_apps: {exc}") + errors.append("search_apps") + + try: + out = tools.call_tool("search_apps_knowledge", {"query": "turno guardia", "limit": 3}, claims) + data = json.loads(out["content"][0]["text"]) + print(f"OK tool search_apps_knowledge: {len(data.get('results', []))} hits") + except Exception as exc: + print(f"FAIL tool search_apps_knowledge: {exc}") + errors.append("tool-search") + + try: + combined = indexer.search_knowledge(user, "irrigazione valvola", limit=5, is_admin=True) + apps_hits = [h for h in combined if h.get("source") in ("irrigazione", "turni")] + print(f"search_knowledge includes apps: {len(apps_hits)} app hits / {len(combined)} total") + except Exception as exc: + print(f"FAIL search_knowledge: {exc}") + errors.append("search_knowledge") + + if errors: + print("P7 FAILED:", errors) + return 1 + print("P7 OK") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/services/loogle-mcp/scripts/test_p7_step.py b/services/loogle-mcp/scripts/test_p7_step.py new file mode 100644 index 0000000..162a272 --- /dev/null +++ b/services/loogle-mcp/scripts/test_p7_step.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +from app.db import init_db +from app.knowledge.apps_indexer import ( + _summarize_irrigation_status, + _index_text, + list_indexed_records, + search_apps_knowledge, +) +from app.integrations import irrigazione + +init_db() +print("1 db ok") +existing = list_indexed_records(source="irrigazione", limit=1) +if existing and existing[0].get("record_id") == "status-snapshot": + print("2 skip index (status-snapshot exists)") +else: + s = irrigazione.get_status("daniele") + print("3 status ok", len(s)) + text = _summarize_irrigation_status(s) + print("4 summary", len(text)) + r = _index_text("irrigazione", "status-snapshot", "Stato", text) + print("5 indexed", r) +hits = search_apps_knowledge("irrigazione zona", limit=2) +print("6 hits", len(hits)) +print("STEP OK") diff --git a/services/loogle-mcp/scripts/test_project_gitea_p2.py b/services/loogle-mcp/scripts/test_project_gitea_p2.py new file mode 100755 index 0000000..3d69415 --- /dev/null +++ b/services/loogle-mcp/scripts/test_project_gitea_p2.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""Test P2: collegamento progetti MCP ↔ repository Gitea.""" + +from __future__ import annotations + +import json +import os +import shutil +import sys +import tempfile + +ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +if ROOT not in sys.path: + sys.path.insert(0, ROOT) + +os.environ["MCP_DB"] = "/tmp/loogle_mcp_p2_test.db" +TEST_ROOT = tempfile.mkdtemp(prefix="mcp-p2-") + + +def _load_dotenv() -> None: + env_path = os.path.join(ROOT, ".env") + if not os.path.isfile(env_path): + return + with open(env_path, encoding="utf-8") as fh: + for line in fh: + line = line.strip() + if not line or line.startswith("#") or "=" not in line: + continue + key, _, value = line.partition("=") + os.environ.setdefault(key.strip(), value.strip().strip("'").strip('"')) + + +def run_unit_tests() -> None: + os.environ["MCP_CONTEXT_ROOT"] = TEST_ROOT + from app.db import init_db + from app.context import store as context_store + from app.mcp import tools + + init_db() + claims = { + "sub": "daniele", + "scope": "context:read context:write gitea:read gitea:write", + } + + meta = context_store.create_project( + "daniele", + "Progetto unit test", + tags=["test"], + ) + meta_path = os.path.join(TEST_ROOT, "daniele", "projects", meta["id"], "meta.json") + meta["gitea_repo"] = "daniele/rete" + with open(meta_path, "w", encoding="utf-8") as f: + json.dump(meta, f, ensure_ascii=False, indent=2) + + ctx = tools.call_tool( + "get_project_context", + {"project_id": meta["id"], "include_gitea": False}, + claims, + ) + payload = json.loads(ctx["content"][0]["text"]) + assert payload["meta"]["gitea_repo"] == "daniele/rete" + + unlinked = tools.call_tool( + "link_project_repo", + {"project_id": meta["id"], "gitea_repo": ""}, + claims, + ) + payload = json.loads(unlinked["content"][0]["text"]) + assert "gitea_repo" not in payload + + print("OK unit: meta gitea_repo + scollegamento locale") + + +def run_live_tests() -> None: + _load_dotenv() + token = os.environ.get("GITEA_API_TOKEN_DANIELE", "").strip() + if not token: + print("SKIP live: GITEA_API_TOKEN_DANIELE assente") + return + + live_root = os.path.join(TEST_ROOT, "live") + os.makedirs(live_root, exist_ok=True) + os.environ["MCP_CONTEXT_ROOT"] = live_root + + from app.context import store as context_store + from app.mcp import tools + from app.knowledge import gitea + + gitea._tokens_cache = None + claims = { + "sub": "daniele", + "scope": "context:read context:write gitea:read gitea:write", + } + + project_id = "rete-ha-p2-test" + proj_dir = os.path.join(live_root, "daniele", "projects", project_id) + if os.path.isdir(proj_dir): + shutil.rmtree(proj_dir) + + created = tools.call_tool( + "create_project", + { + "title": "Rete HA P2 test", + "tags": ["infra", "test"], + "gitea_repo": "daniele/rete", + "seed_from_gitea": True, + }, + claims, + ) + payload = json.loads(created["content"][0]["text"]) + project_id = payload["id"] + assert payload.get("gitea_repo") == "daniele/rete" + assert payload.get("gitea_seeded_at") + + ctx_path = os.path.join(live_root, "daniele", "projects", project_id, "context.md") + context_md = open(ctx_path, encoding="utf-8").read() + assert "seed:gitea daniele/rete" in context_md + assert len(context_md) > 200 + + enriched = tools.call_tool( + "get_project_context", + {"project_id": project_id, "include_gitea": True, "session_limit": 0}, + claims, + ) + data = json.loads(enriched["content"][0]["text"]) + assert data["meta"]["gitea_repo"] == "daniele/rete" + assert data["gitea"]["available"] is True + assert data["gitea"]["readme"] is not None + assert isinstance(data["gitea"].get("docs_files"), list) + + link_existing = tools.call_tool( + "link_project_repo", + {"project_id": project_id, "gitea_repo": "daniele/rete", "seed_from_gitea": True}, + claims, + ) + meta2 = json.loads(link_existing["content"][0]["text"]) + assert "gitea_seeded_at" in meta2 + + shutil.rmtree(proj_dir) + print(f"OK live: create+seed+enrichment su daniele/rete (project {project_id})") + + +def main() -> int: + try: + run_unit_tests() + run_live_tests() + return 0 + finally: + shutil.rmtree(TEST_ROOT, ignore_errors=True) + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/services/loogle-mcp/scripts/verify_p3_container.py b/services/loogle-mcp/scripts/verify_p3_container.py new file mode 100644 index 0000000..b7b4846 --- /dev/null +++ b/services/loogle-mcp/scripts/verify_p3_container.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +import json, os, sys +os.environ.setdefault('MCP_DB','/data/loogle_mcp.db') +os.environ.setdefault('MCP_VECTOR_FALLBACK','/data/vector_fallback.db') +from app.db import init_db, get_conn +from app.knowledge import gitea_indexer +from app.mcp import tools +init_db() +assert get_conn().execute("SELECT 1 FROM sqlite_master WHERE name='indexed_gitea_files'").fetchone() +repo='daniele/rete' +for path in ['ha/FAILOVER-VOLUMES.md','ha/RUNBOOK-failover.md']: + r=gitea_indexer.index_file(repo, path, username='daniele', private=True, force=True) + print('indexed', path, r.get('chunks'), r.get('skipped'), flush=True) +files=gitea_indexer.list_indexed_files(limit=10, repo=repo) +print('db_files', [f['path'] for f in files], flush=True) +for q in ('failover tier-b','runbook'): + hits=gitea_indexer.search_gitea_knowledge('daniele', q, limit=3, is_admin=True) + print('search', q, hits[0]['path'] if hits else None, round(float(hits[0]['score']),3) if hits else None, flush=True) + if not hits: sys.exit(1) +claims={'sub':'daniele','scope':'knowledge:read gitea:read admin'} +for tool,args in [ + ('search_gitea_knowledge',{'query':'failover tier-b','limit':5}), + ('list_gitea_indexed_files',{'repo':repo,'limit':10}), + ('reindex_gitea_repo',{'repo':repo,'max_files':1}), + ('search_knowledge',{'query':'failover keepalived','limit':8}), +]: + out=tools.call_tool(tool,args,claims) + p=json.loads(out['content'][0]['text']) + if tool=='search_knowledge': + src=sorted({r.get('source') for r in p['results']}) + print(tool, src, flush=True) + assert 'gitea' in src + elif tool=='list_gitea_indexed_files': + print(tool, p['count'], flush=True) + else: + print(tool, 'ok', flush=True) +print('OK P3 COMPLETE', flush=True) diff --git a/services/loogle-mcp/scripts/verify_p3_search_only.py b/services/loogle-mcp/scripts/verify_p3_search_only.py new file mode 100644 index 0000000..a1a7f8a --- /dev/null +++ b/services/loogle-mcp/scripts/verify_p3_search_only.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +import json, os, sys +os.environ.setdefault('MCP_DB','/data/loogle_mcp.db') +os.environ.setdefault('MCP_VECTOR_FALLBACK','/data/vector_fallback.db') +from app.db import init_db, get_conn +from app.knowledge import gitea_indexer +from app.mcp import tools +init_db() +print('table_ok', bool(get_conn().execute("SELECT 1 FROM sqlite_master WHERE name='indexed_gitea_files'").fetchone()), flush=True) +files=gitea_indexer.list_indexed_files(limit=10, repo='daniele/rete') +print('indexed', [f['path'] for f in files], flush=True) +if not files: + print('WARN: nessun file indicizzato — indicizzo stacks.conf (piccolo)', flush=True) + r=gitea_indexer.index_file('daniele/rete','ha/stacks.conf', username='daniele', private=True, force=True) + print('new_index', r, flush=True) + files=gitea_indexer.list_indexed_files(limit=10, repo='daniele/rete') +for q in ('failover','censimento','tier-b'): + hits=gitea_indexer.search_gitea_knowledge('daniele', q, limit=3, is_admin=True) + print('search', q, hits[0]['path'] if hits else 'NONE', round(float(hits[0]['score']),3) if hits else None, flush=True) + if not hits and q=='failover': + sys.exit(1) +claims={'sub':'daniele','scope':'knowledge:read gitea:read admin'} +sg=tools.call_tool('search_gitea_knowledge',{'query':'failover tier-b','limit':5},claims) +assert json.loads(sg['content'][0]['text'])['results'] +print('tool search_gitea_knowledge ok', flush=True) +li=tools.call_tool('list_gitea_indexed_files',{'repo':'daniele/rete','limit':10},claims) +print('tool list', json.loads(li['content'][0]['text'])['count'], flush=True) +ri=tools.call_tool('reindex_gitea_repo',{'repo':'daniele/rete','max_files':1},claims) +print('tool reindex', json.loads(ri['content'][0]['text']).get('files_indexed'), flush=True) +sk=tools.call_tool('search_knowledge',{'query':'failover keepalived','limit':8},claims) +src=sorted({r.get('source') for r in json.loads(sk['content'][0]['text'])['results']}) +print('tool search_knowledge sources', src, flush=True) +assert 'gitea' in src +print('OK P3 SEARCH VERIFIED', flush=True) diff --git a/services/loogle-mcp/worker/indexer_main.py b/services/loogle-mcp/worker/indexer_main.py new file mode 100644 index 0000000..6dee2ce --- /dev/null +++ b/services/loogle-mcp/worker/indexer_main.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- +"""Background indexer worker — cicli separati Paperless / Gitea / Apps.""" + +import logging +import os +import time + +logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s %(message)s") +LOGGER = logging.getLogger("loogle_mcp.worker") + +from app.db import init_db # noqa: E402 +from app.knowledge import apps_indexer, gitea_indexer, indexer # noqa: E402 + + +def _run_gitea() -> None: + if os.environ.get("GITEA_INDEX_ENABLED", "yes").strip().lower() in ("0", "false", "no", "off"): + LOGGER.info("Indicizzazione Gitea disabilitata (GITEA_INDEX_ENABLED)") + return + gitea_result = gitea_indexer.index_all() + stats = gitea_indexer.index_stats() + LOGGER.info("Indicizzazione Gitea completata: %s stats=%s", gitea_result, stats) + + +def _run_paperless() -> None: + result = indexer.index_all(max_pages=10) + LOGGER.info("Indicizzazione Paperless completata: %s", result) + + +def _run_apps() -> None: + apps_result = apps_indexer.index_all() + LOGGER.info("Indicizzazione Apps (P7) completata: %s", apps_result) + + +def main() -> None: + init_db() + interval = int(os.environ.get("INDEXER_INTERVAL_MINUTES", "30")) * 60 + LOGGER.info("Indexer avviato, intervallo %ds", interval) + + from app.knowledge import thermal # noqa: WPS433 + + status = thermal.read_status() + if status: + LOGGER.info( + "Thermal probe OK: temp=%.1f°C load1=%.2f nproc=%s source=%s (hard=%.0f°C soft=%.0f°C cpu_target=%.0f%%)", + float(status.get("cpu_temp_c") or 0), + float(status.get("load1") or 0), + status.get("nproc"), + status.get("source"), + thermal.hard_temp_c(), + thermal.soft_temp_c(), + thermal.cpu_target_pct(), + ) + else: + LOGGER.warning("Thermal probe non raggiungibile all'avvio — gate userà delay conservativi") + + # Gitea per primo: repo piccoli, non bloccato da Paperless lento + try: + thermal.wait_for_headroom(context="cycle:gitea-boot") + _run_gitea() + except Exception as exc: + LOGGER.error("Indicizzazione Gitea fallita: %s", exc) + + while True: + try: + thermal.wait_for_headroom(context="cycle:gitea") + _run_gitea() + except Exception as exc: + LOGGER.error("Indicizzazione Gitea fallita: %s", exc) + + try: + thermal.wait_for_headroom(context="cycle:paperless") + _run_paperless() + except Exception as exc: + LOGGER.error("Indicizzazione Paperless fallita: %s", exc) + + try: + thermal.wait_for_headroom(context="cycle:apps") + _run_apps() + except Exception as exc: + LOGGER.error("Indicizzazione Apps fallita: %s", exc) + + time.sleep(interval) + + +if __name__ == "__main__": + main()