widget ka-agent v4 : cartes d annonces cliquables (ka-card, palette ecosysteme) + choix de clarification en boutons (ka-choix) — sync ka-ui 0c910a8
2 changed files +228 −12
modified
frontend/dist/ka-agent.js
+114 −6
@@ -14,6 +14,12 @@ | ||
| 14 | 14 | * seuil 6 px pour distinguer clic et glisser, bornée aux marges de l'écran, |
| 15 | 15 | * position mémorisée par site en localStorage, re-bornée au resize) ; en mode |
| 16 | 16 | * fenêtré le panneau s'ancre du côté où se trouve la bulle. |
| 17 | + * v4 (2026-08-25) : CARTES d'annonces cliquables (bloc ```ka-card — un JSON | |
| 18 | + * par ligne : site/titre/sous_titre/prix/badge/image/lien) rendues aux | |
| 19 | + * couleurs de la plateforme visée (palette écosystème embarquée), et CHOIX | |
| 20 | + * de clarification (bloc ```ka-choix — {question, options[]}) rendus en | |
| 21 | + * boutons : un clic envoie l'option comme message ; seuls les boutons de la | |
| 22 | + * dernière bulle assistante restent actifs. | |
| 17 | 23 | */ |
| 18 | 24 | (function () { |
| 19 | 25 | "use strict"; |
@@ -96,6 +102,31 @@ | ||
| 96 | 102 | .kaa-in button{min-width:52px;min-height:44px;border:1.5px solid var(--ink,#141814);border-radius:9px; |
| 97 | 103 | background:var(--ink,#141814);color:var(--accent,#d9f26b);font:700 16px "Space Grotesk",system-ui;cursor:pointer;touch-action:manipulation} |
| 98 | 104 | .kaa-in button:disabled{opacity:.45} |
| 105 | + .kaa-cards{display:flex;flex-direction:column;gap:8px;margin:.5em 0 .2em} | |
| 106 | + .kaa-card{display:flex;align-items:stretch;border:1.5px solid var(--ink,#141814);border-radius:11px; | |
| 107 | + overflow:hidden;background:#fff;text-decoration:none!important;color:var(--ink,#141814); | |
| 108 | + box-shadow:3px 3px 0 rgba(20,24,20,.14);border-left:5px solid var(--kaa-c,var(--accent,#d9f26b));transition:transform .12s} | |
| 109 | + .kaa-msg.kaa-a a.kaa-card{text-decoration:none;font-weight:400} | |
| 110 | + .kaa-card:hover{transform:translate(-1px,-1px)} | |
| 111 | + .kaa-card-img{flex:none;width:76px;min-height:76px;background-size:cover;background-position:center; | |
| 112 | + border-right:1.5px solid rgba(20,24,20,.15)} | |
| 113 | + .kaa-card-body{flex:1;display:flex;flex-direction:column;gap:2px;padding:8px 11px;min-width:0} | |
| 114 | + .kaa-card-top{display:flex;gap:6px;align-items:center;flex-wrap:wrap} | |
| 115 | + .kaa-card-site{font:700 9px "JetBrains Mono",monospace;letter-spacing:.08em;text-transform:uppercase; | |
| 116 | + background:var(--kaa-c,var(--accent,#d9f26b));color:var(--kaa-on,var(--on-accent,#141814));border-radius:5px;padding:1px 6px 2px} | |
| 117 | + .kaa-card-badge{font:700 9px "JetBrains Mono",monospace;letter-spacing:.06em;text-transform:uppercase; | |
| 118 | + border:1px dashed var(--ink-2,#4d5551);border-radius:999px;padding:1px 7px;color:var(--ink-2,#4d5551)} | |
| 119 | + .kaa-card-title{font:700 13.5px "Space Grotesk",system-ui,sans-serif;letter-spacing:-.01em;line-height:1.25} | |
| 120 | + .kaa-card-sub{font-size:11.5px;color:var(--ink-2,#4d5551);line-height:1.35} | |
| 121 | + .kaa-card-price{font:700 13px "Space Grotesk",system-ui,sans-serif;margin-top:1px} | |
| 122 | + .kaa-card-go{flex:none;align-self:center;padding:0 10px;font-weight:700;opacity:.55} | |
| 123 | + .kaa-choices{display:flex;flex-wrap:wrap;gap:7px;margin:.45em 0 .15em;align-items:center} | |
| 124 | + .kaa-choices-q{flex-basis:100%;font-size:12px;color:var(--ink-2,#4d5551);font-weight:600} | |
| 125 | + .kaa-choice{border:1.5px solid var(--ink,#141814);border-radius:999px;background:var(--paper,#f5f3ee); | |
| 126 | + color:var(--ink,#141814);font:600 12.5px Inter,system-ui,sans-serif;padding:7px 13px;cursor:pointer; | |
| 127 | + box-shadow:2px 2px 0 rgba(20,24,20,.35);transition:transform .1s;touch-action:manipulation} | |
| 128 | + .kaa-choice:hover{background:var(--accent,#d9f26b);color:var(--on-accent,#141814);transform:translate(-1px,-1px)} | |
| 129 | + .kaa-choices.kaa-done .kaa-choice{opacity:.45;pointer-events:none;box-shadow:none} | |
| 99 | 130 | .kaa-hello{font-size:12.5px;color:var(--ink-2,#4d5551);padding:4px 2px;max-width:760px} |
| 100 | 131 | .kaa-dots::after{content:"…";animation:kaa-b 1.2s infinite} |
| 101 | 132 | @keyframes kaa-b{0%{opacity:.2}50%{opacity:1}100%{opacity:.2}} |
@@ -104,7 +135,63 @@ | ||
| 104 | 135 | |
| 105 | 136 | /* ---------- markdown complet (rendu en streaming, texte échappé d'abord) ---------- */ |
| 106 | 137 | function esc(s) { |
| 107 | − return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); | |
| 138 | + return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """); | |
| 139 | + } | |
| 140 | + | |
| 141 | + /* ---------- cartes + choix (v4) ---------- | |
| 142 | + Palette de l'écosystème (ka-ui/ecosystem.json) embarquée : chaque carte | |
| 143 | + prend les couleurs de la plateforme de SA fiche, pas du site hôte. */ | |
| 144 | + var ECO = { | |
| 145 | + "groupe-ka": ["Groupe KA", "#d9f26b", "#141814"], | |
| 146 | + "trouve-ka": ["Trouve·Ka", "#1c7ed6", "#ffffff"], | |
| 147 | + "lou-ka": ["Lou·Ka", "#ff6a00", "#ffffff"], | |
| 148 | + "immo-ka": ["Immo·Ka", "#e23744", "#ffffff"], | |
| 149 | + "vrai-prix": ["Vrai-Prix", "#ff5148", "#ffffff"], | |
| 150 | + "auto-ka": ["Auto·Ka", "#ff5a2a", "#ffffff"], | |
| 151 | + "fabri-ka": ["Fabri·Ka", "#c4532e", "#ffffff"], | |
| 152 | + "food-ka": ["Food·Ka", "#1f9d55", "#ffffff"], | |
| 153 | + "resto-ka": ["Resto·Ka", "#f08c00", "#141814"], | |
| 154 | + "sorti-ka": ["Sorti·Ka", "#d6336c", "#ffffff"], | |
| 155 | + "crea-ka": ["Créa·Ka", "#7048e8", "#ffffff"], | |
| 156 | + "api-ka": ["API·Ka", "#3b5bdb", "#ffffff"], | |
| 157 | + "job-ka": ["Job·Ka", "#0c8599", "#ffffff"], | |
| 158 | + "valoplex": ["ValoPlex", "#ff9f45", "#141814"] | |
| 159 | + }; | |
| 160 | + function httpUrl(u) { return typeof u === "string" && /^https:\/\//.test(u) ? u : ""; } | |
| 161 | + function cards(lines) { | |
| 162 | + var html = ""; | |
| 163 | + lines.forEach(function (ln) { | |
| 164 | + ln = ln.trim(); | |
| 165 | + if (!ln) return; | |
| 166 | + var o = null; | |
| 167 | + try { o = JSON.parse(ln); } catch (e) { return; } // ligne incomplète (streaming) → ignorée | |
| 168 | + if (!o || !o.titre || !httpUrl(o.lien)) return; | |
| 169 | + var pal = ECO[o.site] || ["Groupe KA", "var(--accent,#d9f26b)", "var(--on-accent,#141814)"]; | |
| 170 | + var img = httpUrl(o.image); | |
| 171 | + html += '<a class="kaa-card" href="' + esc(o.lien) + '" target="_blank" rel="noopener noreferrer"' + | |
| 172 | + ' style="--kaa-c:' + pal[1] + ";--kaa-on:" + pal[2] + '">' + | |
| 173 | + (img ? '<span class="kaa-card-img" style="background-image:url("' + esc(img) + '")"></span>' : "") + | |
| 174 | + '<span class="kaa-card-body"><span class="kaa-card-top">' + | |
| 175 | + '<span class="kaa-card-site">' + esc(pal[0]) + "</span>" + | |
| 176 | + (o.badge ? '<span class="kaa-card-badge">' + esc(String(o.badge)) + "</span>" : "") + | |
| 177 | + "</span>" + | |
| 178 | + '<span class="kaa-card-title">' + esc(String(o.titre)) + "</span>" + | |
| 179 | + (o.sous_titre ? '<span class="kaa-card-sub">' + esc(String(o.sous_titre)) + "</span>" : "") + | |
| 180 | + (o.prix ? '<span class="kaa-card-price">' + esc(String(o.prix)) + "</span>" : "") + | |
| 181 | + '</span><span class="kaa-card-go">→</span></a>'; | |
| 182 | + }); | |
| 183 | + return html ? '<div class="kaa-cards">' + html + "</div>" : ""; | |
| 184 | + } | |
| 185 | + function choices(lines) { | |
| 186 | + var o = null; | |
| 187 | + try { o = JSON.parse(lines.join("\n")); } catch (e) { return ""; } // bloc incomplet (streaming) | |
| 188 | + if (!o || !Array.isArray(o.options) || !o.options.length) return ""; | |
| 189 | + var h = '<span class="kaa-choices">' + | |
| 190 | + (o.question ? '<span class="kaa-choices-q">' + esc(String(o.question)) + "</span>" : ""); | |
| 191 | + o.options.slice(0, 6).forEach(function (op) { | |
| 192 | + h += '<button type="button" class="kaa-choice">' + esc(String(op)) + "</button>"; | |
| 193 | + }); | |
| 194 | + return h + "</span>"; | |
| 108 | 195 | } |
| 109 | 196 | function inline(s) { |
| 110 | 197 | s = esc(s); |
@@ -124,11 +211,14 @@ | ||
| 124 | 211 | function para(buf) { if (buf.length) out.push("<p>" + buf.map(inline).join("<br>") + "</p>"); } |
| 125 | 212 | while (i < lines.length) { |
| 126 | 213 | var l = lines[i]; |
| 127 | − if (/^\s*```/.test(l)) { /* bloc de code */ | |
| 214 | + if (/^\s*```/.test(l)) { /* bloc de code / carte / choix */ | |
| 215 | + var lang = (l.match(/^\s*```\s*([\w-]+)?/) || [])[1] || ""; | |
| 128 | 216 | var code = []; i++; |
| 129 | 217 | while (i < lines.length && !/^\s*```/.test(lines[i])) code.push(lines[i++]); |
| 130 | 218 | i++; |
| 131 | − out.push("<pre><code>" + esc(code.join("\n")) + "</code></pre>"); | |
| 219 | + if (lang === "ka-card") out.push(cards(code)); | |
| 220 | + else if (lang === "ka-choix") out.push(choices(code)); | |
| 221 | + else out.push("<pre><code>" + esc(code.join("\n")) + "</code></pre>"); | |
| 132 | 222 | } else if ((m = l.match(/^\s*(#{1,4})\s+(.*)$/))) { /* titres */ |
| 133 | 223 | out.push("<h" + m[1].length + ">" + inline(m[2]) + "</h" + m[1].length + ">"); i++; |
| 134 | 224 | } else if (/^\s*(---+|\*\*\*+)\s*$/.test(l)) { /* filet */ |
@@ -230,15 +320,25 @@ | ||
| 230 | 320 | if (log.length) return; |
| 231 | 321 | var d = document.createElement("div"); |
| 232 | 322 | d.className = "kaa-hello"; |
| 233 | − d.textContent = "👋 Je suis KA Agent, l'assistant de l'écosystème Groupe KA. Posez-moi une question sur ce site, ses données (prix, annonces, fiches, stats…) ou sur le groupe."; | |
| 323 | + d.textContent = "👋 Je suis KA Agent, l'assistant de l'écosystème Groupe KA. Je peux chercher dans TOUTES les plateformes du groupe : logements, propriétés, autos, emplois, épicerie, restos, sorties, créateurs, produits d'ici — plus estimations de valeur, annuaires (déménageurs, inspecteurs), historiques et statistiques. Posez votre question !"; | |
| 234 | 324 | logEl.appendChild(d); |
| 235 | 325 | } |
| 326 | + /* les boutons de choix ne restent actifs que dans la DERNIÈRE bulle assistante */ | |
| 327 | + function retireChoices(keepLast) { | |
| 328 | + var groups = logEl.querySelectorAll(".kaa-choices:not(.kaa-done)"); | |
| 329 | + var msgs = logEl.querySelectorAll(".kaa-msg.kaa-a"); | |
| 330 | + var last = msgs.length ? msgs[msgs.length - 1] : null; | |
| 331 | + groups.forEach(function (g) { | |
| 332 | + if (!(keepLast && last && last.contains(g))) g.classList.add("kaa-done"); | |
| 333 | + }); | |
| 334 | + } | |
| 236 | 335 | function render() { |
| 237 | 336 | logEl.innerHTML = ""; |
| 238 | 337 | hello(); |
| 239 | 338 | log.forEach(function (m) { |
| 240 | 339 | m.role === "user" ? bubble("kaa-u", esc(m.content)) : bubble("kaa-a", md(m.content)); |
| 241 | 340 | }); |
| 341 | + retireChoices(log.length && log[log.length - 1].role === "assistant"); | |
| 242 | 342 | scroll(); |
| 243 | 343 | } |
| 244 | 344 | |
@@ -385,6 +485,7 @@ | ||
| 385 | 485 | busy = true; |
| 386 | 486 | send.disabled = true; |
| 387 | 487 | ta.value = ""; |
| 488 | + retireChoices(false); // un nouveau message clôt les choix en suspens | |
| 388 | 489 | log.push({ role: "user", content: q }); |
| 389 | 490 | save(); |
| 390 | 491 | bubble("kaa-u", esc(q)); |
@@ -453,6 +554,13 @@ | ||
| 453 | 554 | ta.addEventListener("keydown", function (e) { |
| 454 | 555 | if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); ask(); } |
| 455 | 556 | }); |
| 557 | + logEl.addEventListener("click", function (e) { /* clic sur un bouton de choix (v4) */ | |
| 558 | + var b = e.target && e.target.closest ? e.target.closest(".kaa-choice") : null; | |
| 559 | + if (!b || busy) return; | |
| 560 | + var g = b.closest(".kaa-choices"); | |
| 561 | + if (g && g.classList.contains("kaa-done")) return; | |
| 562 | + ta.value = b.textContent; | |
| 563 | + ask(); | |
| 564 | + }); | |
| 456 | 565 | })(); |
| 457 | − | |
| 458 | −;/*KA_ANALYTICS*/(function(){try{if(window.__kaAn)return;window.__kaAn=1;var k="KA_VID",v=localStorage.getItem(k);if(!v){v=Date.now().toString(36)+Math.random().toString(36).slice(2,8);localStorage.setItem(k,v);}var b=function(){var i=new Image();i.src="https://www.administration-ka.com/collect?site=crea-ka&vid="+v+"&p="+encodeURIComponent(location.pathname)+"&t="+Date.now();};b();setInterval(b,60000);}catch(e){}})(); | |
| 566 | +/*KA_ANALYTICS*/(function(){try{if(window.__kaAn)return;window.__kaAn=1;var k="KA_VID",v=localStorage.getItem(k);if(!v){v=Date.now().toString(36)+Math.random().toString(36).slice(2,8);localStorage.setItem(k,v);}var b=function(){var i=new Image();i.src="https://www.administration-ka.com/collect?site=crea-ka&vid="+v+"&p="+encodeURIComponent(location.pathname)+"&t="+Date.now();};b();setInterval(b,60000);}catch(e){}})(); | |
modified
frontend/src/ka-agent.js
+114 −6
@@ -14,6 +14,12 @@ | ||
| 14 | 14 | * seuil 6 px pour distinguer clic et glisser, bornée aux marges de l'écran, |
| 15 | 15 | * position mémorisée par site en localStorage, re-bornée au resize) ; en mode |
| 16 | 16 | * fenêtré le panneau s'ancre du côté où se trouve la bulle. |
| 17 | + * v4 (2026-08-25) : CARTES d'annonces cliquables (bloc ```ka-card — un JSON | |
| 18 | + * par ligne : site/titre/sous_titre/prix/badge/image/lien) rendues aux | |
| 19 | + * couleurs de la plateforme visée (palette écosystème embarquée), et CHOIX | |
| 20 | + * de clarification (bloc ```ka-choix — {question, options[]}) rendus en | |
| 21 | + * boutons : un clic envoie l'option comme message ; seuls les boutons de la | |
| 22 | + * dernière bulle assistante restent actifs. | |
| 17 | 23 | */ |
| 18 | 24 | (function () { |
| 19 | 25 | "use strict"; |
@@ -96,6 +102,31 @@ | ||
| 96 | 102 | .kaa-in button{min-width:52px;min-height:44px;border:1.5px solid var(--ink,#141814);border-radius:9px; |
| 97 | 103 | background:var(--ink,#141814);color:var(--accent,#d9f26b);font:700 16px "Space Grotesk",system-ui;cursor:pointer;touch-action:manipulation} |
| 98 | 104 | .kaa-in button:disabled{opacity:.45} |
| 105 | + .kaa-cards{display:flex;flex-direction:column;gap:8px;margin:.5em 0 .2em} | |
| 106 | + .kaa-card{display:flex;align-items:stretch;border:1.5px solid var(--ink,#141814);border-radius:11px; | |
| 107 | + overflow:hidden;background:#fff;text-decoration:none!important;color:var(--ink,#141814); | |
| 108 | + box-shadow:3px 3px 0 rgba(20,24,20,.14);border-left:5px solid var(--kaa-c,var(--accent,#d9f26b));transition:transform .12s} | |
| 109 | + .kaa-msg.kaa-a a.kaa-card{text-decoration:none;font-weight:400} | |
| 110 | + .kaa-card:hover{transform:translate(-1px,-1px)} | |
| 111 | + .kaa-card-img{flex:none;width:76px;min-height:76px;background-size:cover;background-position:center; | |
| 112 | + border-right:1.5px solid rgba(20,24,20,.15)} | |
| 113 | + .kaa-card-body{flex:1;display:flex;flex-direction:column;gap:2px;padding:8px 11px;min-width:0} | |
| 114 | + .kaa-card-top{display:flex;gap:6px;align-items:center;flex-wrap:wrap} | |
| 115 | + .kaa-card-site{font:700 9px "JetBrains Mono",monospace;letter-spacing:.08em;text-transform:uppercase; | |
| 116 | + background:var(--kaa-c,var(--accent,#d9f26b));color:var(--kaa-on,var(--on-accent,#141814));border-radius:5px;padding:1px 6px 2px} | |
| 117 | + .kaa-card-badge{font:700 9px "JetBrains Mono",monospace;letter-spacing:.06em;text-transform:uppercase; | |
| 118 | + border:1px dashed var(--ink-2,#4d5551);border-radius:999px;padding:1px 7px;color:var(--ink-2,#4d5551)} | |
| 119 | + .kaa-card-title{font:700 13.5px "Space Grotesk",system-ui,sans-serif;letter-spacing:-.01em;line-height:1.25} | |
| 120 | + .kaa-card-sub{font-size:11.5px;color:var(--ink-2,#4d5551);line-height:1.35} | |
| 121 | + .kaa-card-price{font:700 13px "Space Grotesk",system-ui,sans-serif;margin-top:1px} | |
| 122 | + .kaa-card-go{flex:none;align-self:center;padding:0 10px;font-weight:700;opacity:.55} | |
| 123 | + .kaa-choices{display:flex;flex-wrap:wrap;gap:7px;margin:.45em 0 .15em;align-items:center} | |
| 124 | + .kaa-choices-q{flex-basis:100%;font-size:12px;color:var(--ink-2,#4d5551);font-weight:600} | |
| 125 | + .kaa-choice{border:1.5px solid var(--ink,#141814);border-radius:999px;background:var(--paper,#f5f3ee); | |
| 126 | + color:var(--ink,#141814);font:600 12.5px Inter,system-ui,sans-serif;padding:7px 13px;cursor:pointer; | |
| 127 | + box-shadow:2px 2px 0 rgba(20,24,20,.35);transition:transform .1s;touch-action:manipulation} | |
| 128 | + .kaa-choice:hover{background:var(--accent,#d9f26b);color:var(--on-accent,#141814);transform:translate(-1px,-1px)} | |
| 129 | + .kaa-choices.kaa-done .kaa-choice{opacity:.45;pointer-events:none;box-shadow:none} | |
| 99 | 130 | .kaa-hello{font-size:12.5px;color:var(--ink-2,#4d5551);padding:4px 2px;max-width:760px} |
| 100 | 131 | .kaa-dots::after{content:"…";animation:kaa-b 1.2s infinite} |
| 101 | 132 | @keyframes kaa-b{0%{opacity:.2}50%{opacity:1}100%{opacity:.2}} |
@@ -104,7 +135,63 @@ | ||
| 104 | 135 | |
| 105 | 136 | /* ---------- markdown complet (rendu en streaming, texte échappé d'abord) ---------- */ |
| 106 | 137 | function esc(s) { |
| 107 | − return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); | |
| 138 | + return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """); | |
| 139 | + } | |
| 140 | + | |
| 141 | + /* ---------- cartes + choix (v4) ---------- | |
| 142 | + Palette de l'écosystème (ka-ui/ecosystem.json) embarquée : chaque carte | |
| 143 | + prend les couleurs de la plateforme de SA fiche, pas du site hôte. */ | |
| 144 | + var ECO = { | |
| 145 | + "groupe-ka": ["Groupe KA", "#d9f26b", "#141814"], | |
| 146 | + "trouve-ka": ["Trouve·Ka", "#1c7ed6", "#ffffff"], | |
| 147 | + "lou-ka": ["Lou·Ka", "#ff6a00", "#ffffff"], | |
| 148 | + "immo-ka": ["Immo·Ka", "#e23744", "#ffffff"], | |
| 149 | + "vrai-prix": ["Vrai-Prix", "#ff5148", "#ffffff"], | |
| 150 | + "auto-ka": ["Auto·Ka", "#ff5a2a", "#ffffff"], | |
| 151 | + "fabri-ka": ["Fabri·Ka", "#c4532e", "#ffffff"], | |
| 152 | + "food-ka": ["Food·Ka", "#1f9d55", "#ffffff"], | |
| 153 | + "resto-ka": ["Resto·Ka", "#f08c00", "#141814"], | |
| 154 | + "sorti-ka": ["Sorti·Ka", "#d6336c", "#ffffff"], | |
| 155 | + "crea-ka": ["Créa·Ka", "#7048e8", "#ffffff"], | |
| 156 | + "api-ka": ["API·Ka", "#3b5bdb", "#ffffff"], | |
| 157 | + "job-ka": ["Job·Ka", "#0c8599", "#ffffff"], | |
| 158 | + "valoplex": ["ValoPlex", "#ff9f45", "#141814"] | |
| 159 | + }; | |
| 160 | + function httpUrl(u) { return typeof u === "string" && /^https:\/\//.test(u) ? u : ""; } | |
| 161 | + function cards(lines) { | |
| 162 | + var html = ""; | |
| 163 | + lines.forEach(function (ln) { | |
| 164 | + ln = ln.trim(); | |
| 165 | + if (!ln) return; | |
| 166 | + var o = null; | |
| 167 | + try { o = JSON.parse(ln); } catch (e) { return; } // ligne incomplète (streaming) → ignorée | |
| 168 | + if (!o || !o.titre || !httpUrl(o.lien)) return; | |
| 169 | + var pal = ECO[o.site] || ["Groupe KA", "var(--accent,#d9f26b)", "var(--on-accent,#141814)"]; | |
| 170 | + var img = httpUrl(o.image); | |
| 171 | + html += '<a class="kaa-card" href="' + esc(o.lien) + '" target="_blank" rel="noopener noreferrer"' + | |
| 172 | + ' style="--kaa-c:' + pal[1] + ";--kaa-on:" + pal[2] + '">' + | |
| 173 | + (img ? '<span class="kaa-card-img" style="background-image:url("' + esc(img) + '")"></span>' : "") + | |
| 174 | + '<span class="kaa-card-body"><span class="kaa-card-top">' + | |
| 175 | + '<span class="kaa-card-site">' + esc(pal[0]) + "</span>" + | |
| 176 | + (o.badge ? '<span class="kaa-card-badge">' + esc(String(o.badge)) + "</span>" : "") + | |
| 177 | + "</span>" + | |
| 178 | + '<span class="kaa-card-title">' + esc(String(o.titre)) + "</span>" + | |
| 179 | + (o.sous_titre ? '<span class="kaa-card-sub">' + esc(String(o.sous_titre)) + "</span>" : "") + | |
| 180 | + (o.prix ? '<span class="kaa-card-price">' + esc(String(o.prix)) + "</span>" : "") + | |
| 181 | + '</span><span class="kaa-card-go">→</span></a>'; | |
| 182 | + }); | |
| 183 | + return html ? '<div class="kaa-cards">' + html + "</div>" : ""; | |
| 184 | + } | |
| 185 | + function choices(lines) { | |
| 186 | + var o = null; | |
| 187 | + try { o = JSON.parse(lines.join("\n")); } catch (e) { return ""; } // bloc incomplet (streaming) | |
| 188 | + if (!o || !Array.isArray(o.options) || !o.options.length) return ""; | |
| 189 | + var h = '<span class="kaa-choices">' + | |
| 190 | + (o.question ? '<span class="kaa-choices-q">' + esc(String(o.question)) + "</span>" : ""); | |
| 191 | + o.options.slice(0, 6).forEach(function (op) { | |
| 192 | + h += '<button type="button" class="kaa-choice">' + esc(String(op)) + "</button>"; | |
| 193 | + }); | |
| 194 | + return h + "</span>"; | |
| 108 | 195 | } |
| 109 | 196 | function inline(s) { |
| 110 | 197 | s = esc(s); |
@@ -124,11 +211,14 @@ | ||
| 124 | 211 | function para(buf) { if (buf.length) out.push("<p>" + buf.map(inline).join("<br>") + "</p>"); } |
| 125 | 212 | while (i < lines.length) { |
| 126 | 213 | var l = lines[i]; |
| 127 | − if (/^\s*```/.test(l)) { /* bloc de code */ | |
| 214 | + if (/^\s*```/.test(l)) { /* bloc de code / carte / choix */ | |
| 215 | + var lang = (l.match(/^\s*```\s*([\w-]+)?/) || [])[1] || ""; | |
| 128 | 216 | var code = []; i++; |
| 129 | 217 | while (i < lines.length && !/^\s*```/.test(lines[i])) code.push(lines[i++]); |
| 130 | 218 | i++; |
| 131 | − out.push("<pre><code>" + esc(code.join("\n")) + "</code></pre>"); | |
| 219 | + if (lang === "ka-card") out.push(cards(code)); | |
| 220 | + else if (lang === "ka-choix") out.push(choices(code)); | |
| 221 | + else out.push("<pre><code>" + esc(code.join("\n")) + "</code></pre>"); | |
| 132 | 222 | } else if ((m = l.match(/^\s*(#{1,4})\s+(.*)$/))) { /* titres */ |
| 133 | 223 | out.push("<h" + m[1].length + ">" + inline(m[2]) + "</h" + m[1].length + ">"); i++; |
| 134 | 224 | } else if (/^\s*(---+|\*\*\*+)\s*$/.test(l)) { /* filet */ |
@@ -230,15 +320,25 @@ | ||
| 230 | 320 | if (log.length) return; |
| 231 | 321 | var d = document.createElement("div"); |
| 232 | 322 | d.className = "kaa-hello"; |
| 233 | − d.textContent = "👋 Je suis KA Agent, l'assistant de l'écosystème Groupe KA. Posez-moi une question sur ce site, ses données (prix, annonces, fiches, stats…) ou sur le groupe."; | |
| 323 | + d.textContent = "👋 Je suis KA Agent, l'assistant de l'écosystème Groupe KA. Je peux chercher dans TOUTES les plateformes du groupe : logements, propriétés, autos, emplois, épicerie, restos, sorties, créateurs, produits d'ici — plus estimations de valeur, annuaires (déménageurs, inspecteurs), historiques et statistiques. Posez votre question !"; | |
| 234 | 324 | logEl.appendChild(d); |
| 235 | 325 | } |
| 326 | + /* les boutons de choix ne restent actifs que dans la DERNIÈRE bulle assistante */ | |
| 327 | + function retireChoices(keepLast) { | |
| 328 | + var groups = logEl.querySelectorAll(".kaa-choices:not(.kaa-done)"); | |
| 329 | + var msgs = logEl.querySelectorAll(".kaa-msg.kaa-a"); | |
| 330 | + var last = msgs.length ? msgs[msgs.length - 1] : null; | |
| 331 | + groups.forEach(function (g) { | |
| 332 | + if (!(keepLast && last && last.contains(g))) g.classList.add("kaa-done"); | |
| 333 | + }); | |
| 334 | + } | |
| 236 | 335 | function render() { |
| 237 | 336 | logEl.innerHTML = ""; |
| 238 | 337 | hello(); |
| 239 | 338 | log.forEach(function (m) { |
| 240 | 339 | m.role === "user" ? bubble("kaa-u", esc(m.content)) : bubble("kaa-a", md(m.content)); |
| 241 | 340 | }); |
| 341 | + retireChoices(log.length && log[log.length - 1].role === "assistant"); | |
| 242 | 342 | scroll(); |
| 243 | 343 | } |
| 244 | 344 | |
@@ -385,6 +485,7 @@ | ||
| 385 | 485 | busy = true; |
| 386 | 486 | send.disabled = true; |
| 387 | 487 | ta.value = ""; |
| 488 | + retireChoices(false); // un nouveau message clôt les choix en suspens | |
| 388 | 489 | log.push({ role: "user", content: q }); |
| 389 | 490 | save(); |
| 390 | 491 | bubble("kaa-u", esc(q)); |
@@ -453,6 +554,13 @@ | ||
| 453 | 554 | ta.addEventListener("keydown", function (e) { |
| 454 | 555 | if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); ask(); } |
| 455 | 556 | }); |
| 557 | + logEl.addEventListener("click", function (e) { /* clic sur un bouton de choix (v4) */ | |
| 558 | + var b = e.target && e.target.closest ? e.target.closest(".kaa-choice") : null; | |
| 559 | + if (!b || busy) return; | |
| 560 | + var g = b.closest(".kaa-choices"); | |
| 561 | + if (g && g.classList.contains("kaa-done")) return; | |
| 562 | + ta.value = b.textContent; | |
| 563 | + ask(); | |
| 564 | + }); | |
| 456 | 565 | })(); |
| 457 | − | |
| 458 | −;/*KA_ANALYTICS*/(function(){try{if(window.__kaAn)return;window.__kaAn=1;var k="KA_VID",v=localStorage.getItem(k);if(!v){v=Date.now().toString(36)+Math.random().toString(36).slice(2,8);localStorage.setItem(k,v);}var b=function(){var i=new Image();i.src="https://www.administration-ka.com/collect?site=crea-ka&vid="+v+"&p="+encodeURIComponent(location.pathname)+"&t="+Date.now();};b();setInterval(b,60000);}catch(e){}})(); | |
| 566 | +/*KA_ANALYTICS*/(function(){try{if(window.__kaAn)return;window.__kaAn=1;var k="KA_VID",v=localStorage.getItem(k);if(!v){v=Date.now().toString(36)+Math.random().toString(36).slice(2,8);localStorage.setItem(k,v);}var b=function(){var i=new Image();i.src="https://www.administration-ka.com/collect?site=crea-ka&vid="+v+"&p="+encodeURIComponent(location.pathname)+"&t="+Date.now();};b();setInterval(b,60000);}catch(e){}})(); | |
| 459 | 567 | |