Sidekick代码定义分析:核心类与函数架构解析

Sidekick代码定义分析:核心类与函数架构解析

【免费下载链接】Sidekick A native macOS app that allows users to chat with a local LLM that can respond with information from files, folders and websites on your Mac without installing any other software. 【免费下载链接】Sidekick 项目地址: https://gitcode.com/GitHub_Trending/sidekick/Sidekick

核心管理类架构

Sidekick作为一款本地LLM对话应用,其架构围绕三大核心管理类构建:对话管理专家系统模型控制。这些类通过Swift的ObservableObject协议实现响应式状态管理,确保UI与数据实时同步。

ConversationManager:对话生命周期控制器

该类位于Sidekick/Logic/Data Models/ConversationManager.swift,负责所有对话数据的持久化与状态维护。核心属性包括:

  • @Published var conversations: [Conversation]:存储所有对话记录,变更时自动触发UI更新
  • var recentConversation: Conversation?:获取最近更新的对话,无对话时自动创建

关键功能实现:

public func newConversation() {
    let newConversation: Conversation = Conversation(
        title: Date.now.formatted(), 
        createdAt: .now, 
        messages: []
    )
    self.conversations = [newConversation] + self.conversations
    NotificationCenter.default.post(name: Notifications.newConversation.name, object: nil)
}

数据持久化通过JSON编解码实现,存储路径由datastoreUrl计算属性指定:

public var datastoreUrl: URL {
    return Settings.containerUrl.appendingPathComponent("Conversations/conversations.json")
}

ExpertManager:专家角色系统

位于Sidekick/Logic/Data Models/ExpertManager.swift的专家管理系统支持多角色定制,核心特性包括:

  • 专家资源管理:通过resources属性关联本地文件、网页等知识源
  • 系统提示定制:systemPrompt属性支持角色行为定义
  • 资源持久化控制:persistResources开关控制跨会话数据保留

