fix(umind): faltaba el botón para editar las notas del conocimiento
Las plantillas de rubro dejan las notas con valores entre corchetes y la propia pantalla dice "abrilas y reemplazalas por tus datos" — pero no había con qué. El endpoint para editarlas existía desde que se agregaron las fuentes de texto; lo que nunca se agregó fue el botón, así que el flujo que el producto promete no se podía completar. Se elegía la plantilla de restaurante y quedaban cuatro notas diciendo "[12:00]" sin forma de arreglarlas salvo borrarlas y escribirlas de nuevo. Ahora cada nota tiene "Editar": abre el contenido, se corrige y al guardar se rehacen los fragmentos, así que el agente pasa a contestar con lo nuevo en el momento. También se puede editar el texto que se le extrajo a un archivo: si el OCR de un PDF salió torcido, corregirlo a mano es tan válido como escribir la nota, y es el mismo código. Las URLs no — su contenido se rehace crawleando y cualquier corrección se perdería en la próxima actualización. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
3ceb61c035
commit
195590f5e4
@@ -109,6 +109,35 @@ 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é.
|
||||
const editandoDoc = ref(null)
|
||||
const docForm = ref({ titulo: '', contenido: '' })
|
||||
const guardandoDoc = ref(false)
|
||||
|
||||
function editarDocumento(d) {
|
||||
editandoDoc.value = d
|
||||
docForm.value = { titulo: d.origen, contenido: d.contenido || '' }
|
||||
}
|
||||
|
||||
async function guardarDocumento() {
|
||||
if (!editandoDoc.value) return
|
||||
guardandoDoc.value = true
|
||||
error.value = ''
|
||||
try {
|
||||
await api.put(apiUmind(`/umind/documentos/${editandoDoc.value.ID}`), {
|
||||
titulo: docForm.value.titulo,
|
||||
contenido: docForm.value.contenido,
|
||||
})
|
||||
editandoDoc.value = null
|
||||
await cargarDocumentos()
|
||||
} catch (e) {
|
||||
error.value = e.message
|
||||
} finally {
|
||||
guardandoDoc.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function reprocesar(d) {
|
||||
error.value = ''
|
||||
try {
|
||||
@@ -584,15 +613,63 @@ watch(
|
||||
:title="d.auto_actualizar ? 'Dejar de releer sola' : 'Releer el sitio cada semana'"
|
||||
@click="alternarAuto(d)"
|
||||
>{{ d.auto_actualizar ? '🔁 auto' : '↻ manual' }}</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
|
||||
class="text-sm text-brand hover:underline disabled:opacity-40"
|
||||
v-if="d.tipo === 'texto' || d.tipo === 'archivo'"
|
||||
class="text-sm text-brand hover:underline"
|
||||
@click="editarDocumento(d)"
|
||||
>Editar</button>
|
||||
<button
|
||||
class="text-sm text-tenue hover:text-texto disabled:opacity-40"
|
||||
:disabled="d.estado === 'procesando'"
|
||||
:title="d.tipo === 'url' ? 'Volver a leer el sitio' : 'Rehacer los fragmentos'"
|
||||
@click="reprocesar(d)"
|
||||
>Actualizar</button>
|
||||
<button class="text-red-500 hover:text-red-700 text-sm" @click="eliminarDocumento(d.ID)">Eliminar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Editar una nota o el texto extraído de un archivo -->
|
||||
<div
|
||||
v-if="editandoDoc"
|
||||
class="fixed inset-0 bg-black/40 flex items-center justify-center p-4 z-50"
|
||||
@click.self="editandoDoc = null"
|
||||
>
|
||||
<div class="card w-full max-w-2xl p-6 max-h-[calc(100vh-2rem)] overflow-y-auto">
|
||||
<h2 class="font-semibold text-texto mb-1">Editar fuente</h2>
|
||||
<p class="text-xs text-tenue mb-4">
|
||||
Al guardar se vuelve a leer y el agente empieza a contestar con esto.
|
||||
</p>
|
||||
|
||||
<form class="space-y-3" @submit.prevent="guardarDocumento">
|
||||
<div>
|
||||
<label class="label">Título</label>
|
||||
<input v-model="docForm.titulo" required class="input" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="label">Contenido</label>
|
||||
<textarea
|
||||
v-model="docForm.contenido"
|
||||
rows="16"
|
||||
required
|
||||
class="input font-normal leading-relaxed"
|
||||
></textarea>
|
||||
<p class="text-xs text-tenue mt-1.5">
|
||||
Si viene de una plantilla, reemplazá lo que está [entre corchetes] por tus datos.
|
||||
Lo que quede sin reemplazar el agente lo va a leer tal cual.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex justify-end gap-2 pt-1">
|
||||
<button type="button" class="btn-ghost" @click="editandoDoc = null">Cancelar</button>
|
||||
<button type="submit" class="btn-primary" :disabled="guardandoDoc">
|
||||
{{ guardandoDoc ? 'Guardando…' : 'Guardar y volver a leer' }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Herramientas -->
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,8 +5,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 96 96'%3E%3Crect width='96' height='96' rx='22' fill='%238eb02f'/%3E%3Cpath d='M32,42 V58 A14,14 0 0 0 60,58 V42' fill='none' stroke='%23fff' stroke-width='10' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M60,58 V64' fill='none' stroke='%23fff' stroke-width='10' stroke-linecap='round'/%3E%3Ccircle cx='60' cy='28' r='7' fill='%23fff'/%3E%3C/svg%3E" />
|
||||
<title>uMind Studio</title>
|
||||
<script type="module" crossorigin src="/orchestrator/assets/index-Da7ZrNMD.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/orchestrator/assets/index-DNRtUHD7.css">
|
||||
<script type="module" crossorigin src="/orchestrator/assets/index-Cv_aH8gm.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/orchestrator/assets/index-Bk6phDz-.css">
|
||||
</head>
|
||||
<!-- Sin clase de fondo: el color lo pone body en style.css desde los tokens,
|
||||
que son los que cambian con el tema. Una utilidad acá le ganaba a la
|
||||
|
||||
@@ -1015,7 +1015,11 @@ func ActualizarUmindDocumentoHandler(c *fiber.Ctx) error {
|
||||
updates["auto_actualizar"] = *req.AutoActualizar
|
||||
}
|
||||
reprocesar := false
|
||||
if doc.Tipo == "texto" && strings.TrimSpace(req.Contenido) != "" {
|
||||
// "texto" son las notas escritas a mano; "archivo" guarda lo que se le
|
||||
// extrajo al PDF o al Word, y corregir una extracción torcida a mano es
|
||||
// tan válido como escribir la nota. Una URL no: su contenido se rehace
|
||||
// crawleando, editarlo se perdería en la próxima actualización.
|
||||
if (doc.Tipo == "texto" || doc.Tipo == "archivo") && strings.TrimSpace(req.Contenido) != "" {
|
||||
updates["contenido"] = req.Contenido
|
||||
if t := strings.TrimSpace(req.Titulo); t != "" {
|
||||
updates["origen"] = t
|
||||
|
||||
Reference in New Issue
Block a user