initial commit

This commit is contained in:
2025-10-26 23:39:49 -05:00
commit 5fb0909e8d
120 changed files with 11279 additions and 0 deletions

136
scripts/README.md Normal file
View File

@@ -0,0 +1,136 @@
# 🛠️ Scripts de Utilidades
Este directorio contiene scripts útiles para el desarrollo y mantenimiento del proyecto Balotario.
## 📁 Scripts Disponibles
### 🐍 `dev.py`
**Script principal de desarrollo en Python**
#### Comandos:
```bash
# Limpiar cache y archivos temporales
python scripts/dev.py clean
# Ejecutar todos los tests de Python
python scripts/dev.py test
# Verificar dependencias instaladas
python scripts/dev.py deps
# Iniciar servidor de desarrollo
python scripts/dev.py dev
# Mostrar ayuda
python scripts/dev.py help
```
#### Funcionalidades:
- ✅ Limpieza automática de `__pycache__` y archivos `.pyc`
- ✅ Ejecución de tests de Python
- ✅ Verificación de dependencias
- ✅ Inicio del servidor de desarrollo
- ✅ Ayuda integrada
### 🧹 `clean.sh`
**Script de limpieza rápida en Bash**
#### Uso:
```bash
# Ejecutar limpieza completa
./scripts/clean.sh
# O con bash explícito
bash scripts/clean.sh
```
#### Funcionalidades:
- ✅ Elimina `__pycache__` recursivamente
- ✅ Elimina archivos `.pyc`, `.pyo`
- ✅ Elimina archivos temporales (`.tmp`, `.temp`, `*~`)
- ✅ Elimina archivos del sistema (`.DS_Store`)
- ✅ Elimina logs (`.log`)
- ✅ Muestra estadísticas del proyecto
## 🚀 Uso Rápido
### Desarrollo Diario
```bash
# 1. Limpiar proyecto
./scripts/clean.sh
# 2. Verificar que todo esté bien
python scripts/dev.py test
# 3. Iniciar desarrollo
python scripts/dev.py dev
```
### Antes de Commit
```bash
# Limpiar y verificar
./scripts/clean.sh
python scripts/dev.py test
```
### Configuración Inicial
```bash
# Verificar dependencias
python scripts/dev.py deps
# Si faltan dependencias
pip install -r requirements.txt
```
## 🔧 Personalización
### Agregar Nuevos Comandos a `dev.py`
1. Crear nueva función en `dev.py`
2. Agregar comando en `main()`
3. Documentar en `show_help()`
### Modificar `clean.sh`
- Agregar nuevos patrones de archivos a limpiar
- Modificar las estadísticas mostradas
- Agregar verificaciones adicionales
## 📊 Estadísticas
El script `clean.sh` muestra:
- 📁 Directorio actual
- 📄 Número de archivos Python
- 🌐 Número de archivos HTML
- 🎨 Número de archivos CSS
- ⚡ Número de archivos JavaScript
- 🧪 Número de tests
## 🐛 Troubleshooting
### Permisos en Linux/macOS
```bash
# Dar permisos de ejecución
chmod +x scripts/clean.sh
chmod +x scripts/dev.py
```
### Problemas con Python
```bash
# Verificar versión de Python
python --version
# Verificar que esté en el entorno virtual
which python
```
### Problemas con Bash
```bash
# Ejecutar con bash explícito
bash scripts/clean.sh
# Verificar sintaxis
bash -n scripts/clean.sh
```
---
**Nota**: Estos scripts están diseñados para facilitar el desarrollo. Úsalos regularmente para mantener el proyecto limpio y organizado.

31
scripts/clean.sh Executable file
View File

