abxda commited on
Commit
391b4b4
·
0 Parent(s):

Final clean initial commit for deployment

Browse files
.gitattributes ADDED
@@ -0,0 +1 @@
 
 
1
+ *.gpq filter=lfs diff=lfs merge=lfs -text
Dockerfile ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Usar una imagen base de Python basada en Debian estable (slim-buster es una buena opción)
2
+ FROM python:3.10-slim-buster
3
+
4
+ # Evitar que 'apt' solicite entradas interactivas durante la construcción
5
+ ENV DEBIAN_FRONTEND=noninteractive
6
+
7
+ # 1. Instalar dependencias del sistema (El "Paso GDAL" crítico)
8
+ # - libgdal-dev: Proporciona los encabezados de C++ y la herramienta gdal-config
9
+ # que 'pip' necesita para compilar los bindings de geopandas/fiona.
10
+ # - build-essential: Compiladores C/C++ básicos.
11
+ RUN apt-get update && \
12
+ apt-get install -y --no-install-recommends \
13
+ gdal-bin \
14
+ libgdal-dev \
15
+ build-essential \
16
+ && rm -rf /var/lib/apt/lists/*
17
+
18
+ # 2. Configurar el entorno de la aplicación
19
+ WORKDIR /app
20
+
21
+ # Crear un usuario no-root por seguridad, una buena práctica en contenedores
22
+ RUN useradd -m -u 1000 user
23
+ USER user
24
+ ENV HOME=/home/user \
25
+ PATH=/home/user/.local/bin:$PATH
26
+
27
+ # 3. Instalar dependencias de Python
28
+ # Copiar solo requirements.txt primero para aprovechar el caché de capas de Docker.
29
+ # Si requirements.txt no cambia, Docker no volverá a ejecutar este paso.
30
+ COPY --chown=user requirements.txt .
31
+
32
+ # Instalar usando pip en el directorio del usuario, sin guardar caché para mantener la imagen ligera.
33
+ RUN pip install --no-cache-dir --user -r requirements.txt
34
+
35
+ # 4. Copiar el resto del código de la aplicación
36
+ # El 'chown' asegura que el usuario 'user' sea el propietario de los archivos.
37
+ COPY --chown=user . .
38
+
39
+ # 5. Exponer el puerto que Hugging Face Spaces espera
40
+ EXPOSE 7860
41
+
42
+ # 6. Comando para ejecutar la aplicación
43
+ # Usar Gunicorn como un servidor WSGI de producción, no el servidor de desarrollo de Dash.
44
+ # app_00:server -> Busca la variable 'server' en el archivo 'app_00.py'.
45
+ # --bind 0.0.0.0:7860 -> Escucha en todas las interfaces de red en el puerto 7860.
46
+ CMD ["gunicorn", "app_00:server", "--workers", "4", "--bind", "0.0.0.0:7860"]
README.md ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Dashboard Geoespacial DuckDB
3
+ emoji: 🗺️
4
+ colorFrom: blue
5
+ colorTo: green
6
+ sdk: docker
7
+ app_port: 7860
8
+ ---
9
+
10
+ # Dashboard Geoespacial con DuckDB y GeoParquet
11
+
12
+ Este Space demuestra la capacidad de realizar análisis geoespaciales de alto rendimiento
13
+ leyendo archivos GeoParquet locales con DuckDB dentro de un entorno contenedorizado.
14
+
15
+ **Tecnologías:**
16
+ - Dash
17
+ - DuckDB (con extensión `spatial`)
18
+ - GeoPandas
19
+ - Docker
20
+ - Git LFS
app_00.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import dash
2
+ from dash import html
3
+ import duckdb
4
+ import os
5
+
6
+ # --- Configuración ---
7
+ CENSO_PATH = "./data/censo_manzanas_optimizado.gpq"
8
+
9
+ # --- Inicialización de la App ---
10
+ # Inicializa la aplicación Dash
11
+ app = dash.Dash(__name__)
12
+ # Variable 'server' que Gunicorn usará para iniciar la aplicación
13
+ server = app.server
14
+
15
+ # --- Lógica de la Consulta ---
16
+ # Esta función se ejecuta UNA VEZ cuando la aplicación se inicia.
17
+ def get_total_manzanas():
18
+ """
19
+ Realiza una consulta simple para contar el total de filas en el archivo GeoParquet.
20
+ """
21
+ if not os.path.exists(CENSO_PATH):
22
+ return "Error: No se encontró el archivo de datos. Asegúrate de que exista en ./data/"
23
+
24
+ try:
25
+ con = duckdb.connect(database=':memory:')
26
+ # La extensión espacial es necesaria para que DuckDB entienda el tipo GEOMETRY del GeoParquet
27
+ con.install_extension("spatial")
28
+ con.load_extension("spatial")
29
+
30
+ query = f"SELECT COUNT(*) FROM read_parquet('{CENSO_PATH}');"
31
+ result = con.execute(query).fetchdf().iloc[0, 0]
32
+ con.close()
33
+ return f"¡Éxito! El contenedor Docker y DuckDB funcionan. Total de manzanas leídas: {result}"
34
+ except Exception as e:
35
+ return f"Error durante la consulta de DuckDB: {e}"
36
+
37
+ # --- Layout de la Aplicación ---
38
+ # Define la estructura visual de la página.
39
+ app.layout = html.Div(style={'textAlign': 'center', 'fontFamily': 'Arial'}, children=[
40
+ html.H1("Prueba de Despliegue: Dash + DuckDB en Hugging Face Spaces"),
41
+ html.Hr(),
42
+ html.H2("Resultado de la consulta de prueba:"),
43
+ html.P(
44
+ id='query-result',
45
+ children=get_total_manzanas(), # Llama a la función para obtener el resultado
46
+ style={'fontSize': '20px', 'color': 'green' if 'Éxito' in get_total_manzanas() else 'red'}
47
+ )
48
+ ])
49
+
50
+ # --- Punto de Entrada (para desarrollo local) ---
51
+ if __name__ == '__main__':
52
+ # Este bloque solo se ejecuta si corres 'python app_00.py' localmente.
53
+ # Gunicorn no lo usa.
54
+ app.run_server(debug=True)
data/censo_manzanas_optimizado.gpq ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:340b4c8f89ee22b905280f8c594ecc796756bd85780404e1d9867ca61a2af4ce
3
+ size 287211917
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ dash
2
+ dash-bootstrap-components
3
+ dash-leaflet
4
+ plotly
5
+ gunicorn
6
+ duckdb>=0.10.0
7
+ geopandas