Lightpack Logo

GitHub release (latest by date) Swift Platforms Swift Package Manager Package Size GitHub stars

在你的 iOS 和 macOS 应用中,用 3 行代码即可在本地运行 Llama 3.2 和 Gemma 2。开源、离线且私密。 在 TestFlight 上试用。

安装

对于应用开发者

将 Lightpack 添加到你的 Xcode 项目

  1. 在 Xcode 中,选择 "File" → "Add Packages..."
  2. 在搜索栏中,输入 Lightpack 仓库的 URL
https://github.com/lightpack-run/lightpack.git
  1. 将 Dependency Rule(依赖规则)设置为 "Branch" 并选择 "main"
  2. 在 "Add to Target"(添加到目标)部分,选择你的应用目标(例如,HelloLightpack2)
  3. 选择你想要遵循的版本规则(例如,"Up to Next Major" 版本)
  4. 点击 "Add Package"(添加包)

你的包设置应该类似于这样

Lightpack Package Setup

安装完成后,你可以在你的 Swift 文件中导入 Lightpack

import Lightpack

对于 Swift 包开发者

如果你正在开发一个 Swift 包,将以下行添加到你的 Package.swift 文件的 dependencies(依赖项)中

.package(url: "https://github.com/lightpack-run/lightpack.git", from: "0.0.6")

然后,将 "Lightpack" 作为你目标的依赖项包含进去

.target(name: "YourTarget", dependencies: ["Lightpack"]),

然后你就可以在你的 Swift 文件中导入 Lightpack 了

import Lightpack

开始使用

获取 API 密钥

在使用 Lightpack 之前,你需要获取一个 API 密钥。按照以下步骤操作

  1. 访问 https://lightpack.run
  2. 如果你还没有账户,注册一个
  3. 转到 API Keys(API 密钥)
  4. 点击 "Create New"(创建新的)来生成一个新的 API 密钥
  5. 复制生成的 API 密钥

有了你的 API 密钥后,你可以像这样在你的代码中初始化 Lightpack

let lightpack = Lightpack(apiKey: "your_api_key")

"your_api_key" 替换为你从 Lightpack 网站复制的实际 API 密钥。

重要提示:保护你的 API 密钥安全,永远不要公开分享它或将其提交到版本控制系统。API 密钥的使用受我们的 隐私政策 约束,其中包含我们如何收集和处理 API 使用情况数据的信息。

使用 Lightpack

这是一个简单的例子,让你开始使用 Lightpack

import Lightpack

let lightpack = Lightpack(apiKey: "your_api_key")

do {
    let messages = [LPChatMessage(role: .user, content: "Why is the sky blue?")]
    
    var response = ""
    try await lightpack.chatModel("23a77013-fe73-4f26-9ab2-33d315a71924", messages: messages) { token in
        response += token
        print("Received token: \(token)")
    }
    
    print("Full response: \(response)")
} catch {
    print("[Lightpack] Error: \(error)")
}

这个例子使用你的 API 密钥初始化 Lightpack,然后使用 chatModel 函数与默认模型进行交互。

SwiftUI 示例

这是一个基本的 SwiftUI 示例,演示了如何在聊天界面中使用 Lightpack

import SwiftUI
import Lightpack

struct ContentView: View {
    @StateObject private var lightpack = Lightpack(apiKey: "your_api_key")
    @State private var userInput = ""
    @State private var chatMessages: [LPChatMessage] = []
    @State private var isLoading = false

    var body: some View {
        VStack {
            ScrollView {
                ForEach(chatMessages, id: \.content) { message in
                    MessageView(message: message)
                }
            }
            
            HStack {
                TextField("Type a message", text: $userInput)
                    .textFieldStyle(RoundedBorderTextFieldStyle())
                
                Button("Send") {
                    sendMessage()
                }
                .disabled(userInput.isEmpty || isLoading)
            }
            .padding()
        }
    }

    func sendMessage() {
        let userMessage = LPChatMessage(role: .user, content: userInput)
        chatMessages.append(userMessage)
        isLoading = true
        
        Task {
            do {
                var assistantResponse = ""
                try await lightpack.chatModel(messages: chatMessages) { token in
                    assistantResponse += token
                }
                
                let assistantMessage = LPChatMessage(role: .assistant, content: assistantResponse)
                chatMessages.append(assistantMessage)
                isLoading = false
                userInput = ""
            } catch {
                print("[Lightpack] Error: \(error)")
                isLoading = false
            }
        }
    }
}

struct MessageView: View {
    let message: LPChatMessage
    