@@ -0,0 +1,31 @@
#!/bin/bash
# Script de limpieza para el proyecto Balotario
echo "🧹 Limpiando proyecto Balotario..."
# Limpiar cache de Python
echo "📦 Eliminando __pycache__..."
find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
find . -name "*.pyc" -delete 2>/dev/null || true
find . -name "*.pyo" -delete 2>/dev/null || true
# Limpiar archivos temporales
echo "🗑️ Eliminando archivos temporales..."
find . -name "*.tmp" -delete 2>/dev/null || true
find . -name "*.temp" -delete 2>/dev/null || true
find . -name "*~" -delete 2>/dev/null || true
find . -name ".DS_Store" -delete 2>/dev/null || true
# Limpiar logs
echo "📝 Eliminando logs..."
find . -name "*.log" -delete 2>/dev/null || true
echo "✅ Limpieza completada"
echo ""
echo "📊 Estado del proyecto:"
echo " 📁 Directorio principal: $(pwd)"
echo " 📄 Archivos Python: $(find . -name "*.py" | wc -l)"
echo " 🌐 Archivos HTML: $(find . -name "*.html" | wc -l)"
echo " 🎨 Archivos CSS: $(find . -name "*.css" | wc -l)"
echo " ⚡ Archivos JS: $(find . -name "*.js" | wc -l)"
echo " 🧪 Tests: $(find test/ -name "test_*" | wc -l)"

127
scripts/dev.py Normal file
View File

@@ -0,0 +1,127 @@
#!/usr/bin/env python3
"""
Script de utilidades para desarrollo del Balotario
"""
import os
import sys
import subprocess
import shutil
from pathlib import Path
def clean_cache():
"""Limpiar archivos de cache y temporales"""
print("🧹 Limpiando archivos de cache...")
# Limpiar __pycache__
for root, dirs, files in os.walk('.'):
for dir_name in dirs:
if dir_name == '__pycache__':
cache_path = os.path.join(root, dir_name)
print(f" Eliminando: {cache_path}")
shutil.rmtree(cache_path)
# Limpiar archivos .pyc
for root, dirs, files in os.walk('.'):
for file in files:
if file.endswith('.pyc'):
pyc_path = os.path.join(root, file)
print(f" Eliminando: {pyc_path}")
os.remove(pyc_path)
print("✅ Cache limpiado")
def run_tests():
"""Ejecutar todos los tests de Python"""
print("🧪 Ejecutando tests de Python...")
test_files = [
'test/test_parser.py',
'test/test_clean_parser.py'
]
for test_file in test_files:
if os.path.exists(test_file):
print(f"\n📝 Ejecutando: {test_file}")
try:
subprocess.run([sys.executable, test_file], check=True)
print(f"{test_file} - PASÓ")
except subprocess.CalledProcessError:
print(f"{test_file} - FALLÓ")
else:
print(f"⚠️ {test_file} - NO ENCONTRADO")
def check_dependencies():
"""Verificar que las dependencias estén instaladas"""
print("📦 Verificando dependencias...")
try:
import flask
print(f"✅ Flask {flask.__version__}")
except ImportError:
print("❌ Flask no instalado")
return False
return True
def start_dev_server():
"""Iniciar servidor de desarrollo"""
print("🚀 Iniciando servidor de desarrollo...")
if not check_dependencies():
print("❌ Faltan dependencias. Ejecuta: pip install -r requirements.txt")
return
# Configurar variables de entorno para desarrollo
os.environ['FLASK_ENV'] = 'development'
os.environ['FLASK_DEBUG'] = 'true'
try:
subprocess.run([sys.executable, 'run.py'])
except KeyboardInterrupt:
print("\n👋 Servidor detenido")
def show_help():
"""Mostrar ayuda"""
print("""
🛠️ Script de Utilidades - Balotario Licencia A-I
Comandos disponibles:
clean - Limpiar archivos de cache y temporales
test - Ejecutar todos los tests de Python
deps - Verificar dependencias instaladas
dev - Iniciar servidor de desarrollo
help - Mostrar esta ayuda
Uso:
python scripts/dev.py <comando>
Ejemplos:
python scripts/dev.py clean
python scripts/dev.py test
python scripts/dev.py dev
""")
def main():
if len(sys.argv) < 2:
show_help()
return
command = sys.argv[1].lower()
if command == 'clean':
clean_cache()
elif command == 'test':
run_tests()
elif command == 'deps':
check_dependencies()
elif command == 'dev':
start_dev_server()
elif command == 'help':
show_help()
else:
print(f"❌ Comando desconocido: {command}")
show_help()
if __name__ == '__main__':
main()

192
scripts/docker.sh Executable file
View File

