Files
kangkang/康康/AI/VLSession.swift
link2026 32180d7c0e 根据提供的code differences信息,由于没有具体的代码变更内容,我将生成一个通用的commit message模板:
```
docs(readme): 更新文档说明

- 添加项目使用指南
- 完善API接口说明
- 修正错误的配置示例
```
2026-07-13 18:47:11 +08:00

80 lines
2.9 KiB
Swift

import Foundation
import MLX
import MLXVLM
import MLXLMCommon
// 3.x HF Hub/ opt-in ( LLMSession )
import MLXHuggingFace
import HuggingFace
import Tokenizers
/// MLX VL (Qwen3-VL)
/// LLMSession actor , AIRuntime
actor VLSession {
let container: ModelContainer
init(container: ModelContainer) {
self.container = container
}
private static func withDeviceOverride<R>(
_ body: () async throws -> R
) async rethrows -> R {
#if targetEnvironment(simulator)
return try await Device.withDefaultDevice(.cpu, body)
#else
return try await body()
#endif
}
/// VL ( config.json + weights + tokenizer + processor)
static func load(folderURL: URL) async throws -> VLSession {
let configuration = ModelConfiguration(directory: folderURL)
// 3.31.4: LLMSession, Downloader()+ HF
let container = try await withDeviceOverride {
try await VLMModelFactory.shared.loadContainer(
from: #hubDownloader(),
using: #huggingFaceTokenizerLoader(),
configuration: configuration
)
}
return VLSession(container: container)
}
/// ( token )
/// VL JSON , JSON UI
/// - Parameters:
/// - imageURLs: file:// URL, FileVault
/// - prompt: (VLPrompts.reportExtraction)
/// - maxTokens: 512(JSON 200-400)
func analyze(imageURLs: [URL],
prompt: String,
maxTokens: Int = 512) async throws -> String {
try await Self.withDeviceOverride {
try await container.perform { (context: ModelContext) in
let images = imageURLs.map { UserInput.Image.url($0) }
let userInput = UserInput(prompt: prompt, images: images)
let lmInput = try await context.processor.prepare(input: userInput)
let parameters = GenerateParameters(
maxTokens: maxTokens,
temperature: Float(0.2), // JSON ,
topP: Float(0.9)
)
var collected = ""
for await event in try MLXLMCommon.generate(
input: lmInput,
parameters: parameters,
context: context
) {
if Task.isCancelled { break }
if case .chunk(let text) = event {
collected.append(text)
}
}
return collected
}
}
}
}