104 lines
4.0 KiB
Swift
104 lines
4.0 KiB
Swift
import SwiftUI
|
|
import SwiftData
|
|
|
|
struct ModelManagementView: View {
|
|
@ObservedObject var whisperState: WhisperState
|
|
@State private var modelToDelete: WhisperModel?
|
|
@StateObject private var aiService = AIService()
|
|
@EnvironmentObject private var enhancementService: AIEnhancementService
|
|
@Environment(\.modelContext) private var modelContext
|
|
@StateObject private var whisperPrompt = WhisperPrompt()
|
|
|
|
var body: some View {
|
|
ScrollView {
|
|
VStack(alignment: .leading, spacing: 24) {
|
|
defaultModelSection
|
|
languageSelectionSection
|
|
availableModelsSection
|
|
}
|
|
.padding(40)
|
|
}
|
|
.frame(minWidth: 600, minHeight: 500)
|
|
.background(Color(NSColor.controlBackgroundColor))
|
|
.alert(item: $modelToDelete) { model in
|
|
Alert(
|
|
title: Text("Delete Model"),
|
|
message: Text("Are you sure you want to delete the model '\(model.name)'?"),
|
|
primaryButton: .destructive(Text("Delete")) {
|
|
Task {
|
|
await whisperState.deleteModel(model)
|
|
}
|
|
},
|
|
secondaryButton: .cancel()
|
|
)
|
|
}
|
|
}
|
|
|
|
private var defaultModelSection: some View {
|
|
VStack(alignment: .leading, spacing: 8) {
|
|
Text("Default Model")
|
|
.font(.headline)
|
|
.foregroundColor(.secondary)
|
|
Text(whisperState.currentModel.flatMap { model in
|
|
PredefinedModels.models.first { $0.name == model.name }?.displayName
|
|
} ?? "No model selected")
|
|
.font(.title2)
|
|
.fontWeight(.bold)
|
|
}
|
|
.padding()
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
.background(Color(.windowBackgroundColor).opacity(0.4))
|
|
.cornerRadius(10)
|
|
}
|
|
|
|
private var languageSelectionSection: some View {
|
|
LanguageSelectionView(whisperState: whisperState, displayMode: .full, whisperPrompt: whisperPrompt)
|
|
}
|
|
|
|
private var availableModelsSection: some View {
|
|
VStack(alignment: .leading, spacing: 16) {
|
|
HStack {
|
|
Text("Available Models")
|
|
.font(.title3)
|
|
.fontWeight(.semibold)
|
|
|
|
Text("(\(whisperState.predefinedModels.count))")
|
|
.foregroundColor(.secondary)
|
|
.font(.subheadline)
|
|
|
|
Spacer()
|
|
}
|
|
|
|
VStack(spacing: 12) {
|
|
ForEach(whisperState.predefinedModels) { model in
|
|
ModelCardRowView(
|
|
model: model,
|
|
isDownloaded: whisperState.availableModels.contains { $0.name == model.name },
|
|
isCurrent: whisperState.currentModel?.name == model.name,
|
|
downloadProgress: whisperState.downloadProgress,
|
|
modelURL: whisperState.availableModels.first { $0.name == model.name }?.url,
|
|
deleteAction: {
|
|
if let downloadedModel = whisperState.availableModels.first(where: { $0.name == model.name }) {
|
|
modelToDelete = downloadedModel
|
|
}
|
|
},
|
|
setDefaultAction: {
|
|
if let downloadedModel = whisperState.availableModels.first(where: { $0.name == model.name }) {
|
|
Task {
|
|
await whisperState.setDefaultModel(downloadedModel)
|
|
}
|
|
}
|
|
},
|
|
downloadAction: {
|
|
Task {
|
|
await whisperState.downloadModel(model)
|
|
}
|
|
}
|
|
)
|
|
}
|
|
}
|
|
}
|
|
.padding()
|
|
}
|
|
}
|