openprompt-lang 1.2.7 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -8
- package/bin/cli.js +2 -0
- package/docs/00-ARCHITECTURE/OPL-BOOST-MULTI-AGENT.md +406 -0
- package/docs/02-STANDARDS/AGENTS.template.md +89 -0
- package/docs/02-STANDARDS/ticket-driven-development.md +99 -0
- package/docs/04-TICKETS/BOOST-001-profile-registry.md +66 -0
- package/docs/04-TICKETS/BOOST-002-context-compression.md +58 -0
- package/docs/04-TICKETS/BOOST-003-template-hydration.md +69 -0
- package/docs/04-TICKETS/BOOST-004-fewshot-engine.md +58 -0
- package/docs/04-TICKETS/BOOST-005-agent-pool.md +69 -0
- package/docs/04-TICKETS/BOOST-006-specialized-agents.md +53 -0
- package/docs/04-TICKETS/BOOST-007-validation-loop.md +56 -0
- package/docs/04-TICKETS/BOOST-008-orchestrator.md +71 -0
- package/docs/04-TICKETS/BOOST-009-cache-system.md +56 -0
- package/docs/04-TICKETS/BOOST-010-cli-mcp.md +67 -0
- package/docs/04-TICKETS/BOOST-011-self-learning.md +50 -0
- package/docs/04-TICKETS/BOOST-012-prompt-preamble.md +109 -0
- package/docs/04-TICKETS/BOOST-013-hydrator-duplicate-code.md +132 -0
- package/docs/04-TICKETS/BOOST-014-multiagent-missing-parts.md +87 -0
- package/docs/04-TICKETS/BOOST-015-skeleton-type-missing.md +76 -0
- package/docs/04-TICKETS/BOOST-016-output-path-duplicate.md +68 -0
- package/docs/04-TICKETS/INDEX.md +89 -0
- package/docs/04-TICKETS/_archive/BOOST-005-micro-tasking.md +67 -0
- package/docs/04-TICKETS/_archive/BOOST-006-validation-loop.md +66 -0
- package/docs/04-TICKETS/_archive/BOOST-007-progressive-pipeline.md +69 -0
- package/docs/04-TICKETS/_archive/BOOST-008-cli-mcp-integration.md +74 -0
- package/docs/AI_CONTEXT.md +16 -0
- package/docs/EMBEDDINGS.md +214 -0
- package/docs/ONBOARDING_WORKFLOW.md +151 -0
- package/docs/OPL_ACADEMIC_ISSUES.md +158 -0
- package/docs/WEB_SCRAPER_PLAN.md +454 -0
- package/package.json +9 -2
- package/scripts/postinstall.js +37 -0
- package/src/boost/agent-pool.js +442 -0
- package/src/boost/agents/index.js +79 -0
- package/src/boost/cache.js +241 -0
- package/src/boost/context-compressor.js +354 -0
- package/src/boost/fewshot-retriever.js +332 -0
- package/src/boost/hardware-detector.js +486 -0
- package/src/boost/hydrator.js +398 -0
- package/src/boost/index.js +60 -0
- package/src/boost/orchestrator.js +615 -0
- package/src/boost/preamble.js +217 -0
- package/src/boost/profile-registry.js +264 -0
- package/src/boost/self-learn.js +247 -0
- package/src/boost/skeletons/component.skeleton.js +24 -0
- package/src/boost/skeletons/hook.skeleton.js +27 -0
- package/src/boost/skeletons/index.js +67 -0
- package/src/boost/skeletons/page.skeleton.js +22 -0
- package/src/boost/skeletons/service.skeleton.js +20 -0
- package/src/boost/skeletons/store.skeleton.js +18 -0
- package/src/boost/skeletons/type.skeleton.js +11 -0
- package/src/boost/task-dispatcher.js +142 -0
- package/src/boost/validation-loop.js +495 -0
- package/src/cli/commands-boost.js +394 -0
- package/src/cli/commands-knowledge.js +1 -0
- package/src/cli/commands-opl.js +79 -1
- package/src/cli/commands-workflow.js +125 -6
- package/src/commands/init-core.js +169 -5
- package/src/commands/knowledge-ops.js +52 -0
- package/src/commands/opl-embeddings.js +556 -0
- package/src/commands/opl-help.js +26 -2
- package/src/commands/opl-search.js +106 -2
- package/src/commands/opl-webscrape.js +390 -0
- package/src/commands/workflow/epic-cli.js +192 -0
- package/src/commands/workflow/select.js +146 -0
- package/src/commands/workflow/sprint-cli.js +174 -0
- package/src/core/webscrape/analyzer.js +481 -0
- package/src/core/webscrape/deep-scraper.js +1027 -0
- package/src/core/workflow/epic-manager.js +845 -0
- package/src/core/workflow/gates.js +180 -1
- package/src/core/workflow/selector.js +707 -0
- package/src/embeddings/chunker.js +450 -0
- package/src/embeddings/embedder.js +431 -0
- package/src/embeddings/index-pipeline.js +320 -0
- package/src/embeddings/vector-store.js +505 -0
- package/src/mcp-refactor/handlers/boost.js +295 -0
- package/src/mcp-refactor/router.js +19 -0
- package/src/mcp-refactor/tools.js +113 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# 🎓 OPL Academic — Bitácora de Problemas
|
|
2
|
+
|
|
3
|
+
> Documento para registrar problemas, fricciones y errores detectados en el sistema de enseñanza (Teaching System) de openPrompt-Lang.
|
|
4
|
+
> Cada entrada documenta: síntoma, causa raíz, impacto, solución propuesta y estado.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 📋 Índice de Problemas
|
|
9
|
+
|
|
10
|
+
| # | Fecha | Título | Severidad | Estado |
|
|
11
|
+
|---|-------|--------|-----------|--------|
|
|
12
|
+
| 1 | 2026-05-24 | Onboarding IA en proyecto existente | 🔴 Alta | Abierto |
|
|
13
|
+
| 2 | 2026-05-24 | `opl rebuild` no detecta OPL automáticamente | 🟡 Media | Abierto |
|
|
14
|
+
| 3 | 2026-05-24 | Falta documento post-init para IA | 🔴 Alta | Abierto |
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 🐛 Problemas Reportados
|
|
19
|
+
|
|
20
|
+
### P-001: Onboarding IA en proyecto existente
|
|
21
|
+
|
|
22
|
+
| Campo | Valor |
|
|
23
|
+
|-------|-------|
|
|
24
|
+
| **Fecha** | 2026-05-24 |
|
|
25
|
+
| **Reportado por** | usuario |
|
|
26
|
+
| **Severidad** | 🔴 Alta |
|
|
27
|
+
| **Módulo** | Academic — Init / Onboarding |
|
|
28
|
+
| **Estado** | 🔴 Abierto |
|
|
29
|
+
|
|
30
|
+
**Síntoma:**
|
|
31
|
+
Al iniciar una sesión con IA en un proyecto existente que ya tiene elementos de OPL, la IA no sabe qué hacer. No hay un punto de entrada claro que le diga "esto ya tiene OPL, aquí está el estado actual, continúa desde aquí".
|
|
32
|
+
|
|
33
|
+
**Causa raíz:**
|
|
34
|
+
No existe un documento de onboarding generado automáticamente que la IA pueda leer al inicio de cada sesión para restaurar contexto.
|
|
35
|
+
|
|
36
|
+
**Impacto:**
|
|
37
|
+
- La IA pierde ~15 minutos regenerando contexto cada sesión
|
|
38
|
+
- Toma decisiones inconsistentes porque no conoce el estado real del proyecto
|
|
39
|
+
- El usuario tiene que re-explicar manualmente lo que ya se hizo
|
|
40
|
+
|
|
41
|
+
**Solución propuesta:**
|
|
42
|
+
- Crear `docs/ONBOARDING_WORKFLOW.md` — documento canónico que la IA lee al iniciar
|
|
43
|
+
- Integrar `opl init` para que genere este documento automáticamente
|
|
44
|
+
- Dos versiones: `INICIAR_NUEVO.md` (proyecto nuevo) e `INICIAR_EXISTENTE.md` (proyecto en curso)
|
|
45
|
+
|
|
46
|
+
**Referencias:**
|
|
47
|
+
- `erroresDeFlujo.md` (línea 2)
|
|
48
|
+
- Sprint embeddings → TICKET-011 (propuesto)
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
### P-002: `opl rebuild` no detecta OPL automáticamente
|
|
53
|
+
|
|
54
|
+
| Campo | Valor |
|
|
55
|
+
|-------|-------|
|
|
56
|
+
| **Fecha** | 2026-05-24 |
|
|
57
|
+
| **Reportado por** | usuario |
|
|
58
|
+
| **Severidad** | 🟡 Media |
|
|
59
|
+
| **Módulo** | CLI — rebuild |
|
|
60
|
+
| **Estado** | 🟡 Abierto |
|
|
61
|
+
|
|
62
|
+
**Síntoma:**
|
|
63
|
+
`opl rebuild` falla o funciona incorrectamente cuando los elementos de OPL no están presentes o no son detectables automáticamente.
|
|
64
|
+
|
|
65
|
+
**Causa raíz:**
|
|
66
|
+
El comando `rebuild` asume cierta estructura pre-existente en lugar de ser autosuficiente.
|
|
67
|
+
|
|
68
|
+
**Solución propuesta:**
|
|
69
|
+
Hacer que `rebuild` funciones en dos modos:
|
|
70
|
+
1. **Con detección**: Si encuentra elementos OPL, los respeta y reconstruye
|
|
71
|
+
2. **Sin detección**: Si no encuentra nada, crea la estructura desde cero con defaults inteligentes
|
|
72
|
+
|
|
73
|
+
**Referencias:**
|
|
74
|
+
- `erroresDeFlujo.md` (línea 4)
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
### P-003: Falta documento post-init para IA
|
|
79
|
+
|
|
80
|
+
| Campo | Valor |
|
|
81
|
+
|-------|-------|
|
|
82
|
+
| **Fecha** | 2026-05-24 |
|
|
83
|
+
| **Reportado por** | usuario |
|
|
84
|
+
| **Severidad** | 🔴 Alta |
|
|
85
|
+
| **Módulo** | CLI — init |
|
|
86
|
+
| **Estado** | 🔴 Abierto |
|
|
87
|
+
|
|
88
|
+
**Síntoma:**
|
|
89
|
+
Después de ejecutar `opl init`, no se genera ningún documento que la IA pueda usar para entender el contexto del proyecto. La IA llega "en frío" a cada sesión.
|
|
90
|
+
|
|
91
|
+
**Causa raíz:**
|
|
92
|
+
`opl init` configura el proyecto (crea prompt-lang.json, AGENTS.md, etc.) pero no genera un punto de entrada específico para la IA que le diga "esto es lo que hay, esto es lo que falta, continúa".
|
|
93
|
+
|
|
94
|
+
**Solución propuesta:**
|
|
95
|
+
Que `opl init` genere automáticamente:
|
|
96
|
+
- `INICIAR_NUEVO.md` si es proyecto nuevo
|
|
97
|
+
- `INICIAR_EXISTENTE.md` si es proyecto existente con OPL
|
|
98
|
+
|
|
99
|
+
Estos documentos deben incluir:
|
|
100
|
+
- Stack detectado
|
|
101
|
+
- Estado de la configuración OPL
|
|
102
|
+
- Próximos pasos recomendados
|
|
103
|
+
- Enlace a `AGENTS.md` y `docs/AI_CONTEXT.md`
|
|
104
|
+
|
|
105
|
+
**Referencias:**
|
|
106
|
+
- `erroresDeFlujo.md` (línea 6)
|
|
107
|
+
- `docs/ONBOARDING_WORKFLOW.md`
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 📊 Estadísticas
|
|
112
|
+
|
|
113
|
+
| Métrica | Valor |
|
|
114
|
+
|---------|-------|
|
|
115
|
+
| Total problemas | 3 |
|
|
116
|
+
| Severidad Alta | 2 |
|
|
117
|
+
| Severidad Media | 1 |
|
|
118
|
+
| Severidad Baja | 0 |
|
|
119
|
+
| Abiertos | 3 |
|
|
120
|
+
| En Progreso | 0 |
|
|
121
|
+
| Resueltos | 0 |
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 📝 Cómo Reportar un Problema Nuevo
|
|
126
|
+
|
|
127
|
+
Usa esta plantilla al añadir una nueva entrada:
|
|
128
|
+
|
|
129
|
+
```markdown
|
|
130
|
+
### P-XXX: Título descriptivo
|
|
131
|
+
|
|
132
|
+
| Campo | Valor |
|
|
133
|
+
|-------|-------|
|
|
134
|
+
| **Fecha** | YYYY-MM-DD |
|
|
135
|
+
| **Reportado por** | — |
|
|
136
|
+
| **Severidad** | 🔴 Alta / 🟡 Media / 🟢 Baja |
|
|
137
|
+
| **Módulo** | — |
|
|
138
|
+
| **Estado** | 🔴 Abierto |
|
|
139
|
+
|
|
140
|
+
**Síntoma:**
|
|
141
|
+
_¿Qué ocurre exactamente?_
|
|
142
|
+
|
|
143
|
+
**Causa raíz:**
|
|
144
|
+
_¿Por qué ocurre?_
|
|
145
|
+
|
|
146
|
+
**Impacto:**
|
|
147
|
+
_¿A quién afecta y cómo?_
|
|
148
|
+
|
|
149
|
+
**Solución propuesta:**
|
|
150
|
+
_¿Cómo se arreglaría?_
|
|
151
|
+
|
|
152
|
+
**Referencias:**
|
|
153
|
+
- _enlaces a código, docs, commits_
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
*Última actualización: 2026-05-24*
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
# Web Scraper Evolution — Plan Ollama-Driven
|
|
2
|
+
|
|
3
|
+
> **Versión:** 2.0 (revisado)
|
|
4
|
+
> **Objetivo:** Reemplazar `opl webscrape` (Readability.js + Turndown) por un extractor
|
|
5
|
+
> **inteligente asistido por Ollama** que analiza la estructura de cada página y genera
|
|
6
|
+
> un plan de extracción personalizado.
|
|
7
|
+
>
|
|
8
|
+
> **Stack:** 100% Node.js + Ollama (local) → Sin dependencia de Python.
|
|
9
|
+
> **Principio:** Cada página es única → cada página merece un plan de extracción único.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. Filosofía: Por qué IA en vez de Reglas Fijas
|
|
14
|
+
|
|
15
|
+
### Enfoque tradicional (hardcoded)
|
|
16
|
+
```python
|
|
17
|
+
# Reglas fijas que fallan en el 50% de las páginas
|
|
18
|
+
extract_og_tags(html)
|
|
19
|
+
extract_metadata(html)
|
|
20
|
+
extract_articles(html)
|
|
21
|
+
extract_tables(html)
|
|
22
|
+
```
|
|
23
|
+
❌ Cada sitio tiene markup distinto → reglas imposibles de mantener
|
|
24
|
+
❌ No entiende el **significado** de las secciones
|
|
25
|
+
❌ No distingue contenido principal de navegación/publicidad
|
|
26
|
+
❌ Cada nuevo tipo de página requiere más reglas
|
|
27
|
+
|
|
28
|
+
### Enfoque Ollama-driven
|
|
29
|
+
```
|
|
30
|
+
fetch(url) → HTML + layout estructurado
|
|
31
|
+
↓
|
|
32
|
+
🧠 Ollama analiza: "¿qué hay aquí?"
|
|
33
|
+
↓
|
|
34
|
+
← plan de extracción JSON ←
|
|
35
|
+
↓
|
|
36
|
+
Ejecuta el plan (selectores dinámicos)
|
|
37
|
+
↓
|
|
38
|
+
knowledge/<domain>/<slug>/
|
|
39
|
+
```
|
|
40
|
+
✅ Se adapta a cualquier página
|
|
41
|
+
✅ Entiende semántica del contenido
|
|
42
|
+
✅ Decide QUÉ extraer según el tipo de página
|
|
43
|
+
✅ Sin reglas hardcodeadas — el LLM decide
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 2. Arquitectura General
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
┌──────────────────────────────────────────────────────────────────┐
|
|
51
|
+
│ Input │
|
|
52
|
+
│ url → fetchPage(url) │
|
|
53
|
+
│ ├── simple: node-fetch (rápido, HTML estático) │
|
|
54
|
+
│ └── headless: @playwright (SPA, JS-heavy, lazy-load) │
|
|
55
|
+
│ │
|
|
56
|
+
│ Resultado: PageSnapshot { html, text, links, meta, ...} │
|
|
57
|
+
└──────────────────┬───────────────────────────────────────────────┘
|
|
58
|
+
↓
|
|
59
|
+
┌──────────────────┴───────────────────────────────────────────────┐
|
|
60
|
+
│ PASO 1: 🧠 Escaneo con Ollama (analyzePage) │
|
|
61
|
+
│ │
|
|
62
|
+
│ Envía a Ollama: │
|
|
63
|
+
│ - Título de la página │
|
|
64
|
+
│ - Meta tags básicos │
|
|
65
|
+
│ - HTML estructural resumido (árbol de secciones, no el HTML │
|
|
66
|
+
│ completo — eso sería demasiado tokens) │
|
|
67
|
+
│ - Texto visible (primeros ~2000 chars) │
|
|
68
|
+
│ - Cantidad y tipos de elementos (cuántos <article>, <section>, │
|
|
69
|
+
│ <table>, <img>, <form>, cards, listas, etc.) │
|
|
70
|
+
│ │
|
|
71
|
+
│ Ollama responde: │
|
|
72
|
+
│ { │
|
|
73
|
+
│ pageType: "article" | "product" | "docs" | "blog" | │
|
|
74
|
+
│ "catalog" | "landing" | "profile" | "generic", │
|
|
75
|
+
│ title: "Título detectado", │
|
|
76
|
+
│ description: "Descripción detectada", │
|
|
77
|
+
│ contentBlocks: [ │
|
|
78
|
+
│ { │
|
|
79
|
+
│ type: "main-content" | "sidebar" | "nav" | "footer" | │
|
|
80
|
+
│ "cards" | "table" | "form" | "gallery", │
|
|
81
|
+
│ selector: "main article", ← selector CSS sugerido │
|
|
82
|
+
│ importance: 1-10, ← qué tan importante │
|
|
83
|
+
│ extractMode: "markdown" | "json" | "table" | "cards", │
|
|
84
|
+
│ description: "El artículo principal con su contenido" │
|
|
85
|
+
│ } │
|
|
86
|
+
│ ], │
|
|
87
|
+
│ metadata: { │
|
|
88
|
+
│ og: true, twitter: true, jsonld: true, microdata: false │
|
|
89
|
+
│ }, │
|
|
90
|
+
│ specialFeatures: ["scroll-infinity", "load-more", │
|
|
91
|
+
│ "pagination", "tabs", "accordion"], │
|
|
92
|
+
│ extractionPlan: { │
|
|
93
|
+
│ steps: ["extract-main-content", "extract-og", │
|
|
94
|
+
│ "extract-images", "extract-tables"], │
|
|
95
|
+
│ outputFormat: "markdown+json" │
|
|
96
|
+
│ } │
|
|
97
|
+
│ } │
|
|
98
|
+
└──────────────────┬───────────────────────────────────────────────┘
|
|
99
|
+
↓
|
|
100
|
+
┌──────────────────┴───────────────────────────────────────────────┐
|
|
101
|
+
│ PASO 2: Ejecutar el plan (executePlan) │
|
|
102
|
+
│ │
|
|
103
|
+
│ Según el plan de Ollama, ejecuta SOLO los extractores │
|
|
104
|
+
│ necesarios para esta página: │
|
|
105
|
+
│ │
|
|
106
|
+
│ ├── main-content: Readability.js + limpieza │
|
|
107
|
+
│ ├── og/twitter/jsonld: extractores específicos (jsdom) │
|
|
108
|
+
│ ├── images: src, alt, caption, dimensiones │
|
|
109
|
+
│ ├── tables: caption + headers + rows (markdown/JSON) │
|
|
110
|
+
│ ├── cards: tarjetas de producto/artículo/post │
|
|
111
|
+
│ ├── forms: action, method, inputs │
|
|
112
|
+
│ └── special: auto-scroll, load-more, pagination │
|
|
113
|
+
│ │
|
|
114
|
+
│ Resultado: ExtractedPage { ... } │
|
|
115
|
+
└──────────────────┬───────────────────────────────────────────────┘
|
|
116
|
+
↓
|
|
117
|
+
┌──────────────────┴───────────────────────────────────────────────┐
|
|
118
|
+
│ PASO 3: Post-procesamiento (postProcess) │
|
|
119
|
+
│ │
|
|
120
|
+
│ ├── Convertir a markdown estructurado │
|
|
121
|
+
│ ├── Clasificar contenido (dominio OPL) │
|
|
122
|
+
│ ├── Generar resumen con Ollama (opcional) │
|
|
123
|
+
│ ├── Generar embeddings vía pipeline existente │
|
|
124
|
+
│ └── Guardar en knowledge/<domain>/<slug>/ │
|
|
125
|
+
│ ├── page.md ← markdown completo │
|
|
126
|
+
│ ├── metadata.json ← datos estructurados │
|
|
127
|
+
│ ├── plan.json ← el plan que usó Ollama │
|
|
128
|
+
│ └── embeddings.json ← vectores │
|
|
129
|
+
└──────────────────────────────────────────────────────────────────┘
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 3. Componentes a Implementar
|
|
135
|
+
|
|
136
|
+
### 3.1 Core (`src/core/webscrape/`)
|
|
137
|
+
|
|
138
|
+
| Archivo | Descripción | Deps |
|
|
139
|
+
|---------|-------------|------|
|
|
140
|
+
| `analyzer.js` | Envía estructura de página a Ollama, recibe plan JSON | `@xenova/transformers`? No, es puro Ollama API |
|
|
141
|
+
| `executor.js` | Ejecuta el plan de extracción paso a paso | `jsdom` |
|
|
142
|
+
| `fetcher.js` | Fetch de página (simple + headless) | `node-fetch`, `playwright` (opt) |
|
|
143
|
+
| `models.js` | PageSnapshot, ExtractPlan, ExtractedPage, PageType | — |
|
|
144
|
+
| `postprocessor.js` | Markdown, metadata, embeddings, guardado | — |
|
|
145
|
+
| `config.js` | URL de Ollama, timeouts, modelos, cache | — |
|
|
146
|
+
|
|
147
|
+
### 3.2 Extractores (`src/core/webscrape/extractors/`)
|
|
148
|
+
|
|
149
|
+
| Archivo | Descripción |
|
|
150
|
+
|---------|-------------|
|
|
151
|
+
| `extract-content.js` | Extrae contenido principal (Readability.js mejorado) |
|
|
152
|
+
| `extract-og.js` | Open Graph + Twitter Cards |
|
|
153
|
+
| `extract-jsonld.js` | JSON-LD structured data |
|
|
154
|
+
| `extract-microdata.js` | Microdata / schema.org |
|
|
155
|
+
| `extract-images.js` | Imágenes con alt, caption, dimensiones |
|
|
156
|
+
| `extract-tables.js` | Tablas con caption, headers, rows |
|
|
157
|
+
| `extract-cards.js` | Tarjetas de producto/artículo/post |
|
|
158
|
+
| `extract-forms.js` | Formularios con campos |
|
|
159
|
+
| `extract-special.js` | Load-more, paginación, scroll infinito |
|
|
160
|
+
|
|
161
|
+
### 3.3 CLI (`src/commands/opl-webscrape.js`)
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
opl webscrape <url> # Modo normal (Ollama analyze + execute)
|
|
165
|
+
opl webscrape <url> --plan-only # Solo mostrar el plan de Ollama, no ejecutar
|
|
166
|
+
opl webscrape <url> --plan <plan.json> # Usar un plan guardado (re-ejecutar)
|
|
167
|
+
opl webscrape <url> --simple # Forzar Readability.js (sin Ollama)
|
|
168
|
+
opl webscrape <url> --headless # Forzar Playwright (para SPAs)
|
|
169
|
+
opl webscrape <url> --output json # Salida JSON estructurada
|
|
170
|
+
opl webscrape <url> --no-embeddings # No generar embeddings
|
|
171
|
+
opl webscrape <url> --dry-run # Mostrar plan sin guardar
|
|
172
|
+
opl webscrape plan <url> # Shorthand para --plan-only
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 4. Prompt de Análisis (Ollama)
|
|
178
|
+
|
|
179
|
+
El prompt que se envía a Ollama es **la pieza clave**. Debe ser:
|
|
180
|
+
|
|
181
|
+
- Compacto (no enviar HTML completo — solo resumen estructural)
|
|
182
|
+
- Rico en señales semánticas (tipo de elementos, no su contenido)
|
|
183
|
+
- Determinista en la respuesta (JSON estructurado)
|
|
184
|
+
|
|
185
|
+
### Formato del prompt
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
Eres un analista de páginas web. Tu trabajo es examinar la estructura
|
|
189
|
+
de una página web y generar un plan de extracción.
|
|
190
|
+
|
|
191
|
+
## Información de la página
|
|
192
|
+
URL: {url}
|
|
193
|
+
Título: {title}
|
|
194
|
+
Meta description: {description}
|
|
195
|
+
Tamaño HTML: {htmlSize} chars
|
|
196
|
+
|
|
197
|
+
## Resumen estructural
|
|
198
|
+
- Tipo de elementos en la página:
|
|
199
|
+
{summary: article: 3, section: 5, nav: 1, main: 1, aside: 2,
|
|
200
|
+
footer: 1, table: 1, form: 0, img: 12, video: 0, article_card: 6,
|
|
201
|
+
list: 4, breadcrumb: 0}
|
|
202
|
+
- Primeros 2000 caracteres del texto visible:
|
|
203
|
+
"{truncatedText}"
|
|
204
|
+
|
|
205
|
+
## Enlaces principales (primeros 10)
|
|
206
|
+
{links: [
|
|
207
|
+
{href: "/articulo-1", text: "Cómo hacer X", type: "internal"},
|
|
208
|
+
{href: "/categoria/y", text: "Categoría Y", type: "internal"},
|
|
209
|
+
...
|
|
210
|
+
]}
|
|
211
|
+
|
|
212
|
+
## Meta tags encontrados
|
|
213
|
+
{meta: {
|
|
214
|
+
og: ["og:title", "og:description", "og:image"],
|
|
215
|
+
twitter: ["twitter:card", "twitter:site"],
|
|
216
|
+
jsonld: true,
|
|
217
|
+
microdata: false
|
|
218
|
+
}}
|
|
219
|
+
|
|
220
|
+
## Instrucciones
|
|
221
|
+
Analiza esta página y devuelve un JSON con:
|
|
222
|
+
1. pageType: qué tipo de página es
|
|
223
|
+
2. contentBlocks: qué bloques de contenido identificas y cómo extraerlos
|
|
224
|
+
3. extractionPlan: pasos concretos a seguir
|
|
225
|
+
4. metadata: qué meta tags extraer
|
|
226
|
+
5. specialFeatures: si hay scroll infinito, load-more, paginación, etc.
|
|
227
|
+
|
|
228
|
+
Responde ÚNICAMENTE con el JSON. No incluyas explicaciones.
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Respuesta esperada
|
|
232
|
+
|
|
233
|
+
```json
|
|
234
|
+
{
|
|
235
|
+
"pageType": "article",
|
|
236
|
+
"confidence": 0.92,
|
|
237
|
+
"title": "Cómo implementar un scraper con IA",
|
|
238
|
+
"description": "Guía paso a paso para construir un extractor web inteligente",
|
|
239
|
+
"contentBlocks": [
|
|
240
|
+
{
|
|
241
|
+
"type": "main-content",
|
|
242
|
+
"selector": "main article",
|
|
243
|
+
"importance": 10,
|
|
244
|
+
"extractMode": "markdown",
|
|
245
|
+
"description": "Artículo principal con contenido completo"
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"type": "sidebar",
|
|
249
|
+
"selector": "aside.related-posts",
|
|
250
|
+
"importance": 3,
|
|
251
|
+
"extractMode": "links",
|
|
252
|
+
"description": "Artículos relacionados en la barra lateral"
|
|
253
|
+
}
|
|
254
|
+
],
|
|
255
|
+
"metadata": {
|
|
256
|
+
"og": true,
|
|
257
|
+
"twitter": true,
|
|
258
|
+
"jsonld": true,
|
|
259
|
+
"microdata": false,
|
|
260
|
+
"priority": ["og:title", "og:description", "og:image"]
|
|
261
|
+
},
|
|
262
|
+
"specialFeatures": [],
|
|
263
|
+
"extractionPlan": {
|
|
264
|
+
"steps": [
|
|
265
|
+
"extract-main-content",
|
|
266
|
+
"extract-og",
|
|
267
|
+
"extract-jsonld",
|
|
268
|
+
"extract-images"
|
|
269
|
+
],
|
|
270
|
+
"outputFormat": "markdown+json",
|
|
271
|
+
"notes": "Página de blog estándar con contenido principal rico en imágenes"
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## 5. Integración con el Sistema OPL Existente
|
|
279
|
+
|
|
280
|
+
### Pipeline completo con embeddings
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
cli: opl webscrape https://ejemplo.com/articulo
|
|
284
|
+
↓
|
|
285
|
+
fetcher.fetch(url) → PageSnapshot { html, text, links, meta, elementCounts }
|
|
286
|
+
↓
|
|
287
|
+
analyzer.analyze(snapshot, ollama) → ExtractPlan { pageType, blocks, steps }
|
|
288
|
+
↓
|
|
289
|
+
executor.execute(html, plan) → ExtractedPage { content, metadata, media, ... }
|
|
290
|
+
↓
|
|
291
|
+
postprocessor.process(extracted) → { markdown, metadata, cards }
|
|
292
|
+
↓
|
|
293
|
+
→ knowledge/<domain>/<slug>/page.md
|
|
294
|
+
→ knowledge/<domain>/<slug>/metadata.json
|
|
295
|
+
→ knowledge/<domain>/<slug>/plan.json
|
|
296
|
+
→ knowledge/<domain>/<slug>/cards.json (si aplica)
|
|
297
|
+
↓
|
|
298
|
+
embedder.indexDocument(slug) ← pipeline de embeddings existente
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Reutilización de infraestructura existente
|
|
302
|
+
|
|
303
|
+
| Componente OPL existente | Se reutiliza |
|
|
304
|
+
|--------------------------|:------------:|
|
|
305
|
+
| `src/embeddings/pipeline.js` | ✅ Indexación automática |
|
|
306
|
+
| `src/embeddings/sqlite-store.js` | ✅ Cache + almacenamiento |
|
|
307
|
+
| `src/commands/opl-webscrape.js` | ✅ Refactorizado como entry point |
|
|
308
|
+
| `src/cli/commands-opl.js` | ✅ Flags nuevos (`--plan-only`, `--headless`) |
|
|
309
|
+
| Readability.js + Turndown | ✅ Como extractores de contenido (PASO 2) |
|
|
310
|
+
| `opl knowledge` | ✅ Integración con knowledge base |
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## 6. Estrategia de Implementación por Fases
|
|
315
|
+
|
|
316
|
+
| Fase | Qué se hace | Archivos | Esfuerzo |
|
|
317
|
+
|------|-------------|----------|:--------:|
|
|
318
|
+
| **F0** | Models + Fetcher | `models.js`, `fetcher.js`, `config.js` | 1 día |
|
|
319
|
+
| **F1** | **Analyzer (Ollama) — el corazón** | `analyzer.js`, prompt template | 2-3 días |
|
|
320
|
+
| **F2** | Executor básico (main-content + og + jsonld) | `executor.js`, `extract-content.js`, `extract-og.js`, `extract-jsonld.js` | 3-4 días |
|
|
321
|
+
| **F3** | Extractores avanzados (images, tables, cards, forms) | `extract-images.js`, `extract-tables.js`, `extract-cards.js`, `extract-forms.js` | 3-4 días |
|
|
322
|
+
| **F4** | Post-processor + integración knowledge/embeddings | `postprocessor.js`, refactor `opl-webscrape.js` | 2 días |
|
|
323
|
+
| **F5** | Headless browser (Playwright opcional) | `fetcher.js` (modo headless), `extract-special.js` | 2 días |
|
|
324
|
+
| **F6** | Tests + documentación + CLI flags | tests, docs, `commands-opl.js` | 2 días |
|
|
325
|
+
|
|
326
|
+
**Total estimado:** 2-3 semanas (trabajo parcial, OLLAMA-first)
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## 7. Beneficios Clave del Enfoque IA
|
|
331
|
+
|
|
332
|
+
| Aspecto | Readability.js | Scraper Python hardcoded | **Ollama-driven (esta propuesta)** |
|
|
333
|
+
|---------|:--------------:|:------------------------:|:----------------------------------:|
|
|
334
|
+
| **Adaptabilidad** | Solo artículos | Media (reglas fijas) | **Alta (analiza cada página)** |
|
|
335
|
+
| **Clasificación** | No | Heurística | **IA entiende el tipo** |
|
|
336
|
+
| **Metadata** | Mínima | Completa | **Selectiva (solo lo relevante)** |
|
|
337
|
+
| **SPA/JS** | No | Sí (Playwright) | **Sí (Playwright opcional)** |
|
|
338
|
+
| **Mantenimiento** | Nulo | Alto (nuevas reglas) | **Bajo (mejora el prompt)** |
|
|
339
|
+
| **Precisión** | 60-70% | 70-85% | **85-95% (IA entiende contexto)** |
|
|
340
|
+
| **Cobertura** | Blogs/news | Sitios conocidos | **Cualquier página web** |
|
|
341
|
+
| **Dependencias** | Mínimas | Python + librerías | **Node.js + Ollama** |
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## 8. Riesgos y Mitigaciones
|
|
346
|
+
|
|
347
|
+
| Riesgo | Probabilidad | Impacto | Mitigación |
|
|
348
|
+
|--------|:------------:|:-------:|------------|
|
|
349
|
+
| Ollama no disponible | Alta | Alto | Fallback automático a Readability.js + Turndown |
|
|
350
|
+
| Prompts largos (>4K tokens) | Media | Medio | Resumir HTML estructuralmente (árbol, no HTML crudo) |
|
|
351
|
+
| Respuesta JSON malformada de Ollama | Media | Medio | Validar JSON + reintentar con `--strict` |
|
|
352
|
+
| Páginas con anti-bot | Media | Alto | Modo headless + User-Agent rotación |
|
|
353
|
+
| Latencia (Ollama analyse = 2-5s) | Alta | Bajo | Cache de planes por dominio + extracción async |
|
|
354
|
+
| Precisión del plan depende del modelo | Alta | Medio | Usar modelos >= 7B (phi-4, llama3.2, qwen2.5) |
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
## 9. Comandos Futuros (Post-F6)
|
|
359
|
+
|
|
360
|
+
```bash
|
|
361
|
+
# Extracción básica con IA
|
|
362
|
+
opl webscrape https://ejemplo.com
|
|
363
|
+
|
|
364
|
+
# Solo ver el plan que Ollama generaría (sin extraer)
|
|
365
|
+
opl webscrape https://ejemplo.com --plan-only
|
|
366
|
+
|
|
367
|
+
# Re-ejecutar con un plan guardado
|
|
368
|
+
opl webscrape https://ejemplo.com --plan ./plan.json
|
|
369
|
+
|
|
370
|
+
# Crawl completo de un sitio con IA por página
|
|
371
|
+
opl webscrape https://ejemplo.com --crawl --depth 2
|
|
372
|
+
|
|
373
|
+
# Forzar Playwright para SPAs pesados
|
|
374
|
+
opl webscrape https://spa-ejemplo.com --headless
|
|
375
|
+
|
|
376
|
+
# Salida JSON para pipeline
|
|
377
|
+
opl webscrape https://ejemplo.com --output json
|
|
378
|
+
|
|
379
|
+
# Forzar Readability.js (sin IA)
|
|
380
|
+
opl webscrape https://ejemplo.com --simple
|
|
381
|
+
|
|
382
|
+
# Extraer diseño visual (colores, tipografía, componentes)
|
|
383
|
+
opl webscrape https://ejemplo.com --extract-design
|
|
384
|
+
|
|
385
|
+
# Ver el prompt que se envía a Ollama
|
|
386
|
+
opl webscrape https://ejemplo.com --debug-prompt
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## 10. Primeros Pasos Concretos
|
|
392
|
+
|
|
393
|
+
### Fase 0: Preparación
|
|
394
|
+
|
|
395
|
+
1. Verificar que Ollama corre localmente:
|
|
396
|
+
```bash
|
|
397
|
+
curl http://localhost:11434/api/tags
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
2. Elegir modelo base (recomendado: `phi-4:14b` o `llama3.2:8b`):
|
|
401
|
+
```bash
|
|
402
|
+
ollama pull phi-4:14b # Buen balance calidad/velocidad
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
3. Crear estructura de directorios:
|
|
406
|
+
```
|
|
407
|
+
src/core/webscrape/
|
|
408
|
+
├── index.js # Re-export
|
|
409
|
+
├── config.js # Ollama URL, modelo, timeouts
|
|
410
|
+
├── models.js # PageSnapshot, ExtractPlan, ExtractedPage
|
|
411
|
+
├── fetcher.js # node-fetch + Playwright opcional
|
|
412
|
+
├── analyzer.js # Ollama prompt + parseo JSON
|
|
413
|
+
├── executor.js # Ejecuta plan paso a paso
|
|
414
|
+
├── postprocessor.js # Markdown + metadata + guardado
|
|
415
|
+
└── extractors/
|
|
416
|
+
├── extract-content.js
|
|
417
|
+
├── extract-og.js
|
|
418
|
+
├── extract-jsonld.js
|
|
419
|
+
├── extract-images.js
|
|
420
|
+
├── extract-tables.js
|
|
421
|
+
└── ...
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
4. Implementar `models.js` + `config.js` + `fetcher.js` (F0, 1 día)
|
|
425
|
+
|
|
426
|
+
### Fase 1: Analyzer (el corazón)
|
|
427
|
+
|
|
428
|
+
5. Implementar `analyzer.js`:
|
|
429
|
+
- Construir resumen estructural del HTML (árbol de secciones, conteo de elementos)
|
|
430
|
+
- Extraer texto visible (primeros ~2000 chars)
|
|
431
|
+
- Detectar meta tags OG, Twitter, JSON-LD
|
|
432
|
+
- Enviar prompt a Ollama (`POST /api/generate`)
|
|
433
|
+
- Parsear y validar respuesta JSON
|
|
434
|
+
- Cachear plan por URL en SQLite
|
|
435
|
+
|
|
436
|
+
6. Probar con 5 tipos de página distintos (article, product, docs, blog, landing)
|
|
437
|
+
|
|
438
|
+
### Fase 2: Executor básico
|
|
439
|
+
|
|
440
|
+
7. Implementar extractores core + `executor.js`
|
|
441
|
+
8. Probar end-to-end con `opl webscrape <url>`
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## 11. Medición de Éxito
|
|
446
|
+
|
|
447
|
+
| Métrica | Objetivo | Cómo se mide |
|
|
448
|
+
|---------|:--------:|--------------|
|
|
449
|
+
| Precisión del plan | >90% | Validación manual de 50 páginas |
|
|
450
|
+
| Tiempo total por URL | <10s | Benchmark automático |
|
|
451
|
+
| Fallback a Readability | <20% de los casos | Log de modo usado |
|
|
452
|
+
| Tokens por análisis | <3000 | Prompt logging |
|
|
453
|
+
| Cobertura de tipos de página | >80% | Test con 100 URLs diversas |
|
|
454
|
+
| Embeddings generados por scraper | >90% de URLs | Pipeline count |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openprompt-lang",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "PromptLang CLI — Context Engine de anotaciones para desarrollo asistido por IA",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./bin/cli.js",
|
|
@@ -55,7 +55,8 @@
|
|
|
55
55
|
"opencode:wizard": "openprompt-lang wizard",
|
|
56
56
|
"opencode:plan": "openprompt-lang plan",
|
|
57
57
|
"opencode:execute": "openprompt-lang execute",
|
|
58
|
-
"opencode:mode": "openprompt-lang mode"
|
|
58
|
+
"opencode:mode": "openprompt-lang mode",
|
|
59
|
+
"opl:enforce": "node scripts/opl-enforce-setup.mjs"
|
|
59
60
|
},
|
|
60
61
|
"keywords": [
|
|
61
62
|
"prompt-lang",
|
|
@@ -72,14 +73,17 @@
|
|
|
72
73
|
"node": ">=18"
|
|
73
74
|
},
|
|
74
75
|
"dependencies": {
|
|
76
|
+
"@mozilla/readability": "^0.6.0",
|
|
75
77
|
"ajv": "^8.20.0",
|
|
76
78
|
"better-sqlite3": "^12.10.0",
|
|
77
79
|
"chalk": "^5.3.0",
|
|
78
80
|
"commander": "^12.0.0",
|
|
79
81
|
"handlebars": "^4.7.9",
|
|
80
82
|
"inquirer": "^9.3.0",
|
|
83
|
+
"jsdom": "^29.1.1",
|
|
81
84
|
"pdf-parse": "^2.4.5",
|
|
82
85
|
"tesseract.js": "^7.0.0",
|
|
86
|
+
"turndown": "^7.2.4",
|
|
83
87
|
"typescript": "^6.0.3"
|
|
84
88
|
},
|
|
85
89
|
"devDependencies": {
|
|
@@ -105,5 +109,8 @@
|
|
|
105
109
|
"*.{ts,tsx,js,jsx}": [
|
|
106
110
|
"openprompt-lang lint-file"
|
|
107
111
|
]
|
|
112
|
+
},
|
|
113
|
+
"optionalDependencies": {
|
|
114
|
+
"@xenova/transformers": "^2.17.2"
|
|
108
115
|
}
|
|
109
116
|
}
|