开发者文档
API 参考
MoeCopy AI 的技术 API 文档和开发者参考
API 参考
本文档详细介绍 MoeCopy AI 的内部 API、消息通信机制和扩展接口。
消息通信 API
MoeCopy AI 使用 Chrome Extension 的消息传递机制进行组件间通信。
消息格式
所有消息遵循统一格式:
interface Message {
action: string
[key: string]: any
}
核心消息类型
scrapeContent
从当前页面提取内容:
// 请求
{
action: "scrapeContent",
options?: {
mode?: ExtractionMode
customSelectors?: Partial<Record<SelectorType, string>>
}
}
// 响应
interface ScrapeResponse {
success: boolean
data?: ScrapedContent
error?: string
}
testSelector
测试 CSS 选择器:
// 请求
interface SelectorTestRequest {
action: "testSelector"
selector: string
}
// 响应
interface SelectorTestResponse {
matches: number
content?: string
error?: string
}
openOptionsPage
打开扩展选项页面:
{
action: "openOptionsPage"
}
数据结构
ScrapedContent
提取内容的完整结构:
interface ScrapedContent {
// 基础信息
title: string
url: string
author: string
publishDate: string
// 内容
articleContent: string // 原始 HTML
cleanedContent: string // 清理后的文本
// 元数据
metadata: Record<string, string>
// 图片
images: ImageInfo[]
// 选择器结果(调试用)
selectorResults?: Record<SelectorType, SelectorResultItem[]>
}
ImageInfo
图片信息结构:
interface ImageInfo {
src: string // 图片 URL
alt: string // 替代文本
title: string // 标题
index: number // 在文档中的索引
}
SelectorResultItem
选择器匹配结果:
interface SelectorResultItem {
selector: string // 使用的选择器
content: string // 第一个匹配内容
allContent?: string[] // 所有匹配内容
}
存储 API
设置存储
使用 Chrome 同步存储保存用户设置:
import { Storage } from "@plasmohq/storage"
const storage = new Storage()
// 保存设置
await storage.set("settings", {
extractionMode: "hybrid",
showFloatButton: true
})
// 读取设置
const settings = await storage.get("settings")
本地存储
AI 聊天历史使用本地存储:
// 保存聊天历史
interface AiChatHistoryItem {
id: string
timestamp: number
url: string
prompt: string
content: string
processedPrompt?: string
usage?: {
total_tokens?: number
prompt_tokens?: number
completion_tokens?: number
}
}
// 存储操作
const history = (await storage.get("aiChatHistory")) || { items: [] }
history.items.push(newItem)
await storage.set("aiChatHistory", history)
工具函数
文本处理
// 清理 HTML
export function cleanHtml(html: string): string
// 提取纯文本
export function extractText(element: Element): string
// 格式化日期
export function formatDate(dateString: string): string
选择器工具
// 查找元素
export function findElements(
selectors: string[],
root?: Document | Element
): Element[]
// 获取元素文本
export function getElementText(
element: Element,
options?: { trim?: boolean }
): string
模板引擎
支持变量替换的简单模板引擎:
export function processTemplate(
template: string,
variables: Record<string, any>
): string
// 使用示例
const result = processTemplate("标题:{{title}}\n作者:{{author}}", {
title: "示例文章",
author: "张三"
})
AI 服务接口
初始化 AI 客户端
import { createAiClient } from "~/utils/ai-service"
const client = createAiClient({
apiKey: "your-api-key",
apiUrl: "https://api.openai.com/v1",
model: "gpt-4o-mini"
})
生成文本
const stream = await generateText({
prompt: "总结这篇文章",
content: articleContent,
systemPrompt: "你是一个专业的内容摘要助手"
})
// 处理流式响应
for await (const chunk of stream) {
console.log(chunk)
}
使用统计
interface UsageStats {
promptTokens: number
completionTokens: number
totalTokens: number
}
const { text, usage } = await generateTextWithUsage(options)
提取器 API
创建提取器实例
import { createExtractor } from "~/utils/extractor"
const extractor = createExtractor({
mode: "hybrid",
customSelectors: {
content: ".custom-content",
title: "h1.custom-title"
},
readabilityConfig: {
charThreshold: 500
}
})
提取内容
const result = await extractor.extract(document)
// 结果包含
{
title: string
content: string
author: string
publishDate: string
images: ImageInfo[]
metadata: Record<string, string>
}
日志系统
配置日志
import { logger } from "~/utils/logger"
// 设置日志级别
logger.setLevel("debug")
// 使用日志
logger.debug("调试信息", { data })
logger.info("一般信息")
logger.error("错误信息", error)
日志格式
interface LogEntry {
level: string
timestamp: number
message: string
data?: any
error?: Error
}
错误处理
错误类型
// 基础错误类
export class MoeCopyError extends Error {
code: string
details?: any
}
// 具体错误类型
export class ExtractionError extends MoeCopyError
export class SelectorError extends MoeCopyError
export class ApiError extends MoeCopyError
错误处理示例
try {
const content = await extractor.extract(document)
} catch (error) {
if (error instanceof ExtractionError) {
// 处理提取错误
logger.error("提取失败", error)
} else if (error instanceof ApiError) {
// 处理 API 错误
logger.error("API 调用失败", error)
}
}
扩展生命周期
Background Script
// background.ts
chrome.runtime.onInstalled.addListener(() => {
// 安装或更新时执行
initializeExtension()
})
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
// 处理消息
handleMessage(message, sender, sendResponse)
return true // 异步响应
})
Content Script
// contents/scraper.ts
// 页面加载完成后注入
window.addEventListener("load", () => {
initializeScraper()
})
// 监听来自扩展的消息
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "scrapeContent") {
const content = scrapeCurrentPage()
sendResponse(content)
}
})
性能优化
缓存机制
// 简单的内存缓存
const cache = new Map<string, CacheEntry>()
interface CacheEntry {
data: any
expires: number
}
export function getCached<T>(key: string): T | null {
const entry = cache.get(key)
if (entry && entry.expires > Date.now()) {
return entry.data
}
return null
}
防抖和节流
// 防抖函数
export function debounce<T extends (...args: any[]) => any>(
func: T,
wait: number
): T
// 节流函数
export function throttle<T extends (...args: any[]) => any>(
func: T,
limit: number
): T
开发工具
类型定义
完整的 TypeScript 类型定义位于:
constants/types.ts
- 核心类型utils/index.ts
- 工具函数类型
测试工具
// 模拟 Chrome API
import { mockChrome } from "~/test-utils"
beforeEach(() => {
global.chrome = mockChrome()
})
// 测试提取器
it("should extract content", async () => {
const extractor = createExtractor()
const result = await extractor.extract(mockDocument)
expect(result.title).toBe("Test Title")
})
版本兼容性
Chrome Manifest V3
MoeCopy AI 完全兼容 Manifest V3:
- 使用 Service Worker 替代 Background Page
- 遵循新的权限模型
- 支持新的 API 限制
浏览器兼容性
- Chrome 88+
- Edge 88+
- 其他基于 Chromium 的浏览器
贡献指南
欢迎贡献代码!请查看 GitHub 仓库 了解:
- 代码规范
- 提交指南
- 问题反馈