    var body: some View {
        HStack {
            if message.role == .user {
                Spacer()
            }
            Text(message.content)
                .padding()
                .background(message.role == .user ? Color.blue : Color.gray)
                .foregroundColor(.white)
                .cornerRadius(10)
            if message.role == .assistant {
                Spacer()
            }
        }
        .padding(.horizontal)
    }
}

#Preview {
    ContentView()
}

这个 SwiftUI 示例创建了一个简单的聊天界面,其中:

  1. 用户可以输入消息并将其发送到 AI 模型。
  2. AI 模型的回复会显示在聊天中。
  3. 消息在视觉上区分用户和 AI。
  4. 管理加载状态,以防止在等待响应时发送多条消息。

记住将 "your_api_key" 替换为你实际的 Lightpack API 密钥。

可用的模型系列

Lightpack 支持各种模型系列。以下是可用系列的概述

系列 作者 参数 许可 论文 系列 ID
Llama 3.1 Meta 8B 自定义 AI Meta 3dbcfe36-17fc-45b8-acb6-b3af2c320431
Llama 3 Meta 8B 自定义 AI Meta 4dd3eef8-c83e-4338-b7b9-17a9ae2a557e
Gemma 2 Google 9B 自定义 DeepMind 50be08ec-d6a1-45c8-8c6f-efa34ee9ba17
Gemma 1 Google 2B 自定义 DeepMind 4464c014-d2ed-4be6-a8c5-0cf86c6c87ab
Phi 3 Microsoft Mini-4K 自定义 arXiv 7d64ec31-667f-45bb-8d6e-fdb0dffe7fe4
Mistral v0.3 Mistral 7B Apache 2.0 Mistral 文档 3486641f-27ee-4eee-85be-68a1826873ca
Qwen2 Alibaba 0.5B, 1.5B, 7B Apache 2.0 arXiv a9a97695-2573-4d12-99e0-371aae7ac009
TinyLlama Zhang Peiyuan 1.1B Apache 2.0 arXiv 75f98968-be6d-48c8-9b32-e76598e262be

有关每个模型的更多详细信息,包括可用版本和特定功能,请参阅 Lightpack 模型

典型工作流程和功能可用性

Lightpack 旨在灵活且用户友好。以下是典型工作流程的概述

基本操作步骤

  1. 获取模型 ID: 你可以使用 getModels() 向用户展示一个模型列表供选择。如果未提供模型 ID,我们将使用默认模型。
  2. 下载模型: 使用 downloadModel(modelId) 下载选定的模型。
  3. 加载模型: 使用 loadModel(modelId) 将模型加载到聊天上下文窗口中。
  4. 与模型聊天: 使用 chatModel(modelId, messages) 与加载的模型进行交互。

简化用法

为方便起见,你可以直接跳到使用 chatModel()。如果任何先决条件步骤(例如下载或加载)尚未完成,Lightpack 将自动处理它们。这意味着你只需调用 chatModel() 即可提供无缝体验,我们将一次性处理使用默认模型 ID、下载、加载和聊天设置的所有问题。

但是,为了获得最佳用户体验,特别是对于较大的模型,我们建议在你的应用程序的 UI 中显式处理这些步骤,以便向用户提供进度反馈。

在线与离线功能。 以下是哪些功能需要互联网连接以及哪些功能可以离线工作的细分:仅在线功能

downloadModel(modelId) getModels() getModelFamilies() resumeDownloadModel()

可离线功能(如果模型已下载或正在下载)

loadModel(modelId) chatModel() pauseDownloadModel() cancelDownloadModel() removeModels() clearChat()

请注意,虽然 chatModel() 可以使用下载的模型离线工作,但如果该模型在本地不可用,它会自动尝试下载该模型,这需要互联网连接。

可用功能及代码片段

以下是 Lightpack 提供的每个核心功能的快速代码片段

模型信息

获取模型

lightpack.getModels(
    bitMax: 8,
    bitMin: 0,
    familyIds: ["3dbcfe36-17fc-45b8-acb6-b3af2c320431"],
    modelIds: nil,
    page: 1,
    pageSize: 10,
    parameterIds: ["8B"],
    quantizationIds: ["Q4_K_M"],
    sizeMax: 5,  // 5 GB
    sizeMin: 1,   // 500 MB
    sort: "size:desc"
) { result in
    switch result {
    case .success((let response, let updatedModelIds)):
        print("Fetched \(response.models.count) models")
        print("Updated model IDs: \(updatedModelIds)")
        response.models.forEach { model in
            print("Model: \(model.title), Size: \(model.size) GB")
        }
    case .failure(let error):
        print("Error fetching models: \(error)")
    }
}

