fix: parseo JSON robusto, UI upload full-width, selector en header, multiple files

- session-analyzer.ts: extractJSON() con 4 estrategias de parseo + log raw
- TranscriptionsView: selector proyecto movido al header, upload card full-width
- TranscriptionsView: soporte multi-file con cola, banner de progreso
- TranscriptionsView: download .md con revokeObjectURL diferido
- TranscriptionsView: upload deshabilitado sin proyecto seleccionado
- session-analyzer + project-doc exportados como servicios independientes
- i18n: keys titleView, statusParsing/Analyzing/Generating, filesLoaded
- i18n: fix key title duplicado (title -> titleLabel)
This commit is contained in:
2026-05-28 13:20:23 -05:00
parent 7d299554bf
commit b974788a16
4 changed files with 194 additions and 60 deletions
+29 -2
View File
@@ -63,12 +63,39 @@ export async function analyzeSession(
)
try {
const jsonStr = content.replace(/```json\s*/gi, '').replace(/```\s*$/g, '').trim()
const jsonStr = extractJSON(content)
const result: SessionExtraction = JSON.parse(jsonStr)
console.log(`[Alpha] Session analysis complete — ${result.pendingTasks.length} tasks, ${result.decisions.length} decisions`)
return result
} catch (e) {
console.error('[Alpha] Failed to parse session analysis:', content)
console.error('[Alpha] Failed to parse session analysis. Raw response:', content)
throw new Error('No se pudo parsear el análisis de la sesión')
}
}
/**
* Extrae el primer objeto JSON válido del texto.
* Maneja markdown code blocks, texto antes/después, etc.
*/
function extractJSON(text: string): string {
// 1. Intentar parse directo
try { JSON.parse(text); return text } catch {}
// 2. Extraer entre ```json y ```
const jsonBlock = text.match(/```(?:json)?\s*([\s\S]*?)```/)
if (jsonBlock) {
const candidate = jsonBlock[1].trim()
try { JSON.parse(candidate); return candidate } catch {}
}
// 3. Extraer entre { y } (first { to last })
const firstBrace = text.indexOf('{')
const lastBrace = text.lastIndexOf('}')
if (firstBrace !== -1 && lastBrace > firstBrace) {
const candidate = text.slice(firstBrace, lastBrace + 1)
try { JSON.parse(candidate); return candidate } catch {}
}
// 4. Fallback: devolver el texto original (lanzará error en el caller)
return text
}