```
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:
@@ -8,9 +8,12 @@ struct CaptureReviewForm: View {
|
||||
@State var parsed: ParsedReport
|
||||
let assets: [FileVault.SavedAsset]
|
||||
let warning: String?
|
||||
/// 归档模式:只存原图 + 基本信息(标题/类型/日期/机构),隐藏指标区与摘要。
|
||||
/// 报告归档不再逐项识别(逐项多模态在 2B 上易 OOM 卡死),见 CaptureService.extractReportMeta。
|
||||
var metaOnly: Bool = false
|
||||
let onSave: (ParsedReport) -> Void
|
||||
let onCancel: () -> Void
|
||||
/// 「重新识别」回调。assets 为空(写图失败)时传 nil,banner 上不显示该按钮。
|
||||
/// 「重新识别信息」回调。assets 为空(写图失败)时传 nil,banner 上不显示该按钮。
|
||||
var onReanalyze: (() -> Void)? = nil
|
||||
|
||||
var body: some View {
|
||||
@@ -23,7 +26,9 @@ struct CaptureReviewForm: View {
|
||||
pageThumbnails
|
||||
}
|
||||
metaSection
|
||||
indicatorSection
|
||||
if !metaOnly {
|
||||
indicatorSection
|
||||
}
|
||||
Spacer(minLength: 8)
|
||||
actions
|
||||
}
|
||||
@@ -68,20 +73,26 @@ struct CaptureReviewForm: View {
|
||||
private var pageThumbnails: some View {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
sectionLabel(String(appLoc: "已保存 \(assets.count) 页(端侧加密)"))
|
||||
if metaOnly {
|
||||
Text("原图已加密保存,详情页随时可翻看放大。系统只识别报告日期与机构作为标签,不逐项录入数值。")
|
||||
.font(.tjScaled( 11))
|
||||
.foregroundStyle(Tj.Palette.text3)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack(spacing: 10) {
|
||||
ForEach(Array(assets.enumerated()), id: \.offset) { _, asset in
|
||||
if let img = try? FileVault.shared.loadImage(relativePath: asset.relativePath) {
|
||||
Image(uiImage: img)
|
||||
.resizable()
|
||||
.scaledToFill()
|
||||
.frame(width: 84, height: 110)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 8, style: .continuous)
|
||||
.strokeBorder(Tj.Palette.line, lineWidth: 1)
|
||||
)
|
||||
VaultImage(relativePath: asset.relativePath, maxPixel: 400) { img in
|
||||
Image(uiImage: img).resizable().scaledToFill()
|
||||
} placeholder: { _ in
|
||||
Tj.Palette.paper
|
||||
}
|
||||
.frame(width: 84, height: 110)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 8, style: .continuous)
|
||||
.strokeBorder(Tj.Palette.line, lineWidth: 1)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,9 +128,11 @@ struct CaptureReviewForm: View {
|
||||
labeledField(String(appLoc: "机构(可选)")) {
|
||||
TextField("如:协和医院", text: $parsed.institution)
|
||||
}
|
||||
labeledField(String(appLoc: "摘要(可选)")) {
|
||||
TextField("一句话总结", text: $parsed.summary, axis: .vertical)
|
||||
.lineLimit(1...3)
|
||||
if !metaOnly {
|
||||
labeledField(String(appLoc: "摘要(可选)")) {
|
||||
TextField("一句话总结", text: $parsed.summary, axis: .vertical)
|
||||
.lineLimit(1...3)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(12)
|
||||
|
||||
Reference in New Issue
Block a user