```
feat(AI): 集成MNN推理引擎替换MLX作为主AI运行时 - 引入MNN(alibaba) + Arm SME2 + CPU作为主AI运行时,支持A19/iPhone17的 SME2和A17的NEON加速 - 添加MLX Swift作为兜底GPU推理方案,实现双后端切换机制 - 使用单一Qwen3.5-2B多模态模型(1.2GB),替代原有的LLM+VL分离架构 - 实现InferenceEngine.current引擎选择逻辑,真机默认MNN,模拟器回退MLX - 更新AIAgent架构,通过MNNLLMBridge(ObjC++) → MNNBackend进行推理 - 修改队列机制防止并发推理导致OOM,使用信号量闸门控制显存占用 - 更新文档中的技术栈说明、模块边界和周次交付计划 ```
This commit is contained in:
47
康康/DesignSystem/VaultImage.swift
Normal file
47
康康/DesignSystem/VaultImage.swift
Normal file
@@ -0,0 +1,47 @@
|
||||
import SwiftUI
|
||||
|
||||
/// 从加密 Vault 异步加载并降采样显示原图的通用组件。
|
||||
///
|
||||
/// 替代「在 body 里 `try? FileVault.shared.loadImage(...)` 同步读盘 + 全量解码」的旧写法,
|
||||
/// 解决两个真实问题:
|
||||
/// 1. **OOM**:全分辨率位图(4000×3000 ≈ 48MB)进内存,翻几页就触发 jetsam。这里按 `maxPixel`
|
||||
/// 降采样,缩略图几百 KB,全屏图几 MB。
|
||||
/// 2. **主线程卡顿**:读盘 + JPEG 解码在主线程会掉帧。这里放到后台线程,主线程只拿结果绘制。
|
||||
///
|
||||
/// 区分「加载中」与「读取失败」两态:加载中显示中性占位,只有真正失败才显示「原图无法读取」,
|
||||
/// 不会一打开就闪一下吓人的错误文案。`content` 拿到 `UIImage`(而非 `Image`),
|
||||
/// 方便需要 `image.size` 的调用方(如证据高亮 overlay)按真实宽高比定位。
|
||||
struct VaultImage<Content: View, Placeholder: View>: View {
|
||||
let relativePath: String
|
||||
/// 降采样目标最大边(像素)。缩略图给 ~400,全屏查看器给 ~2000。
|
||||
var maxPixel: CGFloat = 1024
|
||||
|
||||
@ViewBuilder var content: (UIImage) -> Content
|
||||
/// 占位回调,`isLoading == true` 表示仍在加载,`false` 表示加载完成但失败。
|
||||
@ViewBuilder var placeholder: (_ isLoading: Bool) -> Placeholder
|
||||
|
||||
@State private var image: UIImage?
|
||||
@State private var loading = true
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if let image {
|
||||
content(image)
|
||||
} else {
|
||||
placeholder(loading)
|
||||
}
|
||||
}
|
||||
// id 变了(TabView 翻到新页 / 行复用换 asset)就重新加载;同一身份重渲染不会重复读盘。
|
||||
.task(id: relativePath) {
|
||||
loading = true
|
||||
let path = relativePath
|
||||
let mp = maxPixel
|
||||
let loaded = await Task.detached(priority: .userInitiated) {
|
||||
try? FileVault.shared.loadDownsampledImage(relativePath: path, maxPixelSize: mp)
|
||||
}.value
|
||||
guard !Task.isCancelled else { return }
|
||||
image = loaded
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user