@@ -0,0 +1,192 @@
#!/bin/bash
# Scripts de utilidades para Docker
set -e
# Colores para output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Funciones de utilidad
log_info() {
echo -e "${BLUE} $1${NC}"
}
log_success() {
echo -e "${GREEN}$1${NC}"
}
log_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
log_error() {
echo -e "${RED}$1${NC}"
}
# Función para construir la imagen
build() {
log_info "Construyendo imagen Docker..."
docker build -t balotario:latest .
log_success "Imagen construida exitosamente"
}
# Función para ejecutar en desarrollo
dev() {
log_info "Iniciando contenedor en modo desarrollo..."
docker run -it --rm \
-p 5000:5000 \
-v $(pwd):/app \
-e FLASK_ENV=development \
-e FLASK_DEBUG=true \
-e DOCKER_CONTAINER=true \
--name balotario-dev \
balotario:latest
}
# Función para ejecutar en producción
prod() {
log_info "Iniciando contenedor en modo producción..."
docker run -d \
-p 5000:5000 \
-e FLASK_ENV=production \
-e FLASK_DEBUG=false \
-e DOCKER_CONTAINER=true \
--name balotario-prod \
--restart unless-stopped \
balotario:latest
log_success "Contenedor iniciado en modo producción"
log_info "Accede a: http://localhost:5000"
}
# Función para usar Docker Compose
compose_up() {
log_info "Iniciando servicios con Docker Compose..."
docker-compose up -d
log_success "Servicios iniciados"
log_info "Aplicación: http://localhost:5000"
log_info "Nginx: http://localhost:80"
}
# Función para detener Docker Compose
compose_down() {
log_info "Deteniendo servicios..."
docker-compose down
log_success "Servicios detenidos"
}
# Función para ver logs
logs() {
local service=${1:-balotario}
log_info "Mostrando logs de $service..."
docker-compose logs -f $service
}
# Función para limpiar contenedores e imágenes
clean() {
log_warning "Limpiando contenedores e imágenes..."
# Detener contenedores
docker stop balotario-dev balotario-prod 2>/dev/null || true
docker rm balotario-dev balotario-prod 2>/dev/null || true
# Limpiar con docker-compose
docker-compose down --rmi all --volumes --remove-orphans 2>/dev/null || true
# Limpiar imágenes huérfanas
docker image prune -f
log_success "Limpieza completada"
}
# Función para mostrar estado
status() {
log_info "Estado de contenedores:"
docker ps -a --filter "name=balotario"
echo ""
log_info "Estado de servicios Docker Compose:"
docker-compose ps
}
# Función para entrar al contenedor
shell() {
local container=${1:-balotario-prod}
log_info "Entrando al contenedor $container..."
docker exec -it $container /bin/bash
}
# Función de ayuda
help() {
echo "🐳 Scripts de Docker para Balotario"
echo ""
echo "Uso: $0 <comando>"
echo ""
echo "Comandos disponibles:"
echo " build - Construir imagen Docker"
echo " dev - Ejecutar en modo desarrollo"
echo " prod - Ejecutar en modo producción"
echo " compose-up - Iniciar con Docker Compose"
echo " compose-down - Detener Docker Compose"
echo " logs [service]- Ver logs (default: balotario)"
echo " clean - Limpiar contenedores e imágenes"
echo " status - Mostrar estado de contenedores"
echo " shell [name] - Entrar al contenedor"
echo " help - Mostrar esta ayuda"
echo ""
echo "Ejemplos:"
echo " $0 build"
echo " $0 compose-up"
echo " $0 logs nginx"
echo " $0 shell balotario-prod"
}
# Función principal
main() {
case "${1:-help}" in
build)
build
;;
dev)
build
dev
;;
prod)
build
prod
;;
compose-up)
compose_up
;;
compose-down)
compose_down
;;
logs)
logs $2
;;
clean)
clean
;;
status)
status
;;
shell)
shell $2
;;
help|*)
help
;;
esac
}
# Verificar que Docker esté instalado
if ! command -v docker &> /dev/null; then
log_error "Docker no está instalado"
exit 1
fi
# Ejecutar función principal
main "$@"

156
scripts/download_images.py Normal file
View File