![专家选择界面](https://raw.gitcode.com/GitHub_Trending/sidekick/Sidekick/raw/cb7353c50be8d81bb162e164d8d6e1e6e296f169/Docs Images/Features/Experts/selectExpertMenu.png?utm_source=gitcode_repo_files)

创建专家的核心代码:

public func newExpert(
    name: String,
    symbolName: String,
    color: Color,
    resources: [Resource]
) async {
    var expert: Expert = Expert(name: name, symbolName: symbolName, color: color)
    await expert.resources.setup()
    await expert.resources.addResources(resources, expertName: name)
    self.experts.append(expert)
}

数据模型定义

Conversation:对话数据结构

Sidekick/Types/Conversation/Conversation.swift定义了对话的核心数据结构,主要属性包括:

  • id: UUID:唯一标识符
  • title: String:对话标题(默认使用创建时间)
  • messages: [Message]:消息列表
  • expertId: UUID?:关联专家ID

消息管理核心方法:

public mutating func addMessage(_ message: Message) -> Bool {
    let lastSender: Sender? = self.messages.last?.getSender()
    if lastSender != nil && lastSender == message.getSender() {
        return false // 防止连续发送相同角色消息
    }
    self.messages.append(message)
    return true
}

Expert:专家配置模型

Sidekick/Types/Expert/Expert.swift定义了专家角色的核心属性:

public struct Expert: Identifiable, Codable {
    public var id: UUID = UUID()
    public var name: String
    public var symbolName: String  // SF Symbol图标名称
    public var color: Color
    public var useWebSearch: Bool = true
    public var resources: Resources = Resources()
    public var systemPrompt: String? = nil
}

系统默认专家通过静态属性实现:

public static let `default`: Expert = Expert(
    name: String(localized: "Default"),
    symbolName: "person.fill",
    color: Color.blue,
    useWebSearch: false,
    persistResources: false
)

关键功能控制器

CanvasController:可视化交互核心

Sidekick/Logic/View Controllers/Conversation/CanvasController.swift实现了对话内容的可视化提取功能。核心方法extractSnapshot通过以下流程工作:

  1. 定位最新助手消息
  2. 使用worker模型提取纯内容
  3. 创建快照并关联到消息

![Canvas功能演示](https://raw.gitcode.com/GitHub_Trending/sidekick/Sidekick/raw/cb7353c50be8d81bb162e164d8d6e1e6e296f169/Docs Images/Features/Canvas/canvasSelectiveEdit.png?utm_source=gitcode_repo_files)

核心实现代码:

public func extractSnapshot(selectedConversation: Conversation?) async throws {
    guard var assistantMessage = selectedConversation?.messages
        .filter({ $0.getSender() == .assistant }).last else {
        throw Snapshot.ExtractionError.noAssistantMessages
    }
    
    let snapshot: Snapshot = Snapshot(
        text: response.text.reasoningRemoved.trimmingWhitespaceAndNewlines()
    )
    assistantMessage.snapshot = snapshot
    selectedConversation?.updateMessage(assistantMessage)
}

ModelManager:本地模型控制器

Sidekick/Logic/Data Models/ModelManager.swift负责本地LLM模型的管理,支持:

  • 模型文件选择与验证
  • 模型元数据持久化
  • 多模型切换

模型添加流程:

public func addModel() -> Bool {
    if let modelUrls = try? FileManager.selectFile(
        dialogTitle: String(localized: "Select a Model"),
        allowedContentTypes: [UTType("com.npc-pet.Chats.gguf") ?? .data]
    ) {
        guard let modelUrl = modelUrls.first else { return false }
        ModelManager.shared.add(modelUrl)
        return true
    }
    return false
}

![模型选择界面](https://raw.gitcode.com/GitHub_Trending/sidekick/Sidekick/raw/cb7353c50be8d81bb162e164d8d6e1e6e296f169/Docs Images/Features/Local Models/modelSelector.png?utm_source=gitcode_repo_files)

架构交互关系

三大核心模块通过以下方式协同工作:

mermaid

  • 数据流:用户输入 → ConversationManager创建消息 → ModelManager获取LLM响应 → 更新UI
  • 状态同步:各管理类通过@Published属性实现状态共享,确保多视图一致性
  • 扩展点:Expert的resources系统支持接入新类型知识源,ModelManager可扩展支持更多模型格式

关键函数性能分析

对话序列化性能

ConversationManager的save()方法使用JSONEncoder对整个对话数组进行编码:

public func save() {
    let rawData: Data = try JSONEncoder().encode(self.conversations)
    try rawData.write(to: self.datastoreUrl, options: .atomic)
}

对于包含大量消息的对话,此实现可能导致性能瓶颈。建议考虑:

  • 增量序列化仅变更对话
  • 分页加载历史消息

专家资源索引优化

Expert.resources的addResources方法需要异步处理文件扫描:

public func addResources(_ resources: [Resource], expertName: String) async {
    for resource in resources {
        switch resource.type {
        case .file, .folder:
            await self.indexFile(resource: resource, expertName: expertName)
        case .website:
            await self.indexWebsite(resource: resource)
        }
    }
}

当前实现为顺序处理,可通过并发调度优化大资源集的索引速度。

总结与扩展建议

Sidekick的核心架构采用清晰的职责分离设计,通过响应式状态管理实现流畅的用户体验。主要改进方向包括:

  1. 性能优化

    • 实现对话数据的增量持久化
    • 优化大型资源库的索引效率
  2. 功能扩展

  3. 架构演进

    • 引入中间件模式处理复杂业务逻辑
    • 实现插件系统支持第三方扩展

完整代码结构可参考项目Markdown文档,核心业务逻辑集中在Sidekick/Logic/目录,UI组件则位于Sidekick/Views/目录。

【免费下载链接】Sidekick A native macOS app that allows users to chat with a local LLM that can respond with information from files, folders and websites on your Mac without installing any other software. 【免费下载链接】Sidekick 项目地址: https://gitcode.com/GitHub_Trending/sidekick/Sidekick

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值