alexp97 commited on
Commit
32765f0
·
1 Parent(s): 4eccaa5

feat(deploy): despliegue a Hugging Face Spaces (Dockerfile raíz + deploy_hf.ps1 + frontmatter)

Browse files
Files changed (4) hide show
  1. .env.example +15 -10
  2. Dockerfile +49 -0
  3. README.md +14 -0
  4. scripts/deploy_hf.ps1 +64 -0
.env.example CHANGED
@@ -29,21 +29,26 @@ CONFIDENCE_THRESHOLD=0.25
29
  MAX_UPLOAD_MB=50
30
 
31
  # -----------------------------------------------------------------------------------
32
- # 3) Despliegue UI -> ShinyApps.io (rsconnect)
33
- # Tokens en: https://www.shinyapps.io/admin/#/tokens
34
- # Uso: rsconnect add --account $SHINYAPPS_ACCOUNT --name $SHINYAPPS_ACCOUNT \
35
- # --token $SHINYAPPS_TOKEN --secret $SHINYAPPS_SECRET
36
- # -----------------------------------------------------------------------------------
37
- SHINYAPPS_ACCOUNT=
38
- SHINYAPPS_TOKEN=
39
- SHINYAPPS_SECRET=
40
 
41
  # -----------------------------------------------------------------------------------
42
- # 4) Despliegue Backend -> Render (opcional, para deploy por API/CI)
43
- # API Key en: https://dashboard.render.com/u/settings
 
 
44
  # -----------------------------------------------------------------------------------
45
  RENDER_API_KEY=
46
  RENDER_SERVICE_ID=
 
 
 
47
 
48
  # -----------------------------------------------------------------------------------
49
  # 5) Modelo de conteo + Hugging Face Hub
 
29
  MAX_UPLOAD_MB=50
30
 
31
  # -----------------------------------------------------------------------------------
32
+ # 3) Despliegue -> Hugging Face Spaces (SDK Docker) [VÍA ACTIVA — ver docs/ejecucion.md §5]
33
+ # HF construye el Dockerfile de la raíz (gateway FastAPI: UI / + API /api).
34
+ # Token (write) en: https://huggingface.co/settings/tokens
35
+ # Crea el Space (una vez, web): https://huggingface.co/new-space -> SDK "Docker".
36
+ # Deploy: .\scripts\deploy_hf.ps1
37
+ # -----------------------------------------------------------------------------------
38
+ HF_SPACE_ID= # <usuario>/<space>, p. ej. alexprieto/agrovision
39
+ # (HF_TOKEN se define en la sección 5; sirve tanto para el Space como para el modelo.)
40
 
41
  # -----------------------------------------------------------------------------------
42
+ # 3b) Alternativas de despliegue (opcionales):
43
+ # - Render (Docker, free): backend/Dockerfile + render.yaml. API en dashboard.render.com/u/settings
44
+ # - Posit Connect (de pago): rsconnect deploy fastapi (scripts/deploy_prod.ps1).
45
+ # OJO: shinyapps.io NO hospeda FastAPI (solo Shiny); estas vars solo aplican a Posit Connect.
46
  # -----------------------------------------------------------------------------------
47
  RENDER_API_KEY=
48
  RENDER_SERVICE_ID=
49
+ SHINYAPPS_ACCOUNT=
50
+ SHINYAPPS_TOKEN=
51
+ SHINYAPPS_SECRET=
52
 
53
  # -----------------------------------------------------------------------------------
54
  # 5) Modelo de conteo + Hugging Face Hub
