Metadata-Version: 2.3
Name: qry-doc
Version: 0.1.3
Summary: Motor de análisis generativo que transforma el lenguaje natural en código ejecutable, visualizaciones y reportes PDF profesionales.
Author: danro-dev
Author-email: danro-dev <drgrassnk445@gmail.com>
Requires-Dist: matplotlib>=3.7.5
Requires-Dist: pandasai>=3.0.0
Requires-Dist: pillow>=10.4.0
Requires-Dist: reportlab>=4.4.7
Requires-Dist: sqlalchemy>=2.0.0
Requires-Dist: pandasai-openai>=0.1.0 ; extra == 'all'
Requires-Dist: pandasai-litellm>=0.0.1 ; extra == 'all'
Requires-Dist: psycopg2-binary>=2.9.0 ; extra == 'all'
Requires-Dist: hypothesis>=6.148.8 ; extra == 'dev'
Requires-Dist: pytest>=9.0.2 ; extra == 'dev'
Requires-Dist: pytest-cov>=7.0.0 ; extra == 'dev'
Requires-Dist: pandasai-litellm>=0.0.1 ; extra == 'litellm'
Requires-Dist: pymysql>=1.0.0 ; extra == 'mysql'
Requires-Dist: pandasai-openai>=0.1.0 ; extra == 'openai'
Requires-Dist: psycopg2-binary>=2.9.0 ; extra == 'postgres'
Requires-Python: >=3.11
Provides-Extra: all
Provides-Extra: dev
Provides-Extra: litellm
Provides-Extra: mysql
Provides-Extra: openai
Provides-Extra: postgres
Description-Content-Type: text/markdown

<p align="center">
  <img src="https://raw.githubusercontent.com/danro-dev/qry-proyect-examples/refs/heads/master/public/logo_op.png" alt="qry-doc" width="600" heigt="200">
</p>

<h1 align="center">qry-doc</h1>


<p align="center">
  <strong>Motor de análisis generativo para consultas en lenguaje natural</strong>
</p>

  <a href="#instalación">Instalación</a> 
  
  <a href="#inicio-rápido">Inicio Rápido</a>

  <a href="#características">Características</a>

  <a href="#ejemplos">Ejemplos</a> 

  <a href="#api">API</a> 

  <a href="#contribuir">Contribuir</a>


---

**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.

```python
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")
```

## Características

- 🗣️ **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

### Con uv (recomendado)

```bash
# 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]"
```

### Con pip

```bash
# 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]"
```

### Desde código fuente

```bash
git clone https://github.com/danro-dev/qry-doc.git
cd qry-doc
uv sync
```

## Inicio Rápido

### 1. Configura tu LLM

qry-doc utiliza [PandasAI](https://pandas-ai.com/) como motor de IA. Instala con el extra que necesites:

```bash
# Para OpenAI
pip install "qry-doc[openai]"

# Para múltiples proveedores
pip install "qry-doc[litellm]"
```

```python
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...

### 2. Carga tus datos

```python
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)
```

### 3. Haz preguntas

```python
# 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")
```

## Ejemplos

### Exportar datos a CSV

```python
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
)
```

### Generar reportes PDF

```python
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
)
```

### Reportes con portada personalizada

```python
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
)
```

### Personalización del logo en pie de página

```python
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
)
```

### Fuentes personalizadas (TTF/OTF)

```python
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áticamente
```

### Sistema de secciones personalizadas

```python
from 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
]
```

### Templates predefinidos

```python
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
)
```

### Uso como context manager

```python
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áticamente
```

### Acceso a datos subyacentes

```python
import 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)
```

## API

### QryDoc

Clase principal que actúa como punto de entrada (Facade) para toda la funcionalidad.

```python
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]` |

### ReportTemplate

Configuración para personalizar el estilo de reportes PDF.

```python
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
)
```

### SectionType (v0.2.3+)

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 |

### SectionConfig (v0.2.3+)

Configuración para una sección del reporte.

```python
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
)
```

### LogoPosition (v0.2.3+)

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 |

### AssetManager (v0.2.3+)

Clase para gestión de assets del paquete (uso avanzado).

```python
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"))
```

### Excepciones

| 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 usuario
- `internal_error`: Excepción original para debugging

```python
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
```

## Configuración avanzada

### Variables de entorno

| Variable | Descripción |
|----------|-------------|
| `OPENAI_API_KEY` | API key de OpenAI (fallback) |

### Encoding de archivos

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.

## Desarrollo

### Requisitos

- Python 3.11+
- [uv](https://docs.astral.sh/uv/) (gestor de paquetes)

### Setup

```bash
git clone https://github.com/danro-dev/qry-doc.git
cd qry-doc
uv sync --all-extras
```

### Tests

```bash
# 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 -v
```

### Estructura del proyecto

```
qry-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
```

## Roadmap

- [ ] 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

## Contribuir

¡Las contribuciones son bienvenidas! Por favor:

1. Fork el repositorio
2. Crea una rama para tu feature (`git checkout -b feature/nueva-funcionalidad`)
3. Commit tus cambios (`git commit -m 'feat: agregar nueva funcionalidad'`)
4. Push a la rama (`git push origin feature/nueva-funcionalidad`)
5. Abre un Pull Request

## Licencia

MIT License - ver [LICENSE](LICENSE) para más detalles.

---

<p align="center">
  Hecho con ❤️ por <a href="https://github.com/danro-dev">danro-dev</a>
</p>
