feat(umind): ver qué se leyó de cada fuente, fragmento por fragmento

Una fuente crawleada decía "9 fragmentos" y nada más. Las notas y archivos al
menos tienen Editar, que muestra su texto; un sitio no tiene nada — era una
caja negra, sin forma de saber si el crawler leyó los precios o el pie de
página. Y cuando el agente contesta mal, la primera pregunta es justamente
qué tiene cargado de verdad.

Cada fuente gana un "Ver" que abre sus fragmentos tal como quedaron indexados,
numerados y en orden, con la advertencia que importa: esto es exactamente lo
que el asistente puede consultar — si acá falta algo, eso mismo le va a faltar
en las respuestas.

El botón se apaga cuando la fuente no tiene fragmentos todavía (procesando o
con error): abrir un visor vacío no informa nada.

El endpoint pasa por accesoDocumento como todos los sub-recursos, y devuelve
solo el contenido — el embedding no viaja: son miles de números que no le
sirven a nadie en pantalla.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-08-23 19:42:18 -05:00
co-authored by Claude Opus 5
parent be01d95631
commit ffa24a068f
9 changed files with 150 additions and 29 deletions
+64
View File
@@ -120,6 +120,28 @@ async function subirArchivo() {
// Editar una fuente escrita a mano. Las plantillas de rubro dejan las notas
// con valores entre corchetes para reemplazar — sin esto, no había con qué.
// Ver qué se leyó de una fuente, fragmento por fragmento. Para un sitio
// crawleado es la única ventana: no tiene Editar (se rehace crawleando) y
// hasta ahora "9 fragmentos" era una caja negra.
const viendoDoc = ref(null)
const fragmentos = ref([])
const cargandoFragmentos = ref(false)
async function verFragmentos(d) {
viendoDoc.value = d
fragmentos.value = []
cargandoFragmentos.value = true
try {
const r = await api.get(apiUmind(`/umind/documentos/${d.ID}/fragmentos`))
fragmentos.value = r.items || []
} catch (e) {
error.value = e.message
viendoDoc.value = null
} finally {
cargandoFragmentos.value = false
}
}
const editandoDoc = ref(null)
const docForm = ref({ titulo: '', contenido: '' })
const guardandoDoc = ref(false)
@@ -473,6 +495,13 @@ watch(
:title="d.auto_actualizar ? 'Dejar de releer sola' : 'Releer el sitio cada semana'"
@click="alternarAuto(d)"
><UiIcono :nombre="d.auto_actualizar ? 'auto' : 'refrescar'" :tam="13" class="mr-1" />{{ d.auto_actualizar ? 'auto' : 'manual' }}</button>
<button
class="text-sm text-tenue hover:text-texto"
:disabled="!d.total_chunks"
:class="!d.total_chunks ? 'opacity-40 cursor-default' : ''"
title="Ver qué se leyó de esta fuente"
@click="verFragmentos(d)"
>Ver</button>
<!-- Solo lo que tiene texto propio guardado: una URL se rehace
crawleando, editarla a mano se perdería en la próxima pasada. -->
<button
@@ -501,6 +530,41 @@ watch(
<TabChat :agente-id="agenteIdNum" />
</div>
<!-- Ver los fragmentos de una fuente, solo lectura -->
<div
v-if="viendoDoc"
class="fixed inset-0 bg-black/40 flex items-center justify-center p-4 z-50"
@click.self="viendoDoc = null"
>
<div class="card w-full max-w-2xl p-6 max-h-[calc(100vh-2rem)] overflow-y-auto">
<div class="flex items-baseline justify-between gap-3 mb-1">
<h2 class="font-semibold text-texto truncate">{{ viendoDoc.origen }}</h2>
<span class="text-xs text-tenue shrink-0 tabular-nums">
{{ fragmentos.length }} {{ fragmentos.length === 1 ? 'fragmento' : 'fragmentos' }}
</span>
</div>
<p class="text-xs text-tenue mb-4">
Esto es exactamente lo que el asistente puede consultar de esta fuente.
Si acá falta algo o se leyó mal, eso mismo le va a faltar en las respuestas.
</p>
<p v-if="cargandoFragmentos" class="text-sm text-tenue">Cargando</p>
<div v-else class="space-y-2">
<div
v-for="(f, i) in fragmentos"
:key="f.ID"
class="bg-elevado border border-borde rounded-lg p-3 text-sm text-texto whitespace-pre-wrap"
>
<span class="text-[10px] text-tenue tabular-nums block mb-1">#{{ i + 1 }}</span>{{ f.contenido }}
</div>
</div>
<div class="flex justify-end pt-4">
<button class="btn-ghost" @click="viendoDoc = null">Cerrar</button>
</div>
</div>
</div>
<!-- Editar una nota o el texto extraído de un archivo -->
<div
v-if="editandoDoc"