@@ -0,0 +1,156 @@
#!/usr/bin/env python3
"""
Script to download all images from the MTC website and store them locally.
This makes the application work completely offline.
"""
import os
import re
import requests
from urllib.parse import urlparse
import time
from pathlib import Path
def create_images_directory():
"""Create the static/images directory if it doesn't exist."""
images_dir = Path("static/images")
images_dir.mkdir(parents=True, exist_ok=True)
return images_dir
def extract_image_urls_from_markdown():
"""Extract all image URLs from the markdown file."""
markdown_file = Path("data/balotario_clase_a_cat_I.md")
if not markdown_file.exists():
print(f"Error: {markdown_file} not found!")
return []
with open(markdown_file, 'r', encoding='utf-8') as f:
content = f.read()
# Find all image URLs
pattern = r'!\[\]\((https://sierdgtt\.mtc\.gob\.pe/Content/img-data/img\d+\.jpg)\)'
urls = re.findall(pattern, content)
return list(set(urls)) # Remove duplicates
def download_image(url, images_dir, retries=3):
"""Download a single image with retry logic."""
try:
# Extract filename from URL
filename = os.path.basename(urlparse(url).path)
filepath = images_dir / filename
# Skip if already exists
if filepath.exists():
print(f"{filename} already exists")
return True
print(f"📥 Downloading {filename}...")
# Download with retries
for attempt in range(retries):
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
response = requests.get(url, headers=headers, timeout=30)
response.raise_for_status()
# Save the image
with open(filepath, 'wb') as f:
f.write(response.content)
print(f"✅ Downloaded {filename} ({len(response.content)} bytes)")
return True
except requests.RequestException as e:
print(f"❌ Attempt {attempt + 1} failed for {filename}: {e}")
if attempt < retries - 1:
time.sleep(2) # Wait before retry
print(f"💥 Failed to download {filename} after {retries} attempts")
return False
except Exception as e:
print(f"💥 Error downloading {url}: {e}")
return False
def update_markdown_file(images_dir):
"""Update the markdown file to use local image paths."""
markdown_file = Path("data/balotario_clase_a_cat_I.md")
backup_file = Path("data/balotario_clase_a_cat_I.md.backup")
# Create backup
if not backup_file.exists():
with open(markdown_file, 'r', encoding='utf-8') as f:
content = f.read()
with open(backup_file, 'w', encoding='utf-8') as f:
f.write(content)
print(f"📋 Created backup: {backup_file}")
# Read current content
with open(markdown_file, 'r', encoding='utf-8') as f:
content = f.read()
# Replace URLs with local paths
pattern = r'!\[\]\(https://sierdgtt\.mtc\.gob\.pe/Content/img-data/(img\d+\.jpg)\)'
replacement = r'![](/static/images/\1)'
updated_content = re.sub(pattern, replacement, content)
# Write updated content
with open(markdown_file, 'w', encoding='utf-8') as f:
f.write(updated_content)
print("📝 Updated markdown file to use local image paths")
def main():
"""Main function to download all images."""
print("🚀 Starting image download process...")
# Create images directory
images_dir = create_images_directory()
print(f"📁 Images will be saved to: {images_dir}")
# Extract image URLs
urls = extract_image_urls_from_markdown()
print(f"🔍 Found {len(urls)} unique images to download")
if not urls:
print("❌ No image URLs found!")
return
# Download images
successful = 0
failed = 0
for i, url in enumerate(urls, 1):
print(f"\n[{i}/{len(urls)}] Processing: {url}")
if download_image(url, images_dir):
successful += 1
else:
failed += 1
# Small delay to be respectful to the server
time.sleep(0.5)
# Summary
print(f"\n📊 Download Summary:")
print(f"✅ Successful: {successful}")
print(f"❌ Failed: {failed}")
print(f"📁 Total files: {len(list(images_dir.glob('*.jpg')))}")
# Update markdown file
if successful > 0:
print(f"\n🔄 Updating markdown file...")
update_markdown_file(images_dir)
print(f"✅ Process completed!")
print(f"💡 You can now run your app completely offline!")
else:
print(f"❌ No images were downloaded successfully")
if __name__ == "__main__":
main()

288
scripts/env-setup.bat Normal file
View File

