diff --git a/src/content/content.js b/src/content/content.js index c8e1243..28446b9 100644 --- a/src/content/content.js +++ b/src/content/content.js @@ -791,12 +791,45 @@ if (isExamPage) { return `Certification Exam: ${title}. Page type: exam/assessment. DO NOT help with answers.`; } - const headings = Array.from(document.querySelectorAll('h1, h2, h3, h4')) - .map((h) => h.textContent.trim()) - .slice(0, 5) + // Heading map with the section the user is currently reading marked — + // gives the tutor a table of contents plus "you are here". + const hs = Array.from(document.querySelectorAll('h1, h2, h3, h4')); + let currentIdx = -1; + for (let i = 0; i < hs.length; i++) { + if (hs[i].getBoundingClientRect().top <= 80) currentIdx = i; + } + const headings = hs + .slice(0, 8) + .map((h, i) => (i === currentIdx ? `▶ ${h.textContent.trim()}` : h.textContent.trim())) .join(', '); const lessonBody = document.querySelector('#lesson-main, .lesson-content, .course-content, main'); - const bodyText = lessonBody ? lessonBody.innerText.replace(/\s+/g, ' ').trim().slice(0, 2000) : ''; + // Viewport-centred extract: long lessons used to send only the FIRST + // 2,000 chars, so questions about anything past the fold had no grounding. + // Now: a short lesson opening for global context + the text from the block + // the user is actually looking at. Hard-capped at 2,000 chars total — the + // privacy policy discloses "≤2,000 chars of lesson context" and that cap + // must hold no matter how the pieces combine. + let bodyText = ''; + if (lessonBody) { + const flat = lessonBody.innerText.replace(/\s+/g, ' ').trim(); + const blocks = Array.from(lessonBody.querySelectorAll('p, li, h2, h3, h4, pre, td')); + const vpIdx = blocks.findIndex((el) => el.getBoundingClientRect().bottom > 0); + if (vpIdx > 0) { + let current = ''; + for (let i = Math.max(0, vpIdx - 1); i < blocks.length && current.length < 1500; i++) { + current += blocks[i].innerText.replace(/\s+/g, ' ').trim() + ' '; + } + current = current.trim().slice(0, 1500); + const opening = flat.slice(0, 400); + bodyText = + current && !opening.includes(current.slice(0, 80)) + ? `${opening}\n\n[User is currently viewing:]\n${current}` + : flat.slice(0, 2000); + } else { + bodyText = flat.slice(0, 2000); + } + bodyText = bodyText.slice(0, 2000); + } return `Course: ${title}. Sections: ${headings}${bodyText ? `\n\nLesson content:\n${bodyText}` : ''}`; } diff --git a/src/lib/constants.js b/src/lib/constants.js index 3f1964b..ab36cb9 100644 --- a/src/lib/constants.js +++ b/src/lib/constants.js @@ -422,17 +422,47 @@ const ONBOARDING_LABELS = { }; const EXAMPLE_QUESTIONS = { - en: ['Explain this concept simply', 'What are the key takeaways?', 'Give me a practical example'], - ko: ['이 개념을 쉽게 설명해줘', '핵심 포인트가 뭐야?', '실제 예시를 들어줘'], - ja: ['この概念を簡単に説明して', '重要なポイントは?', '実例を教えて'], - 'zh-CN': ['简单解释一下这个概念', '关键要点是什么?', '给我一个实际例子'], - 'zh-TW': ['簡單解釋一下這個概念', '關鍵要點是什麼?', '給我一個實際例子'], - es: ['Explica este concepto de forma simple', '¿Cuáles son los puntos clave?', 'Dame un ejemplo práctico'], - fr: ['Explique ce concept simplement', 'Quels sont les points clés ?', 'Donne-moi un exemple pratique'], - de: ['Erkläre dieses Konzept einfach', 'Was sind die wichtigsten Punkte?', 'Gib mir ein praktisches Beispiel'], - 'pt-BR': ['Explique este conceito de forma simples', 'Quais são os pontos-chave?', 'Me dê um exemplo prático'], - ru: ['Объясни эту концепцию простыми словами', 'Какие ключевые выводы?', 'Приведи практический пример'], - vi: ['Giải thích khái niệm này một cách đơn giản', 'Những điểm chính là gì?', 'Cho tôi một ví dụ thực tế'], + en: ['Explain this concept simply', 'What are the key takeaways?', 'Quiz me on this lesson', 'Summarize this lesson'], + ko: ['이 개념을 쉽게 설명해줘', '핵심 포인트가 뭐야?', '이 레슨으로 퀴즈 내줘', '이 레슨 요약해줘'], + ja: ['この概念を簡単に説明して', '重要なポイントは?', 'このレッスンでクイズを出して', 'このレッスンを要約して'], + 'zh-CN': ['简单解释一下这个概念', '关键要点是什么?', '就这节课考考我', '总结一下这节课'], + 'zh-TW': ['簡單解釋一下這個概念', '關鍵要點是什麼?', '就這節課考考我', '總結一下這節課'], + es: [ + 'Explica este concepto de forma simple', + '¿Cuáles son los puntos clave?', + 'Hazme un quiz sobre esta lección', + 'Resume esta lección', + ], + fr: [ + 'Explique ce concept simplement', + 'Quels sont les points clés ?', + 'Fais-moi un quiz sur cette leçon', + 'Résume cette leçon', + ], + de: [ + 'Erkläre dieses Konzept einfach', + 'Was sind die wichtigsten Punkte?', + 'Frag mich zu dieser Lektion ab', + 'Fasse diese Lektion zusammen', + ], + 'pt-BR': [ + 'Explique este conceito de forma simples', + 'Quais são os pontos-chave?', + 'Me faça um quiz sobre esta lição', + 'Resuma esta lição', + ], + ru: [ + 'Объясни эту концепцию простыми словами', + 'Какие ключевые выводы?', + 'Проверь меня по этому уроку', + 'Кратко изложи этот урок', + ], + vi: [ + 'Giải thích khái niệm này một cách đơn giản', + 'Những điểm chính là gì?', + 'Đố tôi về bài học này', + 'Tóm tắt bài học này', + ], }; const A11Y_LABELS = {