Grammarly 插件在检测到错误后,Grammarly 插件会通过以下方式在网页上标记错误并显示下划线提示:

错误标记

  • 动态插入元素:插件会在检测到错误的文本位置动态插入 HTML 元素(如 <span>),并为这些元素添加特定的 CSS 类(如 grammarly-error)。

  • CSS 样式:通过 CSS 样式为这些元素添加下划线(通常是红色波浪线)或其他视觉提示。

逻辑推测

在 Overleaf 或其他类似的在线编辑器中,虽然表面上没有明显的 <input><textarea> 输入框,但实际上编辑器是通过 自定义的富文本编辑器代码编辑器 来实现文本输入的。这些编辑器通常基于 内容可编辑的 HTML 元素(如 contenteditable)或 自定义的 DOM 结构,Grammarly 插件能够通过监听这些元素的输入事件来实现语法检查。

以下是 Grammarly 插件在 Overleaf 中实现监听和语法检查的原理:


1. 内容可编辑的 HTML 元素

Overleaf 的编辑器通常使用 contenteditable 属性来实现文本输入。contenteditable 是 HTML5 的一个特性,允许用户直接编辑 HTML 元素的内容。

示例

<div class="cm-content" contenteditable="true" spellcheck="false">
    \documentclass{article}
    \usepackage{graphicx}
    \title{AI Helper}
    \author{福来科技 金}
    \date{July 2024}
    \begin{document}
    \maketitle
    \section{Introduction}
    \end{document}
</div>

运行 HTML

  • contenteditable="true":表示该元素的内容可以被用户编辑。

  • spellcheck="false":禁用浏览器的默认拼写检查(因为 Grammarly 会接管)。

Grammarly 的监听机制

Grammarly 插件会通过以下方式监听 contenteditable 元素的输入事件:

  1. DOM 监听:插件会监听 contenteditable 元素的 input 事件,实时捕获用户输入的内容。

  2. 文本分析:捕获的文本会被发送到 Grammarly 的服务器进行分析,返回语法错误和建议。

  3. 错误标记:插件会在 contenteditable 元素中动态插入 HTML 元素(如 <span>),并通过 CSS 样式添加下划线提示。


2. 自定义的代码编辑器

Overleaf 的编辑器是基于 CodeMirrorMonaco Editor 等代码编辑器实现的。这些编辑器通常会将用户输入的内容渲染为自定义的 DOM 结构,而不是传统的 <input><textarea>

示例

从代码片段中可以看到,Overleaf 使用了类似以下的 DOM 结构:

<div class="cm-content" role="textbox" aria-multiline="true" spellcheck="false" autocorrect="off" autocapitalize="off" translate="no" contenteditable="true">
    <div class="cm-line">\documentclass{article}</div>
    <div class="cm-line">\usepackage{graphicx}</div>
    <div class="cm-line">\title{AI Helper}</div>
    <div class="cm-line">\author{福来科技 金}</div>
    <div class="cm-line">\date{July 2024}</div>
    <div class="cm-line">\begin{document}</div>
    <div class="cm-line">\maketitle</div>
    <div class="cm-line">\section{Introduction}</div>
    <div class="cm-line">\end{document}</div>
</div>

运行 HTML

  • 每一行文本都被渲染为一个 <div class="cm-line"> 元素。

  • 整个编辑器区域是一个 contenteditable 的容器。

Grammarly 的监听机制

Grammarly 插件会通过以下方式监听自定义编辑器的输入事件:

  1. 监听 DOM 变化:插件会监听 cm-content 容器的 input 事件或 MutationObserver,实时捕获用户输入的内容。

  2. 文本分析:捕获的文本会被发送到 Grammarly 的服务器进行分析,返回语法错误和建议。

  3. 错误标记:插件会在 cm-line 元素中动态插入 HTML 元素(如 <span>),并通过 CSS 样式添加下划线提示。


3. Grammarly 插件的实现细节

Grammarly 插件通过以下技术实现监听和错误标记:

DOM 监听

  • MutationObserver:Grammarly 使用 MutationObserver 监听 contenteditable 元素或其子元素的变化(如文本插入、删除、修改等)。

  • input 事件:插件会监听 input 事件,实时捕获用户输入的内容。

错误标记

  • 动态插入元素:插件会在检测到错误的文本位置动态插入 HTML 元素(如 <span>),并为这些元素添加特定的 CSS 类(如 grammarly-error)。

  • CSS 样式:通过 CSS 样式为这些元素添加下划线(通常是红色波浪线)或其他视觉提示。

示例代码

以下是一个简化的示例,展示 Grammarly 插件如何实现错误标记:

// 监听 contenteditable 元素的 input 事件
document.querySelector('.cm-content').addEventListener('input', function(event) {
    const text = event.target.textContent;
    // 发送文本到 Grammarly 服务器进行分析
    grammarlyAnalyze(text).then(errors => {
        // 动态插入错误标记
        errors.forEach(error => {
            const span = document.createElement('span');
            span.className = 'grammarly-error';
            span.textContent = error.text;
            event.target.insertBefore(span, error.position);
        });
    });
});

