@page "/models" @attribute [Authorize] @inject IOllamaService OllamaService @inject NavigationManager Navigation @inject ILocalizationService Loc @Loc["page.title.models"]

@Loc["models.heading"]

@if (isLoading) {

@Loc["models.status.loading"]

} else if (!string.IsNullOrEmpty(errorMessage)) {
@errorMessage
} else {
@foreach (var model in localModels) {
@model.Name
@Loc["models.label.size"] @FormatSize(model.Size) | @Loc["models.label.modified"] @model.ModifiedAt?.ToString("g")
}
}

@Loc["models.pull.heading"]

@if (isPulling) {
@pullStatus (@pullPercentDisplay)
}
@if (pullResult != null) {
@pullResult
} @if (_confirmDeleteModel != null) { } @code { private List localModels = new(); private bool isLoading; private string? errorMessage; private string modelToPull = string.Empty; private bool isPulling; private bool _pullDisabled => isPulling || string.IsNullOrWhiteSpace(modelToPull); private double pullProgress; private string pullStatus = string.Empty; private string? pullResult; private string pullPercentDisplay => $"{pullProgress:F0}%"; private string? _confirmDeleteModel; protected override async Task OnInitializedAsync() { await RefreshModels(); } private async Task RefreshModels() { isLoading = true; errorMessage = null; try { var models = await OllamaService.GetLocalModelsAsync(); localModels = models.ToList(); } catch (Exception ex) { errorMessage = $"{Loc["models.error.loading"]} {ex.Message}"; localModels = new(); } finally { isLoading = false; } } private async Task PullModel() { if (string.IsNullOrWhiteSpace(modelToPull)) return; isPulling = true; pullProgress = 0; pullStatus = Loc["models.pull.status.starting"]; pullResult = null; try { var progress = new Progress(status => { pullStatus = status; var m = System.Text.RegularExpressions.Regex.Match(status, @"\((\d+)%\)"); if (m.Success && double.TryParse(m.Groups[1].Value, out var pct)) pullProgress = pct; InvokeAsync(StateHasChanged); }); await OllamaService.PullModelAsync(modelToPull, progress); pullResult = $"{Loc["models.pull.status.model"]} '{modelToPull}' {Loc["models.pull.status.success"]}"; modelToPull = string.Empty; await RefreshModels(); } catch (Exception ex) { pullResult = $"{Loc["common.error"]} {ex.Message}"; } finally { isPulling = false; } } private void DeleteModel(string name) { _confirmDeleteModel = name; } private void CancelDelete() { _confirmDeleteModel = null; } private async Task ConfirmDelete() { if (_confirmDeleteModel == null) return; try { var deleted = await OllamaService.DeleteModelAsync(_confirmDeleteModel); if (deleted) await RefreshModels(); else errorMessage = $"Fehler beim Löschen von '{_confirmDeleteModel}'"; } catch (Exception ex) { errorMessage = $"Fehler: {ex.Message}"; } finally { _confirmDeleteModel = null; } } private static string FormatSize(long? bytes) { if (!bytes.HasValue) return "---"; if (bytes < 1024 * 1024) return $"{bytes / 1024.0:F1} KB"; if (bytes < 1024 * 1024 * 1024) return $"{bytes / (1024.0 * 1024):F1} MB"; return $"{bytes / (1024.0 * 1024 * 1024):F1} GB"; } }