Lecto- (lectura, texto, lo legible) + -grafo (trazar, representar): "lo que grafica la lectura". Sistema local y soberano para extraer y visualizar grafos conceptuales desde transcripciones de analisis filosoficos.
- Ingesta una transcripcion (texto plano, VTT o subtitulos de YouTube).
- Normaliza el texto y conserva timestamps cuando estan disponibles; el texto fuente se puede editar en cualquier momento, con historial de revisiones y re-normalizacion.
- Pide a un LLM que extraiga conceptos, relaciones, sinonimia candidata, bidireccionalidad, metalenguaje y bucles, mostrando el grafo emerger en vivo lote a lote.
- Presenta puntos de decision al investigador para validar caso a caso.
- Persiste el grafo refinado en un JSON versionable.
- Detecta nodos sueltos y propone reconectarlos (getYourStuffTogether), y detecta conceptos duplicados para fusionarlos en un nodo canonico (consolidacion de sinonimos) — ambos flujos via LLM con revision humana.
- Visualiza el grafo en un mapa interactivo, alternando entre vista 2D (D3/SVG) y 3D (three.js): resalta el concepto seleccionado, aisla su vecindad al pasar el mouse y atenua el resto.
- Permite crear y editar grafos personales del investigador, independientes de cualquier transcripcion.
- Permite anotar, exportar y publicar versiones inmutables del grafo.
- Local y soberano: los datos viven en el repo. Sin servicios SaaS de almacenamiento ni base de datos.
- Multi-provider para el LLM: Anthropic, OpenAI o Gemini se eligen en
.env. Sin default. - Comportamiento antes que implementacion: el contrato del sistema vive en
specs/escrito en Allium. El codigo es la expresion de esa especificacion. - Iterativo: el LLM propone, el investigador refina. El sistema preserva la trazabilidad de cada decision.
lectografo/
├── README.md
├── .env.example Plantilla de variables; nunca commitear .env real
├── .gitignore
├── specs/ Especificaciones Allium (lenguaje de comportamiento)
│ ├── lectografo.allium Modulo raiz: scope, given, config, defaults
│ ├── transcripcion.allium
│ ├── edicion-texto.allium Edicion del texto fuente y re-normalizacion
│ ├── extraccion.allium
│ ├── extraccion-incremental.allium
│ ├── procesamiento-visible.allium Emergencia visual del grafo durante la extraccion
│ ├── validacion.allium
│ ├── grafo.allium
│ ├── getYourStuffTogether.allium Reconexion de nodos sueltos
│ ├── grafos-personales.allium
│ └── surfaces.allium
├── transcripts/ Transcripciones crudas (.txt, .vtt) ingresadas por el investigador
├── data/
│ └── grafos/ Grafos persistidos en JSON, una version por archivo
├── prompts/ Plantillas de prompts versionadas (Markdown)
├── static/ Frontend: HTML/CSS/JS vanilla, mapa D3 (2D) y three.js (3D)
└── src/
├── app.py FastAPI: rutas y orquestacion
├── llm/ Providers intercambiables (Anthropic, OpenAI, Gemini, Ollama)
├── models/ Modelos Pydantic (grafo, validacion, reconexion, consolidacion...)
├── persistencia/ Lectura/escritura de estado en data/
└── pipeline/ Extraccion, validacion, reconexion, consolidacion, grafo
Python con FastAPI para todo el backend (ingesta, extraccion LLM, persistencia, servir el frontend estatico). Frontend D3 vanilla servido como HTML+JS estatico desde el mismo proceso.
Razones que justifican esta eleccion:
- Ecosistema NLP maduro:
yt-dlppara descarga de YouTube,faster-whisperpara transcripcion local cuando hace falta, librerias estables para limpieza de texto y parsing VTT. - Runtime unico: un solo
pythoncorre el pipeline, el servidor y los scripts de mantenimiento. Reduce dependencias y simplifica elrequirements.txt. - Frontend sin bundler: D3 y three.js/3d-force-graph cargados por CDN (via import map) evitan el ciclo de build de un frontend Node.js. El investigador puede abrir el HTML directamente si quisiera.
- SDK oficiales para LLM: Anthropic, OpenAI y Google publican SDK Python que se intercambian detras de una interfaz
LLMProvider.
La alternativa Node.js queda descartada por menor disponibilidad de utilidades de transcripcion local. La opcion hibrida (Node frontend + Python pipeline) anade complejidad sin beneficio observable a este alcance.
# 1. Clonar e instalar
git clone <repo> lectografo && cd lectografo
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# 2. Configurar
cp .env.example .env # editar con tu proveedor LLM
# 3. Arrancar
./run.sh # o: make run
# → http://localhost:8000Desde la interfaz web puedes añadir transcripciones en transcripts/ y lanzar
la extraccion con el boton "Procesar". Tambien puedes usar la linea de comandos:
make extraer TEXTO=transcripts/mi-charla.txt # extrae y guarda
make actualizar TEXTO=transcripts/mi-charla.txt # re-extrae preservando validacion
make estado # lista transcripts y extracciones
make ayuda # lista todos los comandosLee specs/lectografo.allium para entender el comportamiento esperado del sistema.
El comportamiento esta definido en specs/ (Allium v3). Cualquier ambiguedad debe resolverse contra esos archivos, no contra esta descripcion en prosa.
La app es stateful (guarda archivos en data/grafos/ y transcripts/), por lo
que necesita almacenamiento persistente. Opciones recomendadas:
Fly.io (recomendado para uso personal):
fly launch --no-deploy
# editar fly.toml: añadir un volumen persistente para data/ y transcripts/
fly deployVPS propio (control total):
# En el servidor, con systemd o supervisord apuntando a: make run
uvicorn src.app:app --host 0.0.0.0 --port 8000Render / Railway: Requieren configurar un disco persistente para data/.
Sin persistencia las extracciones se pierden al reiniciar el contenedor.
Nota: los proveedores LLM remotos (Anthropic, OpenAI, Gemini) requieren que el servidor tenga acceso a internet. Ollama necesita correr en el mismo host.
Para compartir los grafos ya validados sin exponer la app completa (ni sus
claves LLM), publicar.py genera un sitio estático de solo lectura en
docs/: una biblioteca con los grafos publicables (cualquier slug con
{slug}_validacion.json) y un visor 2D/3D por grafo, reusando
static/grafo.js / static/grafo3d.js sin depender de la API.
make publicar # genera docs/ localmente, para previsualizarEl deploy real ocurre vía .github/workflows/deploy-pages.yml al pushear a
main (o manualmente desde la pestaña Actions). Paso único de configuración
en GitHub: Settings → Pages → Source: GitHub Actions.