Skip to main content

| 协议 | 认证方式 | 说明 ||------|----------|------|| Gmail API | OAuth2 | 需要 Google Cloud 项目 || IMAP | SSL/TLS | 传统邮箱协议 || Microsoft Graph | OAuth2 | Outlook/Office365 |**凭证配置(预留)**:

  1. | 协议 | 认证方式 | 说明 |
    |------|----------|------|
    | Gmail API | OAuth2 | 需要 Google Cloud 项目 |
    | IMAP | SSL/TLS | 传统邮箱协议 |
    | Microsoft Graph | OAuth2 | Outlook/Office365 |

    **凭证配置(预留)**:
    
    # config.yaml
    email:
      provider: gmail  # gmail | imap | microsoft
      gmail:
        client_id_env: GMAIL_CLIENT_ID
        client_secret_env: GMAIL_CLIENT_SECRET
      imap:
        server: imap.example.com
        port: 993
        username_env: IMAP_USERNAME
        password_env: IMAP_PASSWORD
    


    ---

    ## 12. 配置

    ### 12.1 配置文件示例

    
    # ~/.config/synapse/config.yaml
    
    workspace: ~/synapse-data
    default_namespace: personal
    
    namespaces:
      - personal      # 1
      - work-project  # 2
      - study         # 3
    
    editor:
      windows: { default: notepad, options: [notepad, typora, code] }
      linux: { default: vim, options: [vim, typora] }
      macos: { default: vim, options: [vim, typora] }
    
    git:
      auto_commit: true
      commit_style: conventional  # conventional | simple | llm
      llm:
        enabled: false
        provider: litellm
        model: gpt-4o-mini
        api_base: https://api.openai.com/v1
        api_key_env: OPENAI_API_KEY
      remotes:
        - name: origin
          url: [email protected]:user/synapse-data.git
          auto_push: true
    
    johnny_decimal:
      areas:
        00: "Inbox"
        10: "个人管理"
        20: "工作项目"
        30: "学习成长"
    
    review:
      daily_time: "08:00"
      weekly_day: friday
      weekly_time: "18:00"
    


    ---

    ## 13. 性能与索引机制

    ### 13.1 性能目标

    | 操作 | 目标 | 实现方式 |
    |------|------|----------|
    | 列表 10,000 资源 | < 500ms | SQLite 索引 |
    | 全文搜索 | < 1s | Ripgrep |
    | 创建/更新 | < 300ms | 增量索引更新 |

    ### 13.2 SQLite Sidecar Index

    **问题**:10,000 个 Markdown 文件逐个解析 Frontmatter,IO 开销巨大。

    **方案**:`.synapse/index.db` 缓存所有元数据。

    
    -- 主索引表
    CREATE TABLE resources (
        id TEXT PRIMARY KEY,        -- "10.001.0015"
        namespace TEXT,
        area TEXT,                  -- "10"
        category TEXT,              -- "001"
        type TEXT,
        title TEXT,
        status TEXT,
        priority TEXT,
        due DATE,
        created DATETIME,
        modified DATETIME,
        tags TEXT,                  -- JSON array
        content_hash TEXT,          -- 用于变更检测
        file_path TEXT
    );
    
    -- 全文搜索 (FTS5) - 存储预分词后的内容
    CREATE VIRTUAL TABLE resources_fts USING fts5(
        id, title_tokens, tags_tokens, content_tokens,
        tokenize = 'simple'  -- 使用默认分词器,输入已分词字符串
    );
    


    **中文搜索:应用层分词方案**(推荐)

    SQLite 原生不支持加载 Python jieba 作为分词器。最佳实践是**应用层分词**:

    
    import jieba
    import re
    
    # 停用词表(标点、空格、无意义字符)
    STOPWORDS = set(['的', '了', '是', '在', '我', '有', '和', '就', 
                      '不', '人', '都', '一', '一个', '上', '也', '很',
                      '到', '说', '要', '去', '你', '会', '着', '没有'])
    
    class SearchEngine:
        def _tokenize(self, text: str) -> str:
            """分词 + 停用词过滤 + 标点清理"""
            # 1. 移除标点符号和特殊字符
            text = re.sub(r'[^\w\s\u4e00-\u9fff]', ' ', text)
            
            # 2. jieba 分词
            tokens = jieba.cut_for_search(text)
            
            # 3. 停用词过滤 + 去除空白
            filtered = [t.strip() for t in tokens 
                        if t.strip() and t not in STOPWORDS]
            
            return " ".join(filtered)
        
        def update_index(self, id: str, title: str, content: str):
            """写入索引前,用 jieba 预处理 + 停用词过滤"""
            title_tokens = self._tokenize(title)
            content_tokens = self._tokenize(content)
            
            cursor.execute("""
                INSERT INTO resources_fts (id, title_tokens, content_tokens) 
                VALUES (?, ?, ?)
            """, (id, title_tokens, content_tokens))
        
        def search(self, query: str):
            """搜索时,同样分词处理"""
            query_tokens = " AND ".join(self._tokenize(query).split())
            
            cursor.execute("""
                SELECT id FROM resources_fts 
                WHERE content_tokens MATCH ?
            """, (query_tokens,))
    


    **停用词过滤的好处**:
    - 减小 index.db 体积(去除 30%+ 无意义词)
    - 提高搜索精度(避免"的"、"了"等高频词干扰)
    - 加快搜索速度

    **工作流程**:
    - **写入**:"完成了需求设计!" → 清理标点 → jieba → 过滤停用词 → "完成 需求 设计" → 存入 FTS
    - **搜索**:用户搜 "需求" → 同样处理 → "需求" → MATCH 成功

    ### 13.3 索引更新策略

    | 触发时机 | 动作 |
    |----------|------|
    | syn 启动 | 检测 Git 变更,增量更新索引 |
    | CRUD 操作 | 实时更新索引 |
    | Git hook | post-merge, post-checkout 触发重建 |
    | 手动 | syn index rebuild 强制重建 |

    ### 13.4 查询路由