获取模型系列

lightpack.getModelFamilies(
    familyIds: ["3dbcfe36-17fc-45b8-acb6-b3af2c320431"],
    modelParameterIds: ["8B"],
    page: 1,
    pageSize: 5,
    sort: "title:asc"
) { result in
    switch result {
    case .success((let response, let updatedFamilyIds)):
        print("Fetched \(response.modelFamilies.count) model families")
        print("Updated family IDs: \(updatedFamilyIds)")
        response.modelFamilies.forEach { family in
            print("Family: \(family.title), Parameters: \(family.modelParameterIds)")
        }
    case .failure(let error):
        print("Error fetching model families: \(error)")
    }
}

模型管理

将示例 "23a77013-fe73-4f26-9ab2-33d315a71924" 替换为你实际的模型 ID

下载模型

Task {
  do {
      try await lightpack.downloadModel("23a77013-fe73-4f26-9ab2-33d315a71924")
      print("Model downloaded successfully")
  } catch {
      print("Error downloading model: \(error)")
  }
}

暂停模型下载

Task {
  do {
      try await lightpack.pauseDownloadModel("23a77013-fe73-4f26-9ab2-33d315a71924")
      print("Model download paused")
  } catch {
      print("Error pausing download: \(error)")
  }
}

恢复模型下载

Task {
  do {
      try await lightpack.resumeDownloadModel("23a77013-fe73-4f26-9ab2-33d315a71924")
      print("Model download resumed")
  } catch {
      print("Error resuming download: \(error)")
  }
}

取消模型下载

Task {
  do {
      try await lightpack.cancelDownloadModel("23a77013-fe73-4f26-9ab2-33d315a71924")
      print("Model download cancelled")
  } catch {
      print("Error cancelling download: \(error)")
  }
}

移除模型

Task {
  do {
      // Remove specific models
      try await lightpack.removeModels(modelIds: ["model_id_1", "model_id_2"], removeAll: false)
      
      // Or remove all models
      // try await lightpack.removeModels(removeAll: true)
      
      print("Models removed successfully")
  } catch {
      print("Error removing models: \(error)")
  }
}

加载模型

Task {
  do {
      try await lightpack.loadModel("23a77013-fe73-4f26-9ab2-33d315a71924")
      print("Model loaded and set as active")
  } catch {
      print("Error loading model: \(error)")
  }
}

聊天互动

与模型聊天

Task {
  do {
      let messages = [
          LPChatMessage(role: .user, content: "Why is water blue?")
      ]
      
      try await lightpack.chatModel("23a77013-fe73-4f26-9ab2-33d315a71924", messages: messages) { token in
          print(token)
      }
  } catch {
      print("Error in chat: \(error)")
  }
}

清除聊天记录

Task {
  do {
      try await lightpack.clearChat()
      print("Chat history cleared")
  } catch {
      print("Error clearing chat: \(error)")
  }
}

检查模型更新

Lightpack 提供了一种使用 getModelsgetModelFamilies 函数检查模型更新的方法。如果返回任何更新的模型,你可以使用此信息提示用户更新其本地模型,或者在后台自动更新它们。

以下是如何检查模型更新

func checkForModelUpdates() {
    lightpack.getModels(modelIds["23a77013-fe73-4f26-9ab2-33d315a71924"]) { result in
        switch result {
        case .success((let response, let updatedModelIds)):
            if !updatedModelIds.isEmpty {
                print("Updates available for \(updatedModelIds.count) models")
                // Prompt user to update or automatically update
                for modelId in updatedModelIds {
                    updateModel(modelId: modelId)
                }
            } else {
                print("All models are up to date")
            }
        case .failure(let error):
            print("Error checking for updates: \(error)")
        }
    }
}

func updateModel(modelId: String) {
    Task {
        do {
            try await lightpack.downloadModel(modelId)
            print("Model \(modelId) updated successfully")
        } catch {
            print("Error updating model \(modelId): \(error)")
        }
    }
}

在此示例中:

  1. 我们使用 getModels 函数来获取最新的模型信息。
  2. 我们检查结果中的 updatedModelIds 数组,以查看是否有任何模型有可用的更新。
  3. 如果更新可用,我们要么提示用户,要么使用 downloadModel 函数自动更新模型。

你可以定期调用 checkForModelUpdates 函数(例如,每天一次或在你的应用程序启动时),以确保你的本地模型是最新的。

请记住以一种优雅的方式处理更新过程,特别是对于大型模型文件,方法是向用户显示进度,并允许他们根据需要暂停或取消更新。

[先前的内容保持不变]

公共变量

