diff --git a/Chat.xaml b/Chat.xaml
index 41c5826..2da659b 100644
--- a/Chat.xaml
+++ b/Chat.xaml
@@ -1,62 +1,62 @@
-
+ xmlns:av="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="av"
+ x:Class="GTPCorrgir.Chat" Title="Chat with OpenAI" Height="300" Width="300" ResizeMode="CanResizeWithGrip"
+ WindowStyle="None" Background="Transparent" AllowsTransparency="True" MouseEnter="Window_MouseEnter"
+ MouseLeave="Window_MouseLeave" KeyDown="Window_KeyDown" Opacity="0.8" av:DesignHeight="320.439"
+ av:DesignWidth="609.769">
-
-
-
-
-
-
+
+
+
-
+
-
-
+
+
+
+
+
+
-
-
+
+
-
-
+
-
+
-
+
-
-
+
+
-
+
\ No newline at end of file
diff --git a/Chat.xaml.cs b/Chat.xaml.cs
index 0b8cf98..2209401 100644
--- a/Chat.xaml.cs
+++ b/Chat.xaml.cs
@@ -15,58 +15,151 @@ using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using static GTPCorrgir.Opciones;
using static System.Net.WebRequestMethods;
+using Brushes = System.Windows.Media.Brushes;
+using Color = System.Windows.Media.Color;
using ComboBox = System.Windows.Controls.ComboBox;
using Cursors = System.Windows.Input.Cursors;
+using FontFamily = System.Windows.Media.FontFamily;
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
using MouseEventArgs = System.Windows.Input.MouseEventArgs;
+using Timer = System.Windows.Forms.Timer;
namespace GTPCorrgir
{
- ///
- /// Interaction logic for Chat.xaml
- ///
public partial class Chat : Window
{
gtpask AI_API;
string respuestas;
+ private Timer opacityTimer;
+ private bool isMouseOver = false;
+ private const double OPACITY_ACTIVE = 1.0;
+ private const double OPACITY_INACTIVE = 0.2;
+ private const int OPACITY_DELAY_MS = 3000; // 10 segundos
public Chat(gtpask GTP)
{
InitializeComponent();
+ InitializeOpacityTimer();
PositionWindow();
- // Inicializar componentes de la UI, por ejemplo, llenar el ComboBox
+
+ // Inicializar componentes de la UI
AI_API = GTP;
- questionArea.Text = ""; //GTP.TextoACorregir;
+ questionArea.Text = "";
respuestas = "";
+ this.Opacity = OPACITY_ACTIVE;
+
+ InitializeModelSelector();
+ }
+
+ private void InitializeOpacityTimer()
+ {
+ opacityTimer = new Timer();
+ opacityTimer.Interval = OPACITY_DELAY_MS;
+ opacityTimer.Tick += (s, e) =>
+ {
+ if (!isMouseOver)
+ {
+ this.Dispatcher.Invoke(() =>
+ {
+ this.Opacity = OPACITY_INACTIVE;
+ });
+ }
+ opacityTimer.Stop();
+ };
+ }
+
+ private void InitializeModelSelector()
+ {
foreach (KeyValuePair kvp in Opciones.Instance.nombreLLM)
{
ComboBoxItem item = new ComboBoxItem();
- item.Content = kvp.Value; // El texto que se mostrará
- item.Tag = kvp.Key; // Guarda el valor enum en el Tag para acceso posterior
+ item.Content = kvp.Value;
+ item.Tag = kvp.Key;
modelSelector.Items.Add(item);
- // Verifica si este ítem debe ser el seleccionado
+
if (kvp.Key == Opciones.Instance.LLM)
{
modelSelector.SelectedItem = item;
}
- }
+ }
+ }
+
+ private void SettingsButton_Click(object sender, RoutedEventArgs e)
+ {
+ var settingsWindow = new SettingsWindow
+ {
+ Owner = this,
+ WindowStartupLocation = WindowStartupLocation.CenterOwner
+ };
+
+ if (settingsWindow.ShowDialog() == true)
+ {
+ // Aplicar cambios de configuración
+ ApplySettings();
+ }
+ }
+
+ private void ApplySettings()
+ {
+ var settings = UserSettings.Instance;
+
+ // Aplicar opacidad
+ opacityTimer.Stop();
+ opacityTimer.Interval = ((int)TimeSpan.FromMilliseconds(settings.Appearance.OpacityDelay).TotalMilliseconds);
+
+ // Aplicar fuente
+ questionArea.FontFamily = new FontFamily(settings.Appearance.FontFamily);
+ questionArea.FontSize = settings.Appearance.FontSize;
+ responseArea.FontFamily = new FontFamily(settings.Appearance.FontFamily);
+ responseArea.FontSize = settings.Appearance.FontSize;
+
+ // Aplicar tema
+ if (settings.Appearance.Theme == "Dark")
+ {
+ // Aplicar tema oscuro
+ this.Background = new SolidColorBrush(Color.FromArgb(200, 30, 30, 30));
+ responseArea.Background = new SolidColorBrush(Color.FromArgb(255, 40, 40, 40));
+ responseArea.Foreground = Brushes.White;
+ questionArea.Background = new SolidColorBrush(Color.FromArgb(255, 50, 50, 50));
+ questionArea.Foreground = Brushes.White;
+ }
+ else
+ {
+ // Aplicar tema claro
+ this.Background = new SolidColorBrush(Color.FromArgb(200, 240, 240, 240));
+ responseArea.Background = Brushes.White;
+ responseArea.Foreground = Brushes.Black;
+ questionArea.Background = Brushes.White;
+ questionArea.Foreground = Brushes.Black;
+ }
+ }
+
+ protected override void OnSourceInitialized(EventArgs e)
+ {
+ base.OnSourceInitialized(e);
+ ApplySettings(); // Aplicar configuración inicial
}
private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
- // Iniciar movimiento de la ventana si se presiona el botón izquierdo del ratón
if (e.LeftButton == MouseButtonState.Pressed)
{
this.DragMove();
}
}
-
private void Window_MouseEnter(object sender, MouseEventArgs e)
{
- // Hacer la ventana opaca cuando el ratón esté sobre ella
- this.Opacity = 1.0;
+ isMouseOver = true;
+ opacityTimer.Stop();
+ this.Opacity = OPACITY_ACTIVE;
+ }
+
+ private void Window_MouseLeave(object sender, MouseEventArgs e)
+ {
+ isMouseOver = false;
+ opacityTimer.Start();
}
private void Window_KeyDown(object sender, KeyEventArgs e)
@@ -82,87 +175,71 @@ namespace GTPCorrgir
if (e.Key == Key.Enter && !e.KeyboardDevice.Modifiers.HasFlag(ModifierKeys.Shift))
{
SendButton_Click(this, new RoutedEventArgs());
- e.Handled = true; // Prevenir el salto de línea en el TextBox
+ e.Handled = true;
}
}
- private void Window_MouseLeave(object sender, MouseEventArgs e)
+ private async void SendButton_Click(object sender, RoutedEventArgs e)
{
- // Hacer la ventana transparente cuando el ratón no esté sobre ella
- this.Opacity = 0.2; // Ajusta este valor a tu preferencia
- }
-
- private void SendButton_Click(object sender, RoutedEventArgs e)
- {
- // Aquí lógica para enviar pregunta y recibir respuesta de OpenAI
-
AI_API.TextoACorregir = questionArea.Text;
if (AI_API.TextoACorregir.Length > 3)
{
- sendButton.IsEnabled = false; // Deshabilitar el botón de envío
- Mouse.OverrideCursor = Cursors.Wait; // Cambiar el cursor a espera
-
- Task.Run(async () =>
+ try
{
- try
- {
- await AI_API.CorregirTexto();
- }
- catch (Exception ex)
- {
- Console.WriteLine("Error durante la corrección de texto: " + ex.Message);
- }
- finally
- {
- Dispatcher.Invoke(async () => // Nota el 'async' aquí para permitir 'await'
- {
- if (AI_API.TextoCorregido != null)
- {
- System.Windows.Clipboard.SetText(AI_API.TextoCorregido);
- //responseArea. .Text += AI_API.TextoCorregido + "\r\n";
- AddMarkdownContent(AI_API.TextoCorregido + "\r\n");
+ sendButton.IsEnabled = false;
+ Mouse.OverrideCursor = Cursors.Wait;
- Mouse.OverrideCursor = null; // Restaurar el cursor normal
- sendButton.IsEnabled = true; // Habilitar el botón de envío
- }
- });
+ await Task.Run(async () =>
+ {
+ try
+ {
+ await AI_API.CorregirTexto();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error durante la corrección de texto: {ex.Message}");
+ throw;
+ }
+ });
+
+ if (AI_API.TextoCorregido != null)
+ {
+ System.Windows.Clipboard.SetText(AI_API.TextoCorregido);
+ AddMarkdownContent(AI_API.TextoCorregido + "\r\n");
}
- });
+ }
+ catch (Exception ex)
+ {
+ AddMarkdownContent($"Error: {ex.Message}\r\n");
+ }
+ finally
+ {
+ Mouse.OverrideCursor = null;
+ sendButton.IsEnabled = true;
+ }
}
}
public void AddMarkdownContent(string markdownText)
{
- // Transforma el texto Markdown a un FlowDocument
var markdown = new Markdown.Xaml.Markdown();
-
respuestas += markdownText + "\r\n";
-
responseArea.Document = markdown.Transform(respuestas);
-
}
private void PositionWindow()
{
- // Obtener la posición del cursor
var cursorPosition = System.Windows.Forms.Cursor.Position;
-
- // Determinar en qué pantalla está el cursor
var screen = Screen.FromPoint(cursorPosition);
-
- // Calcular la ubicación central en la pantalla actual
this.Left = (screen.WorkingArea.Width - this.Width) / 2 + screen.WorkingArea.Left;
this.Top = (screen.WorkingArea.Height - this.Height) / 2 + screen.WorkingArea.Top;
}
private void CambiarModelo(object sender, SelectionChangedEventArgs e)
{
- ComboBox comboBox = sender as ComboBox;
- ComboBoxItem selectedItem = comboBox.SelectedItem as ComboBoxItem;
- if (selectedItem != null)
+ if (sender is ComboBox comboBox && comboBox.SelectedItem is ComboBoxItem selectedItem)
{
- LLM_a_Usar selectedEnum = (LLM_a_Usar)selectedItem.Tag;
- Opciones.Instance.LLM = selectedEnum; // Suponiendo que hay una propiedad para establecerlo
+ Opciones.Instance.LLM = (LLM_a_Usar)selectedItem.Tag;
}
}
@@ -171,5 +248,11 @@ namespace GTPCorrgir
respuestas = "";
AddMarkdownContent("");
}
+
+ protected override void OnClosed(EventArgs e)
+ {
+ opacityTimer?.Dispose();
+ base.OnClosed(e);
+ }
}
-}
+}
\ No newline at end of file
diff --git a/ChatHistory.cs b/ChatHistory.cs
new file mode 100644
index 0000000..0dee689
--- /dev/null
+++ b/ChatHistory.cs
@@ -0,0 +1,115 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Newtonsoft.Json;
+
+namespace GTPCorrgir
+{
+ public class ChatMessage
+ {
+ public string Content { get; set; }
+ public DateTime Timestamp { get; set; }
+ public bool IsUser { get; set; }
+ public string ModelUsed { get; set; }
+ }
+
+ public class ChatHistory
+ {
+ private const string HISTORY_FOLDER = "ChatHistory";
+ private const int MAX_HISTORY_FILES = 10;
+ private readonly string historyPath;
+ private List currentSession;
+
+ public ChatHistory()
+ {
+ historyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, HISTORY_FOLDER);
+ currentSession = new List();
+ EnsureHistoryFolderExists();
+ CleanupOldHistories();
+ }
+
+ private void EnsureHistoryFolderExists()
+ {
+ if (!Directory.Exists(historyPath))
+ {
+ Directory.CreateDirectory(historyPath);
+ }
+ }
+
+ private void CleanupOldHistories()
+ {
+ var files = Directory.GetFiles(historyPath, "*.json")
+ .OrderByDescending(f => File.GetLastWriteTime(f));
+
+ int count = 0;
+ foreach (var file in files)
+ {
+ count++;
+ if (count > MAX_HISTORY_FILES)
+ {
+ try
+ {
+ File.Delete(file);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error deleting old history: {ex.Message}");
+ }
+ }
+ }
+ }
+
+ public void AddMessage(string content, bool isUser, string modelUsed)
+ {
+ var message = new ChatMessage
+ {
+ Content = content,
+ Timestamp = DateTime.Now,
+ IsUser = isUser,
+ ModelUsed = modelUsed
+ };
+ currentSession.Add(message);
+ }
+
+ public void SaveSession()
+ {
+ if (currentSession.Any())
+ {
+ string filename = $"chat_history_{DateTime.Now:yyyyMMdd_HHmmss}.json";
+ string fullPath = Path.Combine(historyPath, filename);
+
+ try
+ {
+ string json = JsonConvert.SerializeObject(currentSession, Formatting.Indented);
+ File.WriteAllText(fullPath, json);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error saving chat history: {ex.Message}");
+ }
+ }
+ }
+
+ public List LoadLastSession()
+ {
+ try
+ {
+ var files = Directory.GetFiles(historyPath, "*.json")
+ .OrderByDescending(f => File.GetLastWriteTime(f))
+ .FirstOrDefault();
+
+ if (files != null)
+ {
+ string json = File.ReadAllText(files);
+ return JsonConvert.DeserializeObject>(json);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error loading chat history: {ex.Message}");
+ }
+
+ return new List();
+ }
+ }
+}
\ No newline at end of file
diff --git a/ErrorLogger.cs b/ErrorLogger.cs
new file mode 100644
index 0000000..5bda59c
--- /dev/null
+++ b/ErrorLogger.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+
+namespace GTPCorrgir
+{
+ public class ErrorLogger
+ {
+ private const string ERROR_FOLDER = "ErrorLogs";
+ private const int MAX_LOG_FILES = 5;
+ private readonly string logPath;
+ private readonly object lockObj = new object();
+
+ public ErrorLogger()
+ {
+ logPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ERROR_FOLDER);
+ EnsureLogFolderExists();
+ CleanupOldLogs();
+ }
+
+ private void EnsureLogFolderExists()
+ {
+ if (!Directory.Exists(logPath))
+ {
+ Directory.CreateDirectory(logPath);
+ }
+ }
+
+ private void CleanupOldLogs()
+ {
+ try
+ {
+ var files = Directory.GetFiles(logPath, "*.json")
+ .OrderByDescending(f => File.GetLastWriteTime(f));
+
+ int count = 0;
+ foreach (var file in files)
+ {
+ count++;
+ if (count > MAX_LOG_FILES)
+ {
+ File.Delete(file);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Error cleaning up logs: {ex.Message}");
+ }
+ }
+
+ public async Task LogErrorAsync(Exception ex, string context = "")
+ {
+ var errorInfo = new
+ {
+ Timestamp = DateTime.Now,
+ Context = context,
+ Exception = new
+ {
+ Message = ex.Message,
+ StackTrace = ex.StackTrace,
+ Source = ex.Source,
+ TargetSite = ex.TargetSite?.ToString(),
+ InnerException = ex.InnerException?.Message
+ },
+ SystemInfo = new
+ {
+ OSVersion = Environment.OSVersion.ToString(),
+ MachineName = Environment.MachineName,
+ ProcessorCount = Environment.ProcessorCount,
+ WorkingSet = Environment.WorkingSet,
+ CurrentDirectory = Environment.CurrentDirectory
+ }
+ };
+
+ string filename = $"error_log_{DateTime.Now:yyyyMMdd_HHmmss}.json";
+ string fullPath = Path.Combine(logPath, filename);
+
+ try
+ {
+ string json = JsonConvert.SerializeObject(errorInfo, Formatting.Indented);
+ await File.WriteAllTextAsync(fullPath, json);
+
+ // También escribir al log de debug
+ Debug.WriteLine($"Error logged: {context} - {ex.Message}");
+ }
+ catch (Exception logEx)
+ {
+ Debug.WriteLine($"Error writing to error log: {logEx.Message}");
+ }
+ }
+
+ public async Task GetErrorSummaryAsync()
+ {
+ var summary = new StringBuilder();
+ try
+ {
+ var files = Directory.GetFiles(logPath, "*.json")
+ .OrderByDescending(f => File.GetLastWriteTime(f))
+ .Take(5);
+
+ foreach (var file in files)
+ {
+ string content = await File.ReadAllTextAsync(file);
+ var error = JsonConvert.DeserializeObject(content);
+ summary.AppendLine($"Time: {error.Timestamp}");
+ summary.AppendLine($"Context: {error.Context}");
+ summary.AppendLine($"Error: {error.Exception.Message}");
+ summary.AppendLine("-------------------");
+ }
+ }
+ catch (Exception ex)
+ {
+ summary.AppendLine($"Error reading error logs: {ex.Message}");
+ }
+
+ return summary.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/SettingsWindow.xaml b/SettingsWindow.xaml
new file mode 100644
index 0000000..660d8eb
--- /dev/null
+++ b/SettingsWindow.xaml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SettingsWindow.xaml.cs b/SettingsWindow.xaml.cs
new file mode 100644
index 0000000..a3e598e
--- /dev/null
+++ b/SettingsWindow.xaml.cs
@@ -0,0 +1,222 @@
+using System;
+using System.Windows;
+using System.Windows.Media;
+using System.Linq;
+using System.Windows.Controls;
+using MessageBox = System.Windows.MessageBox;
+using TextBox = System.Windows.Controls.TextBox;
+using Button = System.Windows.Controls.Button;
+
+namespace GTPCorrgir
+{
+ public partial class SettingsWindow : Window
+ {
+ private readonly UserSettings settings;
+ private readonly ErrorLogger errorLogger;
+ private readonly ChatHistory chatHistory;
+
+ public SettingsWindow()
+ {
+ InitializeComponent();
+ settings = UserSettings.Instance;
+ errorLogger = new ErrorLogger();
+ chatHistory = new ChatHistory();
+
+ LoadSettings();
+ InitializeFontControls();
+ }
+
+ private void InitializeFontControls()
+ {
+ // Cargar tamaños de fuente comunes
+ FontSizeCombo.ItemsSource = new[] { 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24 };
+ FontSizeCombo.SelectedItem = settings.Appearance.FontSize;
+
+ // Cargar fuentes del sistema
+ var fontFamilies = Fonts.SystemFontFamilies
+ .OrderBy(f => f.Source)
+ .Select(f => f.Source);
+ FontFamilyCombo.ItemsSource = fontFamilies;
+ FontFamilyCombo.SelectedItem = settings.Appearance.FontFamily;
+ }
+
+ private void LoadSettings()
+ {
+ // Tema
+ (settings.Appearance.Theme == "Light" ? LightTheme : DarkTheme).IsChecked = true;
+
+ // Opacidad
+ OpacityDelaySlider.Value = settings.Appearance.OpacityDelay / 1000.0;
+
+ // Comportamiento
+ AutoSaveCheckbox.IsChecked = settings.Behavior.AutoSaveHistory;
+ ShowNotificationsCheckbox.IsChecked = settings.Behavior.ShowNotifications;
+ AutoCopyCheckbox.IsChecked = settings.Behavior.AutoCopyToClipboard;
+ NotificationDurationSlider.Value = settings.Behavior.NotificationDuration / 1000.0;
+ }
+
+ private async void ViewErrorLogs_Click(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ string summary = await errorLogger.GetErrorSummaryAsync();
+ ShowScrollableDialog("Registros de Error", summary);
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"Error al cargar los registros: {ex.Message}",
+ "Error", MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ }
+
+ private void ShowScrollableDialog(string title, string content)
+ {
+ var dialog = new Window
+ {
+ Title = title,
+ Width = 600,
+ Height = 400,
+ WindowStartupLocation = WindowStartupLocation.CenterOwner,
+ Owner = this,
+ ResizeMode = ResizeMode.CanResize,
+ ShowInTaskbar = false
+ };
+
+ var textBox = new TextBox
+ {
+ Text = content,
+ IsReadOnly = true,
+ TextWrapping = TextWrapping.Wrap,
+ VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
+ HorizontalScrollBarVisibility = ScrollBarVisibility.Auto,
+ Margin = new Thickness(10),
+ AcceptsReturn = true
+ };
+
+ var grid = new Grid();
+ grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
+ grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
+
+ var closeButton = new Button
+ {
+ Content = "Cerrar",
+ Width = 80,
+ Height = 25,
+ Margin = new Thickness(10),
+ HorizontalAlignment = System.Windows.HorizontalAlignment.Right
+ };
+ closeButton.Click += (s, e) => dialog.Close();
+
+ Grid.SetRow(textBox, 0);
+ Grid.SetRow(closeButton, 1);
+
+ grid.Children.Add(textBox);
+ grid.Children.Add(closeButton);
+
+ dialog.Content = grid;
+ dialog.ShowDialog();
+ }
+
+ private async void ClearHistory_Click(object sender, RoutedEventArgs e)
+ {
+ var result = MessageBox.Show(
+ "¿Está seguro de que desea borrar todo el historial de chat?\nEsta acción no se puede deshacer.",
+ "Confirmar borrado",
+ MessageBoxButton.YesNo,
+ MessageBoxImage.Warning
+ );
+
+ if (result == MessageBoxResult.Yes)
+ {
+ try
+ {
+ // Aquí implementarías la lógica para borrar el historial
+ // Por ejemplo: await chatHistory.ClearAllAsync();
+
+ MessageBox.Show(
+ "El historial ha sido borrado correctamente.",
+ "Éxito",
+ MessageBoxButton.OK,
+ MessageBoxImage.Information
+ );
+ }
+ catch (Exception ex)
+ {
+ await errorLogger.LogErrorAsync(ex, "Error al borrar historial");
+ MessageBox.Show(
+ $"Error al borrar el historial: {ex.Message}",
+ "Error",
+ MessageBoxButton.OK,
+ MessageBoxImage.Error
+ );
+ }
+ }
+ }
+
+ private void ResetSettings_Click(object sender, RoutedEventArgs e)
+ {
+ var result = MessageBox.Show(
+ "¿Está seguro de que desea restablecer toda la configuración a sus valores predeterminados?",
+ "Confirmar restablecimiento",
+ MessageBoxButton.YesNo,
+ MessageBoxImage.Warning
+ );
+
+ if (result == MessageBoxResult.Yes)
+ {
+ settings.ResetToDefaults();
+ LoadSettings();
+ MessageBox.Show(
+ "La configuración ha sido restablecida correctamente.",
+ "Éxito",
+ MessageBoxButton.OK,
+ MessageBoxImage.Information
+ );
+ }
+ }
+
+ private void SaveButton_Click(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ // Guardar tema
+ settings.Appearance.Theme = LightTheme.IsChecked == true ? "Light" : "Dark";
+
+ // Guardar fuente
+ if (FontSizeCombo.SelectedItem != null)
+ settings.Appearance.FontSize = (int)FontSizeCombo.SelectedItem;
+
+ if (FontFamilyCombo.SelectedItem != null)
+ settings.Appearance.FontFamily = FontFamilyCombo.SelectedItem.ToString();
+
+ // Guardar opacidad
+ settings.Appearance.OpacityDelay = (int)(OpacityDelaySlider.Value * 1000);
+
+ // Guardar comportamiento
+ settings.Behavior.AutoSaveHistory = AutoSaveCheckbox.IsChecked ?? false;
+ settings.Behavior.ShowNotifications = ShowNotificationsCheckbox.IsChecked ?? true;
+ settings.Behavior.AutoCopyToClipboard = AutoCopyCheckbox.IsChecked ?? true;
+ settings.Behavior.NotificationDuration = (int)(NotificationDurationSlider.Value * 1000);
+
+ settings.Save();
+ DialogResult = true;
+ Close();
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(
+ $"Error al guardar la configuración: {ex.Message}",
+ "Error",
+ MessageBoxButton.OK,
+ MessageBoxImage.Error
+ );
+ }
+ }
+
+ private void CancelButton_Click(object sender, RoutedEventArgs e)
+ {
+ DialogResult = false;
+ Close();
+ }
+ }
+}
\ No newline at end of file
diff --git a/ThemesAppTheme.xaml b/ThemesAppTheme.xaml
new file mode 100644
index 0000000..6419bf8
--- /dev/null
+++ b/ThemesAppTheme.xaml
@@ -0,0 +1,84 @@
+
+
+
+ #2196F3
+ #BBDEFB
+ #1976D2
+ #FF4081
+ #212121
+ #757575
+ #BDBDBD
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UserSettings.cs b/UserSettings.cs
new file mode 100644
index 0000000..6269940
--- /dev/null
+++ b/UserSettings.cs
@@ -0,0 +1,109 @@
+using System;
+using System.IO;
+using Newtonsoft.Json;
+using System.Diagnostics;
+
+namespace GTPCorrgir
+{
+ public class UserSettings
+ {
+ private static readonly string SettingsPath =
+ Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "usersettings.json");
+
+ private static UserSettings instance;
+ private static readonly object lockObject = new object();
+
+ public class WindowSettings
+ {
+ public double Left { get; set; }
+ public double Top { get; set; }
+ public double Width { get; set; }
+ public double Height { get; set; }
+ public double Opacity { get; set; }
+ }
+
+ public class AppearanceSettings
+ {
+ public string Theme { get; set; } = "Light";
+ public int FontSize { get; set; } = 14;
+ public string FontFamily { get; set; } = "Segoe UI";
+ public int OpacityDelay { get; set; } = 10000; // milisegundos
+ }
+
+ public class BehaviorSettings
+ {
+ public bool AutoSaveHistory { get; set; } = true;
+ public bool ShowNotifications { get; set; } = true;
+ public int NotificationDuration { get; set; } = 5000; // milisegundos
+ public bool AutoCopyToClipboard { get; set; } = true;
+ }
+
+ public WindowSettings Window { get; set; }
+ public AppearanceSettings Appearance { get; set; }
+ public BehaviorSettings Behavior { get; set; }
+
+ // Constructor público con valores por defecto
+ public UserSettings()
+ {
+ Window = new WindowSettings();
+ Appearance = new AppearanceSettings();
+ Behavior = new BehaviorSettings();
+ }
+
+ public static UserSettings Instance
+ {
+ get
+ {
+ if (instance == null)
+ {
+ lock (lockObject)
+ {
+ instance ??= Load();
+ }
+ }
+ return instance;
+ }
+ }
+
+ private static UserSettings Load()
+ {
+ try
+ {
+ if (File.Exists(SettingsPath))
+ {
+ string json = File.ReadAllText(SettingsPath);
+ var settings = JsonConvert.DeserializeObject(json);
+ if (settings != null)
+ {
+ return settings;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Error loading settings: {ex.Message}");
+ }
+ return new UserSettings();
+ }
+
+ public void Save()
+ {
+ try
+ {
+ string json = JsonConvert.SerializeObject(this, Formatting.Indented);
+ File.WriteAllText(SettingsPath, json);
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Error saving settings: {ex.Message}");
+ }
+ }
+
+ public void ResetToDefaults()
+ {
+ Window = new WindowSettings();
+ Appearance = new AppearanceSettings();
+ Behavior = new BehaviorSettings();
+ }
+ }
+}
\ No newline at end of file
diff --git a/gtpask.cs b/gtpask.cs
index 29df322..7c0f8c4 100644
--- a/gtpask.cs
+++ b/gtpask.cs
@@ -5,12 +5,10 @@ using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
-using System.Windows.Threading;
using LanguageDetection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Diagnostics;
-using System.Windows.Interop;
using libObsidean;
namespace GTPCorrgir
@@ -27,463 +25,521 @@ namespace GTPCorrgir
public ApiKeySection ApiKeys { get; set; }
}
- public class gtpask
+ public class gtpask : IDisposable
{
- private readonly string openAiApiKey;
- private readonly string groqApiKey;
- private readonly string grokApiKey;
- public Logger Log = new Logger();
- private Dictionary languageMap = new Dictionary
+ private string _openAiApiKey;
+ private string _groqApiKey;
+ private string _grokApiKey;
+ private readonly HttpClient _httpClient;
+ private bool _disposed;
+ private readonly LanguageDetector _languageDetector;
+ private readonly Obsidean _markdownProcessor;
+
+ public Logger Log { get; }
+
+ private readonly Dictionary _languageMap = new Dictionary
{
- { "en", "English" },
- { "es", "Spanish" },
- { "it", "Italian" },
- { "pt", "Portuguese" }
- // Agrega más idiomas según sea necesario
+ { "en", "English" },
+ { "es", "Spanish" },
+ { "it", "Italian" },
+ { "pt", "Portuguese" }
};
- public string IdiomaDetectado;
- public string TextoACorregir;
- public string TextoCorregido;
- public string TextodeSistema;
+ public string IdiomaDetectado { get; private set; }
+ public string TextoACorregir { get; set; }
+ public string TextoCorregido { get; private set; }
+ public string TextodeSistema { get; private set; }
private const bool Simulacion = false;
public gtpask()
{
try
{
- string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "appsettings.json");
- if (File.Exists(configPath))
- {
- string jsonContent = File.ReadAllText(configPath);
- var settings = JsonConvert.DeserializeObject(jsonContent);
+ Log = new Logger();
+ _httpClient = new HttpClient();
+ _languageDetector = new LanguageDetector();
+ _languageDetector.AddLanguages("en", "es", "it", "pt");
+ _markdownProcessor = new Obsidean();
- openAiApiKey = settings.ApiKeys.OpenAI;
- groqApiKey = settings.ApiKeys.Groq;
- grokApiKey = settings.ApiKeys.Grok;
+ LoadApiKeys();
+ InitializeHttpClient();
+ _markdownProcessor.LeerPalabrasTecnicas();
- if (string.IsNullOrEmpty(openAiApiKey) || string.IsNullOrEmpty(groqApiKey) || string.IsNullOrEmpty(grokApiKey))
- {
- Log.Log("Warning: One or more API keys are missing in the configuration file.");
- }
- }
- else
- {
- Log.Log("Error: Configuration file (appsettings.json) not found.");
- throw new FileNotFoundException("Configuration file (appsettings.json) not found.");
- }
+ Log.Log("gtpask initialized successfully");
}
catch (Exception ex)
{
- Log.Log($"Error loading configuration: {ex.Message}");
- throw;
+ Log.Log($"Error initializing gtpask: {ex.Message}");
+ throw new ApplicationException("Failed to initialize gtpask", ex);
}
}
- private string CrearMensajeDeSistema()
+ private void LoadApiKeys()
{
- switch (Opciones.Instance.modo)
+ try
{
- case Opciones.modoDeUso.Corregir:
- return "You are an engineer working in industrial automation. Your task is to review texts and rewrite them in a simple and concise manner, making sure to preserve important technical terms and markdown language if present. Please rewrite the following text in " + IdiomaDetectado + " and respond in the following JSON format: { \"Rewritten_text\": \"Your text here\" }.";
- case Opciones.modoDeUso.Ortografia:
- return "Please check the following text for spelling errors and provide the corrected version. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find, making sure to preserve important technical terms and markdown language if present. Please write in " + IdiomaDetectado + " and respond in the following JSON format: { \"Rewritten_text\": \"Your text here\" }.";
- default:
- return "You are an engineer working specialiazed industrial automation. Please answer the following question in " + IdiomaDetectado + " and respond in the following JSON format: { \"Reply_text\": \"Your text here\" }.";
- }
- }
+ string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "appsettings.json");
+ if (!File.Exists(configPath))
+ {
+ throw new FileNotFoundException("Configuration file (appsettings.json) not found.");
+ }
- private string CrearMensajeDeUsuario(string texto)
- {
- switch (Opciones.Instance.modo)
+ string jsonContent = File.ReadAllText(configPath);
+ var settings = JsonConvert.DeserializeObject(jsonContent);
+
+ _openAiApiKey = settings?.ApiKeys?.OpenAI;
+ _groqApiKey = settings?.ApiKeys?.Groq;
+ _grokApiKey = settings?.ApiKeys?.Grok;
+
+ ValidateApiKeys();
+ }
+ catch (Exception ex)
{
- case Opciones.modoDeUso.Corregir:
- return "Please rewrite and improve the following text to make it clearer and more concise the words inside brackets are technical words: \"" + texto + "\"";
- case Opciones.modoDeUso.Ortografia:
- return "Please check the following text for spelling errors and provide the corrected version. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"" + texto + "\"";
- case Opciones.modoDeUso.Traducir_a_Ingles:
- return "Please check the following text for spelling errors and provide the corrected version in English. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"" + texto + "\"";
- case Opciones.modoDeUso.Traducir_a_Italiano:
- return "Please check the following text for spelling errors and provide the corrected version in Italian. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"" + texto + "\"";
- case Opciones.modoDeUso.Traducir_a_Espanol:
- return "Please check the following text for spelling errors and provide the corrected version in Spanish. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"" + texto + "\"";
-
- default:
- return texto;
+ Log.Log($"Error loading API keys: {ex.Message}");
+ throw new ApplicationException("Failed to load API keys", ex);
}
}
-
- private string DetectarIdioma(string TextoACorregir)
+ private void ValidateApiKeys()
{
- if (Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Ingles)
- return languageMap["en"];
- if (Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Italiano)
- return languageMap["it"];
- if (Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Espanol)
- return languageMap["es"];
+ var missingKeys = new List();
- LanguageDetector detector = new LanguageDetector();
-
- detector.AddLanguages("en", "es", "it");
- string detectedLanguageCode = detector.Detect(TextoACorregir);
+ if (string.IsNullOrEmpty(_openAiApiKey)) missingKeys.Add("OpenAI");
+ if (string.IsNullOrEmpty(_groqApiKey)) missingKeys.Add("Groq");
+ if (string.IsNullOrEmpty(_grokApiKey)) missingKeys.Add("Grok");
- string detectedLanguageName = languageMap.ContainsKey(detectedLanguageCode)
- ? languageMap[detectedLanguageCode]
- : "Desconocido";
-
- return detectedLanguageName;
- }
- private bool DetectarIdioma()
- {
- if (TextoACorregir.Length>0)
+ if (missingKeys.Any())
{
- IdiomaDetectado = DetectarIdioma(TextoACorregir);
- Log.Log("Idioma: " + IdiomaDetectado);
- if(IdiomaDetectado != "Desconocido")
- return true;
- else return false;
+ string missingKeysStr = string.Join(", ", missingKeys);
+ throw new ApplicationException($"Missing API keys: {missingKeysStr}");
}
- return false;
+ }
+
+ private void InitializeHttpClient()
+ {
+ _httpClient.Timeout = TimeSpan.FromSeconds(30);
+ _httpClient.DefaultRequestHeaders.Clear();
+ _httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
}
public async Task CorregirTexto()
{
- if (Simulacion)
- TextoACorregir = "\t\t* Sic : Synchronism?\r\n\t\t* Cont ? \r\n\t\t* Sensor for tensioning?\r\n\t\t* Max ? Overspeed?\r\n\t\t* Min : Stop / Start\r\n\t\t* Variable Speed. - = reference by filler\r\n\t\t* Formats: ? 66mm a 93mm => 27mm. How is changed?";
-
- Log.Log("");
- Log.Log("Texto a corregir: " + TextoACorregir);
- if (DetectarIdioma()) {
- if (IdiomaDetectado == "Desconocido" || this.TextoACorregir.Length == 0)
- {
- // Nada que hacer
- TextoCorregido = TextoACorregir;
- return;
- }
-
- var md = new Obsidean();
- md.LeerPalabrasTecnicas();
-
- TextoACorregir = md.MarkTechnicalTerms_IgnoreCase(TextoACorregir);
-
- Log.Log("Texto marcado: " + TextoACorregir);
-
- string RespuestaLLM = "";
-
- if (!Simulacion)
- {
- if (Opciones.Instance.LLM == Opciones.LLM_a_Usar.OpenAI) RespuestaLLM = await CallOpenAiApi(TextoACorregir);
- if (Opciones.Instance.LLM == Opciones.LLM_a_Usar.Ollama) RespuestaLLM = await CallOllamaApi(TextoACorregir);
- if (Opciones.Instance.LLM == Opciones.LLM_a_Usar.Groq) RespuestaLLM = await CallGroqAiApi(TextoACorregir);
- if (Opciones.Instance.LLM == Opciones.LLM_a_Usar.Grok) RespuestaLLM = await CallGrokApi(TextoACorregir);
- } else
- {
- await Task.Delay(1000);
- RespuestaLLM = "Here is the rewritten text in a clearer and more concise manner:\r\n\r\n{\r\n'Rewritten_text': '\r\n### FB Tilting System Overview\r\n\r\nThe FB Tilting system consists of two main components:\r\n\r\n* **FB Tilting**: The main machine responsible for tilting and moving bottles.\r\n* **Sic (Synchronism)**: Ensures synchronized movement of the tilting machine with other system components.\r\n\r\n### Key Components and Functions\r\n\r\n* **Cont (Controller)**: The controlling unit that regulates the system's operation.\r\n* **Sensor for Tensioning**: Monitors and adjusts the tension of the moving parts.\r\n* **Max (Maximum Speed) and Overspeed Protection**: Safeguards the system from excessive speeds.\r\n* **Min (Minimum Speed) and Stop/Start Function**: Manages the system's startup and shutdown sequences.\r\n* **Variable Speed**: Allows for adjustable speed control, referenced by the filling machine.\r\n\r\n### Format Adaptation\r\n\r\nThe system accommodates various formats, including:\r\n* 66mm to 93mm, which are adapted to 27mm formats. The format change process is implemented as follows:\r\n\r\n### Startup Sequence\r\n\r\nThe startup procedure involves:\r\n\r\n1. **Fill to Sic with Minimum Accumulation**: Fills the Sic component with a minimum amount of material.\r\n2. **Run Chain at Fixed Speed**: Operates the chain at a constant speed.\r\n3. **Wait for Phase to Start**: Waits for the phase and ramp of the doser to be parameterized.\r\n4. **Ramp to Variable Speed**: Gradually adjusts the speed to the selected variable speed setting after a few bottles have been processed.'\r\n}";
- }
-
- Log.Log("Respuesta: " + RespuestaLLM);
-
- TextoCorregido = ExtraerValorUnicoJSON(RespuestaLLM);
- if (TextoCorregido is null)
- TextoCorregido = "Error en la respuesta.";
-
- // Elimina comillas al principio y al final si existen
- TextoCorregido = md.RemoveTechnicalTermMarkers_IgnoreCase(TextoCorregido).Trim('\"');
-
- Log.Log("Texto corregido: " + TextoCorregido);
- }
- }
-
-
- public string ExtraerValorUnicoJSON(string input)
- {
- // Encuentra los índices del inicio y del final del JSON
- int startJson = input.IndexOf('{');
- int endJson = input.LastIndexOf('}') + 1;
-
- if (startJson == -1 || endJson == -1 || endJson <= startJson)
+ if (string.IsNullOrWhiteSpace(TextoACorregir))
{
- return "No valid JSON found in the input string.";
+ Log.Log("No hay texto para corregir");
+ return;
}
- // Extrae solo la parte JSON de la entrada
- string jsonString = input.Substring(startJson, endJson - startJson);
-
try
{
- // Parsea el JSON
- JObject jsonObject = JObject.Parse(jsonString);
+ Log.Log("Iniciando proceso de corrección");
+ Log.Log($"Texto original: {TextoACorregir}");
- // Obtiene el primer campo independientemente del nombre de la clave
- var firstField = jsonObject.Properties().FirstOrDefault();
- if (firstField != null)
+ if (!DetectarIdioma())
{
- return firstField.Value.ToString(); // Devuelve el valor del primer campo
+ throw new ApplicationException("No se pudo detectar el idioma del texto");
+ }
+
+ string textoMarcado = MarcarPalabrasTecnicas();
+ Log.Log($"Texto marcado: {textoMarcado}");
+
+ if (Simulacion)
+ {
+ await SimularCorreccion();
}
else
{
- return "JSON does not contain any data.";
+ await ProcesarTextoConLLM(textoMarcado);
}
+
+ Log.Log($"Texto corregido: {TextoCorregido}");
}
- catch (JsonException jsonEx)
+ catch (Exception ex)
{
- // Maneja errores de parseo de JSON
- return "Error parsing JSON: " + jsonEx.Message;
+ Log.Log($"Error en CorregirTexto: {ex.Message}");
+ throw;
}
}
-
- static string ExtractCorrectedText(string input)
+ private bool DetectarIdioma()
+ {
+ try
+ {
+ if (EsModoTraduccion())
+ {
+ IdiomaDetectado = ObtenerIdiomaObjetivo();
+ Log.Log($"Modo traducción: idioma objetivo establecido a {IdiomaDetectado}");
+ return true;
+ }
+
+ string detectedLanguageCode = _languageDetector.Detect(TextoACorregir);
+ IdiomaDetectado = _languageMap.GetValueOrDefault(detectedLanguageCode, "Desconocido");
+
+ Log.Log($"Idioma detectado: {IdiomaDetectado}");
+ return IdiomaDetectado != "Desconocido";
+ }
+ catch (Exception ex)
+ {
+ Log.Log($"Error al detectar idioma: {ex.Message}");
+ return false;
+ }
+ }
+
+ private bool EsModoTraduccion()
+ {
+ return Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Ingles ||
+ Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Italiano ||
+ Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Espanol;
+ }
+
+ private string ObtenerIdiomaObjetivo()
+ {
+ return Opciones.Instance.modo switch
+ {
+ Opciones.modoDeUso.Traducir_a_Ingles => _languageMap["en"],
+ Opciones.modoDeUso.Traducir_a_Italiano => _languageMap["it"],
+ Opciones.modoDeUso.Traducir_a_Espanol => _languageMap["es"],
+ _ => throw new ArgumentException("Modo de traducción no válido")
+ };
+ }
+
+ private string MarcarPalabrasTecnicas()
+ {
+ try
+ {
+ return _markdownProcessor.MarkTechnicalTerms_IgnoreCase(TextoACorregir);
+ }
+ catch (Exception ex)
+ {
+ Log.Log($"Error al marcar palabras técnicas: {ex.Message}");
+ throw;
+ }
+ }
+
+ private async Task ProcesarTextoConLLM(string textoMarcado)
+ {
+ try
+ {
+ string respuestaLLM;
+
+ switch (Opciones.Instance.LLM)
+ {
+ case Opciones.LLM_a_Usar.OpenAI:
+ respuestaLLM = await CallOpenAiApi(textoMarcado);
+ break;
+ case Opciones.LLM_a_Usar.Ollama:
+ respuestaLLM = await CallOllamaApi(textoMarcado);
+ break;
+ case Opciones.LLM_a_Usar.Groq:
+ respuestaLLM = await CallGroqAiApi(textoMarcado);
+ break;
+ case Opciones.LLM_a_Usar.Grok:
+ respuestaLLM = await CallGrokApi(textoMarcado);
+ break;
+ default:
+ throw new ArgumentException("LLM no válido");
+ }
+
+ if (string.IsNullOrEmpty(respuestaLLM))
+ {
+ throw new ApplicationException("No se recibió respuesta del LLM");
+ }
+
+ ProcesarRespuestaLLM(respuestaLLM);
+ }
+ catch (Exception ex)
+ {
+ Log.Log($"Error al procesar texto con LLM: {ex.Message}");
+ throw;
+ }
+ }
+
+ private void ProcesarRespuestaLLM(string respuestaLLM)
+ {
+ TextoCorregido = ExtraerValorUnicoJSON(respuestaLLM);
+ if (TextoCorregido == null)
+ {
+ throw new ApplicationException("Error al extraer el texto corregido de la respuesta JSON");
+ }
+
+ TextoCorregido = _markdownProcessor.RemoveTechnicalTermMarkers_IgnoreCase(TextoCorregido).Trim('"');
+ }
+
+ private async Task SimularCorreccion()
+ {
+ await Task.Delay(1000);
+ TextoCorregido = "Texto simulado de prueba";
+ Log.Log("Simulación completada");
+ }
+
+ public string ExtraerValorUnicoJSON(string input)
{
try
{
- // Encuentra el índice del inicio y del final del JSON
int startJson = input.IndexOf('{');
int endJson = input.LastIndexOf('}') + 1;
if (startJson == -1 || endJson == -1 || endJson <= startJson)
{
- throw new Exception("No valid JSON found in the input string.");
+ Log.Log("Formato JSON inválido en la respuesta");
+ return null;
}
- // Extrae solo la parte JSON de la entrada
- string jsonString = input.Substring(startJson, endJson - startJson);
+ string jsonString = input[startJson..endJson];
+ JObject jsonObject = JObject.Parse(jsonString);
+ var firstField = jsonObject.Properties().FirstOrDefault();
- // Busca el inicio del texto después de "Rewritten_text':"
- int startKey = jsonString.IndexOf("'Rewritten_text':") + 17; // 17 es la longitud de "'Rewritten_text':"
- if (startKey == -1)
- {
- throw new Exception("Key 'Rewritten_text' not found.");
- }
-
- // Ajusta para encontrar el inicio del texto después de las comillas simples adicionales
- int startText = jsonString.IndexOf('\'', startKey) + 1;
- int endText = jsonString.LastIndexOf('\'');
-
- if (startText == -1 || endText == -1 || endText <= startText)
- {
- throw new Exception("No valid text found in the JSON string.");
- }
-
- // Extrae el texto entre las comillas simples
- string rewrittenText = jsonString.Substring(startText, endText - startText);
-
- return rewrittenText;
+ return firstField?.Value?.ToString();
}
- catch (Exception ex)
+ catch (JsonException ex)
{
- Console.WriteLine("An error occurred: " + ex.Message);
+ Log.Log($"Error al procesar JSON: {ex.Message}");
return null;
}
}
+ private string CrearMensajeDeSistema()
+ {
+ return Opciones.Instance.modo switch
+ {
+ Opciones.modoDeUso.Corregir =>
+ "You are an engineer working in industrial automation. Your task is to review texts and rewrite them in a simple and concise manner, making sure to preserve important technical terms and markdown language if present. Please rewrite the following text in " + IdiomaDetectado + " and respond in the following JSON format: { \"Rewritten_text\": \"Your text here\" }.",
+
+ Opciones.modoDeUso.Ortografia =>
+ "Please check the following text for spelling errors and provide the corrected version. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find, making sure to preserve important technical terms and markdown language if present. Please write in " + IdiomaDetectado + " and respond in the following JSON format: { \"Rewritten_text\": \"Your text here\" }.",
+
+ _ => "You are an engineer working specialiazed industrial automation. Please answer the following question in " + IdiomaDetectado + " and respond in the following JSON format: { \"Reply_text\": \"Your text here\" }."
+ };
+ }
+
+ private string CrearMensajeDeUsuario(string texto) =>
+ Opciones.Instance.modo switch
+ {
+ Opciones.modoDeUso.Corregir =>
+ $"Please rewrite and improve the following text to make it clearer and more concise the words inside brackets are technical words: \"{texto}\"",
+
+ Opciones.modoDeUso.Ortografia =>
+ $"Please check the following text for spelling errors and provide the corrected version. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"{texto}\"",
+
+ Opciones.modoDeUso.Traducir_a_Ingles =>
+ $"Please check the following text for spelling errors and provide the corrected version in English. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"{texto}\"",
+
+ Opciones.modoDeUso.Traducir_a_Italiano =>
+ $"Please check the following text for spelling errors and provide the corrected version in Italian. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"{texto}\"",
+
+ Opciones.modoDeUso.Traducir_a_Espanol =>
+ $"Please check the following text for spelling errors and provide the corrected version in Spanish. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"{texto}\"",
+
+ _ => texto
+ };
private async Task CallGrokApi(string input)
{
- using var httpClient = new HttpClient();
- string Mensaje_Sistema = CrearMensajeDeSistema();
- string Mensaje_Usuario = CrearMensajeDeUsuario(input);
-
- // Configurar headers
- httpClient.DefaultRequestHeaders.Clear();
- httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {grokApiKey}");
-
- // Crear el objeto de solicitud siguiendo exactamente el formato del ejemplo curl
- var requestData = new
- {
- messages = new[]
- {
- new { role = "system", content = Mensaje_Sistema },
- new { role = "user", content = Mensaje_Usuario }
- },
- model = "grok-beta",
- stream = false,
- temperature = 0
- };
-
- var content = new StringContent(
- JsonConvert.SerializeObject(requestData),
- Encoding.UTF8,
- "application/json"
- );
-
try
{
- Log.Log("Ask Grok: " + JsonConvert.SerializeObject(requestData));
+ _httpClient.DefaultRequestHeaders.Clear();
+ _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_grokApiKey}");
- // URL corregida para coincidir con el ejemplo
- var response = await httpClient.PostAsync("https://api.x.ai/v1/chat/completions", content);
- response.EnsureSuccessStatusCode();
+ var requestData = new
+ {
+ messages = new[]
+ {
+ new { role = "system", content = CrearMensajeDeSistema() },
+ new { role = "user", content = CrearMensajeDeUsuario(input) }
+ },
+ model = "grok-beta",
+ stream = false,
+ temperature = 0
+ };
- var jsonResponse = await response.Content.ReadAsStringAsync();
- Log.Log("Grok Response: " + jsonResponse); // Logging la respuesta para debug
-
- dynamic data = JsonConvert.DeserializeObject(jsonResponse);
- return data.choices[0].message.content;
+ return await EnviarSolicitudLLM("https://api.x.ai/v1/chat/completions", requestData);
}
- catch (HttpRequestException e)
+ catch (Exception ex)
{
- Log.Log($"Error en la solicitud HTTP: {e.Message}");
- Console.WriteLine($"Error making HTTP request: {e.Message}");
- return null;
- }
- catch (JsonException e)
- {
- Log.Log($"Error al procesar JSON: {e.Message}");
- Console.WriteLine($"Error processing JSON response: {e.Message}");
- return null;
- }
- catch (Exception e)
- {
- Log.Log($"Error general: {e.Message}");
- Console.WriteLine($"An error occurred: {e.Message}");
- return null;
- }
- finally
- {
- httpClient?.Dispose();
+ Log.Log($"Error en llamada a Grok API: {ex.Message}");
+ throw;
}
}
-
private async Task CallOllamaApi(string input)
{
- var httpClient = new HttpClient();
- string Mensaje_Sistema = CrearMensajeDeSistema();
- string Mensaje_Usuario = CrearMensajeDeUsuario(input);
-
- httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {openAiApiKey}");
-
- var requestData = new
- {
- model = "llama3.2:latest", // "phi3", //"llama3",
- messages = new[]
- {
- new { role = "system", content = Mensaje_Sistema },
- new { role = "user", content = Mensaje_Usuario }
- },
- stream = false
- };
-
- var content = new StringContent(JsonConvert.SerializeObject(requestData), Encoding.UTF8, "application/json");
try
{
- Log.Log("Ask Ollama: " + JsonConvert.SerializeObject(requestData));
- var response = await httpClient.PostAsync("http://127.0.0.1:11434/api/chat", content);
- response.EnsureSuccessStatusCode();
- var jsonResponse = await response.Content.ReadAsStringAsync();
- dynamic data = JsonConvert.DeserializeObject(jsonResponse);
-
- if (data.done == true && data.message != null)
+ var requestData = new
{
- return data.message.content;
- }
- return "No hubo respuesta del asistente o la sesión aún no ha concluido.";
- }
- catch (HttpRequestException e)
- {
- // Captura errores en la solicitud HTTP, como problemas de red o respuestas de error HTTP.
- Console.WriteLine($"Error making HTTP request: {e.Message}");
- return null;
- }
- catch (Exception e)
- {
- // Captura cualquier otro error
- Console.WriteLine($"An error occurred: {e.Message}");
- return null;
- }
+ model = "llama3.2:latest",
+ messages = new[]
+ {
+ new { role = "system", content = CrearMensajeDeSistema() },
+ new { role = "user", content = CrearMensajeDeUsuario(input) }
+ },
+ stream = false
+ };
+ return await EnviarSolicitudLLM("http://127.0.0.1:11434/api/chat", requestData);
+ }
+ catch (Exception ex)
+ {
+ Log.Log($"Error en llamada a Ollama API: {ex.Message}");
+ throw;
+ }
}
private async Task CallOpenAiApi(string input)
{
- var httpClient = new HttpClient();
- string Mensaje_Sistema = CrearMensajeDeSistema();
- string Mensaje_Usuario = CrearMensajeDeUsuario(input);
-
- httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {openAiApiKey}");
-
- var requestData = new
- {
- model = "gpt-4o-mini", //"gpt -4",
- messages = new[]
- {
- new { role = "system", content = Mensaje_Sistema },
- new { role = "user", content = Mensaje_Usuario }
- }
- };
-
- var content = new StringContent(JsonConvert.SerializeObject(requestData), Encoding.UTF8, "application/json");
try
{
- Log.Log("Ask OpenAI: " + JsonConvert.SerializeObject(requestData));
- var response = await httpClient.PostAsync("https://api.openai.com/v1/chat/completions", content);
- response.EnsureSuccessStatusCode();
- var jsonResponse = await response.Content.ReadAsStringAsync();
- dynamic data = JsonConvert.DeserializeObject(jsonResponse);
- return data.choices[0].message.content;
- }
- catch (HttpRequestException e)
- {
- // Captura errores en la solicitud HTTP, como problemas de red o respuestas de error HTTP.
- Console.WriteLine($"Error making HTTP request: {e.Message}");
- return null;
- }
- catch (Exception e)
- {
- // Captura cualquier otro error
- Console.WriteLine($"An error occurred: {e.Message}");
- return null;
- }
+ _httpClient.DefaultRequestHeaders.Clear();
+ _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_openAiApiKey}");
+ var requestData = new
+ {
+ model = "gpt-4o-mini",
+ messages = new[]
+ {
+ new { role = "system", content = CrearMensajeDeSistema() },
+ new { role = "user", content = CrearMensajeDeUsuario(input) }
+ }
+ };
+
+ return await EnviarSolicitudLLM("https://api.openai.com/v1/chat/completions", requestData);
+ }
+ catch (Exception ex)
+ {
+ Log.Log($"Error en llamada a OpenAI API: {ex.Message}");
+ throw;
+ }
}
private async Task CallGroqAiApi(string input)
{
- var httpClient = new HttpClient();
- string Mensaje_Sistema = CrearMensajeDeSistema();
- string Mensaje_Usuario = CrearMensajeDeUsuario(input);
-
- httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {groqApiKey}");
-
- var requestData = new
- {
- model = "llama-3.1-70b-versatile", // "llama3-70b-8192",
- messages = new[]
- {
- new { role = "system", content = Mensaje_Sistema },
- new { role = "user", content = Mensaje_Usuario }
- },
- max_tokens = 2048,
- stream = false
- };
-
- var content = new StringContent(JsonConvert.SerializeObject(requestData), Encoding.UTF8, "application/json");
try
{
- Log.Log("Ask Groq: " + JsonConvert.SerializeObject(requestData));
- var response = await httpClient.PostAsync("https://api.groq.com/openai/v1/chat/completions", content);
- response.EnsureSuccessStatusCode();
- var jsonResponse = await response.Content.ReadAsStringAsync();
- dynamic data = JsonConvert.DeserializeObject(jsonResponse);
- return data.choices[0].message.content;
- }
- catch (HttpRequestException e)
- {
- // Captura errores en la solicitud HTTP, como problemas de red o respuestas de error HTTP.
- Console.WriteLine($"Error making HTTP request: {e.Message}");
- return null;
- }
- catch (Exception e)
- {
- // Captura cualquier otro error
- Console.WriteLine($"An error occurred: {e.Message}");
- return null;
- }
+ _httpClient.DefaultRequestHeaders.Clear();
+ _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_groqApiKey}");
+ var requestData = new
+ {
+ model = "llama-3.2-3b-preview",
+ messages = new[]
+ {
+ new { role = "system", content = CrearMensajeDeSistema() },
+ new { role = "user", content = CrearMensajeDeUsuario(input) }
+ },
+ max_tokens = 2048,
+ stream = false
+ };
+
+ return await EnviarSolicitudLLM("https://api.groq.com/openai/v1/chat/completions", requestData);
+ }
+ catch (Exception ex)
+ {
+ Log.Log($"Error en llamada a Groq API: {ex.Message}");
+ throw;
+ }
}
+ private async Task EnviarSolicitudLLM(string endpoint, object requestData)
+ {
+ try
+ {
+ var content = new StringContent(
+ JsonConvert.SerializeObject(requestData),
+ Encoding.UTF8,
+ "application/json"
+ );
+
+ Log.Log($"Enviando solicitud a {endpoint}");
+ Log.Log($"Datos de solicitud: {JsonConvert.SerializeObject(requestData)}");
+
+ using var response = await _httpClient.PostAsync(endpoint, content);
+
+ var responseContent = await response.Content.ReadAsStringAsync();
+ Log.Log($"Respuesta recibida: {responseContent}");
+
+ if (!response.IsSuccessStatusCode)
+ {
+ throw new HttpRequestException(
+ $"Error en la solicitud HTTP: {response.StatusCode} - {responseContent}"
+ );
+ }
+
+ var data = JsonConvert.DeserializeObject(responseContent);
+
+ // Manejar diferentes formatos de respuesta según el LLM
+ if (endpoint.Contains("ollama"))
+ {
+ if (data.done == true && data.message != null)
+ {
+ return data.message.content;
+ }
+ throw new ApplicationException("Formato de respuesta de Ollama inválido");
+ }
+ else // OpenAI, Groq, Grok
+ {
+ if (data.choices != null && data.choices.Count > 0)
+ {
+ return data.choices[0].message.content;
+ }
+ throw new ApplicationException("No se encontró contenido en la respuesta del LLM");
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Log($"Error al enviar solicitud a {endpoint}: {ex.Message}");
+ throw;
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ if (disposing)
+ {
+ _httpClient?.Dispose();
+ }
+
+ _disposed = true;
+ }
+ }
+
+ ~gtpask()
+ {
+ Dispose(false);
+ }
}
-}
+
+ // Clase auxiliar para manejar excepciones específicas de la aplicación
+ public class LLMException : Exception
+ {
+ public LLMException(string message) : base(message) { }
+ public LLMException(string message, Exception innerException) : base(message, innerException) { }
+ }
+
+ // Clase auxiliar para validación
+ public static class Validations
+ {
+ public static void ValidateNotNull(object value, string paramName)
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException(paramName);
+ }
+ }
+
+ public static void ValidateNotNullOrEmpty(string value, string paramName)
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ throw new ArgumentException("Value cannot be null or empty", paramName);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/notificacion.xaml b/notificacion.xaml
index 721af8d..699234d 100644
--- a/notificacion.xaml
+++ b/notificacion.xaml
@@ -1,13 +1,63 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/notificacion.xaml.cs b/notificacion.xaml.cs
index 205b3da..58a5a25 100644
--- a/notificacion.xaml.cs
+++ b/notificacion.xaml.cs
@@ -1,41 +1,114 @@
-using System.Windows;
-using Application = System.Windows.Application;
+using System;
+using System.Windows;
+using System.Windows.Media.Animation;
+using System.Windows.Threading;
namespace GTPCorrgir
{
- ///
- /// Interaction logic for notificacion.xaml
- ///
public partial class notificacion : Window
{
+ private readonly DispatcherTimer autoCloseTimer;
+ private readonly DispatcherTimer progressTimer;
+ private double progressValue = 0;
+ private const int AUTO_CLOSE_SECONDS = 5;
+ private const int PROGRESS_UPDATE_INTERVAL = 50; // milisegundos
+
public notificacion()
{
InitializeComponent();
PositionWindow();
+
+ // Configurar el timer para auto-cierre
+ autoCloseTimer = new DispatcherTimer
+ {
+ Interval = TimeSpan.FromSeconds(AUTO_CLOSE_SECONDS)
+ };
+ autoCloseTimer.Tick += AutoCloseTimer_Tick;
+
+ // Configurar el timer para la barra de progreso
+ progressTimer = new DispatcherTimer
+ {
+ Interval = TimeSpan.FromMilliseconds(PROGRESS_UPDATE_INTERVAL)
+ };
+ progressTimer.Tick += ProgressTimer_Tick;
+
+ // Iniciar animación de entrada
+ Loaded += (s, e) =>
+ {
+ var storyboard = (Storyboard)FindResource("FadeIn");
+ storyboard.Begin(this);
+ autoCloseTimer.Start();
+ progressTimer.Start();
+ };
}
private void PositionWindow()
{
- // Obtener la posición del cursor
var cursorPosition = System.Windows.Forms.Cursor.Position;
-
- // Determinar en qué pantalla está el cursor
var screen = System.Windows.Forms.Screen.FromPoint(cursorPosition);
- // Configurar la ubicación de la ventana para que aparezca en la esquina inferior derecha
- this.Left = screen.WorkingArea.Right - this.Width;
- this.Top = screen.WorkingArea.Bottom - this.Height;
+ this.Left = screen.WorkingArea.Right - this.Width - 20;
+ this.Top = screen.WorkingArea.Bottom - this.Height - 20;
}
public void UpdateNotification(string title, string message)
{
TitleText.Text = title;
MessageText.Text = message;
+
+ // Reiniciar timers y progreso
+ progressValue = 0;
+ AutoCloseProgress.Value = 0;
+
+ autoCloseTimer.Stop();
+ progressTimer.Stop();
+
+ autoCloseTimer.Start();
+ progressTimer.Start();
+ }
+
+ private async void AutoCloseTimer_Tick(object sender, EventArgs e)
+ {
+ autoCloseTimer.Stop();
+ progressTimer.Stop();
+
+ var storyboard = (Storyboard)FindResource("FadeOut");
+ storyboard.Completed += (s, _) => Close();
+ storyboard.Begin(this);
+ }
+
+ private void ProgressTimer_Tick(object sender, EventArgs e)
+ {
+ progressValue += (PROGRESS_UPDATE_INTERVAL / (AUTO_CLOSE_SECONDS * 1000.0)) * 100;
+ AutoCloseProgress.Value = progressValue;
+
+ if (progressValue >= 100)
+ {
+ progressTimer.Stop();
+ }
}
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
- Application.Current.Shutdown();
+ autoCloseTimer.Stop();
+ progressTimer.Stop();
+ var storyboard = (Storyboard)FindResource("FadeOut");
+ storyboard.Completed += (s, _) => Close();
+ storyboard.Begin(this);
+ }
+
+ protected override void OnMouseEnter(System.Windows.Input.MouseEventArgs e)
+ {
+ base.OnMouseEnter(e);
+ autoCloseTimer.Stop();
+ progressTimer.Stop();
+ }
+
+ protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e)
+ {
+ base.OnMouseLeave(e);
+ autoCloseTimer.Start();
+ progressTimer.Start();
}
}
-}
+}
\ No newline at end of file