e77f69c5c4dd6192e57e8564b7ae87ea2cc29250
LLM in Text - 智能写作助手
基于 Vue3 和 FastAPI 的智能 Markdown 编辑器,集成大语言模型(LLM)实时补全建议功能,提供类似 GitHub Copilot 的 Ghost Text 体验。
功能特性
Markdown 编辑器
- 基于 Milkdown Crepe 的所见即所得编辑体验
- 支持完整 Markdown 语法和 LaTeX 公式
- 导入/导出 Markdown 文件
AI 智能补全
- 实时生成文本补全建议(灰色显示)
- 流式响应,低延迟体验
- 多种交互方式:
- Tab 键:接受建议
- Esc 键:拒绝建议
- 点击灰色文本:接受建议
- 继续输入:自动拒绝建议
AI 开关控制
- 右下角 AI 开关按钮
- 白色 = AI 启用,黑色 = AI 禁用
- 禁用时自动清除灰色文本并停止 API 调用
技术架构
flowchart TB
subgraph Frontend["前端 (Vue3 + Vite)"]
A[App.vue] --> B[MilkdownEditor.vue]
B --> C[Crepe Editor]
C --> D[ProseMirror]
D --> E[copilotPlugin.ts]
E --> F[copilotGhostMark]
E --> G[api.js]
end
subgraph Backend["后端 (FastAPI + Python)"]
H[main.py<br/>FastAPI Server] --> I[prompt.py<br/>Prompt 构建]
H --> J[llm.py<br/>Ollama 调用]
J --> K[Ollama API]
end
G -->|POST /v1/completions<br/>SSE 流式响应| H
K -->|LLM 响应| J
项目结构
llm-in-text/
├── src/
│ ├── components/
│ │ └── MilkdownEditor.vue # 主编辑器组件
│ ├── plugins/
│ │ ├── copilotPlugin.ts # ProseMirror AI 补全插件
│ │ ├── types.ts # 类型定义
│ │ └── index.ts # 插件导出
│ ├── utils/
│ │ ├── api.js # API 调用封装
│ │ ├── config.js # 配置文件
│ │ └── ocrCache.js # OCR 缓存管理
│ ├── App.vue
│ └── main.js
├── backend/
│ ├── main.py # FastAPI 服务器
│ ├── llm.py # LLM API 调用
│ ├── prompt.py # Prompt 构建
│ └── requirements.txt
└── README.md
快速开始
环境要求
- Node.js 18+
- Python 3.8+
- Ollama 服务(或其他兼容 OpenAI API 的服务)
安装
# 前端
npm install
# 后端
cd backend
pip install -r requirements.txt
配置
在 backend/.env 中配置:
OLLAMA_MODEL=gpt-oss:20b
OLLAMA_HOST=http://localhost:11434
启动
# 后端(端口 8000)
cd backend
python main.py
# 前端(端口 5173)
npm run dev
API 接口
POST /v1/completions
流式获取补全建议
请求:
{
"prefix": "# Title\n\nContent ",
"suffix": "",
"languageId": "markdown"
}
响应(SSE):
data: {"content": "here"}
data: {"content": "here is"}
data: {"done": true}
核心实现
后端设计
main.py - FastAPI 服务器
- 定义
/v1/completions端点 - 使用
StreamingResponse返回 SSE 流式响应 - CORS 配置允许跨域请求
llm.py - LLM 调用封装
- 使用
ollama.AsyncClient异步调用 - 支持
think='high'思考模式 - 返回
content和thinking字段
prompt.py - Prompt 工程
精心设计的 Prompt 模板,包含 7 条核心规则:
| 规则 | 说明 |
|---|---|
| RULE #1 | 无缝连接 - 不重复 suffix 内容,避免"复读机"错误 |
| RULE #2 | 空白处理 - 避免双空格,正确对接标点 |
| RULE #3 | 缩进对齐 - 匹配当前缩进级别和类型 |
| RULE #4 | 列表维护 - 识别并继续任务列表、有序列表、无序列表 |
| RULE #5 | 语法闭合 - 自动闭合未完成的 Markdown 语法 |
| RULE #6 | 输出格式 - 仅输出续写文本,无解释无注释 |
| RULE #7 | 必须输出 - 始终提供有用的续写建议 |
前端设计
ProseMirror Mark 系统
使用 ProseMirror 的 Mark 系统实现灰色建议文本:
// 定义 ghost mark
export const copilotGhostMark = $markSchema('copilot_ghost', () => ({
excludes: '_',
inclusive: true,
toDOM: () => ['span', {
'data-copilot-ghost': '',
class: 'copilot-ghost-text'
}, 0]
}))
// CSS 样式
.copilot-ghost-text {
color: #999;
opacity: 0.6;
}
copilotPlugin 核心逻辑
flowchart LR
A[用户输入] --> B{文档变化?}
B -->|是| C[清除旧建议]
C --> D[防抖 1000ms]
D --> E[发送 API 请求]
E --> F[收到建议]
F --> G[插入 Ghost Text]
G --> H{用户操作}
H -->|Tab| I[接受建议<br/>移除 mark]
H -->|Esc| J[拒绝建议<br/>删除文本]
H -->|点击 Ghost| I
H -->|继续输入| J
关键函数
| 函数 | 作用 |
|---|---|
scheduleFetch |
防抖调度 API 请求 |
insertGhostText |
插入带 mark 的建议文本 |
acceptSuggestion |
Tab 接受建议 |
rejectSuggestion |
Esc 拒绝建议 |
clearGhostText |
清除当前建议 |
数据流
sequenceDiagram
participant U as 用户
participant E as Editor (ProseMirror)
participant P as copilotPlugin
participant A as api.js
participant B as Backend
participant L as LLM
U->>E: 输入文本
E->>P: view.update()
P->>P: 清除旧建议
P->>P: 防抖 1000ms
P->>A: fetchSuggestion(prefix, suffix)
A->>B: POST /v1/completions
B->>B: build_prompt()
B->>L: ollama.chat()
L-->>B: {content, thinking}
B-->>A: SSE stream
A-->>P: suggestion text
P->>E: insertGhostText()
E-->>U: 显示灰色建议
alt Tab 键
U->>P: Tab
P->>E: acceptSuggestion()
E-->>U: 建议变为正常文本
else Esc 键
U->>P: Esc
P->>E: rejectSuggestion()
E-->>U: 建议消失
else 继续输入
U->>E: 输入其他字符
E->>P: handleKeyDown()
P->>E: clearGhostText()
end
设计亮点
- 前后端分离:前端只负责渲染和数据回传,后端负责 LLM 调用、Prompt 构建和数据解析
- 低延迟优化:防抖机制 (1000ms) + SSE 流式响应 + AbortController 取消过期请求
- ProseMirror Mark 系统:与编辑器状态完美集成,支持 Undo/Redo
- 多种交互方式:Tab/Esc/点击/输入,用户体验友好
- 智能大小限制:文档超过 32KB 自动禁用 AI 功能
许可证
MIT License
Languages
Vue
37.9%
Python
26.6%
JavaScript
16.7%
TypeScript
14.4%
CSS
2.7%
Other
1.7%