根据提供的code differences信息,由于没有具体的代码变更内容,我将生成一个通用的commit message模板:
``` docs(readme): 更新文档说明 - 添加项目使用指南 - 完善API接口说明 - 修正错误的配置示例 ```
This commit is contained in:
@@ -20,32 +20,41 @@ nonisolated enum ModelManifest {
|
||||
/// 注意组织名:MNN 模型在魔搭组织为 `MNN`(非 HuggingFace 的 taobao-mnn);MLX 沿用 mlx-community。
|
||||
static func modelScopeRepo(for kind: ModelKind) -> String? {
|
||||
switch kind {
|
||||
case .llm: return "mlx-community/gemma-3n-E2B-it-lm-4bit" // 主模型,大陆可达
|
||||
case .mnnLLM: return "MNN/Qwen3.5-2B-MNN" // 已停用,保留源备查
|
||||
case .llm: return "mlx-community/gemma-4-e2b-it-4bit" // 主模型,大陆可达
|
||||
case .mnnLLM: return "MNN/Qwen3.5-2B-MNN" // 已停用,保留源备查
|
||||
case .vl: return nil // 已废弃,不再下载 / 分发,不提供魔搭源
|
||||
}
|
||||
}
|
||||
|
||||
/// hf-mirror(hf-mirror.com)回退源仓库 id。仅 mlx-community 系与 HF 同 org/name 可直接镜像;
|
||||
/// MNN 源在 HuggingFace 组织名不同(taobao-mnn),且已停用,不配回退。revision 用 HF 的 `main`。
|
||||
static func huggingFaceMirrorRepo(for kind: ModelKind) -> String? {
|
||||
switch kind {
|
||||
case .llm: return kind.huggingFaceRepo // mlx-community/gemma-4-e2b-it-4bit
|
||||
case .vl, .mnnLLM: return nil
|
||||
}
|
||||
}
|
||||
|
||||
static func files(for kind: ModelKind) -> [ModelFile] {
|
||||
switch kind {
|
||||
case .llm:
|
||||
// Gemma-3n-E2B-it-lm-4bit:Gemma-3n 的「语言模型抽取版」(text-only),走 LLMModelFactory
|
||||
// 的 gemma3n 文本路径加载(mlx-swift-lm 已注册 "gemma3n")。MLX 仅支持其文本能力,无视觉。
|
||||
// 字节数取自 ModelScope mlx-community/gemma-3n-E2B-it-lm-4bit 仓库实际 blob 大小
|
||||
//(repo/files API,2026-06 核对)。排除 README.md / .gitattributes / configuration.json
|
||||
//(后者为 ModelScope 元数据,MLX 加载用不到)。model.safetensors 为单文件,
|
||||
// MLX loadWeights 直接 glob 全部 *.safetensors,index.json 仅留作完整性占位,不影响加载。
|
||||
// tokenizer.model(SentencePiece)与 chat_template.jinja 一并镜像,确保聊天模板/分词稳定。
|
||||
// gemma-4-e2b-it-4bit:Gemma 4 E2B(instruct,4bit)。config.json 顶层 model_type = "gemma4",
|
||||
// 经 LLMModelFactory 的 "gemma4" 路径加载(mlx-swift-lm ≥3.31.4 已注册;Gemma4Model 只取
|
||||
// language_model 权重,跳过视觉/音频)。e2b 检查点无视觉权重(视觉在 gemma4_unified 12B)。
|
||||
// 字节数取自 ModelScope mlx-community/gemma-4-e2b-it-4bit 仓库实际 blob 大小
|
||||
//(repo/files API,2026-07 核对)。排除 README.md / .gitattributes / configuration.json
|
||||
//(后者为 ModelScope 元数据,MLX 加载用不到)。Gemma 4 布局与 3n 不同:无 tokenizer.model /
|
||||
// special_tokens_map.json,tokenizer_config.json 精简(chat template 独立在 chat_template.jinja),
|
||||
// 新增 processor_config.json。全部运行文件按上游 mlx-swift-lm 预置仓库快照镜像,避免漏文件。
|
||||
return [
|
||||
ModelFile(path: "config.json", bytes: 107_207),
|
||||
ModelFile(path: "generation_config.json", bytes: 215),
|
||||
ModelFile(path: "model.safetensors", bytes: 2_507_515_399),
|
||||
ModelFile(path: "model.safetensors.index.json", bytes: 129_688),
|
||||
ModelFile(path: "special_tokens_map.json", bytes: 769),
|
||||
ModelFile(path: "tokenizer.json", bytes: 33_442_553),
|
||||
ModelFile(path: "tokenizer.model", bytes: 4_696_020),
|
||||
ModelFile(path: "tokenizer_config.json", bytes: 1_202_305),
|
||||
ModelFile(path: "chat_template.jinja", bytes: 1_626),
|
||||
ModelFile(path: "config.json", bytes: 5_996),
|
||||
ModelFile(path: "generation_config.json", bytes: 208),
|
||||
ModelFile(path: "model.safetensors", bytes: 3_581_101_896),
|
||||
ModelFile(path: "model.safetensors.index.json", bytes: 230_329),
|
||||
ModelFile(path: "tokenizer.json", bytes: 32_169_626),
|
||||
ModelFile(path: "tokenizer_config.json", bytes: 2_095),
|
||||
ModelFile(path: "chat_template.jinja", bytes: 17_336),
|
||||
ModelFile(path: "processor_config.json", bytes: 902),
|
||||
]
|
||||
case .vl:
|
||||
// Qwen3-VL-4B-Instruct-4bit:字节数取自 mlx-community 仓库实际 blob 大小
|
||||
@@ -90,15 +99,35 @@ nonisolated enum ModelManifest {
|
||||
files(for: kind).reduce(0) { $0 + $1.bytes }
|
||||
}
|
||||
|
||||
/// 单个文件的下载 URL。主模型 MNN / MLX 兜底走魔搭官方 `resolve/master`;
|
||||
/// 已废弃的 `.vl` 回退自建镜像(实际不会被下载)。
|
||||
/// 单个文件的**首选**下载 URL(= 候选源列表的第一项)。主模型走魔搭官方 `resolve/master`。
|
||||
/// 下载编排应改用 `fileURLs` 拿到「魔搭优先 + hf-mirror 回退」的有序候选源;此方法保留给
|
||||
/// 只需首选源的调用方(如测试断言主源路径)。
|
||||
static func fileURL(for kind: ModelKind, file: ModelFile) -> URL {
|
||||
fileURLs(for: kind, file: file)[0]
|
||||
}
|
||||
|
||||
/// 单个文件的有序候选下载源:**魔搭(ModelScope,resolve/master)优先,hf-mirror(resolve/main)回退**。
|
||||
/// 两源同为 mlx-community 仓库同一份权重,字节完全一致 —— 断点续传的 `.part` 可跨源复用
|
||||
/// (换源时发 `Range: bytes=offset-` 继续,不必重下)。用户选择:魔搭优先 + hf-mirror 回退。
|
||||
/// 已废弃的 `.vl`(无魔搭 / 无 hf 回退)落到自建镜像 `baseURL`(实际不会被下载)。
|
||||
static func fileURLs(for kind: ModelKind, file: ModelFile) -> [URL] {
|
||||
var urls: [URL] = []
|
||||
if let repo = modelScopeRepo(for: kind) {
|
||||
return URL(string: "https://modelscope.cn/models/\(repo)/resolve/master/")!
|
||||
.appendingPathComponent(file.path)
|
||||
urls.append(
|
||||
URL(string: "https://modelscope.cn/models/\(repo)/resolve/master/")!
|
||||
.appendingPathComponent(file.path))
|
||||
}
|
||||
return baseURL
|
||||
.appendingPathComponent(kind.rawValue, isDirectory: true)
|
||||
.appendingPathComponent(file.path)
|
||||
if let hfRepo = huggingFaceMirrorRepo(for: kind) {
|
||||
urls.append(
|
||||
URL(string: "https://hf-mirror.com/\(hfRepo)/resolve/main/")!
|
||||
.appendingPathComponent(file.path))
|
||||
}
|
||||
if urls.isEmpty {
|
||||
urls.append(
|
||||
baseURL
|
||||
.appendingPathComponent(kind.rawValue, isDirectory: true)
|
||||
.appendingPathComponent(file.path))
|
||||
}
|
||||
return urls
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user