@@ -0,0 +1,288 @@
@echo off
REM ====================================
REM SCRIPT DE CONFIGURACIÓN DE ENTORNO
REM Balotario Licencia A-I (Windows)
REM =============================
setlocal enabledelayedexpansion
REM Función para generar SECRET_KEY
:generate_secret_key
python -c "import secrets; print(secrets.token_hex(32))" 2>nul
if errorlevel 1 (
REM Fallback si Python no está disponible
echo %RANDOM%%RANDOM%%RANDOM%%RANDOM%
)
goto :eof
REM Función para mostrar header
:print_header
echo ======================================
echo 🌍 CONFIGURACIÓN DE ENTORNO
echo Balotario Licencia A-I
echo ======================================
echo.
goto :eof
REM Función para configurar desarrollo
:setup_development
echo Configurando entorno de desarrollo...
REM Generar SECRET_KEY
for /f %%i in ('python -c "import secrets; print(secrets.token_hex(32))" 2^>nul') do set SECRET_KEY=%%i
if "!SECRET_KEY!"=="" set SECRET_KEY=%RANDOM%%RANDOM%%RANDOM%%RANDOM%
REM Crear archivo .env
(
echo # ====================================
echo # CONFIGURACIÓN DE DESARROLLO
echo # Generado automáticamente: %date% %time%
echo # ====================================
echo.
echo # Configuración de Flask
echo SECRET_KEY=!SECRET_KEY!
echo FLASK_ENV=development
echo FLASK_CONFIG=development
echo FLASK_DEBUG=true
echo.
echo # Configuración del servidor
echo HOST=127.0.0.1
echo PORT=5000
echo.
echo # Configuración de Docker
echo DOCKER_CONTAINER=false
echo.
echo # Configuración de logging
echo LOG_LEVEL=DEBUG
echo AUTO_RELOAD=true
echo SHOW_DEBUG_TOOLBAR=false
echo.
echo # ====================================
echo # NOTAS:
echo # - Cambia SECRET_KEY antes de ir a producción
echo # - Revisa .env.sample para más opciones
echo # ====================================
) > .env
echo ✅ Configuración de desarrollo creada en .env
goto :eof
REM Función para configurar producción
:setup_production
echo Configurando entorno de producción...
REM Generar SECRET_KEY
for /f %%i in ('python -c "import secrets; print(secrets.token_hex(32))" 2^>nul') do set SECRET_KEY=%%i
if "!SECRET_KEY!"=="" set SECRET_KEY=%RANDOM%%RANDOM%%RANDOM%%RANDOM%
REM Crear archivo .env
(
echo # ====================================
echo # CONFIGURACIÓN DE PRODUCCIÓN
echo # Generado automáticamente: %date% %time%
echo # ====================================
echo.
echo # Configuración de Flask
echo SECRET_KEY=!SECRET_KEY!
echo FLASK_ENV=production
echo FLASK_CONFIG=production
echo FLASK_DEBUG=false
echo.
echo # Configuración del servidor
echo HOST=0.0.0.0
echo PORT=5000
echo.
echo # Configuración de Docker
echo DOCKER_CONTAINER=true
echo.
echo # Configuración de logging
echo LOG_LEVEL=INFO
echo.
echo # ====================================
echo # IMPORTANTE:
echo # - Guarda SECRET_KEY en lugar seguro
echo # - Revisa todas las configuraciones antes de desplegar
echo # ====================================
) > .env
echo ✅ Configuración de producción creada en .env
echo ⚠️ IMPORTANTE: Guarda la SECRET_KEY en un lugar seguro
goto :eof
REM Función para configurar Docker
:setup_docker
echo Configurando entorno para Docker...
REM Generar SECRET_KEY
for /f %%i in ('python -c "import secrets; print(secrets.token_hex(32))" 2^>nul') do set SECRET_KEY=%%i
if "!SECRET_KEY!"=="" set SECRET_KEY=%RANDOM%%RANDOM%%RANDOM%%RANDOM%
REM Crear archivo .env
(
echo # ====================================
echo # CONFIGURACIÓN PARA DOCKER
echo # Generado automáticamente: %date% %time%
echo # ====================================
echo.
echo # Configuración de Flask
echo SECRET_KEY=!SECRET_KEY!
echo FLASK_ENV=production
echo FLASK_CONFIG=production
echo FLASK_DEBUG=false
echo.
echo # Configuración del servidor
echo HOST=0.0.0.0
echo PORT=5000
echo.
echo # Configuración de Docker
echo DOCKER_CONTAINER=true
echo.
echo # Configuración de logging
echo LOG_LEVEL=INFO
echo.
echo # ====================================
echo # DOCKER NOTES:
echo # - Estas variables pueden ser sobrescritas en docker-compose.yml
echo # - Para desarrollo con Docker, cambia FLASK_ENV=development
echo # ====================================
) > .env
echo ✅ Configuración para Docker creada en .env
goto :eof
REM Función para validar configuración
:validate_env
echo Validando configuración...
if not exist ".env" (
echo ❌ Archivo .env no encontrado
exit /b 1
)
findstr /C:"SECRET_KEY=" .env >nul
if errorlevel 1 (
echo ❌ SECRET_KEY no encontrada en .env
exit /b 1
)
findstr /C:"FLASK_ENV=" .env >nul
if errorlevel 1 (
echo ❌ FLASK_ENV no encontrada en .env
exit /b 1
)
echo ✅ Configuración válida
echo.
echo Resumen de configuración:
echo ------------------------
for /f "tokens=1,2 delims==" %%a in ('findstr /R "^SECRET_KEY= ^FLASK_ENV= ^FLASK_DEBUG= ^HOST= ^PORT=" .env') do (
if "%%a"=="SECRET_KEY" (
echo %%a=***OCULTA***
) else (
echo %%a=%%b
)
)
goto :eof
REM Función para mostrar ayuda
:show_help
echo Uso: %~nx0 [COMANDO]
echo.
echo Comandos disponibles:
echo dev Configurar para desarrollo local
echo prod Configurar para producción
echo docker Configurar para Docker
echo validate Validar configuración actual
echo backup Crear backup de .env actual
echo restore Restaurar desde .env.sample
echo help Mostrar esta ayuda
echo.
echo Ejemplos:
echo %~nx0 dev # Configuración de desarrollo
echo %~nx0 prod # Configuración de producción
echo %~nx0 docker # Configuración para Docker
goto :eof
REM Función para crear backup
:backup_env
if exist ".env" (
set backup_file=.env.backup.%date:~-4%%date:~3,2%%date:~0,2%_%time:~0,2%%time:~3,2%%time:~6,2%
set backup_file=!backup_file: =0!
copy .env "!backup_file!" >nul
echo ✅ Backup creado: !backup_file!
) else (
echo ⚠️ No hay archivo .env para respaldar
)
goto :eof
REM Función para restaurar desde sample
:restore_env
if exist ".env.sample" (
copy .env.sample .env >nul
echo ✅ Configuración restaurada desde .env.sample
echo ⚠️ Recuerda personalizar los valores en .env
) else (
echo ❌ Archivo .env.sample no encontrado
exit /b 1
)
goto :eof
REM Función principal
:main
call :print_header
if "%1"=="" goto help
if "%1"=="dev" goto dev
if "%1"=="development" goto dev
if "%1"=="prod" goto prod
if "%1"=="production" goto prod
if "%1"=="docker" goto docker
if "%1"=="validate" goto validate
if "%1"=="check" goto validate
if "%1"=="backup" goto backup
if "%1"=="restore" goto restore
if "%1"=="help" goto help
if "%1"=="--help" goto help
if "%1"=="-h" goto help
echo ❌ Comando desconocido: %1
echo.
goto help
:dev
call :backup_env
call :setup_development
call :validate_env
goto end
:prod
call :backup_env
call :setup_production
call :validate_env
goto end
:docker
call :backup_env
call :setup_docker
call :validate_env
goto end
:validate
call :validate_env
goto end
:backup
call :backup_env
goto end
:restore
call :backup_env
call :restore_env
goto end
:help
call :show_help
goto end
:end
pause

