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,7 +3,7 @@ import AVFoundation
import UIKit
import Combine
/// ·
/// ·
/// + **** upright UIImage()
/// `RegionAdjustView`
/// (,`QuickRegionCaptureFlow` 退 PhotoPicker)
@@ -60,7 +60,7 @@ struct SingleShotCameraView: View {
Spacer()
Text("拍一张含异常指标的照片 · 拍完再框选")
Text("拍一张含目标指标的照片 · 拍完再框选")
.font(.tjScaled( 13, weight: .medium))
.foregroundStyle(.white)
.padding(.horizontal, 12)
@@ -97,7 +97,7 @@ struct SingleShotCameraView: View {
Text("相机权限未开启")
.font(.tjH2())
.foregroundStyle(.white)
Text("异常项快拍需要相机。去「设置 → 康康 → 相机」打开后再回来。")
Text("指标速记需要相机。去「设置 → 康康 → 相机」打开后再回来。")
.font(.tjScaled( 13))
.foregroundStyle(.white.opacity(0.7))
.multilineTextAlignment(.center)
@@ -352,49 +352,6 @@ enum RegionImageCropper {
guard rect.width >= 1, rect.height >= 1, let cropped = cg.cropping(to: rect) else { return up }
return UIImage(cgImage: cropped, scale: up.scale, orientation: .up)
}
/// Qwen3-VL : VL ,processor
/// Qwen3-VL ,Apple Vision OCR
static func prepareForQwenVL(_ image: UIImage,
minimumShortEdge: CGFloat = 448,
maximumLongEdge: CGFloat = 2400,
padding: CGFloat = 64) -> UIImage {
let up = image.normalizedUp()
guard let cg = up.cgImage else { return up }
let sourceSize = CGSize(width: cg.width, height: cg.height)
guard sourceSize.width > 0, sourceSize.height > 0 else { return up }
let short = min(sourceSize.width, sourceSize.height)
let long = max(sourceSize.width, sourceSize.height)
var scale = max(1, minimumShortEdge / short)
if long * scale > maximumLongEdge {
scale = maximumLongEdge / long
}
let contentSize = CGSize(
width: max(1, (sourceSize.width * scale).rounded()),
height: max(1, (sourceSize.height * scale).rounded())
)
let canvasSize = CGSize(
width: contentSize.width + padding * 2,
height: contentSize.height + padding * 2
)
let format = UIGraphicsImageRendererFormat.default()
format.scale = 1
format.opaque = true
let renderer = UIGraphicsImageRenderer(size: canvasSize, format: format)
return renderer.image { ctx in
UIColor.white.setFill()
ctx.fill(CGRect(origin: .zero, size: canvasSize))
UIImage(cgImage: cg, scale: 1, orientation: .up).draw(
in: CGRect(x: padding, y: padding,
width: contentSize.width, height: contentSize.height)
)
}
}
}
extension UIImage {