mirror of
https://git.openapi.site/https://github.com/desirecore/agent-desirecore.git
synced 2026-09-06 00:24:13 +08:00
feat: 增加求解器验证书 Web (#7)
Co-authored-by: yige <yige@yigedeMacBook-Neo.local>
This commit is contained in:
99
web/solver-report/scripts/audit-screenshot-privacy.swift
Normal file
99
web/solver-report/scripts/audit-screenshot-privacy.swift
Normal file
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env swift
|
||||
import AppKit
|
||||
import Foundation
|
||||
import Vision
|
||||
|
||||
enum AuditError: Error, CustomStringConvertible {
|
||||
case usage
|
||||
case malformedPlan(String)
|
||||
case unsafePath(String)
|
||||
case unreadableImage(String)
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .usage:
|
||||
return "usage: audit-screenshot-privacy.swift <input-root> <screenshot-plan.json> <ocr-output.json>"
|
||||
case .malformedPlan(let detail):
|
||||
return "malformed screenshot plan: \(detail)"
|
||||
case .unsafePath(let path):
|
||||
return "screenshot path escapes input root: \(path)"
|
||||
case .unreadableImage(let path):
|
||||
return "cannot decode screenshot: \(path)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func requiredString(_ object: [String: Any], _ key: String) throws -> String {
|
||||
guard let value = object[key] as? String, !value.isEmpty else {
|
||||
throw AuditError.malformedPlan("missing \(key)")
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
do {
|
||||
guard CommandLine.arguments.count == 4 else { throw AuditError.usage }
|
||||
let inputRoot = URL(fileURLWithPath: CommandLine.arguments[1]).standardizedFileURL
|
||||
let planURL = URL(fileURLWithPath: CommandLine.arguments[2]).standardizedFileURL
|
||||
let outputURL = URL(fileURLWithPath: CommandLine.arguments[3]).standardizedFileURL
|
||||
let planData = try Data(contentsOf: planURL)
|
||||
guard
|
||||
let plan = try JSONSerialization.jsonObject(with: planData) as? [String: Any],
|
||||
let scenarios = plan["scenarios"] as? [[String: Any]]
|
||||
else {
|
||||
throw AuditError.malformedPlan("scenarios must be an array")
|
||||
}
|
||||
|
||||
var entries: [[String: Any]] = []
|
||||
for scenario in scenarios {
|
||||
let scenarioId = try requiredString(scenario, "scenarioId")
|
||||
guard let screenshots = scenario["screenshots"] as? [[String: Any]] else {
|
||||
throw AuditError.malformedPlan("\(scenarioId).screenshots must be an array")
|
||||
}
|
||||
for screenshot in screenshots {
|
||||
let relativePath = try requiredString(screenshot, "file")
|
||||
let imageURL = inputRoot.appendingPathComponent(relativePath).standardizedFileURL
|
||||
let rootPrefix = inputRoot.path.hasSuffix("/") ? inputRoot.path : inputRoot.path + "/"
|
||||
guard imageURL.path.hasPrefix(rootPrefix) else { throw AuditError.unsafePath(relativePath) }
|
||||
|
||||
let recognizedLines: [[String: Any]] = try autoreleasepool {
|
||||
guard
|
||||
let image = NSImage(contentsOf: imageURL),
|
||||
let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil)
|
||||
else {
|
||||
throw AuditError.unreadableImage(relativePath)
|
||||
}
|
||||
let request = VNRecognizeTextRequest()
|
||||
request.recognitionLevel = .accurate
|
||||
request.recognitionLanguages = ["zh-Hans", "en-US"]
|
||||
request.usesLanguageCorrection = true
|
||||
try VNImageRequestHandler(cgImage: cgImage, options: [:]).perform([request])
|
||||
return (request.results ?? []).compactMap { observation in
|
||||
guard let text = observation.topCandidates(1).first?.string else { return nil }
|
||||
let box = observation.boundingBox
|
||||
return [
|
||||
"text": text,
|
||||
"boundingBox": [box.origin.x, box.origin.y, box.size.width, box.size.height],
|
||||
]
|
||||
}
|
||||
}
|
||||
entries.append([
|
||||
"scenarioId": scenarioId,
|
||||
"file": relativePath,
|
||||
"lines": recognizedLines,
|
||||
])
|
||||
FileHandle.standardError.write(Data("OCR \(entries.count): \(relativePath)\n".utf8))
|
||||
}
|
||||
}
|
||||
|
||||
let output: [String: Any] = [
|
||||
"schemaVersion": "solver.screenshot-privacy-ocr/v1",
|
||||
"generatedAt": ISO8601DateFormatter().string(from: Date()),
|
||||
"engine": "Apple Vision VNRecognizeTextRequest accurate zh-Hans+en-US",
|
||||
"entries": entries,
|
||||
]
|
||||
let outputData = try JSONSerialization.data(withJSONObject: output, options: [.prettyPrinted, .sortedKeys])
|
||||
try outputData.write(to: outputURL, options: .atomic)
|
||||
} catch {
|
||||
FileHandle.standardError.write(Data("\(error)\n".utf8))
|
||||
exit(1)
|
||||
}
|
||||
Reference in New Issue
Block a user