```
feat(CaptureService): 改进报告解析逻辑并添加多语言键支持 - 修改应用描述从"个人健康影像档案"到"个人健康随记" - 添加对多种JSON键名的支持,包括中文键名(如"指标"、"项目"、"结果"等) - 实现指标状态智能推断功能,可根据数值和参考范围自动判断高低状态 - 支持多种状态标识符,包括箭头符号(↑↓)和中英文状态词 - 增加对不同参考范围格式的解析支持(如"< 3.40"、"208 - 428"等) - 添加相关单元测试验证中文键名和状态推断功能 ```
This commit is contained in:
@@ -179,7 +179,7 @@ actor CaptureService {
|
||||
let summary = (dict["summary"] as? String) ?? ""
|
||||
let pages = (dict["page_count"] as? Int) ?? pageCount
|
||||
|
||||
let indicatorsRaw = (dict["indicators"] as? [[String: Any]]) ?? []
|
||||
let indicatorsRaw = arrayValue(dict, keys: ["indicators", "indicator", "items", "指标", "指标列表", "项目"])
|
||||
let indicators: [ParsedReport.ParsedIndicator] = indicatorsRaw.compactMap {
|
||||
parseIndicator($0)
|
||||
}
|
||||
@@ -212,7 +212,7 @@ actor CaptureService {
|
||||
// 兼容两种形态:{"indicators":[...]} 或直接 [...](模型偶尔省外层 key)
|
||||
let indicatorsRaw: [[String: Any]]
|
||||
if let dict = obj as? [String: Any] {
|
||||
indicatorsRaw = (dict["indicators"] as? [[String: Any]]) ?? []
|
||||
indicatorsRaw = arrayValue(dict, keys: ["indicators", "indicator", "items", "指标", "指标列表", "项目"])
|
||||
} else if let arr = obj as? [[String: Any]] {
|
||||
indicatorsRaw = arr
|
||||
} else {
|
||||
@@ -335,18 +335,100 @@ actor CaptureService {
|
||||
}
|
||||
|
||||
private static func parseIndicator(_ d: [String: Any]) -> ParsedReport.ParsedIndicator? {
|
||||
guard let name = (d["name"] as? String)?.trimmingCharacters(in: .whitespaces),
|
||||
guard let name = stringValue(d, keys: ["name", "item", "indicator", "test", "项目", "指标", "指标名", "指标名称", "检查项目", "检验项目"])?.trimmingCharacters(in: .whitespaces),
|
||||
!name.isEmpty else { return nil }
|
||||
let value: String
|
||||
if let v = d["value"] as? String { value = v }
|
||||
else if let v = d["value"] as? NSNumber { value = v.stringValue }
|
||||
if let v = stringValue(d, keys: ["value", "result", "reading", "结果", "数值", "检测值", "测定值"]) { value = v }
|
||||
else { value = "" }
|
||||
let unit = (d["unit"] as? String) ?? ""
|
||||
let range = (d["range"] as? String) ?? ""
|
||||
let statusRaw = (d["status"] as? String)?.lowercased() ?? "normal"
|
||||
let status = IndicatorStatus(rawValue: statusRaw) ?? .normal
|
||||
let unit = stringValue(d, keys: ["unit", "单位"]) ?? ""
|
||||
let range = stringValue(d, keys: ["range", "reference", "reference_range", "ref", "参考", "参考值", "参考范围", "正常范围"]) ?? ""
|
||||
let statusRaw = stringValue(d, keys: ["status", "flag", "abnormal", "异常", "提示", "标记"])
|
||||
let status = parseIndicatorStatus(raw: statusRaw, value: value, range: range)
|
||||
return .init(name: name, value: value, unit: unit, range: range, status: status)
|
||||
}
|
||||
|
||||
private static func stringValue(_ d: [String: Any], keys: [String]) -> String? {
|
||||
for key in keys {
|
||||
if let s = d[key] as? String {
|
||||
return s
|
||||
}
|
||||
if let n = d[key] as? NSNumber {
|
||||
return n.stringValue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private static func arrayValue(_ d: [String: Any], keys: [String]) -> [[String: Any]] {
|
||||
for key in keys {
|
||||
if let arr = d[key] as? [[String: Any]] {
|
||||
return arr
|
||||
}
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
private static func parseIndicatorStatus(raw: String?, value: String, range: String) -> IndicatorStatus {
|
||||
let normalized = raw?
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
.lowercased() ?? ""
|
||||
|
||||
if ["high", "h", "hi", "above", "up", "↑", "⬆", "+", "偏高", "高", "增高", "升高", "偏高↑", "h↑"].contains(normalized) {
|
||||
return .high
|
||||
}
|
||||
if ["low", "l", "lo", "below", "down", "↓", "⬇", "-", "偏低", "低", "降低", "偏低↓", "l↓"].contains(normalized) {
|
||||
return .low
|
||||
}
|
||||
if ["normal", "n", "ok", "正常", "阴性", "无异常"].contains(normalized) {
|
||||
return .normal
|
||||
}
|
||||
|
||||
return inferStatus(value: value, range: range) ?? .normal
|
||||
}
|
||||
|
||||
private static func inferStatus(value: String, range: String) -> IndicatorStatus? {
|
||||
guard let v = firstNumber(in: value) else { return nil }
|
||||
let compact = range
|
||||
.replacingOccurrences(of: "—", with: "-")
|
||||
.replacingOccurrences(of: "–", with: "-")
|
||||
.replacingOccurrences(of: "~", with: "-")
|
||||
.replacingOccurrences(of: "~", with: "-")
|
||||
.replacingOccurrences(of: "至", with: "-")
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
guard !compact.isEmpty else { return nil }
|
||||
|
||||
let numbers = numbers(in: compact)
|
||||
if compact.contains("<") || compact.contains("≤") || compact.contains("<") {
|
||||
guard let upper = numbers.first else { return nil }
|
||||
return v > upper ? .high : .normal
|
||||
}
|
||||
if compact.contains(">") || compact.contains("≥") || compact.contains(">") {
|
||||
guard let lower = numbers.first else { return nil }
|
||||
return v < lower ? .low : .normal
|
||||
}
|
||||
if numbers.count >= 2 {
|
||||
let lower = numbers[0]
|
||||
let upper = numbers[1]
|
||||
if v < lower { return .low }
|
||||
if v > upper { return .high }
|
||||
return .normal
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private static func firstNumber(in text: String) -> Double? {
|
||||
numbers(in: text).first
|
||||
}
|
||||
|
||||
private static func numbers(in text: String) -> [Double] {
|
||||
let pattern = #"-?\d+(?:\.\d+)?"#
|
||||
guard let regex = try? NSRegularExpression(pattern: pattern) else { return [] }
|
||||
let ns = text as NSString
|
||||
let range = NSRange(location: 0, length: ns.length)
|
||||
return regex.matches(in: text, range: range).compactMap {
|
||||
Double(ns.substring(with: $0.range))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Report ↔ CaptureService 桥接(MainActor 侧)
|
||||
|
||||
Reference in New Issue
Block a user