乐于分享
好东西不私藏

给 Markdown 编辑器接入 AI 助手:DeepSeek + Gemini 双模型实战

给 Markdown 编辑器接入 AI 助手:DeepSeek + Gemini 双模型实战
从零搭建 Java 后端,为开源 Markdown 编辑器接入 AI 润色、标题生成、摘要提取、配图生成四项能力。

为啥要搞这个

作为后端程序员,平时喜欢写技术博客。前阵子又把那个好久没管的公众号捡起来了。

写东西嘛,总得有个趁手的编辑器。自己也撸过一个 Markdown 编辑器,勉强能用,但界面交互不好,加个功能还得跟 CSS 死磕半天,效率贼低。

后来在 GitHub 上发现了xiaobox/mdeditor,用了一下就爱上了:主题好看、操作流畅、能一键复制公众号格式、所见即所得——这不就是我想要的吗?

现在 AI 正火,对创作者提效也是很有帮助,普通 MD 工具经常得在编辑器、ChatGPT、标题生成器、配图工具之间切来切去,写作节奏全被打乱了。

所以我就想:能不能把这些 AI 能力直接塞进编辑器里? 咱就是搞这个的啊,写个 API 转发那是老本行。说干就干,基于原项目 fork 出来做了扩展,就成了现在这个项目。

项目地址:sqking-coke/mdeditor-ai


都有啥功能

在原版 Markdown 编辑器的基础上,我加了四个 AI 功能,全部通过顶部菜单里的「AI 助手」来用:

1. AI 润色

选中一段文字 → 点「AI 润色」→ 输入你的要求(比如“更正式”、“更简洁”)→ AI 给你结果 → 一键替换原文。

2. AI 生成标题

AI 自动读完你的全文,给你 5 个标题备选。点一下就直接插到文章开头。

3. AI 生成摘要

自动提取文章的核心内容,给你 2-3 句话的摘要,可以一键插到文章末尾。

4. AI 生成配图

输入图片描述 → AI 帮你生图 → 预览 → 插入 Markdown 图片语法。


咋设计的

为什么非要有后端?

你可能会问:前端直接调 AI API 不就行了吗?

行是行,但不安全。在浏览器里调用 API 会暴露你的 API Key。就算用了环境变量,打包之后 Key 还是能在前端代码里找到。

所以我用了「前端 → Java 后端 → AI 服务」的代理模式:

code
浏览器 (Vue 3)                  Java 后端 (Spring Boot)        AI 服务    │                                  │                          │    │  POST /api/ai/polish             │                          │    │  Header: X-Text-Api-Key          │                          │    │  Body: { content, model }        │                          │    │ ──────────────────────────────►  │  POST DeepSeek API       │    │                                  │  Authorization: Bearer   │    │                                  │ ──────────────────────►  │    │                                  │                          │    │                                  │  ◄────────────────────── │    │  ◄────────────────────────────── │  返回润色结果             │

API Key 怎么管

核心原则:后端不存、不记、不留任何用户的密钥

用户在前端设置面板自己填 API Key

Key 存在浏览器的localStorage

每次请求通过 HTTP Header 传给后端

后端只做转发,用完就扔

模型选择也交给用户:文本模型名、图片模型名都在设置面板里自己配,后端啥都不用管。


技术选型

前端:Vue 3 组合式 API

所有 AI 功能的状态通过useAI()这个 composable 集中管理:

js
// src/composables/useAI.jsexportfunctionuseAI() {const { getTextApiKey, getTextModel } = useAISettings()asyncfunctionpolishText(content, instructions) {const data = awaitpostAI('/polish', {      content, instructions, model: getTextModel()    }, { 'X-Text-Api-Key'getTextApiKey() })return data.polishedText  }// ...}

编辑器交互通过useSharedEditorView这个单例,让不同组件共享同一个 CodeMirror 实例,就能拿到选中文本、替换文本这些操作了。

后端:Spring Boot 3.5 + Java 21

就四个 REST 接口,统一返回{ code, data, message }

接口
说明
POST /api/ai/polish
文本润色
POST /api/ai/title
生成标题
POST /api/ai/summary
生成摘要
POST /api/ai/image
生成配图

用了 Java Records 定义 DTO,Lombok 去掉样板代码,@RestControllerAdvice统一处理异常。

HTTP 客户端选型踩坑

一开始用的SimpleClientHttpRequestFactory(底层是HttpsURLConnection),调 DeepSeek 直接报SSLHandshakeException。查了半天发现是 JDK 内置的 TLS 协商跟 DeepSeek 服务端不兼容。

解决方式:换成JdkClientHttpRequestFactory(JDK HttpClient),SSL 兼容性好多了,顺便配了个系统代理支持:

java
HttpClient httpClient = HttpClient.newBuilder()    .connectTimeout(Duration.ofSeconds(60))    .proxy(ProxySelector.getDefault())  // 读取系统代理,兼容 VPN    .build();

一键启动

项目启动很方便:

bash
# 克隆项目git clone https://github.com/sqking-coke/mdeditor-ai.gitcd mdeditor-ai# 安装前端依赖npm install# 一键启动前后端(需要 Java 21 + Maven)npm run dev:all# 或者分别启动npm run dev      # 前端 :3000npm run server   # 后端 :8080

生产环境的话,把前端构建产物丢到后端static/目录里,打包成一个 Fat Jar 就能单进程部署了。


最后说两句

做这个项目的初衷就是“让写作更流畅”——不出编辑器就能搞定润色、标题、摘要、配图这些事。

目前功能还不算多,后面打算加上:

流式响应(SSE),润色结果一个字一个字地出来

更多 AI 模型(Claude、通义千问 等)

自定义 Prompt 模板

AI 续写功能

项目完全开源,欢迎 Star 和 PR。

源码地址:https://github.com/sqking-coke/mdeditor-ai

基于xiaobox/mdeditor改造,感谢原作者的优秀作品。