chore: atualização geral

This commit is contained in:
João Henrique
2026-08-19 16:35:29 -04:00
parent 8fca456ceb
commit e7748c2c58
66 changed files with 13037 additions and 4237 deletions
+52 -4
View File
@@ -105,25 +105,64 @@ struct ModelDownloadView: View {
.font(.caption)
.foregroundStyle(catalog?.diarization == true ? Color.secondary : Color.orange)
}
SecureField("Token HuggingFace (diarização)", text: $hfTokenText)
.textFieldStyle(.roundedBorder)
.help("Token com acesso aos modelos gated pyannote (segmentation + speaker-diarization)")
tokenField
HStack {
TextField("Nº de participantes (vazio = automático)", text: $numSpeakersText)
.textFieldStyle(.roundedBorder)
Button("Salvar") { saveDiarization() }
.disabled(isLoading)
}
setupSteps
}
} header: {
Text("Diarização (participantes)")
} footer: {
Text("Opcional. Sem token, cada fala é atribuída a um único participante padrão.")
Text("Opcional. Sem token, cada fala é atribuída a um único participante padrão. O token só é usado para baixar o modelo uma vez — depois disso a análise roda offline, nesta máquina.")
.font(.caption)
.foregroundStyle(.secondary)
}
}
/// Campo do token. Quando já existe um salvo, mostra o estado em vez de um
/// campo vazio ambíguo — e oferece a remoção, já que salvar vazio não apaga.
@ViewBuilder
private var tokenField: some View {
if catalog?.hfTokenSet == true {
HStack {
Label("Token salvo nesta máquina", systemImage: "key.fill")
.font(.caption)
.foregroundStyle(.secondary)
Spacer()
Button("Remover") { removeToken() }
.buttonStyle(.link)
.disabled(isLoading)
}
}
SecureField(
catalog?.hfTokenSet == true ? "Substituir token…" : "Token HuggingFace (diarização)",
text: $hfTokenText
)
.textFieldStyle(.roundedBorder)
.help("Token com acesso aos modelos gated pyannote (segmentation + speaker-diarization)")
}
/// O token sozinho não basta: os dois modelos pyannote são "gated" e exigem
/// aceitar os termos na conta antes do download funcionar.
private var setupSteps: some View {
VStack(alignment: .leading, spacing: 4) {
Text("Para ativar, uma vez só:")
.font(.caption).bold()
.foregroundStyle(.secondary)
Link("1. Aceitar os termos do modelo de segmentação",
destination: URL(string: "https://huggingface.co/pyannote/segmentation-3.0")!)
Link("2. Aceitar os termos do modelo de diarização",
destination: URL(string: "https://huggingface.co/pyannote/speaker-diarization-3.1")!)
Link("3. Criar um token de acesso e colar acima",
destination: URL(string: "https://huggingface.co/settings/tokens")!)
}
.font(.caption)
}
private func saveDiarization() {
var args: [String: Any] = ["num_speakers": numSpeakersText]
if !hfTokenText.isEmpty {
@@ -138,6 +177,15 @@ struct ModelDownloadView: View {
}
}
private func removeToken() {
PythonBridge.call(command: "set_diarization", arguments: ["token": ""]) { _, _ in
DispatchQueue.main.async {
hfTokenText = ""
Task { await refresh() }
}
}
}
// MARK: - Storage
private var storageSection: some View {