tmwk / pdf-section-splitter-bundle
Bundle desacoplado para Symfony 5.4+ / PHP 8.1+ que segmenta determinísticamente fichas técnicas en PDF en secciones según características tipográficas y genera tablas HTML semánticas.
Package info
bitbucket.org/tmwk/pdf-section-splitter-bundle
Type:symfony-bundle
pkg:composer/tmwk/pdf-section-splitter-bundle
Requires
- php: >=8.1
- smalot/pdfparser: ^2.0 || ^2.13
- symfony/config: ^5.4 || ^6.0 || ^7.0
- symfony/dependency-injection: ^5.4 || ^6.0 || ^7.0
- symfony/http-foundation: ^5.4 || ^6.0 || ^7.0
- symfony/http-kernel: ^5.4 || ^6.0 || ^7.0
Requires (Dev)
- phpunit/phpunit: ^9.5 || ^10.0
Suggests
- tmwk/openai: Permite segmentación y extracción semántica automática mediante OpenAI GPT-4o-mini
Provides
None
Conflicts
None
Replaces
None
README
Bundle reutilizable y desacoplado para Symfony 5.4+ y PHP 8.1+ diseñado para procesar fichas técnicas y documentos en formato PDF, segmentándolos en secciones deterministas según sus características tipográficas (tamaño relativo de fuente, matrices de escala tipográfica y coordenadas espaciales) y convirtiendo bloques tabulares en tablas HTML semánticas (<table>).
100% Determinista en local: No requiere conexión a servicios externos de IA ni APIs de terceros.
Características
- Segmentación Dinámica e Inteligente: Detecta automáticamente el tamaño tipográfico base (moda estadística) y calcula el umbral de títulos de secciones (
base_font_size * font_threshold_ratio). - Detección y Renderizado de Tablas HTML: Convierte automáticamente grillas y listas de columnas tabulares en etiquetas HTML semánticas (
<table class="table table-bordered table-sm">,<th>,<td>). - Preservación Integral de Texto: Mantiene párrafos explicativos anteriores o posteriores a las tablas sin truncamientos ni pérdida de contenido.
- Filtro de Ruido Tipográfico: Omite automáticamente números de página ("Pág 1 de 3", "Página 1", etc.), membretes repetitivos y notas al pie sin eliminar palabras clave válidas en el cuerpo del texto.
- Salida Estandarizada en JSON: Estructura limpia y lista para persistencia en base de datos o APIs REST.
Requisitos
- PHP 8.1 o superior
- Symfony 5.4, 6.x o 7.x
- Extensión
ext-jsonyext-mbstring smalot/pdfparser: ^2.0
Instalación
Instala el bundle en tu proyecto vía Composer:
composer require tmwk/pdf-section-splitter-bundle
Habilitar el Bundle (si no usas Symfony Flex)
Si Symfony Flex no agrega el bundle automáticamente, regístralo en config/bundles.php:
// config/bundles.php
return [
// ...
TMWK\PdfSectionSplitterBundle\TMWKPdfSectionSplitterBundle::class => ['all' => true],
];
Configuración Opcional
Puedes configurar el comportamiento en config/packages/tmwk_pdf_section_splitter.yaml:
tmwk_pdf_section_splitter:
font_threshold_ratio: 1.15 # Multiplicador sobre la fuente base para calificar un texto como título de sección
use_ai: false # Si es true y tmwk/openai está instalado, procesa mediante OpenAI
Uso con Inteligencia Artificial (Opcional)
Si tienes instalado el bundle tmwk/openai (TMWK\OpenAIBundle\Service\OpenAIContentGenerator), puedes habilitar el procesamiento por IA globalmente en el YAML (use_ai: true) o a demanda por llamada:
// Procesar usando IA a demanda (tercer parámetro $useAi):
$jsonResult = $this->pdfSectionSplitter->splitToJson($uploadedFile, customThresholdRatio: null, useAi: true);
Uso
Inyección de Dependencias (Recomendado)
Inyecta el servicio TMWK\PdfSectionSplitterBundle\Service\PdfSectionSplitter en tus controladores, comandos de consola o servicios:
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use TMWK\PdfSectionSplitterBundle\Service\PdfSectionSplitter;
class TechnicalSheetController extends AbstractController
{
public function __construct(
private readonly PdfSectionSplitter $pdfSectionSplitter
) {
}
#[Route('/api/sheets/parse', name: 'api_sheets_parse', methods: ['POST'])]
public function parse(Request $request): JsonResponse
{
$uploadedFile = $request->files->get('pdf_file');
if (!$uploadedFile) {
return new JsonResponse(['error' => 'No se adjuntó ningún archivo PDF.'], Response::HTTP_BAD_REQUEST);
}
// Procesa directamente una instancia de UploadedFile, File o una ruta string absoluta
$jsonResult = $this->pdfSectionSplitter->splitToJson($uploadedFile);
return JsonResponse::fromJsonString($jsonResult, Response::HTTP_OK);
}
}
Uso Directo / Manual
use TMWK\PdfSectionSplitterBundle\Service\PdfSectionSplitter;
$splitter = new PdfSectionSplitter(
defaultFontThresholdRatio: 1.15
);
// 1. Con ruta local absoluta
$jsonString = $splitter->splitToJson('/ruta/a/mi-ficha-tecnica.pdf');
// 2. Con URL remota (descarga segura en temporal, valida magic bytes %PDF- y limpia automáticamente)
$jsonString = $splitter->splitToJson('https://mi-servidor.com/archivos/ficha-tecnica.pdf');
// 3. Con instancia UploadedFile de Symfony
$jsonString = $splitter->splitToJson($uploadedFile);
$data = json_decode($jsonString, true);
Formato del JSON de Salida
El método splitToJson() devuelve una cadena JSON con la siguiente estructura:
{
"document_title": "SPRAY GALVANIZADO EN FRIO",
"used_ai": false,
"base_font_size": 11,
"total_sections": 5,
"sections": [
{
"section_title": "Descripción del producto",
"content": "Imprimante anticorrosivo formulado en base a resinas especiales..."
},
{
"section_title": "Propiedades",
"content": "<table class=\"table table-bordered table-sm\">\n <tr>\n <th>Propiedad</th>\n <th>Descripción</th>\n </tr>\n <tr>\n <td>Colores</td>\n <td>Gris galvanizado</td>\n </tr>\n</table>"
},
{
"section_title": "Preparación de Superficies",
"content": "Para asegurar una adecuada adherencia, las superficies deben estar limpias...\n\n<table class=\"table table-bordered table-sm\">\n <tr>\n <th>Sustrato</th>\n <th>Preparación</th>\n </tr>\n <tr>\n <td>Acero</td>\n <td>Chorreado abrasivo Sa 2 ½...</td>\n </tr>\n</table>"
}
]
}
Licencia
Este proyecto está bajo la licencia MIT.