Landing AI integrado

This commit is contained in:
Sebastian
2025-11-06 13:29:43 +00:00
parent 7c6e8c4858
commit c03d0e27c4
32 changed files with 3908 additions and 728 deletions

View File

@@ -0,0 +1,288 @@
"""
Router para gestión de schemas personalizables.
Endpoints CRUD para crear, leer, actualizar y eliminar schemas.
"""
import logging
import uuid
from fastapi import APIRouter, HTTPException, Query
from typing import List, Optional
from ..models.schema_models import (
CustomSchema,
SchemaListResponse,
SchemaValidationResponse
)
from ..repositories.schema_repository import get_schema_repository
from ..services.schema_builder_service import SchemaBuilderService
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/v1/schemas", tags=["schemas"])
@router.post("/", response_model=CustomSchema, status_code=201)
async def create_schema(schema: CustomSchema):
"""
Crea un nuevo schema personalizado.
Args:
schema: Definición del schema
Returns:
Schema creado con ID y timestamps
Raises:
HTTPException 400: Si el schema es inválido
HTTPException 409: Si ya existe un schema con ese ID
"""
try:
# Generar ID si no viene
if not schema.schema_id:
schema.schema_id = f"schema_{uuid.uuid4().hex[:12]}"
# Verificar que no exista
repo = get_schema_repository()
if repo.exists(schema.schema_id):
raise HTTPException(
status_code=409,
detail=f"Ya existe un schema con ID: {schema.schema_id}"
)
# Validar que se puede construir el schema
builder = SchemaBuilderService()
validation = builder.validate_schema(schema)
if not validation["valid"]:
raise HTTPException(
status_code=400,
detail={
"message": "Schema inválido",
"errors": validation["errors"]
}
)
# Guardar
saved_schema = repo.save(schema)
logger.info(f"Schema creado: {saved_schema.schema_id} - {saved_schema.schema_name}")
return saved_schema
except HTTPException:
raise
except Exception as e:
logger.error(f"Error creando schema: {e}")
raise HTTPException(status_code=500, detail=f"Error interno: {str(e)}")
@router.get("/", response_model=List[CustomSchema])
async def list_schemas(
tema: Optional[str] = Query(None, description="Filtrar por tema (incluye globales)")
):
"""
Lista todos los schemas o filtrados por tema.
Args:
tema: Nombre del tema para filtrar (opcional)
Returns:
Lista de schemas
"""
try:
repo = get_schema_repository()
if tema:
schemas = repo.list_by_tema(tema)
else:
schemas = repo.list_all()
return schemas
except Exception as e:
logger.error(f"Error listando schemas: {e}")
raise HTTPException(status_code=500, detail=f"Error interno: {str(e)}")
@router.get("/{schema_id}", response_model=CustomSchema)
async def get_schema(schema_id: str):
"""
Obtiene un schema por su ID.
Args:
schema_id: ID del schema
Returns:
Schema solicitado
Raises:
HTTPException 404: Si el schema no existe
"""
try:
repo = get_schema_repository()
schema = repo.get_by_id(schema_id)
if not schema:
raise HTTPException(
status_code=404,
detail=f"Schema no encontrado: {schema_id}"
)
return schema
except HTTPException:
raise
except Exception as e:
logger.error(f"Error obteniendo schema {schema_id}: {e}")
raise HTTPException(status_code=500, detail=f"Error interno: {str(e)}")
@router.put("/{schema_id}", response_model=CustomSchema)
async def update_schema(schema_id: str, schema: CustomSchema):
"""
Actualiza un schema existente.
Args:
schema_id: ID del schema a actualizar
schema: Nueva definición del schema
Returns:
Schema actualizado
Raises:
HTTPException 404: Si el schema no existe
HTTPException 400: Si el nuevo schema es inválido
"""
try:
repo = get_schema_repository()
# Verificar que existe
existing = repo.get_by_id(schema_id)
if not existing:
raise HTTPException(
status_code=404,
detail=f"Schema no encontrado: {schema_id}"
)
# Mantener el ID original
schema.schema_id = schema_id
schema.created_at = existing.created_at # Mantener fecha de creación
# Validar nuevo schema
builder = SchemaBuilderService()
validation = builder.validate_schema(schema)
if not validation["valid"]:
raise HTTPException(
status_code=400,
detail={
"message": "Schema inválido",
"errors": validation["errors"]
}
)
# Guardar
updated_schema = repo.save(schema)
logger.info(f"Schema actualizado: {schema_id}")
return updated_schema
except HTTPException:
raise
except Exception as e:
logger.error(f"Error actualizando schema {schema_id}: {e}")
raise HTTPException(status_code=500, detail=f"Error interno: {str(e)}")
@router.delete("/{schema_id}")
async def delete_schema(schema_id: str):
"""
Elimina un schema.
Args:
schema_id: ID del schema a eliminar
Returns:
Mensaje de confirmación
Raises:
HTTPException 404: Si el schema no existe
"""
try:
repo = get_schema_repository()
if not repo.delete(schema_id):
raise HTTPException(
status_code=404,
detail=f"Schema no encontrado: {schema_id}"
)
logger.info(f"Schema eliminado: {schema_id}")
return {
"success": True,
"message": f"Schema {schema_id} eliminado exitosamente"
}
except HTTPException:
raise
except Exception as e:
logger.error(f"Error eliminando schema {schema_id}: {e}")
raise HTTPException(status_code=500, detail=f"Error interno: {str(e)}")
@router.post("/validate", response_model=SchemaValidationResponse)
async def validate_schema(schema: CustomSchema):
"""
Valida un schema sin guardarlo.
Útil para preview en el frontend antes de guardar.
Args:
schema: Schema a validar
Returns:
Resultado de validación con detalles
"""
try:
builder = SchemaBuilderService()
validation = builder.validate_schema(schema)
return SchemaValidationResponse(**validation)
except Exception as e:
logger.error(f"Error validando schema: {e}")
return SchemaValidationResponse(
valid=False,
message="Error en validación",
errors=[str(e)]
)
@router.get("/stats/count")
async def get_schemas_count():
"""
Obtiene estadísticas de schemas.
Returns:
Conteo de schemas total y por tema
"""
try:
repo = get_schema_repository()
all_schemas = repo.list_all()
# Contar por tema
tema_counts = {}
global_count = 0
for schema in all_schemas:
if schema.is_global:
global_count += 1
elif schema.tema:
tema_counts[schema.tema] = tema_counts.get(schema.tema, 0) + 1
return {
"total": len(all_schemas),
"global": global_count,
"by_tema": tema_counts
}
except Exception as e:
logger.error(f"Error obteniendo estadísticas: {e}")
raise HTTPException(status_code=500, detail=f"Error interno: {str(e)}")