Agregado de opcion de configuracion.
This commit is contained in:
parent
2caf2b96f5
commit
c047fb2c01
56
Chat.xaml
56
Chat.xaml
|
@ -1,62 +1,62 @@
|
||||||
<Window
|
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:md="clr-namespace:Markdown.Xaml;assembly=Markdown.Xaml"
|
xmlns:md="clr-namespace:Markdown.Xaml;assembly=Markdown.Xaml"
|
||||||
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"
|
xmlns:av="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
Title="Chat with OpenAI" Height="300" Width="300"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="av"
|
||||||
ResizeMode="CanResizeWithGrip" WindowStyle="None"
|
x:Class="GTPCorrgir.Chat" Title="Chat with OpenAI" Height="300" Width="300" ResizeMode="CanResizeWithGrip"
|
||||||
Background="Transparent" AllowsTransparency="True"
|
WindowStyle="None" Background="Transparent" AllowsTransparency="True" MouseEnter="Window_MouseEnter"
|
||||||
MouseEnter="Window_MouseEnter" MouseLeave="Window_MouseLeave" KeyDown="Window_KeyDown"
|
MouseLeave="Window_MouseLeave" KeyDown="Window_KeyDown" Opacity="0.8" av:DesignHeight="320.439"
|
||||||
Opacity="0.8" av:DesignHeight="320.439" av:DesignWidth="609.769">
|
av:DesignWidth="609.769">
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
<md:Markdown x:Key="MarkdownConverter" />
|
<md:Markdown x:Key="MarkdownConverter" />
|
||||||
</Window.Resources>
|
</Window.Resources>
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto" />
|
||||||
<!-- Model Selector con altura automática -->
|
<RowDefinition Height="2*" />
|
||||||
<RowDefinition Height="2*"/>
|
<RowDefinition Height="*" />
|
||||||
<!-- Área de Respuesta con 2/3 del espacio disponible -->
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
<!-- Área de Pregunta con 1/3 del espacio disponible -->
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<!-- Selector del Modelo -->
|
<!-- Barra superior con controles -->
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*" />
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<!-- Selector de modelo LLM -->
|
<!-- Selector de modelo LLM -->
|
||||||
<ComboBox x:Name="modelSelector" Grid.Column="0" Margin="1" SelectionChanged="CambiarModelo" />
|
<ComboBox x:Name="modelSelector" Grid.Column="0" Margin="1" SelectionChanged="CambiarModelo" />
|
||||||
|
|
||||||
|
<!-- Botón de configuración -->
|
||||||
|
<Button x:Name="settingsButton" Grid.Column="1" Content="⚙" Width="20" Height="20" Margin="5,0"
|
||||||
|
Click="SettingsButton_Click" ToolTip="Configuración" />
|
||||||
|
|
||||||
<!-- Área para mover la ventana -->
|
<!-- Área para mover la ventana -->
|
||||||
<Border Background="#444" Height="20" Width="20" Grid.Column="1" Margin="10,0,10,0"
|
<Border Background="#444" Height="20" Width="20" Grid.Column="2" Margin="5,0,10,0"
|
||||||
MouseLeftButtonDown="Border_MouseLeftButtonDown" Cursor="SizeAll" ToolTip="Mover ventana">
|
MouseLeftButtonDown="Border_MouseLeftButtonDown" Cursor="SizeAll" ToolTip="Mover ventana">
|
||||||
<TextBlock Text="☰" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White"/>
|
<TextBlock Text="☰" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" />
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|
||||||
<!-- Área de Respuesta -->
|
<!-- Área de Respuesta -->
|
||||||
<Grid Grid.Row="1" Margin="1">
|
<Grid Grid.Row="1" Margin="1">
|
||||||
<RichTextBox Name="responseArea" IsReadOnly="True" Grid.Row="1">
|
<RichTextBox Name="responseArea" IsReadOnly="True">
|
||||||
<RichTextBox.Resources>
|
<RichTextBox.Resources>
|
||||||
<md:Markdown x:Key="Markdown" />
|
<md:Markdown x:Key="Markdown" />
|
||||||
</RichTextBox.Resources>
|
</RichTextBox.Resources>
|
||||||
</RichTextBox>
|
</RichTextBox>
|
||||||
<Button x:Name="clearButton" Content="Limpiar" Width="40" Height="24"
|
<Button x:Name="clearButton" Content="Limpiar" Width="40" Height="24" HorizontalAlignment="Right"
|
||||||
HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0" Click="clearButton_Click" />
|
VerticalAlignment="Bottom" Margin="0" Click="clearButton_Click" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<!-- Área de Pregunta con Botón Superpuesto -->
|
<!-- Área de Pregunta con Botón -->
|
||||||
<Grid Grid.Row="2" Margin="1">
|
<Grid Grid.Row="2" Margin="1">
|
||||||
<TextBox x:Name="questionArea" Padding="10"
|
<TextBox x:Name="questionArea" Padding="10" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap"
|
||||||
VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" Background="White" PreviewKeyDown="QuestionArea_PreviewKeyDown"/>
|
Background="White" PreviewKeyDown="QuestionArea_PreviewKeyDown" />
|
||||||
<Button x:Name="sendButton" Content="Enviar" Width="40" Height="24"
|
<Button x:Name="sendButton" Content="Enviar" Width="40" Height="24" HorizontalAlignment="Right"
|
||||||
HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0" Click="SendButton_Click"/>
|
VerticalAlignment="Bottom" Margin="0" Click="SendButton_Click" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
183
Chat.xaml.cs
183
Chat.xaml.cs
|
@ -15,37 +15,69 @@ using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using static GTPCorrgir.Opciones;
|
using static GTPCorrgir.Opciones;
|
||||||
using static System.Net.WebRequestMethods;
|
using static System.Net.WebRequestMethods;
|
||||||
|
using Brushes = System.Windows.Media.Brushes;
|
||||||
|
using Color = System.Windows.Media.Color;
|
||||||
using ComboBox = System.Windows.Controls.ComboBox;
|
using ComboBox = System.Windows.Controls.ComboBox;
|
||||||
using Cursors = System.Windows.Input.Cursors;
|
using Cursors = System.Windows.Input.Cursors;
|
||||||
|
using FontFamily = System.Windows.Media.FontFamily;
|
||||||
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
|
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
|
||||||
using MouseEventArgs = System.Windows.Input.MouseEventArgs;
|
using MouseEventArgs = System.Windows.Input.MouseEventArgs;
|
||||||
|
using Timer = System.Windows.Forms.Timer;
|
||||||
|
|
||||||
namespace GTPCorrgir
|
namespace GTPCorrgir
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Interaction logic for Chat.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class Chat : Window
|
public partial class Chat : Window
|
||||||
{
|
{
|
||||||
gtpask AI_API;
|
gtpask AI_API;
|
||||||
string respuestas;
|
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)
|
public Chat(gtpask GTP)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
InitializeOpacityTimer();
|
||||||
PositionWindow();
|
PositionWindow();
|
||||||
// Inicializar componentes de la UI, por ejemplo, llenar el ComboBox
|
|
||||||
|
// Inicializar componentes de la UI
|
||||||
AI_API = GTP;
|
AI_API = GTP;
|
||||||
questionArea.Text = ""; //GTP.TextoACorregir;
|
questionArea.Text = "";
|
||||||
respuestas = "";
|
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<LLM_a_Usar, string> kvp in Opciones.Instance.nombreLLM)
|
foreach (KeyValuePair<LLM_a_Usar, string> kvp in Opciones.Instance.nombreLLM)
|
||||||
{
|
{
|
||||||
ComboBoxItem item = new ComboBoxItem();
|
ComboBoxItem item = new ComboBoxItem();
|
||||||
item.Content = kvp.Value; // El texto que se mostrará
|
item.Content = kvp.Value;
|
||||||
item.Tag = kvp.Key; // Guarda el valor enum en el Tag para acceso posterior
|
item.Tag = kvp.Key;
|
||||||
modelSelector.Items.Add(item);
|
modelSelector.Items.Add(item);
|
||||||
// Verifica si este ítem debe ser el seleccionado
|
|
||||||
if (kvp.Key == Opciones.Instance.LLM)
|
if (kvp.Key == Opciones.Instance.LLM)
|
||||||
{
|
{
|
||||||
modelSelector.SelectedItem = item;
|
modelSelector.SelectedItem = item;
|
||||||
|
@ -53,20 +85,81 @@ namespace GTPCorrgir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
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)
|
if (e.LeftButton == MouseButtonState.Pressed)
|
||||||
{
|
{
|
||||||
this.DragMove();
|
this.DragMove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void Window_MouseEnter(object sender, MouseEventArgs e)
|
private void Window_MouseEnter(object sender, MouseEventArgs e)
|
||||||
{
|
{
|
||||||
// Hacer la ventana opaca cuando el ratón esté sobre ella
|
isMouseOver = true;
|
||||||
this.Opacity = 1.0;
|
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)
|
private void Window_KeyDown(object sender, KeyEventArgs e)
|
||||||
|
@ -82,27 +175,21 @@ namespace GTPCorrgir
|
||||||
if (e.Key == Key.Enter && !e.KeyboardDevice.Modifiers.HasFlag(ModifierKeys.Shift))
|
if (e.Key == Key.Enter && !e.KeyboardDevice.Modifiers.HasFlag(ModifierKeys.Shift))
|
||||||
{
|
{
|
||||||
SendButton_Click(this, new RoutedEventArgs());
|
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;
|
AI_API.TextoACorregir = questionArea.Text;
|
||||||
if (AI_API.TextoACorregir.Length > 3)
|
if (AI_API.TextoACorregir.Length > 3)
|
||||||
{
|
{
|
||||||
sendButton.IsEnabled = false; // Deshabilitar el botón de envío
|
try
|
||||||
Mouse.OverrideCursor = Cursors.Wait; // Cambiar el cursor a espera
|
{
|
||||||
|
sendButton.IsEnabled = false;
|
||||||
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
|
|
||||||
Task.Run(async () =>
|
await Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -110,59 +197,49 @@ namespace GTPCorrgir
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Error durante la corrección de texto: " + ex.Message);
|
Console.WriteLine($"Error durante la corrección de texto: {ex.Message}");
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
finally
|
});
|
||||||
{
|
|
||||||
Dispatcher.Invoke(async () => // Nota el 'async' aquí para permitir 'await'
|
|
||||||
{
|
|
||||||
if (AI_API.TextoCorregido != null)
|
if (AI_API.TextoCorregido != null)
|
||||||
{
|
{
|
||||||
System.Windows.Clipboard.SetText(AI_API.TextoCorregido);
|
System.Windows.Clipboard.SetText(AI_API.TextoCorregido);
|
||||||
//responseArea. .Text += AI_API.TextoCorregido + "\r\n";
|
|
||||||
AddMarkdownContent(AI_API.TextoCorregido + "\r\n");
|
AddMarkdownContent(AI_API.TextoCorregido + "\r\n");
|
||||||
|
|
||||||
Mouse.OverrideCursor = null; // Restaurar el cursor normal
|
|
||||||
sendButton.IsEnabled = true; // Habilitar el botón de envío
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
AddMarkdownContent($"Error: {ex.Message}\r\n");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Mouse.OverrideCursor = null;
|
||||||
|
sendButton.IsEnabled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddMarkdownContent(string markdownText)
|
public void AddMarkdownContent(string markdownText)
|
||||||
{
|
{
|
||||||
// Transforma el texto Markdown a un FlowDocument
|
|
||||||
var markdown = new Markdown.Xaml.Markdown();
|
var markdown = new Markdown.Xaml.Markdown();
|
||||||
|
|
||||||
respuestas += markdownText + "\r\n";
|
respuestas += markdownText + "\r\n";
|
||||||
|
|
||||||
responseArea.Document = markdown.Transform(respuestas);
|
responseArea.Document = markdown.Transform(respuestas);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PositionWindow()
|
private void PositionWindow()
|
||||||
{
|
{
|
||||||
// Obtener la posición del cursor
|
|
||||||
var cursorPosition = System.Windows.Forms.Cursor.Position;
|
var cursorPosition = System.Windows.Forms.Cursor.Position;
|
||||||
|
|
||||||
// Determinar en qué pantalla está el cursor
|
|
||||||
var screen = Screen.FromPoint(cursorPosition);
|
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.Left = (screen.WorkingArea.Width - this.Width) / 2 + screen.WorkingArea.Left;
|
||||||
this.Top = (screen.WorkingArea.Height - this.Height) / 2 + screen.WorkingArea.Top;
|
this.Top = (screen.WorkingArea.Height - this.Height) / 2 + screen.WorkingArea.Top;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CambiarModelo(object sender, SelectionChangedEventArgs e)
|
private void CambiarModelo(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
ComboBox comboBox = sender as ComboBox;
|
if (sender is ComboBox comboBox && comboBox.SelectedItem is ComboBoxItem selectedItem)
|
||||||
ComboBoxItem selectedItem = comboBox.SelectedItem as ComboBoxItem;
|
|
||||||
if (selectedItem != null)
|
|
||||||
{
|
{
|
||||||
LLM_a_Usar selectedEnum = (LLM_a_Usar)selectedItem.Tag;
|
Opciones.Instance.LLM = (LLM_a_Usar)selectedItem.Tag;
|
||||||
Opciones.Instance.LLM = selectedEnum; // Suponiendo que hay una propiedad para establecerlo
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,5 +248,11 @@ namespace GTPCorrgir
|
||||||
respuestas = "";
|
respuestas = "";
|
||||||
AddMarkdownContent("");
|
AddMarkdownContent("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnClosed(EventArgs e)
|
||||||
|
{
|
||||||
|
opacityTimer?.Dispose();
|
||||||
|
base.OnClosed(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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<ChatMessage> currentSession;
|
||||||
|
|
||||||
|
public ChatHistory()
|
||||||
|
{
|
||||||
|
historyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, HISTORY_FOLDER);
|
||||||
|
currentSession = new List<ChatMessage>();
|
||||||
|
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<ChatMessage> 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<List<ChatMessage>>(json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error loading chat history: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new List<ChatMessage>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<string> 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<dynamic>(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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
<Window x:Class="GTPCorrgir.SettingsWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Configuración" Height="450" Width="400"
|
||||||
|
WindowStartupLocation="CenterOwner">
|
||||||
|
<Grid Margin="10">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<TabControl Grid.Row="1" Margin="0,10">
|
||||||
|
<TabItem Header="Apariencia">
|
||||||
|
<StackPanel Margin="10">
|
||||||
|
<GroupBox Header="Tema" Margin="0,0,0,10">
|
||||||
|
<StackPanel Margin="5">
|
||||||
|
<RadioButton x:Name="LightTheme" Content="Claro" Margin="0,5" />
|
||||||
|
<RadioButton x:Name="DarkTheme" Content="Oscuro" Margin="0,5" />
|
||||||
|
</StackPanel>
|
||||||
|
</GroupBox>
|
||||||
|
|
||||||
|
<GroupBox Header="Fuente" Margin="0,0,0,10">
|
||||||
|
<Grid Margin="5">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<TextBlock Text="Tamaño:" Margin="0,5" />
|
||||||
|
<ComboBox x:Name="FontSizeCombo" Grid.Column="1" Margin="5" />
|
||||||
|
|
||||||
|
<TextBlock Text="Familia:" Grid.Row="1" Margin="0,5" />
|
||||||
|
<ComboBox x:Name="FontFamilyCombo" Grid.Row="1" Grid.Column="1" Margin="5" />
|
||||||
|
</Grid>
|
||||||
|
</GroupBox>
|
||||||
|
|
||||||
|
<GroupBox Header="Opacidad" Margin="0,0,0,10">
|
||||||
|
<StackPanel Margin="5">
|
||||||
|
<TextBlock Text="Retraso antes de transparencia (segundos):" />
|
||||||
|
<Slider x:Name="OpacityDelaySlider" Minimum="1" Maximum="30" Value="10" TickFrequency="1"
|
||||||
|
IsSnapToTickEnabled="True" />
|
||||||
|
<TextBlock Text="{Binding ElementName=OpacityDelaySlider, Path=Value, StringFormat={}{0} s}" />
|
||||||
|
</StackPanel>
|
||||||
|
</GroupBox>
|
||||||
|
</StackPanel>
|
||||||
|
</TabItem>
|
||||||
|
|
||||||
|
<TabItem Header="Comportamiento">
|
||||||
|
<StackPanel Margin="10">
|
||||||
|
<CheckBox x:Name="AutoSaveCheckbox" Content="Guardar historial automáticamente" Margin="0,5" />
|
||||||
|
<CheckBox x:Name="ShowNotificationsCheckbox" Content="Mostrar notificaciones" Margin="0,5" />
|
||||||
|
<CheckBox x:Name="AutoCopyCheckbox" Content="Copiar respuestas al portapapeles" Margin="0,5" />
|
||||||
|
|
||||||
|
<GroupBox Header="Notificaciones" Margin="0,10,0,0">
|
||||||
|
<StackPanel Margin="5">
|
||||||
|
<TextBlock Text="Duración de notificaciones (segundos):" />
|
||||||
|
<Slider x:Name="NotificationDurationSlider" Minimum="1" Maximum="10" Value="5"
|
||||||
|
TickFrequency="1" IsSnapToTickEnabled="True" />
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding ElementName=NotificationDurationSlider, Path=Value, StringFormat={}{0} s}" />
|
||||||
|
</StackPanel>
|
||||||
|
</GroupBox>
|
||||||
|
</StackPanel>
|
||||||
|
</TabItem>
|
||||||
|
|
||||||
|
<TabItem Header="Avanzado">
|
||||||
|
<StackPanel Margin="10">
|
||||||
|
<Button Content="Ver registros de error" Click="ViewErrorLogs_Click" Margin="0,5" />
|
||||||
|
<Button Content="Borrar historial" Click="ClearHistory_Click" Margin="0,5" />
|
||||||
|
<Button Content="Restablecer configuración" Click="ResetSettings_Click" Margin="0,5" />
|
||||||
|
</StackPanel>
|
||||||
|
</TabItem>
|
||||||
|
</TabControl>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||||
|
<Button Content="Guardar" Width="80" Click="SaveButton_Click" Margin="0,0,10,0" />
|
||||||
|
<Button Content="Cancelar" Width="80" Click="CancelButton_Click" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
<ResourceDictionary
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
|
||||||
|
<!-- Color Palette -->
|
||||||
|
<Color x:Key="PrimaryColor">#2196F3</Color>
|
||||||
|
<Color x:Key="PrimaryLightColor">#BBDEFB</Color>
|
||||||
|
<Color x:Key="PrimaryDarkColor">#1976D2</Color>
|
||||||
|
<Color x:Key="AccentColor">#FF4081</Color>
|
||||||
|
<Color x:Key="TextPrimaryColor">#212121</Color>
|
||||||
|
<Color x:Key="TextSecondaryColor">#757575</Color>
|
||||||
|
<Color x:Key="DividerColor">#BDBDBD</Color>
|
||||||
|
|
||||||
|
<!-- Brushes -->
|
||||||
|
<SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource PrimaryColor}"/>
|
||||||
|
<SolidColorBrush x:Key="PrimaryLightBrush" Color="{StaticResource PrimaryLightColor}"/>
|
||||||
|
<SolidColorBrush x:Key="PrimaryDarkBrush" Color="{StaticResource PrimaryDarkColor}"/>
|
||||||
|
<SolidColorBrush x:Key="AccentBrush" Color="{StaticResource AccentColor}"/>
|
||||||
|
<SolidColorBrush x:Key="TextPrimaryBrush" Color="{StaticResource TextPrimaryColor}"/>
|
||||||
|
<SolidColorBrush x:Key="TextSecondaryBrush" Color="{StaticResource TextSecondaryColor}"/>
|
||||||
|
<SolidColorBrush x:Key="DividerBrush" Color="{StaticResource DividerColor}"/>
|
||||||
|
|
||||||
|
<!-- Button Styles -->
|
||||||
|
<Style x:Key="DefaultButtonStyle" TargetType="Button">
|
||||||
|
<Setter Property="Background" Value="{StaticResource PrimaryBrush}"/>
|
||||||
|
<Setter Property="Foreground" Value="White"/>
|
||||||
|
<Setter Property="Padding" Value="15,5"/>
|
||||||
|
<Setter Property="BorderThickness" Value="0"/>
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="Button">
|
||||||
|
<Border Background="{TemplateBinding Background}"
|
||||||
|
BorderBrush="{TemplateBinding BorderBrush}"
|
||||||
|
BorderThickness="{TemplateBinding BorderThickness}"
|
||||||
|
CornerRadius="4">
|
||||||
|
<ContentPresenter HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"/>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Style.Triggers>
|
||||||
|
<Trigger Property="IsMouseOver" Value="True">
|
||||||
|
<Setter Property="Background" Value="{StaticResource PrimaryDarkBrush}"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsPressed" Value="True">
|
||||||
|
<Setter Property="Background" Value="{StaticResource PrimaryDarkBrush}"/>
|
||||||
|
<Setter Property="Effect">
|
||||||
|
<Setter.Value>
|
||||||
|
<DropShadowEffect ShadowDepth="0" BlurRadius="10" Color="#40000000"/>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsEnabled" Value="False">
|
||||||
|
<Setter Property="Opacity" Value="0.5"/>
|
||||||
|
</Trigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- Close Button Style -->
|
||||||
|
<Style x:Key="CloseButtonStyle" TargetType="Button">
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
<Setter Property="Foreground" Value="{StaticResource TextSecondaryBrush}"/>
|
||||||
|
<Setter Property="BorderThickness" Value="0"/>
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="Button">
|
||||||
|
<Border Background="{TemplateBinding Background}"
|
||||||
|
CornerRadius="10">
|
||||||
|
<ContentPresenter HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"/>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Style.Triggers>
|
||||||
|
<Trigger Property="IsMouseOver" Value="True">
|
||||||
|
<Setter Property="Background" Value="#20000000"/>
|
||||||
|
<Setter Property="Foreground" Value="{StaticResource AccentBrush}"/>
|
||||||
|
</Trigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
</ResourceDictionary>
|
|
@ -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<UserSettings>(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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
808
gtpask.cs
808
gtpask.cs
|
@ -5,12 +5,10 @@ using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Threading;
|
|
||||||
using LanguageDetection;
|
using LanguageDetection;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Windows.Interop;
|
|
||||||
using libObsidean;
|
using libObsidean;
|
||||||
|
|
||||||
namespace GTPCorrgir
|
namespace GTPCorrgir
|
||||||
|
@ -27,463 +25,521 @@ namespace GTPCorrgir
|
||||||
public ApiKeySection ApiKeys { get; set; }
|
public ApiKeySection ApiKeys { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class gtpask
|
public class gtpask : IDisposable
|
||||||
{
|
{
|
||||||
private readonly string openAiApiKey;
|
private string _openAiApiKey;
|
||||||
private readonly string groqApiKey;
|
private string _groqApiKey;
|
||||||
private readonly string grokApiKey;
|
private string _grokApiKey;
|
||||||
public Logger Log = new Logger();
|
private readonly HttpClient _httpClient;
|
||||||
private Dictionary<string, string> languageMap = new Dictionary<string, string>
|
private bool _disposed;
|
||||||
|
private readonly LanguageDetector _languageDetector;
|
||||||
|
private readonly Obsidean _markdownProcessor;
|
||||||
|
|
||||||
|
public Logger Log { get; }
|
||||||
|
|
||||||
|
private readonly Dictionary<string, string> _languageMap = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
{ "en", "English" },
|
{ "en", "English" },
|
||||||
{ "es", "Spanish" },
|
{ "es", "Spanish" },
|
||||||
{ "it", "Italian" },
|
{ "it", "Italian" },
|
||||||
{ "pt", "Portuguese" }
|
{ "pt", "Portuguese" }
|
||||||
// Agrega más idiomas según sea necesario
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public string IdiomaDetectado;
|
public string IdiomaDetectado { get; private set; }
|
||||||
public string TextoACorregir;
|
public string TextoACorregir { get; set; }
|
||||||
public string TextoCorregido;
|
public string TextoCorregido { get; private set; }
|
||||||
public string TextodeSistema;
|
public string TextodeSistema { get; private set; }
|
||||||
private const bool Simulacion = false;
|
private const bool Simulacion = false;
|
||||||
|
|
||||||
public gtpask()
|
public gtpask()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "appsettings.json");
|
Log = new Logger();
|
||||||
if (File.Exists(configPath))
|
_httpClient = new HttpClient();
|
||||||
{
|
_languageDetector = new LanguageDetector();
|
||||||
string jsonContent = File.ReadAllText(configPath);
|
_languageDetector.AddLanguages("en", "es", "it", "pt");
|
||||||
var settings = JsonConvert.DeserializeObject<ApiSettings>(jsonContent);
|
_markdownProcessor = new Obsidean();
|
||||||
|
|
||||||
openAiApiKey = settings.ApiKeys.OpenAI;
|
LoadApiKeys();
|
||||||
groqApiKey = settings.ApiKeys.Groq;
|
InitializeHttpClient();
|
||||||
grokApiKey = settings.ApiKeys.Grok;
|
_markdownProcessor.LeerPalabrasTecnicas();
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(openAiApiKey) || string.IsNullOrEmpty(groqApiKey) || string.IsNullOrEmpty(grokApiKey))
|
Log.Log("gtpask initialized successfully");
|
||||||
{
|
|
||||||
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.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Log($"Error loading configuration: {ex.Message}");
|
Log.Log($"Error initializing gtpask: {ex.Message}");
|
||||||
|
throw new ApplicationException("Failed to initialize gtpask", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadApiKeys()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "appsettings.json");
|
||||||
|
if (!File.Exists(configPath))
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException("Configuration file (appsettings.json) not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
string jsonContent = File.ReadAllText(configPath);
|
||||||
|
var settings = JsonConvert.DeserializeObject<ApiSettings>(jsonContent);
|
||||||
|
|
||||||
|
_openAiApiKey = settings?.ApiKeys?.OpenAI;
|
||||||
|
_groqApiKey = settings?.ApiKeys?.Groq;
|
||||||
|
_grokApiKey = settings?.ApiKeys?.Grok;
|
||||||
|
|
||||||
|
ValidateApiKeys();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Log($"Error loading API keys: {ex.Message}");
|
||||||
|
throw new ApplicationException("Failed to load API keys", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValidateApiKeys()
|
||||||
|
{
|
||||||
|
var missingKeys = new List<string>();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(_openAiApiKey)) missingKeys.Add("OpenAI");
|
||||||
|
if (string.IsNullOrEmpty(_groqApiKey)) missingKeys.Add("Groq");
|
||||||
|
if (string.IsNullOrEmpty(_grokApiKey)) missingKeys.Add("Grok");
|
||||||
|
|
||||||
|
if (missingKeys.Any())
|
||||||
|
{
|
||||||
|
string missingKeysStr = string.Join(", ", missingKeys);
|
||||||
|
throw new ApplicationException($"Missing API keys: {missingKeysStr}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeHttpClient()
|
||||||
|
{
|
||||||
|
_httpClient.Timeout = TimeSpan.FromSeconds(30);
|
||||||
|
_httpClient.DefaultRequestHeaders.Clear();
|
||||||
|
_httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CorregirTexto()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(TextoACorregir))
|
||||||
|
{
|
||||||
|
Log.Log("No hay texto para corregir");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log.Log("Iniciando proceso de corrección");
|
||||||
|
Log.Log($"Texto original: {TextoACorregir}");
|
||||||
|
|
||||||
|
if (!DetectarIdioma())
|
||||||
|
{
|
||||||
|
throw new ApplicationException("No se pudo detectar el idioma del texto");
|
||||||
|
}
|
||||||
|
|
||||||
|
string textoMarcado = MarcarPalabrasTecnicas();
|
||||||
|
Log.Log($"Texto marcado: {textoMarcado}");
|
||||||
|
|
||||||
|
if (Simulacion)
|
||||||
|
{
|
||||||
|
await SimularCorreccion();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ProcesarTextoConLLM(textoMarcado);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Log($"Texto corregido: {TextoCorregido}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Log($"Error en CorregirTexto: {ex.Message}");
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
int startJson = input.IndexOf('{');
|
||||||
|
int endJson = input.LastIndexOf('}') + 1;
|
||||||
|
|
||||||
|
if (startJson == -1 || endJson == -1 || endJson <= startJson)
|
||||||
|
{
|
||||||
|
Log.Log("Formato JSON inválido en la respuesta");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
string jsonString = input[startJson..endJson];
|
||||||
|
JObject jsonObject = JObject.Parse(jsonString);
|
||||||
|
var firstField = jsonObject.Properties().FirstOrDefault();
|
||||||
|
|
||||||
|
return firstField?.Value?.ToString();
|
||||||
|
}
|
||||||
|
catch (JsonException ex)
|
||||||
|
{
|
||||||
|
Log.Log($"Error al procesar JSON: {ex.Message}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private string CrearMensajeDeSistema()
|
private string CrearMensajeDeSistema()
|
||||||
{
|
{
|
||||||
switch (Opciones.Instance.modo)
|
return Opciones.Instance.modo switch
|
||||||
{
|
{
|
||||||
case Opciones.modoDeUso.Corregir:
|
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\" }.";
|
"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\" }.";
|
Opciones.modoDeUso.Ortografia =>
|
||||||
default:
|
"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\" }.",
|
||||||
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\" }.";
|
|
||||||
}
|
_ => "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)
|
private string CrearMensajeDeUsuario(string texto) =>
|
||||||
|
Opciones.Instance.modo switch
|
||||||
{
|
{
|
||||||
switch (Opciones.Instance.modo)
|
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}\"",
|
||||||
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:
|
Opciones.modoDeUso.Ortografia =>
|
||||||
return texto;
|
$"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}\"",
|
||||||
|
|
||||||
private string DetectarIdioma(string TextoACorregir)
|
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}\"",
|
||||||
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"];
|
|
||||||
|
|
||||||
LanguageDetector detector = new LanguageDetector();
|
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}\"",
|
||||||
detector.AddLanguages("en", "es", "it");
|
|
||||||
string detectedLanguageCode = detector.Detect(TextoACorregir);
|
|
||||||
|
|
||||||
string detectedLanguageName = languageMap.ContainsKey(detectedLanguageCode)
|
|
||||||
? languageMap[detectedLanguageCode]
|
|
||||||
: "Desconocido";
|
|
||||||
|
|
||||||
return detectedLanguageName;
|
|
||||||
}
|
|
||||||
private bool DetectarIdioma()
|
|
||||||
{
|
|
||||||
if (TextoACorregir.Length>0)
|
|
||||||
{
|
|
||||||
IdiomaDetectado = DetectarIdioma(TextoACorregir);
|
|
||||||
Log.Log("Idioma: " + IdiomaDetectado);
|
|
||||||
if(IdiomaDetectado != "Desconocido")
|
|
||||||
return true;
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
return "No valid JSON found in the input string.";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extrae solo la parte JSON de la entrada
|
|
||||||
string jsonString = input.Substring(startJson, endJson - startJson);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Parsea el JSON
|
|
||||||
JObject jsonObject = JObject.Parse(jsonString);
|
|
||||||
|
|
||||||
// Obtiene el primer campo independientemente del nombre de la clave
|
|
||||||
var firstField = jsonObject.Properties().FirstOrDefault();
|
|
||||||
if (firstField != null)
|
|
||||||
{
|
|
||||||
return firstField.Value.ToString(); // Devuelve el valor del primer campo
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return "JSON does not contain any data.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (JsonException jsonEx)
|
|
||||||
{
|
|
||||||
// Maneja errores de parseo de JSON
|
|
||||||
return "Error parsing JSON: " + jsonEx.Message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static string ExtractCorrectedText(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.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extrae solo la parte JSON de la entrada
|
|
||||||
string jsonString = input.Substring(startJson, endJson - startJson);
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine("An error occurred: " + ex.Message);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
_ => texto
|
||||||
|
};
|
||||||
|
|
||||||
private async Task<string> CallGrokApi(string input)
|
private async Task<string> CallGrokApi(string input)
|
||||||
{
|
{
|
||||||
using var httpClient = new HttpClient();
|
try
|
||||||
string Mensaje_Sistema = CrearMensajeDeSistema();
|
{
|
||||||
string Mensaje_Usuario = CrearMensajeDeUsuario(input);
|
_httpClient.DefaultRequestHeaders.Clear();
|
||||||
|
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_grokApiKey}");
|
||||||
|
|
||||||
// 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
|
var requestData = new
|
||||||
{
|
{
|
||||||
messages = new[]
|
messages = new[]
|
||||||
{
|
{
|
||||||
new { role = "system", content = Mensaje_Sistema },
|
new { role = "system", content = CrearMensajeDeSistema() },
|
||||||
new { role = "user", content = Mensaje_Usuario }
|
new { role = "user", content = CrearMensajeDeUsuario(input) }
|
||||||
},
|
},
|
||||||
model = "grok-beta",
|
model = "grok-beta",
|
||||||
stream = false,
|
stream = false,
|
||||||
temperature = 0
|
temperature = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return await EnviarSolicitudLLM("https://api.x.ai/v1/chat/completions", requestData);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Log($"Error en llamada a Grok API: {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> CallOllamaApi(string input)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var requestData = new
|
||||||
|
{
|
||||||
|
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<string> CallOpenAiApi(string input)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_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<string> CallGroqAiApi(string input)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_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<string> EnviarSolicitudLLM(string endpoint, object requestData)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
var content = new StringContent(
|
var content = new StringContent(
|
||||||
JsonConvert.SerializeObject(requestData),
|
JsonConvert.SerializeObject(requestData),
|
||||||
Encoding.UTF8,
|
Encoding.UTF8,
|
||||||
"application/json"
|
"application/json"
|
||||||
);
|
);
|
||||||
|
|
||||||
try
|
Log.Log($"Enviando solicitud a {endpoint}");
|
||||||
{
|
Log.Log($"Datos de solicitud: {JsonConvert.SerializeObject(requestData)}");
|
||||||
Log.Log("Ask Grok: " + JsonConvert.SerializeObject(requestData));
|
|
||||||
|
|
||||||
// URL corregida para coincidir con el ejemplo
|
using var response = await _httpClient.PostAsync(endpoint, content);
|
||||||
var response = await httpClient.PostAsync("https://api.x.ai/v1/chat/completions", content);
|
|
||||||
response.EnsureSuccessStatusCode();
|
|
||||||
|
|
||||||
var jsonResponse = await response.Content.ReadAsStringAsync();
|
var responseContent = await response.Content.ReadAsStringAsync();
|
||||||
Log.Log("Grok Response: " + jsonResponse); // Logging la respuesta para debug
|
Log.Log($"Respuesta recibida: {responseContent}");
|
||||||
|
|
||||||
dynamic data = JsonConvert.DeserializeObject(jsonResponse);
|
if (!response.IsSuccessStatusCode)
|
||||||
return data.choices[0].message.content;
|
|
||||||
}
|
|
||||||
catch (HttpRequestException e)
|
|
||||||
{
|
{
|
||||||
Log.Log($"Error en la solicitud HTTP: {e.Message}");
|
throw new HttpRequestException(
|
||||||
Console.WriteLine($"Error making HTTP request: {e.Message}");
|
$"Error en la solicitud HTTP: {response.StatusCode} - {responseContent}"
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var data = JsonConvert.DeserializeObject<dynamic>(responseContent);
|
||||||
|
|
||||||
private async Task<string> CallOllamaApi(string input)
|
// Manejar diferentes formatos de respuesta según el LLM
|
||||||
|
if (endpoint.Contains("ollama"))
|
||||||
{
|
{
|
||||||
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)
|
if (data.done == true && data.message != null)
|
||||||
{
|
{
|
||||||
return data.message.content;
|
return data.message.content;
|
||||||
}
|
}
|
||||||
return "No hubo respuesta del asistente o la sesión aún no ha concluido.";
|
throw new ApplicationException("Formato de respuesta de Ollama inválido");
|
||||||
}
|
}
|
||||||
catch (HttpRequestException e)
|
else // OpenAI, Groq, Grok
|
||||||
{
|
{
|
||||||
// Captura errores en la solicitud HTTP, como problemas de red o respuestas de error HTTP.
|
if (data.choices != null && data.choices.Count > 0)
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> 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;
|
return data.choices[0].message.content;
|
||||||
}
|
}
|
||||||
catch (HttpRequestException e)
|
throw new ApplicationException("No se encontró contenido en la respuesta del LLM");
|
||||||
{
|
|
||||||
// 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)
|
}
|
||||||
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// Captura cualquier otro error
|
Log.Log($"Error al enviar solicitud a {endpoint}: {ex.Message}");
|
||||||
Console.WriteLine($"An error occurred: {e.Message}");
|
throw;
|
||||||
return null;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> CallGroqAiApi(string input)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
var httpClient = new HttpClient();
|
if (!_disposed)
|
||||||
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",
|
if (disposing)
|
||||||
messages = new[]
|
|
||||||
{
|
{
|
||||||
new { role = "system", content = Mensaje_Sistema },
|
_httpClient?.Dispose();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,13 +1,63 @@
|
||||||
<Window x:Class="GTPCorrgir.notificacion" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
<Window x:Class="GTPCorrgir.notificacion" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="100" Width="300" Topmost="True"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="100" Width="300" Topmost="True"
|
||||||
ShowInTaskbar="False" WindowStyle="None" AllowsTransparency="True" Background="Transparent">
|
ShowInTaskbar="False" WindowStyle="None" AllowsTransparency="True" Background="Transparent">
|
||||||
|
<Window.Resources>
|
||||||
|
<!-- Animaciones -->
|
||||||
|
<Storyboard x:Key="FadeIn">
|
||||||
|
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.0" To="1.0" Duration="0:0:0.3" />
|
||||||
|
</Storyboard>
|
||||||
|
<Storyboard x:Key="FadeOut">
|
||||||
|
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1.0" To="0.0" Duration="0:0:0.3" />
|
||||||
|
</Storyboard>
|
||||||
|
|
||||||
|
<!-- Estilo del botón de cerrar -->
|
||||||
|
<Style x:Key="CloseButtonStyle" TargetType="Button">
|
||||||
|
<Setter Property="Background" Value="Transparent" />
|
||||||
|
<Setter Property="Foreground" Value="#757575" />
|
||||||
|
<Setter Property="BorderThickness" Value="0" />
|
||||||
|
<Setter Property="Width" Value="20" />
|
||||||
|
<Setter Property="Height" Value="20" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="Button">
|
||||||
|
<Border x:Name="border" Background="{TemplateBinding Background}"
|
||||||
|
BorderBrush="{TemplateBinding BorderBrush}"
|
||||||
|
BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="10">
|
||||||
|
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
|
</Border>
|
||||||
|
<ControlTemplate.Triggers>
|
||||||
|
<Trigger Property="IsMouseOver" Value="True">
|
||||||
|
<Setter TargetName="border" Property="Background" Value="#20000000" />
|
||||||
|
<Setter Property="Foreground" Value="#FF4081" />
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsPressed" Value="True">
|
||||||
|
<Setter TargetName="border" Property="Background" Value="#40000000" />
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</Window.Resources>
|
||||||
|
|
||||||
<Border CornerRadius="10" Background="#AAF0F0F0">
|
<Border CornerRadius="10" Background="#AAF0F0F0">
|
||||||
<StackPanel>
|
<Grid>
|
||||||
<TextBlock x:Name="TitleText" FontSize="16" FontWeight="Bold" Margin="10" />
|
<Grid.RowDefinitions>
|
||||||
<TextBlock x:Name="MessageText" FontSize="14" Margin="10" />
|
<RowDefinition Height="Auto" />
|
||||||
<Button Content="Cerrar" Width="75" Height="20" Margin="0" Click="CloseButton_Click"
|
<RowDefinition Height="*" />
|
||||||
HorizontalAlignment="Right" />
|
<RowDefinition Height="Auto" />
|
||||||
</StackPanel>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Grid Grid.Row="0">
|
||||||
|
<TextBlock x:Name="TitleText" FontSize="16" FontWeight="Bold" Margin="10,10,30,5" />
|
||||||
|
|
||||||
|
<Button Content="×" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,5,0"
|
||||||
|
Style="{StaticResource CloseButtonStyle}" Click="CloseButton_Click" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<TextBlock x:Name="MessageText" Grid.Row="1" FontSize="14" Margin="10,0,10,5" TextWrapping="Wrap" />
|
||||||
|
|
||||||
|
<ProgressBar x:Name="AutoCloseProgress" Grid.Row="2" Height="2" Margin="10,0,10,5" Foreground="#FF4081" />
|
||||||
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
</Window>
|
</Window>
|
||||||
|
|
||||||
|
|
|
@ -1,41 +1,114 @@
|
||||||
using System.Windows;
|
using System;
|
||||||
using Application = System.Windows.Application;
|
using System.Windows;
|
||||||
|
using System.Windows.Media.Animation;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
namespace GTPCorrgir
|
namespace GTPCorrgir
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Interaction logic for notificacion.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class notificacion : Window
|
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()
|
public notificacion()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
PositionWindow();
|
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()
|
private void PositionWindow()
|
||||||
{
|
{
|
||||||
// Obtener la posición del cursor
|
|
||||||
var cursorPosition = System.Windows.Forms.Cursor.Position;
|
var cursorPosition = System.Windows.Forms.Cursor.Position;
|
||||||
|
|
||||||
// Determinar en qué pantalla está el cursor
|
|
||||||
var screen = System.Windows.Forms.Screen.FromPoint(cursorPosition);
|
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 - 20;
|
||||||
this.Left = screen.WorkingArea.Right - this.Width;
|
this.Top = screen.WorkingArea.Bottom - this.Height - 20;
|
||||||
this.Top = screen.WorkingArea.Bottom - this.Height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateNotification(string title, string message)
|
public void UpdateNotification(string title, string message)
|
||||||
{
|
{
|
||||||
TitleText.Text = title;
|
TitleText.Text = title;
|
||||||
MessageText.Text = message;
|
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)
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue