Janus-Pro-7B插件开发教程:为Typora编辑器增加AI写作辅助功能

Janus-Pro-7B插件开发教程:为Typora编辑器增加AI写作辅助功能 Janus-Pro-7B插件开发教程为Typora编辑器增加AI写作辅助功能每次在Typora里码字是不是总希望有个智能助手在旁边比如写完一段话想让它更精炼一些或者列好了大纲却对着空白文档发呆不知道如何下笔。要是能直接在编辑器里调用AI来润色、续写、甚至检查语法那写作效率可就大大提升了。今天我们就来动手实现这个想法。我将手把手带你为Typora开发一个专属的AI写作插件把Janus-Pro-7B大模型的能力直接集成到你的写作环境中。整个过程不需要复杂的后端部署核心就是用JavaScript调用模型API再结合Typora的插件机制。跟着做下来你不仅能得到一个实用的工具还能彻底搞懂如何让AI能力无缝嵌入到日常应用里。1. 准备工作理解Typora插件与AI接口在动手写代码之前我们先花点时间把两个核心部分弄清楚Typora插件是怎么工作的以及我们如何跟Janus-Pro-7B模型“对话”。1.1 Typora插件机制初探Typora本身并不像VS Code那样有一个官方的、功能完备的插件市场。但是它提供了一个非常强大的自定义功能入口用户配置文件。我们可以通过编写JavaScript、CSS和HTML文件来修改Typora的界面和行为这本质上就是一种“插件”开发。这些自定义文件存放在一个特定的文件夹里。当你启动Typora时它会自动加载这个文件夹下的所有脚本和样式从而实现对编辑器的功能扩展。我们的AI插件就将以一系列脚本文件的形式存在于此。1.2 与Janus-Pro-7B模型通信Janus-Pro-7B是一个功能强大的开源大语言模型。要使用它我们通常需要通过其提供的API接口。假设你已经通过某种方式例如在本地部署或使用云服务让Janus-Pro-7B的API服务运行起来了并且知道它的访问地址比如http://localhost:8000/v1/chat/completions和可能的API密钥。我们的插件核心任务就是在Typora的JavaScript环境里通过标准的fetch或XMLHttpRequest方法向这个API地址发送HTTP请求。请求体中包含我们想让AI执行的任务指令例如“润色以下文本”和对应的文本内容然后解析API返回的JSON数据提取出AI生成的文本最后将其插入或替换到Typora的编辑器中。简单来说流程就是用户在Typora里选中文本 - 插件捕获动作并组织请求 - 发送给Janus-Pro-7B API - 接收并处理回复 - 更新编辑器内容。2. 构建插件核心功能理解了基本原理后我们开始构建插件的三个核心功能文本润色/缩写、大纲续写以及语法检查。我们会先搭建一个基础的插件框架。2.1 创建插件文件与目录首先找到Typora的用户配置文件夹。它的位置因操作系统而异Windows:%APPDATA%\Typora\confmacOS:~/Library/Application Support/abnerworks.Typora/confLinux:~/.config/Typora/conf在该文件夹下我们创建一个新的子文件夹比如叫做ai-assistant。所有插件文件都将放在这里。然后我们创建第一个核心文件main.js。// main.js - 插件主入口文件 (function() { use strict; // 插件配置这里填写你的Janus-Pro-7B API信息 const config { apiBaseUrl: http://localhost:8000/v1, // 替换为你的API地址 apiKey: your-api-key-here, // 如果需要认证 model: janus-pro-7b // 指定使用的模型 }; // 工具函数显示通知 function showNotification(message, type info) { // 这里可以创建一个简单的浮动提示框 console.log([AI Assistant] ${type}: ${message}); // 在实际插件中你可以用更美观的UI来替代console.log } // 核心函数调用AI API async function callAI(prompt, userContent) { const url ${config.apiBaseUrl}/chat/completions; const payload { model: config.model, messages: [ { role: system, content: prompt }, { role: user, content: userContent } ], temperature: 0.7, max_tokens: 1024 }; const headers { Content-Type: application/json, }; if (config.apiKey) { headers[Authorization] Bearer ${config.apiKey}; } try { showNotification(正在请求AI..., info); const response await fetch(url, { method: POST, headers: headers, body: JSON.stringify(payload) }); if (!response.ok) { throw new Error(API请求失败: ${response.status}); } const data await response.json(); const aiResponse data.choices[0]?.message?.content?.trim(); if (!aiResponse) { throw new Error(AI返回内容为空); } showNotification(AI处理完成, success); return aiResponse; } catch (error) { showNotification(出错: ${error.message}, error); console.error(调用AI API失败:, error); return null; } } // 将核心函数暴露给后续的功能模块 window.AIAssistant { config, callAI, showNotification }; console.log(Typora AI Assistant 插件已加载); })();这个main.js文件做了几件事定义了配置、提供了调用AI的通用函数callAI、以及一个简单的通知函数。我们将功能模块化以便后续添加更多特性。2.2 实现文本润色与缩写功能接下来我们实现第一个实用功能对选中的文本进行润色或缩写。我们在ai-assistant文件夹下创建一个新文件text-enhance.js。// text-enhance.js - 文本增强功能 (function() { if (!window.AIAssistant) { console.error(请先加载 main.js); return; } const { callAI, showNotification } window.AIAssistant; // 功能1文本润色 async function polishText(selectedText) { if (!selectedText || selectedText.trim().length 0) { showNotification(请先选择一段文本, warning); return null; } const prompt 你是一位专业的文本编辑。请润色以下用户提供的文本使其更流畅、优美、专业但不要改变其原意和核心内容。直接返回润色后的文本不要添加任何解释。; return await callAI(prompt, selectedText); } // 功能2文本缩写/总结 async function summarizeText(selectedText) { if (!selectedText || selectedText.trim().length 0) { showNotification(请先选择一段文本, warning); return null; } const prompt 你是一位专业的总结助手。请将以下用户提供的文本进行缩写或总结提取核心信息使其更加简洁。直接返回缩写后的文本不要添加任何解释。; return await callAI(prompt, selectedText); } // 功能3替换编辑器中的选中文本 function replaceSelectedText(newText) { // 这是一个简化的示例。实际Typora中替换选中文本可能需要更复杂的DOM操作。 // 这里假设有一个全局可访问的编辑器实例或使用Typora的内部API。 // 由于Typora未公开完整API以下为概念性代码。 console.log(准备替换文本为:, newText); // 概念获取当前选区并用newText替换其内容 // document.execCommand(insertText, false, newText); // 旧方法可能不适用 // 更实际的做法是监听Typora的事件或研究其内部可用的方法。 // 作为教程我们暂时用alert展示结果后续会探讨更优雅的集成方式。 if (newText) { alert(AI生成内容\n\n${newText}\n\n请手动复制替换原文本); } } // 为Typora添加上下文菜单概念 function setupContextMenu() { // 这里演示如何构想添加右键菜单项 // 实际实现可能需要通过修改Typora的菜单配置文件或注入HTML/JS console.log(文本增强功能已就绪。设想在右键菜单中添加“AI润色”和“AI缩写”选项。); } // 暴露功能给全局方便测试或通过其他方式触发 window.AIAssistant.textEnhance { polishText, summarizeText, replaceSelectedText, setupContextMenu }; // 初始化 setupContextMenu(); console.log(文本增强模块加载完成); })();这个模块提供了两个核心AI函数和一个替换文本的函数。由于直接操作Typora的编辑器核心需要对其内部结构有深入了解我们暂时用alert来展示结果。这验证了AI调用链路是通的。2.3 实现大纲续写与语法检查现在我们添加更智能的功能根据标题大纲生成内容初稿以及检查语法错误。创建文件content-write.js。// content-write.js - 内容生成与检查功能 (function() { if (!window.AIAssistant) { console.error(请先加载 main.js); return; } const { callAI, showNotification } window.AIAssistant; // 功能1根据当前标题或大纲生成内容 async function generateFromOutline() { // 获取当前光标所在行的文本假设它是标题或大纲要点 // 这里是一个简化实现实际需要更精确地获取上下文 let outlineText ; try { // 概念获取当前选中的文本或光标所在行的文本 // 实际中可能需要通过Typora的document或事件对象获取 outlineText window.getSelection().toString(); if (!outlineText) { // 如果没有选中文本尝试获取当前行的文本这需要特定方法 showNotification(请选中标题或大纲文本作为提示, warning); return null; } } catch (e) { console.warn(获取大纲文本失败使用示例文本, e); outlineText 关于人工智能未来发展的五个趋势; } const prompt 你是一位专业的写作者。请根据用户提供的大纲标题或核心要点生成一段连贯、充实、逻辑清晰的段落内容。内容应围绕该要点展开保持专业性和可读性。直接返回生成的段落不要添加任何解释或额外标题。; const generatedContent await callAI(prompt, outlineText); return generatedContent; } // 功能2语法与拼写检查 async function checkGrammar(selectedText) { if (!selectedText || selectedText.trim().length 0) { showNotification(请先选择一段需要检查的文本, warning); return null; } const prompt 你是一位专业的语言编辑。请检查以下文本中的语法错误、拼写错误、标点符号使用不当以及不流畅的表达。请直接列出你发现的所有问题并为每个问题提供修改建议。格式为“问题[描述]建议修改为[修改后的文本]”。如果文本没有问题请回答“未发现明显语法或拼写错误”。; return await callAI(prompt, selectedText); } // 暴露功能 window.AIAssistant.contentWrite { generateFromOutline, checkGrammar }; console.log(内容生成与检查模块加载完成); })();这个模块增加了内容生成和语法检查的能力。generateFromOutline函数尝试利用当前文档的上下文来激发AI的创作而checkGrammar则扮演了校对员的角色。3. 集成到Typora界面让功能在编辑器里用起来才是插件的灵魂。我们有几种方式可以将上述能力集成到Typora中。3.1 添加上下文菜单项最直观的方式是添加右键菜单。我们需要创建一个menu.js文件并尝试通过JavaScript来修改或添加菜单项。由于Typora的菜单系统可能受限制这里提供一种基于HTML注入的替代思路。// menu.js - 界面集成与菜单功能 (function() { if (!window.AIAssistant) { console.error(请先加载 main.js); return; } const { textEnhance, contentWrite } window.AIAssistant; // 方法A尝试注入自定义右键菜单项概念性可能因Typora版本而异 function injectContextMenu() { // 监听文档的右键点击事件 document.addEventListener(contextmenu, function(e) { // 我们无法直接修改原生菜单但可以创建一个自定义的浮动菜单 // 这里先不实现复杂的UI仅打印日志 console.log(右键点击事件发生可以在这里弹出自定义AI菜单); }, true); } // 方法B创建侧边栏按钮更可行的方案 function createSidebarButton() { // 尝试在Typora界面寻找一个合适的位置插入我们的按钮容器 const sidebarPlaceholder document.querySelector(.sidebar-content, .md-sidebar); // 假设的类名 const targetContainer sidebarPlaceholder || document.body; const buttonContainer document.createElement(div); buttonContainer.id ai-assistant-buttons; buttonContainer.style.cssText position: fixed; top: 100px; right: 20px; z-index: 9999; background: white; border: 1px solid #ddd; border-radius: 8px; padding: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);; const buttonStyle display: block; width: 100%; margin-bottom: 8px; padding: 8px 12px; background: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 12px;; const buttonHoverStyle background: #45a049;; const buttons [ { text: AI润色, action: () triggerAction(polish) }, { text: AI缩写, action: () triggerAction(summarize) }, { text: 大纲续写, action: () triggerAction(generate) }, { text: ✅ 语法检查, action: () triggerAction(grammar) } ]; buttons.forEach(btn { const button document.createElement(button); button.textContent btn.text; button.style.cssText buttonStyle; button.onmouseover () button.style.backgroundColor buttonHoverStyle; button.onmouseout () button.style.backgroundColor ; button.onclick btn.action; buttonContainer.appendChild(button); }); targetContainer.appendChild(buttonContainer); console.log(AI助手侧边栏按钮已添加); } async function triggerAction(action) { const selection window.getSelection().toString(); let result null; switch(action) { case polish: result await textEnhance.polishText(selection); break; case summarize: result await textEnhance.summarizeText(selection); break; case generate: result await contentWrite.generateFromOutline(); break; case grammar: result await contentWrite.checkGrammar(selection); break; default: console.warn(未知操作); } if (result) { // 暂时使用alert后续可替换为更美观的模态框 alert(AI助手结果\n\n${result}); // 未来优化点在这里调用 textEnhance.replaceSelectedText(result) 实现直接替换 } } // 初始化等待Typora界面加载完成后添加按钮 if (document.readyState loading) { document.addEventListener(DOMContentLoaded, createSidebarButton); } else { createSidebarButton(); } injectContextMenu(); console.log(界面菜单模块加载完成); })();这个方案在编辑器界面右上角创建了一个浮动工具栏包含了四个核心功能的按钮。这是一个非常实用且可见的集成方式。3.2 创建样式文件为了让我们的按钮看起来更协调可以添加一点简单的样式。创建style.css文件。/* style.css - AI助手插件样式 */ #ai-assistant-buttons { font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; min-width: 140px; } #ai-assistant-buttons button { transition: background-color 0.2s ease; text-align: left; } #ai-assistant-buttons button:hover { transform: translateY(-1px); box-shadow: 0 2px 5px rgba(0,0,0,0.2); } /* 可以添加一个加载动画 */ .ai-loading { display: inline-block; width: 12px; height: 12px; border: 2px solid #f3f3f3; border-top: 2px solid #4CAF50; border-radius: 50%; animation: spin 1s linear infinite; margin-right: 5px; } keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }4. 加载与使用插件所有部件都准备好了现在需要让Typora在启动时加载它们。4.1 创建插件加载清单在ai-assistant文件夹根目录创建一个名为plugin.json的配置文件虽然Typora可能不直接读取但有助于我们管理。{ name: Typora AI Assistant, version: 1.0.0, description: 集成Janus-Pro-7B的AI写作辅助插件, main: main.js, scripts: [ main.js, text-enhance.js, content-write.js, menu.js ], styles: [ style.css ] }4.2 让Typora加载插件最关键的一步是告诉Typora加载我们的脚本。我们需要在Typora的用户配置文件夹中找到或创建一个用于自动加载脚本的文件。通常这可以通过在conf文件夹下创建特定的JavaScript文件来实现Typora会在启动时执行它们。一个常见的方法是直接修改Typora的主题文件或创建一个用户自定义的初始化脚本。更直接的方式是我们创建一个加载器文件load-ai-assistant.js并将其放置在Typora能自动执行的位置具体位置可能需要查阅Typora社区或文档一种可行方法是将其内容放入用户自定义的user.css或通过偏好设置 - 通用 - 打开高级设置中的相关配置引入。由于方法因版本而异这里提供一个概念性的加载器内容你需要根据实际情况调整如何让Typora执行它// 概念性加载器这段代码需要以某种方式在Typora启动时运行 // 例如可以将其保存为 conf/ai-loader.js并通过Typora的某个配置项引入 (function loadAIPlugin() { const pluginDir ai-assistant; // 相对于conf文件夹的路径 const scriptFiles [ ${pluginDir}/main.js, ${pluginDir}/text-enhance.js, ${pluginDir}/content-write.js, ${pluginDir}/menu.js ]; const styleFile ${pluginDir}/style.css; // 动态加载CSS const link document.createElement(link); link.rel stylesheet; link.href styleFile; document.head.appendChild(link); // 动态按顺序加载JS function loadScript(src) { return new Promise((resolve, reject) { const script document.createElement(script); script.src src; script.onload resolve; script.onerror reject; document.head.appendChild(script); }); } (async function() { for (const src of scriptFiles) { try { await loadScript(src); console.log(Loaded: ${src}); } catch (e) { console.error(Failed to load ${src}:, e); } } console.log(All AI Assistant plugins loaded.); })(); })();实际操作建议对于最新版Typora一个更可靠的方法是直接编辑conf目录下的user.css和user.js文件如果不存在就创建。将style.css的内容复制到user.css末尾并将所有*.js文件的代码按顺序main.js,text-enhance.js,content-write.js,menu.js合并到user.js文件中。这样Typora启动时会自动加载它们。4.3 使用你的AI助手完成上述步骤并重启Typora后你应该能在编辑器界面的某个角落根据我们的脚本是右上角看到一个浮动的绿色按钮组。润色/缩写在文档中选中一段文字点击“AI润色”或“AI缩写”按钮稍等片刻AI生成的结果就会以弹窗形式展示。你可以手动复制并替换原文。大纲续写将光标放在一个标题行或者选中代表大纲的几句话点击“大纲续写”按钮AI会尝试围绕它生成一段内容。语法检查选中你觉得可能有问题的段落点击“语法检查”按钮AI会列出潜在问题及修改建议。5. 进阶优化与打包分发基础功能跑通后我们可以考虑让它变得更完善、更易用。5.1 功能优化建议直接替换文本深入研究Typora的DOM结构和事件找到安全可靠的方法来用AI返回的文本直接替换编辑器中的选中内容而不是通过alert。这可能涉及到模拟粘贴操作或直接操作编辑器内部的HTML元素。自定义指令在侧边栏增加一个输入框允许用户临时输入自定义的指令如“翻译成英文”、“改为正式语气”让插件更加灵活。历史记录缓存最近几次的AI请求和回复方便用户查看或重新应用。错误处理与重试增强网络请求的健壮性添加重试机制和更详细的错误提示。性能优化对于长文本可以尝试分段处理或添加“处理中”的加载状态提示。5.2 插件打包与分享如果你想将这个插件分享给其他Typora用户可以将整个ai-assistant文件夹压缩成ZIP包。创建一个详细的README.md使用说明包括如何配置API地址、如何安装即合并user.js和user.css的步骤。提醒用户需要自行部署或拥有可访问的Janus-Pro-7B API服务。由于Typora插件的非官方性分享本质上就是分享代码和配置方法。你可以将它发布在GitHub、博客或相关的技术社区。整个插件开发下来你会发现核心逻辑并不复杂关键在于理解如何将外部AI服务与本地应用桥接起来。Typora的开放性虽然有限但通过JavaScript注入的方式我们依然能创造出非常实用的增强功能。这个项目不仅给你带来了一个方便的写作工具更重要的是提供了一个模板你可以举一反三将类似的AI能力集成到其他你常用的软件中去真正让技术为你的工作流服务。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。