Add macOS LLM model engine support and environment setup
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
// LLMHelper.swift - Interface with macOS native on-device LLM (FoundationModels / Apple Intelligence)
|
||||
//
|
||||
// Usage:
|
||||
// llm-helper --check
|
||||
// llm-helper --prompt "Hello" [--system "System prompt"]
|
||||
|
||||
import Foundation
|
||||
import FoundationModels
|
||||
|
||||
struct Options {
|
||||
var prompt: String = ""
|
||||
var systemPrompt: String? = nil
|
||||
var check: Bool = false
|
||||
}
|
||||
|
||||
func parseArguments() -> Options {
|
||||
var options = Options()
|
||||
var arguments = Array(CommandLine.arguments.dropFirst())
|
||||
while let argument = arguments.first {
|
||||
arguments.removeFirst()
|
||||
switch argument {
|
||||
case "--prompt":
|
||||
if !arguments.isEmpty { options.prompt = arguments.removeFirst() }
|
||||
case "--system":
|
||||
if !arguments.isEmpty { options.systemPrompt = arguments.removeFirst() }
|
||||
case "--check":
|
||||
options.check = true
|
||||
default:
|
||||
if options.prompt.isEmpty && !argument.hasPrefix("--") {
|
||||
options.prompt = argument
|
||||
}
|
||||
}
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
func emit(_ payload: [String: Any]) {
|
||||
if let data = try? JSONSerialization.data(withJSONObject: payload, options: [.sortedKeys]),
|
||||
let str = String(data: data, encoding: .utf8) {
|
||||
print(str)
|
||||
fflush(stdout)
|
||||
}
|
||||
}
|
||||
|
||||
func fail(_ message: String) -> Never {
|
||||
emit(["error": message])
|
||||
exit(1)
|
||||
}
|
||||
|
||||
@main
|
||||
struct LLMHelperApp {
|
||||
static func main() async {
|
||||
let options = parseArguments()
|
||||
|
||||
if options.check {
|
||||
let model = SystemLanguageModel.default
|
||||
let isAvailable = model.isAvailable
|
||||
emit([
|
||||
"available": isAvailable,
|
||||
"model": "macOS SystemLanguageModel",
|
||||
"reason": isAvailable ? "macOS Apple Intelligence model available" : "SystemLanguageModel unavailable on this hardware/OS configuration"
|
||||
])
|
||||
exit(0)
|
||||
}
|
||||
|
||||
guard !options.prompt.isEmpty else {
|
||||
fail("no prompt provided")
|
||||
}
|
||||
|
||||
do {
|
||||
let model = SystemLanguageModel.default
|
||||
guard model.isAvailable else {
|
||||
fail("macOS SystemLanguageModel is not available on this machine")
|
||||
}
|
||||
|
||||
let instructions = options.systemPrompt ?? ""
|
||||
let session: LanguageModelSession
|
||||
if !instructions.isEmpty {
|
||||
session = LanguageModelSession(model: model, instructions: instructions)
|
||||
} else {
|
||||
session = LanguageModelSession(model: model)
|
||||
}
|
||||
|
||||
let response = try await session.respond(to: options.prompt)
|
||||
let resultText = String(describing: response)
|
||||
emit(["done": true, "text": resultText])
|
||||
} catch {
|
||||
fail("LanguageModel error: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-4
@@ -13,14 +13,23 @@ swiftc -O -parse-as-library SpeechHelper.swift -o speech-helper
|
||||
echo "built $HERE/speech-helper"
|
||||
|
||||
if ./speech-helper --check >/dev/null 2>&1; then
|
||||
echo "it runs — ./speech-helper --check for details"
|
||||
echo "speech-helper runs — ./speech-helper --check for details"
|
||||
else
|
||||
status=$?
|
||||
if [ "$status" -eq 137 ]; then
|
||||
echo "built, but killed on launch (137): request binary approval for"
|
||||
echo "built speech-helper, but killed on launch (137): request binary approval for"
|
||||
echo " $HERE/speech-helper"
|
||||
echo "then wait a few minutes for it to sync."
|
||||
else
|
||||
echo "built, but exited $status — run ./speech-helper --check to see why"
|
||||
echo "built speech-helper, but exited $status — run ./speech-helper --check to see why"
|
||||
fi
|
||||
fi
|
||||
|
||||
if swiftc -O LLMHelper.swift -o llm-helper 2>/dev/null; then
|
||||
echo "built $HERE/llm-helper"
|
||||
if ./llm-helper --check >/dev/null 2>&1; then
|
||||
echo "llm-helper runs — ./llm-helper --check for details"
|
||||
fi
|
||||
else
|
||||
echo "could not build llm-helper with FoundationModels; fallback to Python MLX/PyObjC bridge will be available"
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user