SPB Git forge

spb/sorti-ka

Public

Toutes les sorties et tous les événements du Québec, un seul endroit — 7 connecteurs, fiches SSR, design Groupe KA.

58commits 1branches 0releases
13.7 MBsize
maindefault branch
17 days agolast push
HTML 82.9% Python 15.2% TypeScript 0.9% JavaScript 0.7%

widget ka-agent v4.2 : extraction cartes/choix par equilibrage d accolades — sync ka-ui 39e968d

Simon-Pierre Boucher committed 1 mo ago (Aug 25, 2026) parent d0b014b

1 changed file +31 −15

modified frontend/ka-agent.js +31 −15
@@ -20,6 +20,10 @@
20 20 * de clarification (bloc ```ka-choix — {question, options[]}) rendus en
21 21 * boutons : un clic envoie l'option comme message ; seuls les boutons de la
22 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 28 (function () {
25 29 "use strict";
@@ -158,21 +162,34 @@
158 162 "valoplex": ["ValoPlex", "#ff9f45", "#141814"]
159 163 };
160 164 function httpUrl(u) { return typeof u === "string" && /^https:\/\//.test(u) ? u : ""; }
161 − function cards(lines) {
162 − var objs = [];
163 − lines.forEach(function (ln) { // format demandé : un JSON par ligne
164 − ln = ln.trim();
165 − if (!ln) return;
166 − try { objs.push(JSON.parse(ln)); } catch (e) {} // ligne incomplète (streaming) → ignorée
167 − });
168 − if (!objs.length) { // filet : le modèle aère parfois son JSON
169 − try {
170 − var w = JSON.parse(lines.join("\n"));
171 − objs = Array.isArray(w) ? w : [w];
172 − } catch (e) {}
165 + /* Extrait chaque objet JSON de premier niveau d'un bloc ka-card, quelle que
166 + soit sa mise en forme (un par ligne, aéré, tableau, bloc TRONQUÉ par le
167 + streaming) : balayage à équilibrage d'accolades, hors chaînes. */
168 + function jsonObjects(txt) {
169 + var objs = [], depth = 0, start = -1, inStr = false, escp = false;
170 + for (var k = 0; k < txt.length; k++) {
171 + var c = txt[k];
172 + if (inStr) {
173 + if (escp) escp = false;
174 + else if (c === "\\") escp = true;
175 + else if (c === '"') inStr = false;
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 191 var html = "";
175 − objs.forEach(function (o) {
192 + jsonObjects(lines.join("\n")).forEach(function (o) {
176 193 if (!o || !o.titre || !httpUrl(o.lien)) return;
177 194 var pal = ECO[o.site] || ["Groupe KA", "var(--accent,#d9f26b)", "var(--on-accent,#141814)"];
178 195 var img = httpUrl(o.image);
@@ -191,8 +208,7 @@
191 208 return html ? '<div class="kaa-cards">' + html + "</div>" : "";
192 209 }
193 210 function choices(lines) {
194 − var o = null;
195 − try { o = JSON.parse(lines.join("\n")); } catch (e) { return ""; } // bloc incomplet (streaming)
211 + var o = jsonObjects(lines.join("\n"))[0] || null; // bloc incomplet (streaming) → rien
196 212 if (!o || !Array.isArray(o.options) || !o.options.length) return "";
197 213 var h = '<span class="kaa-choices">' +
198 214 (o.question ? '<span class="kaa-choices-q">' + esc(String(o.question)) + "</span>" : "");
199 215