diff --git a/frontend/editor-poc.html b/frontend/editor-poc.html index 5ab5b76..5eae16e 100644 --- a/frontend/editor-poc.html +++ b/frontend/editor-poc.html @@ -1814,14 +1814,23 @@ 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 < 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; + var fullText = ta.value.slice(0, ta.selectionStart); + if (fullText.trim().length < 1) return; + // Detect context: mid-word vs end of phrase + var lastChar = fullText.slice(-1); + var midWord = /[a-zA-Z0-9\u00C0-\u024F]$/.test(lastChar); + + // For mid-word: extract the current word and ask AI to complete just it + var prompt, inputText; + if (midWord) { + var wordMatch = fullText.match(/([\w\u00C0-\u024F]+)$/); + var partialWord = wordMatch ? wordMatch[1] : fullText; + inputText = partialWord; + prompt = 'Complete this word. Return ONLY the remaining letters (no spaces, no extra text): ' + partialWord; + } else { + inputText = fullText; + prompt = 'Continue this text. Return ONLY the new text (do NOT repeat what is already written):\n' + fullText; + } fetch('/api/ai/inline-complete', { method: 'POST', @@ -1830,10 +1839,19 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig }) .then(function(r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); }) .then(function(data) { - var prediction = (data.result || '').trim(); - // Only show if prediction adds something new + var raw = (data.result || '').trim(); + if (!raw || raw.length < 1) return; + // Strip any echoed input from the response + var prediction = raw; + if (midWord && prediction.toLowerCase().startsWith(inputText.toLowerCase())) { + prediction = prediction.slice(inputText.length); + } else if (!midWord && prediction.startsWith(inputText)) { + prediction = prediction.slice(inputText.length); + } + prediction = prediction.trim(); + // Only show if prediction adds something meaningful var alreadyThere = ta.value.slice(ta.selectionStart).trimStart(); - if (prediction && prediction.length > 1 && !alreadyThere.startsWith(prediction.slice(0, Math.min(8, prediction.length)))) { + if (prediction && prediction.length > 0 && !alreadyThere.startsWith(prediction.slice(0, Math.min(6, prediction.length)))) { showGhost(prediction); } })