最近软件开发领域最火的一个应用之一就是Cursor了。结合了VS Code和ChatGPT的代码编辑工具,这个工具的推出直接让AI从流式对话的窗口应用变身成为生产力工具的最佳搭档。当然也有很多的编辑器都增加了AI的功能,比如我当前一直在用的Notion,我们可以选中一段文字,让AI帮我们润色。当这些软件加入了AI之后,立刻变成了一个更酷的产品。 我们一介平民能否也能做出这种效果的功能呢?答案是肯定的! 下面介绍的这种方法就可以实现在编辑器中调用AI功能,帮我们对文章进行润色。
Lexical
要做到带AI功能的文档编辑器,首先需要一个可灵活自定义的文档编辑器,做了一番调研之后,我选择了Lexical。
Lexical 是由 Meta(前 Facebook)开发的一种现代化的文本编辑框架,用于构建功能强大、高性能且可扩展的富文本编辑器。它基于 React,采用模块化设计,提供了一组核心工具和插件,适用于简单文本输入框到复杂富文本编辑器的开发。
Lexical可以通过自定义插件的方式添加你想要的任何功能。官方提供的demo中已经帮我们实现了常见的富文本编辑器的插件。这个框架会把顶部工具栏、markdown支持、代码块、图片通通以插件的形式存在,需要什么引入什么,甚至可以自己实现插件。
正是因为看重了它的灵活性,我们就可以深度定制这个编辑器。让它集成AI相关的功能,比如实现AI润色功能。
以下是官网demo展示的选中悬浮框。
这个是我改造之后的悬浮框,增加了一个AI润色的按钮,点击按钮之后会调用后台AI接口进行文字生成,返回给前端进行文字的替换。
这是润色之后的效果,划线的是原来的内容,黄色的是AI生成的内容。
因为Lexical灵活性高,这也导致了它的复杂性高,代码量很多。主要包括glugin、node、theme这些。官方提供的插件都是可以修改源码的,大家可以去github上查看和参考。
官网的demo在github上也有源码,我就是参考这个源码来完成这个编辑器功能的开发。这是demo源码地址。
悬浮框用到的插件是FloatingTextFormatToolbarPlugin。找准了位置,我们只需要改造这部分代码,引入新的功能按钮,并实现相关的文本操作。
在实现文本操作这块,我们需要了解它的一些API。比如文字范围选择类的API,这里我们用到了insertNodes函数,用于插入ai生成的内容。 这是主要的代码:
const aiGenerate = async () => {
let selectedText = "";
editor.update(() => {
const selection = $getSelection();
if ($isRangeSelection(selection)) {
selectedText = selection.getTextContent();
}
})
// 调用ai api 传递选中内容为文本参数,等待后台数据返回
const data = await insertAi(selectedText)
editor.update(() => {
const selection = $getSelection()
const lineBreakNode = $createLineBreakNode();
if (selection && $isRangeSelection(selection) && selection.getTextContent() == selectedText) {
// 将选中的内容、换行节点和ai生成的内容节点插入
selection.insertNodes([$createTextNode(selectedText).toggleFormat('strikethrough')
, lineBreakNode
, $createTextNode(data).setStyle('color: #fbbf24;')
])
}
})
}
同时需要在src目录下的index.css文件夹下引入图片信息,不然看不到图标按钮。样式代码格式如下:
i.image {
background-image: url(images/icons/file-image.svg);
}
后端实现
这是我使用的是Spring AI 和Java 21,当然Java17也是可以的。
大模型的API用的是智普AI,他提供的免费的模型可用,官网申请一个appkey就行。
主要代码如下 :
引入openai和spring ai依赖pom.xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
......
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
这里引入的是openai的依赖,因为智普ai支持openai api格式,当然你也可以引入智普ai的依赖。Spring AI是支持智普AI 的。
大模型api的信息配置application.yml。
spring:
ai:
openai:
api-key: ${ZHIPU_AI_API_KEY}
base-url: https://open.bigmodel.cn/api/paas/
chat:
api-key: ${ZHIPU_AI_API_KEY}
base-url: https://open.bigmodel.cn/api/paas/
completions-path: /v4/chat/completions
options:
model: GLM-4-flash
功能接口:
@Component
public class EditorAgent {
private final ChatClient chatClient;
public EditorAgent(OpenAiChatModel chatModel) {
this.chatClient = ChatClient.builder(chatModel)
.build();
}
public Prompt getEditorAgentPromptByUserText(String userText) {
String systemText = """
你是一个专业的文字工作者。
以下是你需要准守的准则:
文风与语气:选择适合的语气(如正式、轻松、学术性)或特定风格(如叙述性、说明性),以保持作品的风格一致。
拼写和语法检查:特别关注常见错误或容易混淆的单词,可以创建自定义词库,以适应特定的主题或专业领域。
简洁表达:提炼要点,将复杂的句子转化为简洁有力的表达,减少不必要的修辞和冗余。
结构清晰:使用逻辑顺序(如时间顺序、因果关系等)来组织段落,确保文章脉络清晰、流畅。
精准词汇:根据文章主题选择专业词汇、具象化词语,使表达更具说服力和冲击力。
""";
SystemMessage systemMessage = new SystemMessage(systemText);
Message userMessage = new UserMessage(userText);
return new Prompt(List.of(userMessage, systemMessage));
}
/**
* AI 润色
* @param articleSegment 文章片段
* @return ai生成内容
*/
public String articlePolish(String articleSegment) {
String userText = """
给以下文章片段进行润色。
片段内容:
{segment}
""";
PromptTemplate promptTemplate = new PromptTemplate(userText);
Message message = promptTemplate.createMessage(Map.of("segment", articleSegment));
Prompt editorAgentPrompt= getEditorAgentPromptByUserText(message.getContent());
OpenAiChatOptions options = OpenAiChatOptions.builder().withTemperature(0.5).build();
return chatClient.prompt(editorAgentPrompt).options(options).call().content();
}
}
最后
Lexical这个框架刚开始上手还是比较难得,但当摸索了一段时间之后,就可以驾轻就熟了。Enjoy!
🌈关于我
一位全栈开发工程师。拥有8年开发经验,专长于数据治理平台、大模型应用和后台业务系统开发。目前,我正在开发X.Ryder——一个基于React和Java的WEB开发框架,它还集成了AI功能。这是体验地址:xryder.cn。
你可以通过这些方式跟我联系:
- Email: cutesimba@163.com
- B站: space.bilibili.com/412405219
感谢你在我的互联网角落停留片刻! 💫