Skip to content

Commit f97cabd

Browse files
kochj23claude
andcommitted
feat: Add dynamic Ollama/MLX model discovery to AIBackendManager
Users can now select from whatever models are installed locally. fetchAvailableModels() queries Ollama /api/tags at runtime. fetchMLXModels() queries MLX server /v1/models. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent a917d02 commit f97cabd

1 file changed

Lines changed: 51 additions & 0 deletions

File tree

NMAPScanner/AIBackendManager.swift

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ class AIBackendManager: ObservableObject {
107107

108108
// OpenWebUI-specific
109109
@Published var openWebUIServerURL: String = "http://localhost:8080"
110+
@Published var availableOllamaModels: [String] = []
111+
@Published var selectedOllamaModel: String = ""
112+
@Published var availableMLXModels: [String] = []
113+
@Published var selectedMLXModel: String = ""
110114

111115
// MARK: - Private Properties
112116

@@ -1097,5 +1101,52 @@ struct AIBackendSettingsView_Previews: PreviewProvider {
10971101
static var previews: some View {
10981102
AIBackendSettingsView()
10991103
}
1104+
1105+
// MARK: - Dynamic Model Discovery
1106+
1107+
/// Fetch available models from local Ollama instance
1108+
func fetchAvailableModels() async {
1109+
guard let url = URL(string: "http://127.0.0.1:11434/api/tags") else { return }
1110+
do {
1111+
let (data, _) = try await URLSession.shared.data(from: url)
1112+
struct OllamaModelsResponse: Codable {
1113+
struct Model: Codable {
1114+
let name: String
1115+
let size: Int64?
1116+
}
1117+
let models: [Model]
1118+
}
1119+
let response = try JSONDecoder().decode(OllamaModelsResponse.self, from: data)
1120+
await MainActor.run {
1121+
self.availableOllamaModels = response.models.map { $0.name }
1122+
if self.selectedOllamaModel.isEmpty, let first = self.availableOllamaModels.first {
1123+
self.selectedOllamaModel = first
1124+
}
1125+
}
1126+
} catch {
1127+
NSLog("[AIBackendManager] Failed to fetch Ollama models: \(error)")
1128+
}
1129+
}
1130+
1131+
/// Fetch available models from local MLX server
1132+
func fetchMLXModels() async {
1133+
guard let url = URL(string: "http://127.0.0.1:5050/v1/models") else { return }
1134+
do {
1135+
let (data, _) = try await URLSession.shared.data(from: url)
1136+
struct MLXModelsResponse: Codable {
1137+
struct Model: Codable { let id: String }
1138+
let data: [Model]
1139+
}
1140+
let response = try JSONDecoder().decode(MLXModelsResponse.self, from: data)
1141+
await MainActor.run {
1142+
self.availableMLXModels = response.data.map { $0.id }
1143+
if self.selectedMLXModel.isEmpty, let first = self.availableMLXModels.first {
1144+
self.selectedMLXModel = first
1145+
}
1146+
}
1147+
} catch {
1148+
NSLog("[AIBackendManager] Failed to fetch MLX models: \(error)")
1149+
}
1150+
}
11001151
}
11011152
#endif

0 commit comments

Comments
 (0)