296
scripts/env-setup.sh Executable file
View File

@@ -0,0 +1,296 @@
#!/bin/bash
# ====================================
# SCRIPT DE CONFIGURACIÓN DE ENTORNO
# Balotario Licencia A-I
# ====================================
set -e # Salir en caso de error
# Colores para output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Función para imprimir con colores
print_info() {
echo -e "${ $1${NC}"
}
print_success() {
echo -e "${GREEN}$1${NC}"
}
print_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
print_error() {
echo -e "${RED}$1${NC}"
}
print_header() {
echo -e "${BLUE}"
echo "======================================"
echo "🌍 CONFIGURACIÓN DE ENTORNO"
echo "Balotario Licencia A-I"
echo "======================================"
echo -e "${NC}"
}
# Función para generar SECRET_KEY
generate_secret_key() {
if command -v python3 &> /dev/null; then
python3 -c "import secrets; print(secrets.token_hex(32))"
elif command -v python &> /dev/null; then
python -c "import secrets; print(secrets.token_hex(32))"
elif command -v openssl &> /dev/null; then
openssl rand -hex 32
else
# Fallback básico
date +%s | sha256sum | base64 | head -c 32
fi
}
# Función para configurar desarrollo
setup_development() {
print_info "Configurando entorno de desarrollo..."
SECRET_KEY=$(generate_secret_key)
cat > .env << EOF
# ====================================
# CONFIGURACIÓN DE DESARROLLO
# Generado automáticamente: $(date)
# ====================================
# Configuración de Flask
SECRET_KEY=${SECRET_KEY}
FLASK_ENV=development
FLASK_CONFIG=development
FLASK_DEBUG=true
# Configuración del servidor
HOST=127.0.0.1
PORT=5000
# Configuración de Docker
DOCKER_CONTAINER=false
# Configuración de logging
LOG_LEVEL=DEBUG
AUTO_RELOAD=true
SHOW_DEBUG_TOOLBAR=false
# ====================================
# NOTAS:
# - Cambia SECRET_KEY antes de ir a producción
# - Revisa .env.sample para más opciones
# ====================================
EOF
print_success "Configuración de desarrollo creada en .env"
}
# Función para configurar producción
setup_production() {
print_info "Configurando entorno de producción..."
SECRET_KEY=$(generate_secret_key)
cat > .env << EOF
# ====================================
# CONFIGURACIÓN DE PRODUCCIÓN
# Generado automáticamente: $(date)
# ====================================
# Configuración de Flask
SECRET_KEY=${SECRET_KEY}
FLASK_ENV=production
FLASK_CONFIG=production
FLASK_DEBUG=false
# Configuración del servidor
HOST=0.0.0.0
PORT=5000
# Configuración de Docker
DOCKER_CONTAINER=true
# Configuración de logging
LOG_LEVEL=INFO
# ====================================
# IMPORTANTE:
# - Guarda SECRET_KEY en lugar seguro
# - Revisa todas las configuraciones antes de desplegar
# - Considera usar variables de entorno del sistema
# ====================================
EOF
print_success "Configuración de producción creada en .env"
print_warning "IMPORTANTE: Guarda la SECRET_KEY en un lugar seguro"
}
# Función para configurar Docker
setup_docker() {
print_info "Configurando entorno para Docker..."
SECRET_KEY=$(generate_secret_key)
cat > .env << EOF
# ====================================
# CONFIGURACIÓN PARA DOCKER
# Generado automáticamente: $(date)
# ====================================
# Configuración de Flask
SECRET_KEY=${SECRET_KEY}
FLASK_ENV=production
FLASK_CONFIG=production
FLASK_DEBUG=false
# Configuración del servidor
HOST=0.0.0.0
PORT=5000
# Configuración de Docker
DOCKER_CONTAINER=true
# Configuración de logging
LOG_LEVEL=INFO
# ====================================
# DOCKER NOTES:
# - Estas variables pueden ser sobrescritas en docker-compose.yml
# - Para desarrollo con Docker, cambia FLASK_ENV=development
# ====================================
EOF
print_success "Configuración para Docker creada en .env"
}
# Función para validar configuración
validate_env() {
print_info "Validando configuración..."
if [ ! -f ".env" ]; then
print_error "Archivo .env no encontrado"
return 1
fi
# Verificar variables esenciales
if ! grep -q "SECRET_KEY=" .env; then
print_error "SECRET_KEY no encontrada en .env"
return 1
fi
if ! grep -q "FLASK_ENV=" .env; then
print_error "FLASK_ENV no encontrada en .env"
return 1
fi
print_success "Configuración válida"
# Mostrar resumen
echo ""
print_info "Resumen de configuración:"
echo "------------------------"
grep -E "^(SECRET_KEY|FLASK_ENV|FLASK_DEBUG|HOST|PORT)=" .env | while read line; do
key=$(echo $line | cut -d'=' -f1)
value=$(echo $line | cut -d'=' -f2)
if [ "$key" = "SECRET_KEY" ]; then
echo " $key=***OCULTA***"
else
echo " $key=$value"
fi
done
}
# Función para mostrar ayuda
show_help() {
echo "Uso: $0 [COMANDO]"
echo ""
echo "Comandos disponibles:"
echo " dev Configurar para desarrollo local"
echo " prod Configurar para producción"
echo " docker Configurar para Docker"
echo " validate Validar configuración actual"
echo " backup Crear backup de .env actual"
echo " restore Restaurar desde .env.sample"
echo " help Mostrar esta ayuda"
echo ""
echo "Ejemplos:"
echo " $0 dev # Configuración de desarrollo"
echo " $0 prod # Configuración de producción"
echo " $0 docker # Configuración para Docker"
}
# Función para crear backup
backup_env() {
if [ -f ".env" ]; then
backup_file=".env.backup.$(date +%Y%m%d_%H%M%S)"
cp .env "$backup_file"
print_success "Backup creado: $backup_file"
else
print_warning "No hay archivo .env para respaldar"
fi
}
# Función para restaurar desde sample
restore_env() {
if [ -f ".env.sample" ]; then
cp .env.sample .env
print_success "Configuración restaurada desde .env.sample"
print_warning "Recuerda personalizar los valores en .env"
else
print_error "Archivo .env.sample no encontrado"
return 1
fi
}
# Función principal
main() {
print_header
case "${1:-help}" in
"dev"|"development")
backup_env
setup_development
validate_env
;;
"prod"|"production")
backup_env
setup_production
validate_env
;;
"docker")
backup_env
setup_docker
validate_env
;;
"validate"|"check")
validate_env
;;
"backup")
backup_env
;;
"restore")
backup_env
restore_env
;;
"help"|"--help"|"-h")
show_help
;;
*)
print_error "Comando desconocido: $1"
echo ""
show_help
exit 1
;;
esac
}
# Ejecutar función principal
main "$@"

