Motor de análisis generativo para consultas en lenguaje natural
qry-doc transforma el lenguaje natural en código ejecutable, visualizaciones y reportes PDF profesionales. Simplifica radicalmente la interacción con archivos CSV y bases de datos SQL.
from qry_doc import QryDoc, ReportTemplate
import pandasai as pai
from pandasai_openai import OpenAI
# Configurar LLM
llm = OpenAI()
pai.config.set({"llm": llm})
qry = QryDoc("ventas.csv", llm=llm)
# Pregunta en español
respuesta = qry.ask("¿Cuál fue el producto más vendido en 2024?")
print(respuesta) # "El producto más vendido fue 'Laptop Pro' con 1,234 unidades"
# Exporta resultados a CSV
qry.extract_to_csv("Top 10 clientes por ingresos", "top_clientes.csv")
# Genera reporte PDF profesional
qry.generate_report("Análisis trimestral de ventas", "reporte_q4.pdf")- 🗣️ Consultas en lenguaje natural - Pregunta sobre tus datos como si hablaras con un analista
- 📊 Visualizaciones automáticas - Genera gráficos relevantes sin escribir código
- 📄 Reportes PDF profesionales - Crea documentos con tablas, gráficos y resúmenes
- 📁 Exportación CSV - Extrae resultados tabulares con encoding Excel-compatible
- 🎨 Templates personalizables - Adapta el estilo de reportes a tu marca
- 🖼️ Portadas personalizadas - Añade imágenes de portada a tus reportes
- 🏷️ Logo en pie de página - Logo por defecto o personalizado con posición configurable
- ✏️ Fuentes personalizadas - Soporte para fuentes TTF/OTF
- 📑 Sistema de secciones - Controla el orden y contenido de las secciones del reporte
- 🔒 Sanitización de errores - Protege información sensible en mensajes de error
- 🐍 Python 3.11+ - Type hints completos y código moderno
# Instalación básica
uv add qry-doc
# Con soporte para OpenAI
uv add "qry-doc[openai]"
# Con soporte para múltiples proveedores
uv add "qry-doc[litellm]"
# Con todos los proveedores
uv add "qry-doc[all]"# Instalación básica
pip install qry-doc
# Con soporte para OpenAI
pip install "qry-doc[openai]"
# Con soporte para múltiples proveedores
pip install "qry-doc[litellm]"
# Con todos los proveedores
pip install "qry-doc[all]"git clone https://github.com/danro-dev/qry-doc.git
cd qry-doc
uv syncqry-doc utiliza PandasAI como motor de IA. Instala con el extra que necesites:
# Para OpenAI
pip install "qry-doc[openai]"
# Para múltiples proveedores
pip install "qry-doc[litellm]"import pandasai as pai
from pandasai_openai import OpenAI
# Opción 1: API key como variable de entorno OPENAI_API_KEY
llm = OpenAI()
# Opción 2: Pasar el API key directamente
llm = OpenAI(api_token="sk-...")
# Configurar PandasAI
pai.config.set({"llm": llm})Proveedores soportados vía LiteLLM:
- OpenAI (GPT-4, GPT-3.5)
- Anthropic (Claude)
- Google (Gemini)
- Azure OpenAI
- Ollama (modelos locales)
- Y muchos más...
from qry_doc import QryDoc
import pandas as pd
# Desde archivo CSV
qry = QryDoc("datos.csv", llm=llm)
# Desde DataFrame
df = pd.read_excel("datos.xlsx")
qry = QryDoc(df, llm=llm)
# Desde SQL (próximamente)
# qry = QryDoc("postgresql://user:pass@host/db", llm=llm)# Preguntas simples
total = qry.ask("¿Cuál es el total de ventas?")
# Análisis complejos
tendencia = qry.ask("¿Cómo han evolucionado las ventas mes a mes en 2024?")
# Comparaciones
comparacion = qry.ask("Compara las ventas de Q1 vs Q2 por región")from qry_doc import QryDoc
import pandasai as pai
from pandasai_openai import OpenAI
llm = OpenAI()
pai.config.set({"llm": llm})
qry = QryDoc("clientes.csv", llm=llm)
# Extrae datos filtrados
qry.extract_to_csv(
"Clientes con más de 10 compras en el último año",
"clientes_frecuentes.csv"
)
# Extrae agregaciones
qry.extract_to_csv(
"Ventas totales por categoría de producto",
"ventas_por_categoria.csv"
)
# Incluir índice si es necesario
qry.extract_to_csv(
"Ranking de vendedores por comisión",
"ranking.csv",
include_index=True
)from qry_doc import QryDoc, ReportTemplate
import pandasai as pai
from pandasai_openai import OpenAI
llm = OpenAI()
pai.config.set({"llm": llm})
qry = QryDoc("ventas_2024.csv", llm=llm)
# Reporte con template por defecto
qry.generate_report(
"Análisis de rendimiento del equipo de ventas",
"reporte_ventas.pdf"
)
# Reporte con template personalizado
template = ReportTemplate(
logo_path="mi_logo.png",
primary_color="#003366",
title_font="Helvetica-Bold",
body_font="Helvetica"
)
qry.generate_report(
"Resumen ejecutivo Q4 2024",
"resumen_q4.pdf",
title="Informe Trimestral de Ventas",
template=template
)from qry_doc import ReportTemplate
from pathlib import Path
# Template con imagen de portada
template = ReportTemplate(
cover_image_path=Path("mi_portada.png"), # Imagen a página completa
logo_path="mi_logo.png",
primary_color="#003366"
)
qry.generate_report(
"Análisis anual de ventas",
"reporte_anual.pdf",
title="Informe Anual 2024",
template=template
)from qry_doc import ReportTemplate, LogoPosition
# Logo personalizado en posición específica
template = ReportTemplate(
footer_logo_path=Path("mi_marca.png"), # Logo personalizado (None = logo por defecto)
footer_logo_enabled=True, # Activar/desactivar logo
footer_logo_position=LogoPosition.BOTTOM_LEFT, # BOTTOM_RIGHT, BOTTOM_LEFT, BOTTOM_CENTER
footer_logo_width=50.0, # Ancho en puntos
footer_logo_height=25.0 # Alto en puntos
)
# Desactivar el logo del pie de página
template_sin_logo = ReportTemplate(
footer_logo_enabled=False
)from qry_doc import ReportTemplate
from pathlib import Path
# Usar fuentes personalizadas
template = ReportTemplate(
custom_title_font_path=Path("fonts/Montserrat-Bold.ttf"),
custom_body_font_path=Path("fonts/OpenSans-Regular.ttf"),
primary_color="#1a1a2e"
)
# Si la fuente no existe o es inválida, se usa Helvetica automáticamentefrom qry_doc import ReportTemplate, SectionType, SectionConfig
# Definir orden y contenido de secciones
sections = [
SectionConfig(SectionType.COVER), # Portada
SectionConfig(SectionType.SUMMARY), # Resumen ejecutivo
SectionConfig(SectionType.CHART), # Gráficos
SectionConfig(SectionType.DATA), # Tabla de datos
SectionConfig( # Sección personalizada
SectionType.CUSTOM,
custom_content="Este es contenido adicional personalizado."
),
]
template = ReportTemplate(
cover_image_path=Path("portada.png"),
sections=sections
)
# Desactivar una sección específica
sections_sin_datos = [
SectionConfig(SectionType.SUMMARY),
SectionConfig(SectionType.CHART),
SectionConfig(SectionType.DATA, enabled=False), # No mostrar tabla
]from qry_doc import (
DEFAULT_TEMPLATE, # Estilo profesional estándar
CORPORATE_TEMPLATE, # Azul corporativo
MINIMAL_TEMPLATE, # Minimalista
A4_TEMPLATE, # Tamaño A4 (europeo)
)
qry.generate_report(
"Análisis de mercado",
"analisis.pdf",
template=CORPORATE_TEMPLATE
)from qry_doc import QryDoc
import pandasai as pai
from pandasai_openai import OpenAI
llm = OpenAI()
pai.config.set({"llm": llm})
# Limpieza automática de archivos temporales
with QryDoc("datos.csv", llm=llm) as qry:
respuesta = qry.ask("¿Cuántos registros hay?")
qry.generate_report("Resumen de datos", "resumen.pdf")
# Los archivos temporales se eliminan automáticamenteimport pandasai as pai
from pandasai_openai import OpenAI
llm = OpenAI()
pai.config.set({"llm": llm})
qry = QryDoc("datos.csv", llm=llm)
# Obtener el DataFrame
df = qry.dataframe
# Ver columnas disponibles
print(qry.columns) # ['fecha', 'producto', 'cantidad', 'precio']
# Ver dimensiones
print(qry.shape) # (1000, 4)Clase principal que actúa como punto de entrada (Facade) para toda la funcionalidad.
QryDoc(
data_source: str | Path | DataFrame, # Fuente de datos
llm: Any, # Proveedor LLM
api_key: str | None = None # API key opcional
)Métodos:
| Método | Descripción | Retorno |
|---|---|---|
ask(query) |
Pregunta en lenguaje natural | str |
extract_to_csv(query, path, include_index=False) |
Exporta resultado a CSV | str |
generate_report(query, path, title, template) |
Genera reporte PDF | str |
Propiedades:
| Propiedad | Descripción | Tipo |
|---|---|---|
dataframe |
DataFrame subyacente | pd.DataFrame |
columns |
Nombres de columnas | list[str] |
shape |
Dimensiones (filas, columnas) | tuple[int, int] |
Configuración para personalizar el estilo de reportes PDF.
ReportTemplate(
# Configuración básica
logo_path: Path | None = None, # Ruta al logo del header
primary_color: str = "#1a1a2e", # Color principal (hex)
title_font: str = "Helvetica-Bold", # Fuente de títulos
body_font: str = "Helvetica", # Fuente de cuerpo
page_size: tuple = letter, # Tamaño de página
margin_top: float = 72.0, # Margen superior (puntos)
margin_bottom: float = 72.0, # Margen inferior
margin_left: float = 72.0, # Margen izquierdo
margin_right: float = 72.0, # Margen derecho
# Portada (v0.2.3+)
cover_image_path: Path | None = None, # Imagen de portada a página completa
# Logo en pie de página (v0.2.3+)
footer_logo_path: Path | None = None, # Logo personalizado (None = default)
footer_logo_enabled: bool = True, # Activar/desactivar logo
footer_logo_position: LogoPosition = LogoPosition.BOTTOM_RIGHT,
footer_logo_width: float = 40.0, # Ancho en puntos
footer_logo_height: float = 20.0, # Alto en puntos
# Fuentes personalizadas (v0.2.3+)
custom_title_font_path: Path | None = None, # Fuente TTF/OTF para títulos
custom_body_font_path: Path | None = None, # Fuente TTF/OTF para cuerpo
# Secciones (v0.2.3+)
sections: list[SectionConfig] = [], # Lista de secciones del reporte
)Enum para tipos de secciones disponibles en un reporte.
| Valor | Descripción |
|---|---|
COVER |
Portada con imagen a página completa |
SUMMARY |
Sección de resumen ejecutivo |
DATA |
DataFrame renderizado como tabla |
CHART |
Imagen de gráfico/visualización |
CUSTOM |
Contenido personalizado arbitrario |
Configuración para una sección del reporte.
SectionConfig(
section_type: SectionType, # Tipo de sección
enabled: bool = True, # Si la sección está activa
custom_content: str | None = None, # Contenido para secciones CUSTOM
)Enum para posiciones del logo en el pie de página.
| Valor | Descripción |
|---|---|
BOTTOM_RIGHT |
Esquina inferior derecha (default) |
BOTTOM_LEFT |
Esquina inferior izquierda |
BOTTOM_CENTER |
Centro inferior |
Clase para gestión de assets del paquete (uso avanzado).
from qry_doc import AssetManager
# Obtener ruta al logo por defecto del paquete
default_logo = AssetManager.get_default_logo_path()
# Validar rutas de imágenes
is_valid, error = AssetManager.validate_image_path(Path("imagen.png"))
# Validar rutas de fuentes
is_valid, error = AssetManager.validate_font_path(Path("fuente.ttf"))| Excepción | Descripción |
|---|---|
QryDocError |
Excepción base para todos los errores |
QueryError |
Error al interpretar o ejecutar consulta |
ExportError |
Error al exportar datos |
ReportError |
Error al generar reporte PDF |
DataSourceError |
Error al cargar fuente de datos |
ValidationError |
Error de validación de salidas |
Todas las excepciones incluyen:
user_message: Mensaje amigable para mostrar al usuariointernal_error: Excepción original para debugging
from qry_doc import QryDoc, QueryError
try:
respuesta = qry.ask("consulta ambigua")
except QueryError as e:
print(f"Error: {e.user_message}")
# Logging interno: e.internal_error| Variable | Descripción |
|---|---|
OPENAI_API_KEY |
API key de OpenAI (fallback) |
Por defecto, los CSV se exportan con encoding utf-8-sig (BOM) para compatibilidad con Excel. Esto asegura que caracteres especiales (ñ, acentos, etc.) se muestren correctamente.
- Python 3.11+
- uv (gestor de paquetes)
git clone https://github.com/danro-dev/qry-doc.git
cd qry-doc
uv sync --all-extras# Ejecutar todos los tests
uv run pytest
# Con cobertura
uv run pytest --cov=src/qry_doc --cov-report=html
# Tests específicos
uv run pytest tests/property/test_qrydoc.py -vqry-doc/
├── src/qry_doc/
│ ├── __init__.py # Exports públicos
│ ├── core.py # QryDoc (Facade)
│ ├── ai_adapter.py # PandasAI adapter
│ ├── data_source.py # Carga de datos
│ ├── csv_exporter.py # Exportación CSV
│ ├── report_generator.py # Generación PDF
│ ├── report_template.py # Templates de reportes
│ ├── chart_manager.py # Gestión de gráficos
│ ├── asset_manager.py # Gestión de assets (v0.2.3+)
│ ├── validators.py # Validación y sanitización
│ ├── exceptions.py # Jerarquía de excepciones
│ └── assets/ # Assets del paquete (v0.2.3+)
│ └── default_logo.png # Logo por defecto
├── tests/
│ ├── conftest.py # Fixtures compartidos
│ └── property/ # Property-based tests
├── docs/ # Documentación adicional
├── pyproject.toml
└── README.md
- Soporte para conexiones SQL (PostgreSQL, MySQL, SQLite)
- Caché de consultas para mejorar rendimiento
- Exportación a Excel (.xlsx)
- Más templates predefinidos
- CLI para uso desde terminal
- Integración con Jupyter notebooks
¡Las contribuciones son bienvenidas! Por favor:
- Fork el repositorio
- Crea una rama para tu feature (
git checkout -b feature/nueva-funcionalidad) - Commit tus cambios (
git commit -m 'feat: agregar nueva funcionalidad') - Push a la rama (
git push origin feature/nueva-funcionalidad) - Abre un Pull Request
GPL-3.0 License - ver LICENSE para más detalles.
Hecho con ❤️ por danro-dev
