From 9792c6a08b5549a74c762213c7e22a958d889918 Mon Sep 17 00:00:00 2001 From: Bruno Charest Date: Tue, 16 Jun 2026 11:55:12 -0400 Subject: [PATCH] fix: ghost text visible (innerHTML + span) + IA flexible mot/phrase/bloc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - showGhost utilise innerHTML avec span.ghost-prediction (etait invisible) - Prompt intelligent: mid-word = complete le mot, sinon complete 1-2 phrases - Seuil reduit: 1 caractere minimum (au lieu de 3) - Detection doublon amelioree (trimStart) - Timeout reduit: 800ms → 600ms --- frontend/editor-poc.html | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/frontend/editor-poc.html b/frontend/editor-poc.html index 0ea40b6..5ab5b76 100644 --- a/frontend/editor-poc.html +++ b/frontend/editor-poc.html @@ -1788,14 +1788,15 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig function clearGhost() { _ghostText = ''; - ghostOverlay.textContent = ''; + ghostOverlay.innerHTML = ''; } function showGhost(prediction) { if (!prediction) { clearGhost(); return; } _ghostText = prediction; var before = ta.value.slice(0, ta.selectionStart); - ghostOverlay.textContent = before + prediction; + // Show: existing text (transparent) + prediction (visible faded) + ghostOverlay.innerHTML = escHtml(before) + '' + escHtml(prediction) + ''; } function acceptGhost() { @@ -1814,16 +1815,25 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig function requestGhostCompletion() { var text = ta.value.slice(0, ta.selectionStart); - if (text.trim().length < 3) return; + if (text.trim().length < 1) return; + // Smart prompt: detect if mid-word, mid-phrase, or new block + var lastChar = text.slice(-1); + var midWord = /[a-zA-Z0-9]$/.test(lastChar); + var prompt = midWord + ? 'Complete ONLY the current word being typed. Return ONLY the completion (no extra text):\n\n' + text + : 'Complete this text naturally in 1-2 short phrases. Return ONLY the new text (no repetition):\n\n' + text; + fetch('/api/ai/inline-complete', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ text: text, provider: 'ollama' }) + body: JSON.stringify({ text: prompt, provider: 'ollama' }) }) .then(function(r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); }) .then(function(data) { var prediction = (data.result || '').trim(); - if (prediction && !ta.value.slice(ta.selectionStart).startsWith(prediction.slice(0, 10))) { + // Only show if prediction adds something new + var alreadyThere = ta.value.slice(ta.selectionStart).trimStart(); + if (prediction && prediction.length > 1 && !alreadyThere.startsWith(prediction.slice(0, Math.min(8, prediction.length)))) { showGhost(prediction); } }) @@ -1834,7 +1844,7 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig ta.addEventListener('input', function() { clearGhost(); if (_ghostTimer) clearTimeout(_ghostTimer); - _ghostTimer = setTimeout(requestGhostCompletion, 800); + _ghostTimer = setTimeout(requestGhostCompletion, 600); }); function escHtml(s) { return String(s).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"'); }