Lightpack 公开了几个公共变量,这些变量提供了有关模型和系列当前状态的信息。 这些变量标有 @Published,可以在 SwiftUI 视图中观察,或者在 UIKit 应用程序中使用。

可用变量

访问公共变量

你可以直接从你的 Lightpack 实例访问这些变量。以下是如何使用它们的示例

let lightpack = Lightpack(apiKey: "your_api_key")

// Print information about all models
for (modelId, model) in lightpack.models {
    print("Model ID: \(modelId)")
    print("Model Title: \(model.title)")
    print("Model Status: \(model.status)")
    print("Model Size: \(model.size) GB")
    print("---")
}

// Print information about the currently loaded model
if let loadedModel = lightpack.loadedModel {
    print("Loaded Model: \(loadedModel.title)")
} else {
    print("No model currently loaded")
}

// Print the total size of all downloaded models
print("Total size of downloaded models: \(lightpack.totalModelSize) GB")

观察 SwiftUI 中的更改

在 SwiftUI 中,你可以通过创建 Lightpack 实例的 @StateObject 来观察对这些变量的更改

struct ContentView: View {
    @StateObject var lightpack = Lightpack(apiKey: "your_api_key")

    var body: some View {
        VStack {
            Text("Number of models: \(lightpack.models.count)")
            Text("Number of families: \(lightpack.families.count)")
            if let loadedModel = lightpack.loadedModel {
                Text("Loaded model: \(loadedModel.title)")
            } else {
                Text("No model loaded")
            }
            Text("Total model size: \(lightpack.totalModelSize) GB")
        }
    }
}

这样,每当这些变量发生更改时,你的视图都会自动更新。

有关每个功能的更多详细信息,请参阅内联文档或完整的 API 参考。

贡献

我们欢迎对 Lightpack 的贡献! 如果你想贡献,请按照以下步骤操作

  1. 在 GitHub 上 Fork 仓库。
  2. 为你的功能或错误修复创建一个新分支。
  3. 进行更改并提交它们,附带清晰、描述性的提交消息。
  4. 将你的更改推送到你的 Fork。
  5. 从你的 Fork 创建一个 Pull Request 到主要的 Lightpack 仓库。

要创建 Pull Request:

  1. 导航到 Lightpack 仓库的主页。
  2. 点击 "Pull requests",然后点击 "New pull request" 按钮。
  3. 选择你的 Fork 和包含你的更改的分支。
  4. 填写 Pull Request 模板,附带清晰的标题和更改描述。
  5. 点击 "Create pull request"。

我们将尽快审查你的 Pull Request 并提供反馈。 感谢你的贡献!

Bug

如果你在使用 Lightpack 时遇到 Bug,我们感谢你帮助报告它。 请按照以下步骤提交 Bug 报告

  1. 转到 GitHub 上 Lightpack 仓库的 Issues 页面
  2. 点击 "New issue" 按钮。
  3. 如果可用,选择 "Bug report" 模板,或启动一个空白 issue。
  4. 为 issue 提供一个清晰且描述性的标题。
  5. 在 issue 的正文中,请包含:
    • Bug 的详细描述
    • 重现该问题的步骤
    • 你期望发生的事情
    • 实际发生的事情
    • 你的环境(操作系统版本、Xcode 版本、Lightpack 版本等)
    • 任何相关的代码片段或屏幕截图
  6. 完成后,点击 "Submit new issue"。

在提交新的 Bug 报告之前,请搜索现有的 issue,查看是否有人已经报告了该问题。 如果你找到类似的问题,你可以在评论中添加更多信息。

我们感谢你帮助改进 Lightpack!

隐私和数据收集

Lightpack 在设计时充分考虑了隐私,主要在设备上运行。 但是,我们确实会收集某些分析和使用数据,以改进我们的服务。 有关我们收集哪些数据以及如何使用这些数据的完整详细信息,请参阅我们的隐私政策

服务条款和隐私

使用 Lightpack 即表示您同意我们的服务条款。 我们建议您阅读这些条款和我们的隐私政策,以了解您在使用我们的服务时的权利和义务。

模型许可

请参阅可用模型系列Lightpack 模型中的模型许可。 不同的模型可能有不同的许可条款,因此请务必查看您计划使用的每个模型的特定许可。

支持

如果您需要帮助或对 Lightpack 有任何疑问,包括关于我们的隐私惯例或服务条款的疑问,请随时联系我们。 您可以直接通过founders@lightpack.run联系创始人。

我们力求尽快回复所有咨询,并感谢您的反馈和问题。 有关我们如何处理您的数据的更多信息,请参阅我们的隐私政策