OrangeSAM/monica-exp

★ 0Forks 0JavaScriptGitHub ↗Compare

README

Monica Exp

Chrome 浏览器插件,用于导出 Monica AI 的聊天记录。

功能

  • 从当前 Monica 聊天页面自动获取 conversation_id
  • 调用 Monica API 获取聊天详情
  • 支持导出为 JSON 和 HTML 两种格式
  • HTML 格式使用 marked.js 渲染 Markdown 内容

安装

  1. 克隆仓库
  2. 打开 Chrome,访问 chrome://extensions/
  3. 开启"开发者模式"
  4. 点击"加载已解压的扩展程序"
  5. 选择项目文件夹

使用

  1. 登录 Monica
  2. 打开一个聊天对话
  3. 点击浏览器工具栏的插件图标
  4. 点击"导出聊天记录"
  5. 文件会下载到默认下载目录

项目结构

monica-exp/
├── manifest.json           # Chrome 扩展配置
├── background/
│   └── service-worker.js   # 后台服务(API 调用、数据处理)
├── popup/
│   ├── popup.html          # 弹出面板 UI
│   ├── popup.js            # 弹出面板逻辑
│   └── popup.css           # 弹出面板样式
├── icons/
│   ├── icon16.png
│   ├── icon48.png
│   └── icon128.png
└── utils/
    └── export.js           # 数据导出工具(备用)

技术实现

认证

插件不管理登录状态,直接复用浏览器已登录的 session。通过 credentials: 'include' 让请求自动携带 cookies。

API 调用

使用 Monica 的内部 API:

POST https://api.monica.im/api/custom_bot/get_chat_item_list_v2

请求头包含 x-client-id、x-client-version 等标识字段。

HTML 生成与 Markdown 渲染

整体流程

Monica API 响应
    ↓
service-worker.js 解析数据
    ↓
生成 HTML 模板(内容存为 data-markdown 属性)
    ↓
浏览器下载并打开 HTML 文件
    ↓
页面加载时用 marked.js 渲染 Markdown

关键代码解析

1. 数据存储(Service Worker 中)

消息内容不直接渲染,而是存为转义后的 HTML 属性:

const rawMarkdown = escapeHtml(item.data.content);

// 存储在 data-markdown 属性中
`<div class="message-body" data-markdown="${rawMarkdown}"></div>`

为什么要这样做?

  • Service Worker 不能 import marked 库
  • 需要等浏览器加载 marked CDN 后才能渲染

2. HTML 模板结构

<!-- 样式部分 -->
<style>
  /* CSS 变量定义主题色 */
  /* 消息卡片、排版、代码块等样式 */
</style>

<!-- 内容部分 -->
<main class="container">
  <header>标题、创建时间、消息数量</header>
  <section class="messages">
    <!-- 每条消息包含 data-markdown 属性 -->
    <article class="message user">
      <div class="message-header">头像、角色、时间</div>
      <div class="message-body" data-markdown="原始 Markdown 内容"></div>
    </article>
  </section>
  <footer>导出时间</footer>
</main>

<!-- 渲染脚本 -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script>
  document.querySelectorAll('[data-markdown]').forEach(el => {
    el.innerHTML = marked.parse(el.dataset.markdown);
  });
</script>

3. 文件下载

// 将内容转为 data URI
const base64 = btoa(unescape(encodeURIComponent(content)));
const dataUrl = `data:text/html;base64,${base64}`;

// 调用 Chrome 下载 API
chrome.downloads.download({ url: dataUrl, filename });

为什么用 marked.js?

  • 完整支持 CommonMark 规范
  • 支持 GFM(GitHub Flavored Markdown):表格、任务列表、删除线
  • 轻量(~30KB),通过 CDN 引入无需打包
  • 支持代码高亮扩展

样式设计

使用 CSS 变量管理主题:

:root {
  --bg-page: #faf9f7;      /* 页面背景 */
  --accent-warm: #c47a5a;  /* 链接、代码颜色 */
  --accent-sage: #7a9e7e;  /* 用户消息 */
  --accent-slate: #6b7b8d; /* AI 消息 */
}

字体组合:

  • Source Serif 4 - 标题(衬线)
  • Noto Sans SC - 正文(无衬线)
  • IBM Plex Mono - 代码、时间(等宽)

文件命名

导出文件名格式:{对话标题}_{YYYY-MM-DD}.json/html

依赖

  • Chrome 浏览器
  • Monica 账号(已登录)
  • marked.js(CDN 引入,用于 Markdown 渲染)

Contributors

OrangeSAM

Issues