Dockerfile ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # =====================================================================================
2
+ # Dockerfile para Hugging Face Spaces (SDK: docker) — gateway AgroVisión.
3
+ # HF construye ESTE archivo (debe estar en la raíz del repo) y lo corre como el
4
+ # usuario 1000 (HOME=/home/user). El gateway FastAPI sirve la UI Astro compilada en /
5
+ # y la API en /api. Puerto: 8000 (declarado en README.md con `app_port: 8000`).
6
+ #
7
+ # Multi-stage: (1) Node compila Astro; (2) Python/uv corre el gateway con el build
8
+ # de Astro copiado a backend/static. BYOK: sin secretos en la imagen (las llaves de
9
+ # datos las pone el usuario por sesión vía cabeceras X-User-*).
10
+ #
11
+ # Local/Render usan backend/Dockerfile; este es el equivalente endurecido para HF.
12
+ # =====================================================================================
13
+
14
+ # --- Stage 1: build de la UI Astro ---
15
+ FROM node:22-bookworm-slim AS ui
16
+ WORKDIR /ui
17
+ RUN corepack enable
18
+ COPY frontend/package.json frontend/pnpm-lock.yaml frontend/pnpm-workspace.yaml ./
19
+ RUN pnpm install --frozen-lockfile
20
+ COPY frontend/ ./
21
+ RUN pnpm build
22
+
23
+ # --- Stage 2: backend FastAPI (CPU), como usuario no-root (requisito de HF Spaces) ---
24
+ FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim
25
+
26
+ # HF Spaces ejecuta el contenedor como UID 1000: crear el usuario ANTES de copiar.
27
+ RUN useradd -m -u 1000 user
28
+ ENV HOME=/home/user \
29
+ PATH=/home/user/.local/bin:$PATH \
30
+ UV_PROJECT_ENVIRONMENT=/home/user/app/.venv \
31
+ UV_LINK_MODE=copy \
32
+ UV_CACHE_DIR=/home/user/.cache/uv \
33
+ COUNTING_ENABLED=false \
34
+ EVENTS_PERSIST=false
35
+
36
+ WORKDIR /home/user/app
37
+
38
+ # Dependencias (capa cacheable) — desde el lockfile, sin dev.
39
+ COPY --chown=user pyproject.toml uv.lock ./
40
+ USER user
41
+ RUN uv sync --no-dev --frozen
42
+
43
+ # Código + UI Astro compilada (servida por el gateway en /).
44
+ COPY --chown=user backend/ ./backend/
45
+ COPY --chown=user --from=ui /ui/dist/ ./backend/static/
46
+
47
+ EXPOSE 8000
48
+ # --no-sync: usa el venv ya construido en el build (no re-resuelve en runtime).
49
+ CMD ["uv", "run", "--no-sync", "uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "8000"]
README.md CHANGED
@@ -1,3 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  # AgroVisión — Plataforma de Monitoreo Agronómico
2
 
3
  Plataforma de [AgroVisión](docs/reference/description_proyecto_agrovision.md) para monitoreo agronómico de precisión: **gestión de parcelas**, **teledetección NDVI** (Sentinel-2, 5 años), **agente conversacional (RAG)** y **conteo de plantas por dron** (este último **en desarrollo**). Backend **FastAPI** (monolito modular), persistencia **Supabase (PostGIS) BYOK**, y UI en **migración de Shiny → Astro + Tailwind** (Agro-Stack).
 
1
+ ---
2
+ title: AgroVisión
3
+ emoji: 🫐
4
+ colorFrom: green
5
+ colorTo: blue
6
+ sdk: docker
7
+ app_port: 8000
8
+ pinned: false
9
+ license: agpl-3.0
10
+ ---
11
+
12
+ <!-- ↑ Frontmatter requerido por Hugging Face Spaces (SDK Docker). En GitHub se ve
13
+ como una tabla. El runbook de despliegue está en docs/ejecucion.md §5. -->
14
+
15
  # AgroVisión — Plataforma de Monitoreo Agronómico
16
 
17
  Plataforma de [AgroVisión](docs/reference/description_proyecto_agrovision.md) para monitoreo agronómico de precisión: **gestión de parcelas**, **teledetección NDVI** (Sentinel-2, 5 años), **agente conversacional (RAG)** y **conteo de plantas por dron** (este último **en desarrollo**). Backend **FastAPI** (monolito modular), persistencia **Supabase (PostGIS) BYOK**, y UI en **migración de Shiny → Astro + Tailwind** (Agro-Stack).
scripts/deploy_hf.ps1 ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # scripts/deploy_hf.ps1 — Despliegue de AgroVisión a Hugging Face Spaces (SDK Docker).
2
+ #
3
+ # El Space es un repo git en huggingface.co. HF construye el `Dockerfile` de la raíz
4
+ # (gateway FastAPI: UI Astro en / + API en /api) y lo sirve en el puerto `app_port`
5
+ # del README.md (8000). NO se compila ni empaqueta en local: solo se hace `git push`
6
+ # y HF construye en su lado.
7
+ #
8
+ # Requisitos (en .env, NO se versiona):
9
+ # HF_TOKEN=hf_xxx # token con permiso de escritura (huggingface.co/settings/tokens)
10
+ # HF_SPACE_ID=<usuario>/<space> # p. ej. alexprieto/agrovision (crea el Space ANTES, SDK=Docker)
11
+ #
12
+ # Crear el Space una vez (web): huggingface.co/new-space -> SDK "Docker" -> Blank.
13
+ # BYOK: no se ponen secretos de datos en el Space; el usuario pega sus llaves por sesión.
14
+ #
15
+ # Uso: .\scripts\deploy_hf.ps1
16
+ param(
17
+ [string]$SpaceId = "", # si se omite, se toma de HF_SPACE_ID (.env)
18
+ [switch]$Force # fuerza el push (sobrescribe el historial del Space)
19
+ )
20
+ $ErrorActionPreference = "Stop"
21
+ $root = Split-Path -Parent $PSScriptRoot
22
+ Set-Location $root
23
+
24
+ Write-Host "=== Deploy AgroVisión -> Hugging Face Spaces ===" -ForegroundColor Cyan
25
+
26
+ # Cargar HF_TOKEN / HF_SPACE_ID del .env (sin pisar lo que ya exista en la sesión).
27
+ if (Test-Path ".env") {
28
+ Get-Content ".env" | ForEach-Object {
29
+ if ($_ -match '^\s*(HF_TOKEN|HF_SPACE_ID)\s*=\s*(.+)$') {
30
+ $k = $matches[1]; $v = $matches[2].Trim().Trim('"').Trim("'")
31
+ if ($v -and -not [Environment]::GetEnvironmentVariable($k)) { Set-Item "env:$k" $v }
32
+ }
33
+ }
34
+ }
35
+ if (-not $SpaceId) { $SpaceId = $env:HF_SPACE_ID }
36
+
37
+ if (-not $env:HF_TOKEN) { Write-Error "Falta HF_TOKEN en .env (token de escritura de Hugging Face)."; exit 1 }
38
+ if (-not $SpaceId -or $SpaceId -notmatch '^[^/]+/[^/]+$') {
39
+ Write-Error "Falta HF_SPACE_ID válido (formato <usuario>/<space>). Pon HF_SPACE_ID en .env o pasa -SpaceId."
40
+ exit 1
41
+ }
42
+
43
+ # El dueño del Space (parte antes de '/') hace de usuario en la URL autenticada.
44
+ $owner = $SpaceId.Split("/")[0]
45
+ $remote = "https://${owner}:$($env:HF_TOKEN)@huggingface.co/spaces/$SpaceId"
46
+
47
+ # Aviso: el Space debe existir (SDK Docker). El primer push suele necesitar -Force
48
+ # porque el Space arranca con un commit inicial (README) distinto a nuestro historial.
49
+ Write-Host "Space: huggingface.co/spaces/$SpaceId (rama main)" -ForegroundColor Yellow
50
+ Write-Host "Empujando el repo (HEAD -> main); HF construirá el Dockerfile..." -ForegroundColor Yellow
51
+
52
+ $pushArgs = @("push")
53
+ if ($Force) { $pushArgs += "--force" }
54
+ $pushArgs += @($remote, "HEAD:main")
55
+
56
+ # Nota: el token va en la URL solo para este push (no se guarda como remote).
57
+ & git @pushArgs
58
+ if ($LASTEXITCODE -ne 0) {
59
+ Write-Warning "El push falló. Si es el primer deploy, reintenta con: .\scripts\deploy_hf.ps1 -Force"
60
+ exit 1
61
+ }
62
+
63
+ Write-Host "`n=== Push completado. Sigue el build en huggingface.co/spaces/$SpaceId ===" -ForegroundColor Green
64
+ Write-Host "Cuando termine, abre la URL del Space: la UI carga en / y la API en /api." -ForegroundColor Green