using System; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Windows.Input; using Avalonia.Media.Imaging; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using finder2e_foundry_converter.Models; using finder2e_foundry_converter.Services; namespace finder2e_foundry_converter.ViewModels { public partial class MainWindowViewModel : ViewModelBase { private readonly LlmService _llmService = new LlmService(); [ObservableProperty] private string _lmStudioAddress = "http://localhost:1234"; [ObservableProperty] private bool _isAddressVisible = false; [ObservableProperty] private string _selectedProvider = "LM Studio"; public ObservableCollection Providers { get; } = new() { "LM Studio" }; [ObservableProperty] private string? _selectedModel; public ObservableCollection Models { get; } = new(); [ObservableProperty] private string _description = string.Empty; public ObservableCollection ImageItems { get; } = new(); [ObservableProperty] private string _statusMessage = string.Empty; [ObservableProperty] private bool _isErrorVisible = false; [ObservableProperty] private string _errorText = string.Empty; public MainWindowViewModel() { // Load saved preferences would go here if we had a settings service _ = StartModelRefreshLoop(); } [RelayCommand] private void ToggleAddress() { IsAddressVisible = !IsAddressVisible; } [RelayCommand] private async Task RefreshModels() { if (SelectedProvider != "LM Studio") { IsErrorVisible = false; return; } var models = await _llmService.GetModelsAsync(LmStudioAddress); Models.Clear(); foreach (var m in models) { Models.Add(m); } if (models.Count > 0 && !models[0].StartsWith("Error")) { IsErrorVisible = false; if (SelectedModel == null || !Models.Contains(SelectedModel)) { SelectedModel = Models.FirstOrDefault(); } } else { ErrorText = models.FirstOrDefault() ?? "Error connecting to LM Studio"; IsErrorVisible = true; IsAddressVisible = true; // Auto-show on failure } } [RelayCommand] private async Task Generate() { if (string.IsNullOrEmpty(SelectedModel)) { StatusMessage = "Please select a model first."; return; } StatusMessage = "Generating..."; var result = await _llmService.GenerateResponseAsync(LmStudioAddress, SelectedModel, Description, ImageItems.Select(i => i.Path).ToList()); StatusMessage = result; } [RelayCommand] private void AddImagePath(string path) { if (!string.IsNullOrWhiteSpace(path) && File.Exists(path)) { if (ImageItems.Any(i => i.Path == path)) return; try { // Load thumbnail using var stream = File.OpenRead(path); var bitmap = new Bitmap(stream); // We could resize it here for efficiency if needed, but for now let's just use it ImageItems.Add(new ImageItem { Path = path, Thumbnail = bitmap }); } catch (Exception ex) { StatusMessage = $"Error loading image: {ex.Message}"; } } } [RelayCommand] private void RemoveImage(ImageItem item) { ImageItems.Remove(item); } private async Task StartModelRefreshLoop() { while (true) { await RefreshModels(); await Task.Delay(IsErrorVisible ? 3000 : 10000); } } } }