项目文件夹

文件
wehub-resource-sync e904b667c6
Build/Publish Develop Docs / deploy (push) Failing after 1s
PaddleOCR Code Style Check / check-code-style (push) Failing after 1s
PaddleOCR PR Tests GPU / detect-changes (push) Failing after 1s
PaddleOCR PR Tests / detect-changes (push) Failing after 1s
PaddleOCR PR Tests GPU / test-pr-gpu (push) Has been cancelled
PaddleOCR PR Tests / test-pr (push) Has been cancelled
PaddleOCR PR Tests GPU / test-pr-gpu-impl (push) Has been cancelled
PaddleOCR PR Tests / test-pr-python (3.13) (push) Has been cancelled
PaddleOCR PR Tests / test-pr-python (3.8) (push) Has been cancelled
PaddleOCR PR Tests / test-pr-python (3.9) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 11:59:26 +08:00

108 行
4.9 KiB
Swift

// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
/// Resolves exported ONNX or ORT-format models and their **model config files** in the app bundle (`Models/det`, `Models/rec`).
/// Resource lookup uses the conventional shared basename for the weight file and the model config file in each folder.
/// Weights: prefers `inference*.ort` in the model directory (see ``bundledOrtPath``), otherwise `inference.onnx`.
struct ModelConfig {
let modelPath: String
let configPath: String
/// From `Global.model_name` in the model config file (same directory as the ONNX weights).
let name: String
/// Human-readable label from `Global.model_name` in the model config file; `fallback` if the file cannot be read.
private static func displayName(fromModelConfigPath configPath: String, fallback: String) -> String {
guard let cfg = try? InferenceConfig.load(from: configPath) else {
return fallback
}
return cfg.modelName
}
/// Bundled model weights: any `inference*.ort` in the subdirectory (``ortBundledFileMatchOrder``), else `inference.onnx`.
///
/// ONNX Runtime’s `convert_onnx_models_to_ort` may emit `inference.with_runtime_opt.ort` instead of `inference.ort`
/// when using Runtime optimization style; the bundle cannot resolve that with `forResource: "inference"`.
private static let ortResourceStems: [String] = [
"inference",
"inference.with_runtime_opt",
]
private static func bundledOrtPath(inDirectory directory: String) -> String? {
for stem in ortResourceStems {
if let p = Bundle.main.path(forResource: stem, ofType: "ort", inDirectory: directory) {
return p
}
}
// Other ORT export suffixes (e.g. non-default optim levels): one `inference*.ort` in the folder.
guard let urls = Bundle.main.urls(forResourcesWithExtension: "ort", subdirectory: directory) else {
return nil
}
let matches = urls.filter { url in
let c = url.lastPathComponent
return c.hasPrefix("inference") && c.hasSuffix(".ort")
}
guard !matches.isEmpty else { return nil }
if matches.count == 1 { return matches[0].path }
// If multiple, prefer lexicographic first (deterministic); avoid shipping several exports in one dir.
return matches.sorted { $0.lastPathComponent < $1.lastPathComponent }.first?.path
}
private static func bundledWeightsPath(inDirectory directory: String, notFoundMessage: String) throws -> String {
if let ort = bundledOrtPath(inDirectory: directory) {
return ort
}
if let onnx = Bundle.main.path(forResource: "inference", ofType: "onnx", inDirectory: directory) {
return onnx
}
throw ModelConfigError.modelNotFound(notFoundMessage)
}
static func detection() throws -> ModelConfig {
let modelPath = try Self.bundledWeightsPath(
inDirectory: "Models/det",
notFoundMessage: "det/inference.ort or det/inference.onnx"
)
guard let configPath = Bundle.main.path(forResource: "inference", ofType: "yml", inDirectory: "Models/det") else {
throw ModelConfigError.modelNotFound("det model config file")
}
let name = displayName(fromModelConfigPath: configPath, fallback: "text_detection")
return ModelConfig(modelPath: modelPath, configPath: configPath, name: name)
}
static func recognition() throws -> ModelConfig {
let modelPath = try Self.bundledWeightsPath(
inDirectory: "Models/rec",
notFoundMessage: "rec/inference.ort or rec/inference.onnx"
)
guard let configPath = Bundle.main.path(forResource: "inference", ofType: "yml", inDirectory: "Models/rec") else {
throw ModelConfigError.modelNotFound("rec model config file")
}
let name = displayName(fromModelConfigPath: configPath, fallback: "text_recognition")
return ModelConfig(modelPath: modelPath, configPath: configPath, name: name)
}
}
enum ModelConfigError: LocalizedError {
case modelNotFound(String)
var errorDescription: String? {
switch self {
case .modelNotFound(let path):
return "Model file not found in bundle: \(path)"
}
}
}