feat(iOS): 更新MNN后端模型配置优化性能

将MNN主模型从Qwen3.5-4B(~2.64GiB)降级为Qwen3.5-2B(~1.1GiB),因为4B版本
实测运行过慢,影响用户体验。iPhone17+/SME2设备使用2B模型,保留MLX
兜底方案用于模拟器和备用场景,确保AI推理性能和存储效率的平衡。
```
This commit is contained in:
link2026
2026-06-09 22:20:07 +08:00
parent ca5a3fa38b
commit b79ae54b7b
40 changed files with 1327 additions and 452 deletions

View File

@@ -3,10 +3,10 @@ import SwiftUI
/// : MNN(CPU/SME2,) MLX(GPU,), SME2
/// ; AI (prepare/generate)
struct InferenceSettingsView: View {
@AppStorage("kk.inferenceEngine") private var engineRaw = InferenceEngine.mnn.rawValue
@AppStorage("kk.inferenceEngine") private var engineRaw = EnginePreference.auto.rawValue
private var selected: InferenceEngine {
InferenceEngine(rawValue: engineRaw) ?? .mnn
private var selected: EnginePreference {
EnginePreference(rawValue: engineRaw) ?? .auto
}
var body: some View {
@@ -21,7 +21,7 @@ struct InferenceSettingsView: View {
.padding(.top, 4)
.padding(.bottom, 6)
ForEach(InferenceEngine.allCases, id: \.self) { engine in
ForEach(EnginePreference.allCases, id: \.self) { engine in
engineRow(engine)
}
@@ -34,8 +34,8 @@ struct InferenceSettingsView: View {
.background(Tj.Palette.sand.ignoresSafeArea())
}
private func engineRow(_ engine: InferenceEngine) -> some View {
let available = engine.isAvailable
private func engineRow(_ engine: EnginePreference) -> some View {
let available = isAvailable(engine)
let isOn = (selected == engine)
return Button {
guard available else { return }
@@ -44,7 +44,7 @@ struct InferenceSettingsView: View {
HStack(spacing: 12) {
ZStack {
Circle().fill(isOn ? Tj.Palette.amber.opacity(0.25) : Tj.Palette.sand2)
Image(systemName: engine == .mnn ? "cpu.fill" : "bolt.fill")
Image(systemName: iconName(engine))
.font(.tjScaled(18))
.foregroundStyle(isOn ? Tj.Palette.ink : Tj.Palette.text2)
}
@@ -74,8 +74,35 @@ struct InferenceSettingsView: View {
.disabled(!available)
}
private func subtitle(_ engine: InferenceEngine, available: Bool) -> String {
/// .auto ;
private func isAvailable(_ engine: EnginePreference) -> Bool {
switch engine {
case .auto: return true
case .mnn: return InferenceEngine.mnn.isAvailable
case .mlx: return InferenceEngine.mlx.isAvailable
}
}
private func iconName(_ engine: EnginePreference) -> String {
switch engine {
case .auto: return "wand.and.stars"
case .mnn: return "cpu.fill"
case .mlx: return "bolt.fill"
}
}
private func subtitle(_ engine: EnginePreference, available: Bool) -> String {
switch engine {
case .auto:
// ,
let resolved = engine.resolved
if resolved == .mnn {
return InferenceEngine.cpuSupportsSME2
? String(appLoc: "按本机配置选择 · 当前 MNN + SME2")
: String(appLoc: "按本机配置选择 · 当前 MNN(NEON)")
} else {
return String(appLoc: "按本机配置选择 · 当前 MLX(MNN 不可用)")
}
case .mnn:
if !available { return String(appLoc: "本设备/模拟器不可用,自动回退 MLX") }
return InferenceEngine.cpuSupportsSME2