ka-agent v4.2 : extraction cartes/choix par equilibrage d accolades (jsonObjects) — toutes les cartes d un bloc rendues quelle que soit la mise en forme, blocs tronques inclus
1 changed file +31 −15
modified
agent/ka-agent.js
+31 −15
@@ -20,6 +20,10 @@ | |||||
| 20 | * de clarification (bloc ```ka-choix — {question, options[]}) rendus en | 20 | * de clarification (bloc ```ka-choix — {question, options[]}) rendus en | ||
| 21 | * boutons : un clic envoie l'option comme message ; seuls les boutons de la | 21 | * boutons : un clic envoie l'option comme message ; seuls les boutons de la | ||
| 22 | * dernière bulle assistante restent actifs. | 22 | * dernière bulle assistante restent actifs. | ||
| 23 | + * v4.2 (2026-08-25) : extraction des cartes/choix par ÉQUILIBRAGE D'ACCOLADES | ||||
| 24 | + * (jsonObjects) — tous les objets JSON d'un bloc sont trouvés quelle que soit | ||||
| 25 | + * la mise en forme (une ligne, aéré, tableau) et un bloc tronqué en plein | ||||
| 26 | + * streaming rend toutes ses cartes complètes au lieu d'une seule. | ||||
| 23 | */ | 27 | */ | ||
| 24 | (function () { | 28 | (function () { | ||
| 25 | "use strict"; | 29 | "use strict"; | ||
@@ -158,21 +162,34 @@ | |||||
| 158 | "valoplex": ["ValoPlex", "#ff9f45", "#141814"] | 162 | "valoplex": ["ValoPlex", "#ff9f45", "#141814"] | ||
| 159 | }; | 163 | }; | ||
| 160 | function httpUrl(u) { return typeof u === "string" && /^https:\/\//.test(u) ? u : ""; } | 164 | function httpUrl(u) { return typeof u === "string" && /^https:\/\//.test(u) ? u : ""; } | ||
| 161 | − function cards(lines) { | 165 | + /* Extrait chaque objet JSON de premier niveau d'un bloc ka-card, quelle que | ||
| 162 | − var objs = []; | 166 | + soit sa mise en forme (un par ligne, aéré, tableau, bloc TRONQUÉ par le | ||
| 163 | − lines.forEach(function (ln) { // format demandé : un JSON par ligne | 167 | + streaming) : balayage à équilibrage d'accolades, hors chaînes. */ | ||
| 164 | − ln = ln.trim(); | 168 | + function jsonObjects(txt) { | ||
| 165 | − if (!ln) return; | 169 | + var objs = [], depth = 0, start = -1, inStr = false, escp = false; | ||
| 166 | − try { objs.push(JSON.parse(ln)); } catch (e) {} // ligne incomplète (streaming) → ignorée | 170 | + for (var k = 0; k < txt.length; k++) { | ||
| 167 | − }); | 171 | + var c = txt[k]; | ||
| 168 | − if (!objs.length) { // filet : le modèle aère parfois son JSON | 172 | + if (inStr) { | ||
| 169 | − try { | 173 | + if (escp) escp = false; | ||
| 170 | − var w = JSON.parse(lines.join("\n")); | 174 | + else if (c === "\\") escp = true; | ||
| 171 | − objs = Array.isArray(w) ? w : [w]; | 175 | + else if (c === '"') inStr = false; | ||
| 172 | − } catch (e) {} | 176 | + continue; | ||
| 177 | + } | ||||
| 178 | + if (c === '"') { inStr = true; continue; } | ||||
| 179 | + if (c === "{") { if (!depth) start = k; depth++; } | ||||
| 180 | + else if (c === "}" && depth) { | ||||
| 181 | + depth--; | ||||
| 182 | + if (!depth && start >= 0) { | ||||
| 183 | + try { objs.push(JSON.parse(txt.slice(start, k + 1))); } catch (e) {} | ||||
| 184 | + start = -1; | ||||
| 185 | + } | ||||
| 186 | + } | ||||
| 173 | } | 187 | } | ||
| 188 | + return objs; // un objet incomplet en fin de bloc est simplement ignoré | ||||
| 189 | + } | ||||
| 190 | + function cards(lines) { | ||||
| 174 | var html = ""; | 191 | var html = ""; | ||
| 175 | − objs.forEach(function (o) { | 192 | + jsonObjects(lines.join("\n")).forEach(function (o) { | ||
| 176 | if (!o || !o.titre || !httpUrl(o.lien)) return; | 193 | if (!o || !o.titre || !httpUrl(o.lien)) return; | ||
| 177 | var pal = ECO[o.site] || ["Groupe KA", "var(--accent,#d9f26b)", "var(--on-accent,#141814)"]; | 194 | var pal = ECO[o.site] || ["Groupe KA", "var(--accent,#d9f26b)", "var(--on-accent,#141814)"]; | ||
| 178 | var img = httpUrl(o.image); | 195 | var img = httpUrl(o.image); | ||
@@ -191,8 +208,7 @@ | |||||
| 191 | return html ? '<div class="kaa-cards">' + html + "</div>" : ""; | 208 | return html ? '<div class="kaa-cards">' + html + "</div>" : ""; | ||
| 192 | } | 209 | } | ||
| 193 | function choices(lines) { | 210 | function choices(lines) { | ||
| 194 | − var o = null; | 211 | + var o = jsonObjects(lines.join("\n"))[0] || null; // bloc incomplet (streaming) → rien | ||
| 195 | − try { o = JSON.parse(lines.join("\n")); } catch (e) { return ""; } // bloc incomplet (streaming) | ||||
| 196 | if (!o || !Array.isArray(o.options) || !o.options.length) return ""; | 212 | if (!o || !Array.isArray(o.options) || !o.options.length) return ""; | ||
| 197 | var h = '<span class="kaa-choices">' + | 213 | var h = '<span class="kaa-choices">' + | ||
| 198 | (o.question ? '<span class="kaa-choices-q">' + esc(String(o.question)) + "</span>" : ""); | 214 | (o.question ? '<span class="kaa-choices-q">' + esc(String(o.question)) + "</span>" : ""); | ||
| 199 | 215 | ||||