85
scripts/verify_images.py Normal file
View File

@@ -0,0 +1,85 @@
#!/usr/bin/env python3
"""
Script to verify that all local images are available and working.
"""
import os
import re
from pathlib import Path
def verify_local_images():
"""Verify that all referenced images exist locally."""
markdown_file = Path("data/balotario_clase_a_cat_I.md")
images_dir = Path("static/images")
if not markdown_file.exists():
print(f"❌ Markdown file not found: {markdown_file}")
return False
if not images_dir.exists():
print(f"❌ Images directory not found: {images_dir}")
return False
# Read markdown content
with open(markdown_file, 'r', encoding='utf-8') as f:
content = f.read()
# Find all local image references
pattern = r'!\[\]\(/static/images/(img\d+\.jpg)\)'
referenced_images = re.findall(pattern, content)
print(f"🔍 Found {len(referenced_images)} image references in markdown")
# Check if all referenced images exist
missing_images = []
existing_images = []
for img_name in referenced_images:
img_path = images_dir / img_name
if img_path.exists():
existing_images.append(img_name)
print(f"{img_name} - {img_path.stat().st_size} bytes")
else:
missing_images.append(img_name)
print(f"{img_name} - NOT FOUND")
# Check for extra images
all_local_images = list(images_dir.glob("*.jpg"))
extra_images = []
for img_path in all_local_images:
if img_path.name not in referenced_images:
extra_images.append(img_path.name)
# Summary
print(f"\n📊 Verification Summary:")
print(f"✅ Images found: {len(existing_images)}")
print(f"❌ Images missing: {len(missing_images)}")
print(f"📁 Total local images: {len(all_local_images)}")
print(f" Extra images: {len(extra_images)}")
if missing_images:
print(f"\n❌ Missing images:")
for img in missing_images:
print(f" - {img}")
if extra_images:
print(f"\n Extra images (not referenced):")
for img in extra_images:
print(f" - {img}")
# Calculate total size
total_size = sum(img.stat().st_size for img in all_local_images)
print(f"\n💾 Total images size: {total_size / 1024 / 1024:.2f} MB")
return len(missing_images) == 0
if __name__ == "__main__":
print("🔍 Verifying local images...")
success = verify_local_images()
if success:
print("\n🎉 All images are available locally!")
print("💡 Your app can now run completely offline!")
else:
print("\n⚠️ Some images are missing. Run download_images.py to fix this.")