4.请求处理

在每次编辑后并没有每次都发送请求?那么他是如何获取到我最新的输入的?

Grammarly 插件在浏览器中运行一个 轻量级的本地分析引擎,用于实时检测常见的语法错误、拼写错误和标点问题。这种设计是为了提供快速反馈并减少对服务器的依赖,从而提升用户体验。

以下是一些支持 Grammarly 使用本地分析引擎的证据:

(1)快速反馈

如果你使用 Grammarly 插件,你会发现它在你输入时几乎 立即 提供拼写和简单语法错误的反馈。这种低延迟的反馈表明,Grammarly 在本地进行了初步分析,而不是每次都依赖服务器。

(2)离线功能

Grammarly 插件在 离线状态 下仍然可以检测拼写错误和部分语法错误。这表明它确实在本地运行了一个分析引擎,而不是完全依赖网络请求。

(3)网络请求优化

通过浏览器的开发者工具(F12 -> Network 选项卡),你可以观察到 Grammarly 插件并不会在每次输入时都发送请求。相反,它会在特定条件下(如复杂语法分析或用户交互)才向服务器发送请求。

(4)官方文档

虽然 Grammarly 没有公开详细的实现细节,但其官方文档和开发者资源中提到,插件会在本地进行初步分析,以减少对服务器的依赖并提高性能。

5.本地分析引擎的实现推测

5.1 自定义实现

(1)拼写检查器

拼写检查器是本地分析引擎的核心组件之一。它通常基于以下技术实现:

  • 本地词典:使用预编译的词典文件(如 Hunspell)来检测拼写错误。

  • 词形变化:支持不同语言的词形变化(如复数、时态等)。

  • 自定义词典:允许用户添加自定义词汇。

(2)简单语法规则

简单语法规则通常以预定义的规则集形式嵌入到插件中。这些规则可以检测常见的语法错误,例如:

  • 主谓一致

  • 时态错误

  • 冠词使用错误

(3)标点符号检查

标点符号检查通常基于简单的规则和上下文分析。例如:

  • 检测缺少句号。

  • 检测逗号使用是否正确。

5.2 本地 AI 模型的可能性

现代浏览器和 JavaScript 引擎的性能已经足够强大,可以运行轻量级的 AI 模型。Grammarly 的本地分析引擎很可能使用了以下技术:

(1)轻量级 AI 模型

  • 模型压缩:通过模型压缩技术(如量化、剪枝、蒸馏等),将 AI 模型压缩到适合在浏览器中运行的规模。

  • 预训练模型:使用预训练的轻量级模型(如 BERT 的小型版本)进行语法和拼写检查。

  • 本地推理:在浏览器中使用 JavaScript 或 WebAssembly 运行这些模型。

(2)WebAssembly 支持

  • 高性能计算:WebAssembly(Wasm)是一种可以在浏览器中运行的高性能二进制格式,适合运行计算密集型的 AI 模型。

  • TensorFlow.js:Google 的 TensorFlow.js 是一个 JavaScript 库,支持在浏览器中运行 AI 模型。

5.3 本地 AI 模型的实现

以下是一个简化的示例,展示如何在浏览器中运行轻量级的 AI 模型:

(1)使用 TensorFlow.js

TensorFlow.js 是一个流行的 JavaScript 库,支持在浏览器中运行 AI 模型。Grammarly 可能使用了类似的技术。

示例代码

// 加载 TensorFlow.js
import * as tf from '@tensorflow/tfjs';

// 加载预训练的轻量级模型
const model = await tf.loadLayersModel('https://example.com/grammar-model.json');

// 输入文本
const text = "This is a example sentence.";

// 将文本转换为模型输入
const input = preprocessText(text);

// 运行模型
const output = model.predict(input);

// 解析模型输出
const errors = parseOutput(output);
console.log(errors); // 输出: [{ error: '语法错误', suggestion: 'an', position: 10 }]

(2)使用 WebAssembly

WebAssembly 可以提供更高的性能,适合运行计算密集型的 AI 模型。

示例代码

// 加载 WebAssembly 模块
const wasmModule = await WebAssembly.compileStreaming(fetch('grammar-checker.wasm'));

// 实例化 WebAssembly 模块
const instance = await WebAssembly.instantiate(wasmModule);

// 输入文本
const text = "This is a example sentence.";

// 将文本传递给 WebAssembly 模块
const errors = instance.exports.checkGrammar(text);
console.log(errors); // 输出: [{ error: '语法错误', suggestion: 'an', position: 10 }]

6. 总结

在 Overleaf 或其他类似的在线编辑器中,虽然没有传统的 <input><textarea> 输入框,但编辑器通过 contenteditable 或自定义的 DOM 结构实现了文本输入。Grammarly 插件通过监听这些元素的输入事件,并结合 AI 和 NLP 技术,实现了语法错误的实时检测和下划线提示。