Skip to content

一键收藏

AI-SideChat 的核心功能之一是一键收藏 AI 对话内容。本文档详细介绍收藏功能的工作原理和使用方法。

功能概述

在支持的 AI 平台上浏览对话时,每个用户提问旁边会自动显示一个收藏按钮:

  • 🤍 空心 - 未收藏状态,点击可收藏
  • ❤️ 红心 - 已收藏状态,点击可取消收藏

收藏按钮位置

Gemini 平台

收藏按钮会显示在 user-query 元素的右上角。

ChatGPT 平台

收藏按钮会显示在 [data-message-author-role='user'] 元素的右上角。

收藏的内容

点击收藏按钮后,系统会自动提取并保存以下信息:

基本信息

字段说明示例
id唯一标识符(时间戳)1706014823456
timestamp收藏时间1706014823456
site平台名称Gemini / ChatGPT
siteColor平台主题色#8850e5 / #10a37f

对话信息

字段说明
convTitle对话标题
url对话完整 URL

问题信息

字段说明
question用户提问的纯文本
questionHash问题内容的哈希值(用于去重和定位)
bubbleIndex问题在对话中的索引位置

回答信息

字段说明
answerAI 回答的纯文本(用于搜索)
answerHtmlAI 回答的 HTML(用于预览显示)
contentHash回答内容的哈希值

标签信息

字段说明
tags标签数组

智能去重机制

哈希校验

AI-Clip 使用自定义哈希算法为每个问题生成唯一标识:

javascript
function simpleHash(text) {
  let hash = 0
  for (let i = 0; i < text.length; i++) {
    const char = text.charCodeAt(i)
    hash = ((hash << 5) - hash) + char
    hash = hash & hash // 转换为 32 位整数
  }
  return hash.toString()
}

重复检测

在收藏前,系统会:

  1. 计算当前问题的哈希值
  2. 检查是否已存在相同哈希值的收藏
  3. 如果存在,按钮显示为红心 ❤️
  4. 如果不存在,按钮显示为空心 🤍

好处

  • 避免重复收藏:相同的问题只会被收藏一次
  • 快速判断:通过哈希值快速查找,无需遍历全部内容
  • 精准定位:哈希值用于跨页跳转时的内容匹配

索引定位

什么是 bubbleIndex?

bubbleIndex 记录了问题在对话中的位置索引(从 0 开始):

  • 第 1 个用户提问:bubbleIndex = 0
  • 第 2 个用户提问:bubbleIndex = 1
  • 第 3 个用户提问:bubbleIndex = 2

作用

  1. 快速定位:跳转时优先使用索引快速定位
  2. 容错机制:当内容变化时,索引可作为备用定位方式
  3. 性能优化:避免全局搜索,直接访问目标位置

数据存储

存储位置

所有收藏数据存储在 chrome.storage.local 中,键名为 aiClipData

数据结构

javascript
{
  "aiClipData": [
    {
      "id": 1706014823456,
      "questionHash": "123456789",
      "bubbleIndex": 2,
      "contentHash": "987654321",
      "site": "Gemini",
      "siteColor": "#8850e5",
      "convTitle": "Python 教程",
      "question": "如何使用 Python 读取文件?",
      "answer": "在 Python 中读取文件...",
      "answerHtml": "<p>在 Python 中读取文件...</p>",
      "url": "https://gemini.google.com/app/xxx",
      "tags": ["Python", "文件操作"],
      "timestamp": 1706014823456
    },
    // 更多收藏...
  ]
}

存储限制

  • Chrome 本地存储上限通常为 5MB
  • 平均每条收藏约 2-5KB(取决于回答长度)
  • 估计可存储 1000-2500 条收藏

收藏状态同步

实时更新

AI-Clip 使用 chrome.storage.onChanged 监听器实现实时同步:

  1. 在任何页面收藏/取消收藏
  2. 所有打开的标签页自动更新按钮状态
  3. 悬浮坞列表实时刷新

跨标签页同步

  • 在标签页 A 收藏了某个问题
  • 标签页 B 中相同问题的按钮会立即变成红心 ❤️
  • 无需刷新页面

收藏操作

收藏步骤

  1. 点击空心按钮 🤍
  2. 系统提取内容
    • 提取问题文本
    • 提取回答内容(纯文本和 HTML)
    • 获取对话标题和 URL
    • 计算哈希值和索引
  3. 保存到存储
    • 添加到 aiClipData 数组
    • 存储到 chrome.storage.local
  4. 更新 UI
    • 按钮变为红心 ❤️
    • 所有标签页同步更新

取消收藏步骤

  1. 点击红心按钮 ❤️
  2. 系统删除数据
    • 根据问题哈希值查找收藏
    • aiClipData 数组中移除
  3. 更新存储
    • 保存新的数组到 chrome.storage.local
  4. 更新 UI
    • 按钮变为空心 🤍
    • 从悬浮坞列表中移除

自动检测机制

DOM 监听

AI-Clip 使用 MutationObserver 监听页面变化:

javascript
const observer = new MutationObserver(() => {
  // 检测新的用户提问气泡
  // 自动添加收藏按钮
})

observer.observe(document.body, {
  childList: true,
  subtree: true
})

智能识别

  • 动态内容:即使对话实时生成,也能及时添加按钮
  • SPA 路由:支持单页应用的路由切换
  • 延迟加载:处理懒加载的对话内容

最佳实践

✅ 建议做法

  • 及时收藏:看到有价值的内容立即收藏
  • 添加标签:为收藏添加有意义的标签
  • 定期整理:清理不再需要的收藏

❌ 避免做法

  • 过度收藏:不要收藏所有对话,保持精选
  • 忽略标签:没有标签的收藏难以管理
  • 忘记清理:定期删除过时的收藏

技术细节

内容提取算法

问题提取

javascript
// Gemini
const question = bubble.querySelector('user-query')?.innerText

// ChatGPT
const question = bubble.querySelector('[data-message-author-role="user"]')?.innerText

回答提取

javascript
// Gemini
const answerHtml = bubble.nextElementSibling?.querySelector('.model-response-text')?.innerHTML

// ChatGPT
const answerHtml = bubble.nextElementSibling?.querySelector('.markdown')?.innerHTML

性能优化

  • 事件委托:使用事件委托减少监听器数量
  • 防抖处理:搜索和筛选操作使用防抖
  • 懒加载:悬浮坞列表支持虚拟滚动(未来版本)

故障排除

按钮不显示

可能原因

  • 页面尚未完全加载
  • DOM 结构发生变化
  • 扩展未正确加载

解决方法

  • 刷新页面
  • 检查浏览器控制台错误
  • 重新加载扩展

收藏失败

可能原因

  • 存储空间已满
  • 内容提取失败

解决方法

  • 清理旧的收藏
  • 检查控制台错误信息

状态不同步

可能原因

  • 存储监听器未正常工作

解决方法

  • 刷新所有标签页
  • 重启浏览器

下一步

Released under the MIT License.