Compare commits
2 Commits
f20ee01e22
...
c047fb2c01
Author | SHA1 | Date |
---|---|---|
Miguel | c047fb2c01 | |
Miguel | 2caf2b96f5 |
226
App.xaml.cs
226
App.xaml.cs
|
@ -2,10 +2,9 @@
|
|||
using System.Data;
|
||||
using System.Windows;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms; // Necesitas agregar una referencia a System.Windows.Forms
|
||||
using System.Windows.Forms;
|
||||
using Application = System.Windows.Application;
|
||||
using System.Diagnostics; // Asegúrate de incluir esta directiva para usar Stopwatch
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
@ -13,11 +12,6 @@ using System.Runtime.InteropServices;
|
|||
|
||||
namespace GTPCorrgir
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
///
|
||||
|
||||
public partial class App : Application
|
||||
{
|
||||
gtpask GTP = new gtpask();
|
||||
|
@ -26,128 +20,199 @@ namespace GTPCorrgir
|
|||
bool CorreccionFinalizada = false;
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
private notificacion notificationWindow;
|
||||
private readonly int TimeoutSeconds = 60; // Timeout máximo para esperar la respuesta
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
|
||||
KeyboardHelper pasteLogic = new KeyboardHelper();
|
||||
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
base.OnStartup(e);
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
pasteLogic.SaveCurrentWindow();
|
||||
|
||||
if (System.Windows.Clipboard.ContainsText())
|
||||
try
|
||||
{
|
||||
GTP.TextoACorregir = System.Windows.Clipboard.GetText();
|
||||
pasteLogic.SaveCurrentWindow();
|
||||
|
||||
if (System.Windows.Clipboard.ContainsText())
|
||||
{
|
||||
GTP.TextoACorregir = System.Windows.Clipboard.GetText();
|
||||
}
|
||||
|
||||
if (Opciones.Instance.modo == Opciones.modoDeUso.Corregir ||
|
||||
Opciones.Instance.modo == Opciones.modoDeUso.Ortografia)
|
||||
{
|
||||
GTP.Log.Log("Iniciando proceso de corrección");
|
||||
stopwatch.Start();
|
||||
|
||||
ShowCustomNotification("Espera", $"Corrigiendo texto con {Opciones.Instance.nombreDeLLM()}...");
|
||||
IniciarCronometro();
|
||||
|
||||
// Ejecuta la tarea de corrección con timeout
|
||||
_ = ProcessCorreccionWithTimeout();
|
||||
}
|
||||
else if (Opciones.Instance.modo == Opciones.modoDeUso.Chat)
|
||||
{
|
||||
var chatWindows = new Chat(GTP);
|
||||
chatWindows.Show();
|
||||
}
|
||||
}
|
||||
|
||||
if (Opciones.Instance.modo == Opciones.modoDeUso.Corregir || Opciones.Instance.modo == Opciones.modoDeUso.Ortografia)
|
||||
catch (Exception ex)
|
||||
{
|
||||
GTP.Log.Log($"Error en OnStartup: {ex.Message}");
|
||||
GTP.Log.Log($"StackTrace: {ex.StackTrace}");
|
||||
ShowCustomNotification("Error", "Se produjo un error al iniciar la aplicación");
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
stopwatch.Start();
|
||||
private async Task ProcessCorreccionWithTimeout()
|
||||
{
|
||||
try
|
||||
{
|
||||
using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(TimeoutSeconds));
|
||||
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(
|
||||
timeoutCts.Token, _cancellationTokenSource.Token);
|
||||
|
||||
// Muestra notificación inicial y comienza el cronómetro en el hilo de la UI
|
||||
ShowCustomNotification("Espera", $"Corrigiendo texto con .{Opciones.Instance.nombreDeLLM()} ..");
|
||||
IniciarCronometro();
|
||||
|
||||
|
||||
// Ejecuta la tarea de corrección en un hilo secundario
|
||||
Task.Run(async () =>
|
||||
var correccionTask = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
GTP.Log.Log("Iniciando corrección de texto");
|
||||
await GTP.CorregirTexto();
|
||||
GTP.Log.Log("Corrección de texto completada");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error durante la corrección de texto: " + ex.Message);
|
||||
GTP.Log.Log($"Error durante la corrección: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}, linkedCts.Token);
|
||||
|
||||
await correccionTask;
|
||||
|
||||
await Dispatcher.InvokeAsync(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
GTP.Log.Log("Procesando resultado de la corrección");
|
||||
CorreccionFinalizada = true;
|
||||
DetenerCronometro();
|
||||
|
||||
if (GTP.TextoCorregido != null)
|
||||
{
|
||||
GTP.Log.Log("Copiando texto corregido al portapapeles");
|
||||
System.Windows.Clipboard.SetText(GTP.TextoCorregido);
|
||||
ShowCustomNotification("Se puede pegar",
|
||||
$"Corrección en: {Math.Round(stopwatch.ElapsedMilliseconds / 1000.0, 1)} s");
|
||||
|
||||
if (Opciones.Instance.modo == Opciones.modoDeUso.Corregir)
|
||||
{
|
||||
GTP.Log.Log("Mostrando ventana de resultado");
|
||||
var resultadoWindow = new VentanaResultado(GTP.TextoCorregido);
|
||||
resultadoWindow.Show();
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
else if (Opciones.Instance.modo == Opciones.modoDeUso.Ortografia)
|
||||
{
|
||||
GTP.Log.Log("Ejecutando pegado automático");
|
||||
pasteLogic.RestoreAndSimulatePaste();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GTP.Log.Log("Error: TextoCorregido es null");
|
||||
ShowCustomNotification("Error", "No se pudo obtener el texto corregido");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
GTP.Log.Log($"Error en el procesamiento final: {ex.Message}");
|
||||
ShowCustomNotification("Error", "Error al procesar el resultado");
|
||||
}
|
||||
finally
|
||||
{
|
||||
await Dispatcher.Invoke(async () => // Nota el 'async' aquí para permitir 'await'
|
||||
{
|
||||
CorreccionFinalizada = true;
|
||||
DetenerCronometro();
|
||||
if (GTP.TextoCorregido != null)
|
||||
{
|
||||
System.Windows.Clipboard.SetText(GTP.TextoCorregido);
|
||||
ShowCustomNotification("Se puede pegar", $"Corrección en : {Math.Round(stopwatch.ElapsedMilliseconds / 1000.0, 1)} s");
|
||||
|
||||
if (Opciones.Instance.modo == Opciones.modoDeUso.Corregir)
|
||||
{
|
||||
var resultadoWindow = new VentanaResultado(GTP.TextoCorregido);
|
||||
resultadoWindow.Show();
|
||||
await Task.Delay(1000); // Asíncrono espera 5 segundos
|
||||
}
|
||||
else if (Opciones.Instance.modo == Opciones.modoDeUso.Ortografia)
|
||||
pasteLogic.RestoreAndSimulatePaste();
|
||||
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
MostrarNotificacion("Error", "No se pudo corregir el texto.");
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
});
|
||||
GTP.Log.Log("Cerrando aplicación");
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
});
|
||||
} else if (Opciones.Instance.modo == Opciones.modoDeUso.Chat)
|
||||
{
|
||||
var chatWindows = new Chat(GTP);
|
||||
chatWindows.Show();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
GTP.Log.Log("Operación cancelada por timeout");
|
||||
await Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
ShowCustomNotification("Error", "La operación excedió el tiempo límite");
|
||||
Application.Current.Shutdown();
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
GTP.Log.Log($"Error no controlado: {ex.Message}");
|
||||
await Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
ShowCustomNotification("Error", "Se produjo un error inesperado");
|
||||
Application.Current.Shutdown();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnExit(ExitEventArgs e)
|
||||
{
|
||||
_cancellationTokenSource?.Cancel();
|
||||
_cancellationTokenSource?.Dispose();
|
||||
base.OnExit(e);
|
||||
}
|
||||
|
||||
private void ShowCustomNotification(string title, string message)
|
||||
{
|
||||
if (notificationWindow == null)
|
||||
try
|
||||
{
|
||||
notificationWindow = new notificacion();
|
||||
notificationWindow.Show();
|
||||
GTP.Log.Log($"Mostrando notificación: {title} - {message}");
|
||||
if (notificationWindow == null)
|
||||
{
|
||||
notificationWindow = new notificacion();
|
||||
notificationWindow.Show();
|
||||
}
|
||||
notificationWindow.UpdateNotification(title, message);
|
||||
}
|
||||
|
||||
notificationWindow.UpdateNotification(title, message);
|
||||
}
|
||||
|
||||
private void MostrarNotificacion(string titulo, string mensaje)
|
||||
{
|
||||
notificacion = new NotifyIcon
|
||||
catch (Exception ex)
|
||||
{
|
||||
Icon = SystemIcons.Information,
|
||||
BalloonTipTitle = titulo,
|
||||
BalloonTipText = mensaje,
|
||||
Visible = true
|
||||
};
|
||||
notificacion.ShowBalloonTip(1000);
|
||||
GTP.Log.Log($"Error al mostrar notificación: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void IniciarCronometro()
|
||||
{
|
||||
timer = new System.Windows.Forms.Timer();
|
||||
timer.Interval = 100; // 1000 milisegundos (1 segundo)
|
||||
timer.Interval = 100;
|
||||
timer.Tick += ActualizarCronometro;
|
||||
timer.Start();
|
||||
GTP.Log.Log("Cronómetro iniciado");
|
||||
}
|
||||
|
||||
private void ActualizarCronometro(object sender, EventArgs e)
|
||||
{
|
||||
if (!CorreccionFinalizada) {
|
||||
//notificacion.BalloonTipText = $"Texto en {GTP.IdiomaDetectado} pasados: {Math.Round(stopwatch.ElapsedMilliseconds/1000.0,1)} s";
|
||||
//notificacion.ShowBalloonTip(1000);
|
||||
ShowCustomNotification($"{Opciones.Instance.nombreDeLLM()} Trabajando..", $"Texto en {GTP.IdiomaDetectado} pasados: {Math.Round(stopwatch.ElapsedMilliseconds / 1000.0, 1)} s");
|
||||
if (!CorreccionFinalizada)
|
||||
{
|
||||
ShowCustomNotification(
|
||||
$"{Opciones.Instance.nombreDeLLM()} Trabajando..",
|
||||
$"Texto en {GTP.IdiomaDetectado} pasados: {Math.Round(stopwatch.ElapsedMilliseconds / 1000.0, 1)} s"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void DetenerCronometro()
|
||||
{
|
||||
timer.Stop();
|
||||
timer.Dispose();
|
||||
if (timer != null)
|
||||
{
|
||||
timer.Stop();
|
||||
timer.Dispose();
|
||||
GTP.Log.Log("Cronómetro detenido");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class KeyboardHelper
|
||||
{
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
|
@ -182,7 +247,4 @@ namespace GTPCorrgir
|
|||
keybd_event((byte)VK_CONTROL, 0x9d, KEYEVENTF_KEYUP, UIntPtr.Zero); // Ctrl Release
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
60
Chat.xaml
60
Chat.xaml
|
@ -1,62 +1,62 @@
|
|||
<Window
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/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"
|
||||
Title="Chat with OpenAI" Height="300" Width="300"
|
||||
ResizeMode="CanResizeWithGrip" WindowStyle="None"
|
||||
Background="Transparent" AllowsTransparency="True"
|
||||
MouseEnter="Window_MouseEnter" MouseLeave="Window_MouseLeave" KeyDown="Window_KeyDown"
|
||||
Opacity="0.8" av:DesignHeight="320.439" av:DesignWidth="609.769">
|
||||
xmlns:av="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="av"
|
||||
x:Class="GTPCorrgir.Chat" Title="Chat with OpenAI" Height="300" Width="300" ResizeMode="CanResizeWithGrip"
|
||||
WindowStyle="None" Background="Transparent" AllowsTransparency="True" MouseEnter="Window_MouseEnter"
|
||||
MouseLeave="Window_MouseLeave" KeyDown="Window_KeyDown" Opacity="0.8" av:DesignHeight="320.439"
|
||||
av:DesignWidth="609.769">
|
||||
<Window.Resources>
|
||||
<md:Markdown x:Key="MarkdownConverter" />
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<!-- Model Selector con altura automática -->
|
||||
<RowDefinition Height="2*"/>
|
||||
<!-- Área de Respuesta con 2/3 del espacio disponible -->
|
||||
<RowDefinition Height="*"/>
|
||||
<!-- Área de Pregunta con 1/3 del espacio disponible -->
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="2*" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Selector del Modelo -->
|
||||
<!-- Barra superior con controles -->
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Selector de modelo LLM -->
|
||||
<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 -->
|
||||
<Border Background="#444" Height="20" Width="20" Grid.Column="1" Margin="10,0,10,0"
|
||||
MouseLeftButtonDown="Border_MouseLeftButtonDown" Cursor="SizeAll" ToolTip="Mover ventana">
|
||||
<TextBlock Text="☰" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White"/>
|
||||
<Border Background="#444" Height="20" Width="20" Grid.Column="2" Margin="5,0,10,0"
|
||||
MouseLeftButtonDown="Border_MouseLeftButtonDown" Cursor="SizeAll" ToolTip="Mover ventana">
|
||||
<TextBlock Text="☰" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" />
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
|
||||
<!-- Área de Respuesta -->
|
||||
<Grid Grid.Row="1" Margin="1">
|
||||
<RichTextBox Name="responseArea" IsReadOnly="True" Grid.Row="1">
|
||||
<RichTextBox Name="responseArea" IsReadOnly="True">
|
||||
<RichTextBox.Resources>
|
||||
<md:Markdown x:Key="Markdown" />
|
||||
</RichTextBox.Resources>
|
||||
</RichTextBox>
|
||||
<Button x:Name="clearButton" Content="Limpiar" Width="40" Height="24"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0" Click="clearButton_Click" />
|
||||
<Button x:Name="clearButton" Content="Limpiar" Width="40" Height="24" HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom" Margin="0" Click="clearButton_Click" />
|
||||
</Grid>
|
||||
|
||||
<!-- Área de Pregunta con Botón Superpuesto -->
|
||||
<!-- Área de Pregunta con Botón -->
|
||||
<Grid Grid.Row="2" Margin="1">
|
||||
<TextBox x:Name="questionArea" Padding="10"
|
||||
VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" Background="White" PreviewKeyDown="QuestionArea_PreviewKeyDown"/>
|
||||
<Button x:Name="sendButton" Content="Enviar" Width="40" Height="24"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0" Click="SendButton_Click"/>
|
||||
<TextBox x:Name="questionArea" Padding="10" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap"
|
||||
Background="White" PreviewKeyDown="QuestionArea_PreviewKeyDown" />
|
||||
<Button x:Name="sendButton" Content="Enviar" Width="40" Height="24" HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom" Margin="0" Click="SendButton_Click" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
</Window>
|
211
Chat.xaml.cs
211
Chat.xaml.cs
|
@ -15,58 +15,151 @@ using System.Windows.Media.Imaging;
|
|||
using System.Windows.Shapes;
|
||||
using static GTPCorrgir.Opciones;
|
||||
using static System.Net.WebRequestMethods;
|
||||
using Brushes = System.Windows.Media.Brushes;
|
||||
using Color = System.Windows.Media.Color;
|
||||
using ComboBox = System.Windows.Controls.ComboBox;
|
||||
using Cursors = System.Windows.Input.Cursors;
|
||||
using FontFamily = System.Windows.Media.FontFamily;
|
||||
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
|
||||
using MouseEventArgs = System.Windows.Input.MouseEventArgs;
|
||||
using Timer = System.Windows.Forms.Timer;
|
||||
|
||||
namespace GTPCorrgir
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for Chat.xaml
|
||||
/// </summary>
|
||||
public partial class Chat : Window
|
||||
{
|
||||
gtpask AI_API;
|
||||
string respuestas;
|
||||
private Timer opacityTimer;
|
||||
private bool isMouseOver = false;
|
||||
private const double OPACITY_ACTIVE = 1.0;
|
||||
private const double OPACITY_INACTIVE = 0.2;
|
||||
private const int OPACITY_DELAY_MS = 3000; // 10 segundos
|
||||
|
||||
public Chat(gtpask GTP)
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializeOpacityTimer();
|
||||
PositionWindow();
|
||||
// Inicializar componentes de la UI, por ejemplo, llenar el ComboBox
|
||||
|
||||
// Inicializar componentes de la UI
|
||||
AI_API = GTP;
|
||||
questionArea.Text = ""; //GTP.TextoACorregir;
|
||||
questionArea.Text = "";
|
||||
respuestas = "";
|
||||
|
||||
this.Opacity = OPACITY_ACTIVE;
|
||||
|
||||
InitializeModelSelector();
|
||||
}
|
||||
|
||||
private void InitializeOpacityTimer()
|
||||
{
|
||||
opacityTimer = new Timer();
|
||||
opacityTimer.Interval = OPACITY_DELAY_MS;
|
||||
opacityTimer.Tick += (s, e) =>
|
||||
{
|
||||
if (!isMouseOver)
|
||||
{
|
||||
this.Dispatcher.Invoke(() =>
|
||||
{
|
||||
this.Opacity = OPACITY_INACTIVE;
|
||||
});
|
||||
}
|
||||
opacityTimer.Stop();
|
||||
};
|
||||
}
|
||||
|
||||
private void InitializeModelSelector()
|
||||
{
|
||||
foreach (KeyValuePair<LLM_a_Usar, string> kvp in Opciones.Instance.nombreLLM)
|
||||
{
|
||||
ComboBoxItem item = new ComboBoxItem();
|
||||
item.Content = kvp.Value; // El texto que se mostrará
|
||||
item.Tag = kvp.Key; // Guarda el valor enum en el Tag para acceso posterior
|
||||
item.Content = kvp.Value;
|
||||
item.Tag = kvp.Key;
|
||||
modelSelector.Items.Add(item);
|
||||
// Verifica si este ítem debe ser el seleccionado
|
||||
|
||||
if (kvp.Key == Opciones.Instance.LLM)
|
||||
{
|
||||
modelSelector.SelectedItem = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SettingsButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var settingsWindow = new SettingsWindow
|
||||
{
|
||||
Owner = this,
|
||||
WindowStartupLocation = WindowStartupLocation.CenterOwner
|
||||
};
|
||||
|
||||
if (settingsWindow.ShowDialog() == true)
|
||||
{
|
||||
// Aplicar cambios de configuración
|
||||
ApplySettings();
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplySettings()
|
||||
{
|
||||
var settings = UserSettings.Instance;
|
||||
|
||||
// Aplicar opacidad
|
||||
opacityTimer.Stop();
|
||||
opacityTimer.Interval = ((int)TimeSpan.FromMilliseconds(settings.Appearance.OpacityDelay).TotalMilliseconds);
|
||||
|
||||
// Aplicar fuente
|
||||
questionArea.FontFamily = new FontFamily(settings.Appearance.FontFamily);
|
||||
questionArea.FontSize = settings.Appearance.FontSize;
|
||||
responseArea.FontFamily = new FontFamily(settings.Appearance.FontFamily);
|
||||
responseArea.FontSize = settings.Appearance.FontSize;
|
||||
|
||||
// Aplicar tema
|
||||
if (settings.Appearance.Theme == "Dark")
|
||||
{
|
||||
// Aplicar tema oscuro
|
||||
this.Background = new SolidColorBrush(Color.FromArgb(200, 30, 30, 30));
|
||||
responseArea.Background = new SolidColorBrush(Color.FromArgb(255, 40, 40, 40));
|
||||
responseArea.Foreground = Brushes.White;
|
||||
questionArea.Background = new SolidColorBrush(Color.FromArgb(255, 50, 50, 50));
|
||||
questionArea.Foreground = Brushes.White;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Aplicar tema claro
|
||||
this.Background = new SolidColorBrush(Color.FromArgb(200, 240, 240, 240));
|
||||
responseArea.Background = Brushes.White;
|
||||
responseArea.Foreground = Brushes.Black;
|
||||
questionArea.Background = Brushes.White;
|
||||
questionArea.Foreground = Brushes.Black;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSourceInitialized(EventArgs e)
|
||||
{
|
||||
base.OnSourceInitialized(e);
|
||||
ApplySettings(); // Aplicar configuración inicial
|
||||
}
|
||||
|
||||
private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
// Iniciar movimiento de la ventana si se presiona el botón izquierdo del ratón
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
this.DragMove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void Window_MouseEnter(object sender, MouseEventArgs e)
|
||||
{
|
||||
// Hacer la ventana opaca cuando el ratón esté sobre ella
|
||||
this.Opacity = 1.0;
|
||||
isMouseOver = true;
|
||||
opacityTimer.Stop();
|
||||
this.Opacity = OPACITY_ACTIVE;
|
||||
}
|
||||
|
||||
private void Window_MouseLeave(object sender, MouseEventArgs e)
|
||||
{
|
||||
isMouseOver = false;
|
||||
opacityTimer.Start();
|
||||
}
|
||||
|
||||
private void Window_KeyDown(object sender, KeyEventArgs e)
|
||||
|
@ -82,87 +175,71 @@ namespace GTPCorrgir
|
|||
if (e.Key == Key.Enter && !e.KeyboardDevice.Modifiers.HasFlag(ModifierKeys.Shift))
|
||||
{
|
||||
SendButton_Click(this, new RoutedEventArgs());
|
||||
e.Handled = true; // Prevenir el salto de línea en el TextBox
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_MouseLeave(object sender, MouseEventArgs e)
|
||||
private async void SendButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Hacer la ventana transparente cuando el ratón no esté sobre ella
|
||||
this.Opacity = 0.2; // Ajusta este valor a tu preferencia
|
||||
}
|
||||
|
||||
private void SendButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Aquí lógica para enviar pregunta y recibir respuesta de OpenAI
|
||||
|
||||
AI_API.TextoACorregir = questionArea.Text;
|
||||
if (AI_API.TextoACorregir.Length > 3)
|
||||
{
|
||||
sendButton.IsEnabled = false; // Deshabilitar el botón de envío
|
||||
Mouse.OverrideCursor = Cursors.Wait; // Cambiar el cursor a espera
|
||||
|
||||
Task.Run(async () =>
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
await AI_API.CorregirTexto();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error durante la corrección de texto: " + ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Dispatcher.Invoke(async () => // Nota el 'async' aquí para permitir 'await'
|
||||
{
|
||||
if (AI_API.TextoCorregido != null)
|
||||
{
|
||||
System.Windows.Clipboard.SetText(AI_API.TextoCorregido);
|
||||
//responseArea. .Text += AI_API.TextoCorregido + "\r\n";
|
||||
AddMarkdownContent(AI_API.TextoCorregido + "\r\n");
|
||||
sendButton.IsEnabled = false;
|
||||
Mouse.OverrideCursor = Cursors.Wait;
|
||||
|
||||
Mouse.OverrideCursor = null; // Restaurar el cursor normal
|
||||
sendButton.IsEnabled = true; // Habilitar el botón de envío
|
||||
}
|
||||
});
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await AI_API.CorregirTexto();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error durante la corrección de texto: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
});
|
||||
|
||||
if (AI_API.TextoCorregido != null)
|
||||
{
|
||||
System.Windows.Clipboard.SetText(AI_API.TextoCorregido);
|
||||
AddMarkdownContent(AI_API.TextoCorregido + "\r\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AddMarkdownContent($"Error: {ex.Message}\r\n");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Mouse.OverrideCursor = null;
|
||||
sendButton.IsEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddMarkdownContent(string markdownText)
|
||||
{
|
||||
// Transforma el texto Markdown a un FlowDocument
|
||||
var markdown = new Markdown.Xaml.Markdown();
|
||||
|
||||
respuestas += markdownText + "\r\n";
|
||||
|
||||
responseArea.Document = markdown.Transform(respuestas);
|
||||
|
||||
}
|
||||
|
||||
private void PositionWindow()
|
||||
{
|
||||
// Obtener la posición del cursor
|
||||
var cursorPosition = System.Windows.Forms.Cursor.Position;
|
||||
|
||||
// Determinar en qué pantalla está el cursor
|
||||
var screen = Screen.FromPoint(cursorPosition);
|
||||
|
||||
// Calcular la ubicación central en la pantalla actual
|
||||
this.Left = (screen.WorkingArea.Width - this.Width) / 2 + screen.WorkingArea.Left;
|
||||
this.Top = (screen.WorkingArea.Height - this.Height) / 2 + screen.WorkingArea.Top;
|
||||
}
|
||||
|
||||
private void CambiarModelo(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
ComboBox comboBox = sender as ComboBox;
|
||||
ComboBoxItem selectedItem = comboBox.SelectedItem as ComboBoxItem;
|
||||
if (selectedItem != null)
|
||||
if (sender is ComboBox comboBox && comboBox.SelectedItem is ComboBoxItem selectedItem)
|
||||
{
|
||||
LLM_a_Usar selectedEnum = (LLM_a_Usar)selectedItem.Tag;
|
||||
Opciones.Instance.LLM = selectedEnum; // Suponiendo que hay una propiedad para establecerlo
|
||||
Opciones.Instance.LLM = (LLM_a_Usar)selectedItem.Tag;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,5 +248,11 @@ namespace GTPCorrgir
|
|||
respuestas = "";
|
||||
AddMarkdownContent("");
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
opacityTimer?.Dispose();
|
||||
base.OnClosed(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
776
gtpask.cs
776
gtpask.cs
|
@ -5,12 +5,10 @@ using System.Linq;
|
|||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Threading;
|
||||
using LanguageDetection;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Interop;
|
||||
using libObsidean;
|
||||
|
||||
namespace GTPCorrgir
|
||||
|
@ -27,463 +25,521 @@ namespace GTPCorrgir
|
|||
public ApiKeySection ApiKeys { get; set; }
|
||||
}
|
||||
|
||||
public class gtpask
|
||||
public class gtpask : IDisposable
|
||||
{
|
||||
private readonly string openAiApiKey;
|
||||
private readonly string groqApiKey;
|
||||
private readonly string grokApiKey;
|
||||
public Logger Log = new Logger();
|
||||
private Dictionary<string, string> languageMap = new Dictionary<string, string>
|
||||
private string _openAiApiKey;
|
||||
private string _groqApiKey;
|
||||
private string _grokApiKey;
|
||||
private readonly HttpClient _httpClient;
|
||||
private bool _disposed;
|
||||
private readonly LanguageDetector _languageDetector;
|
||||
private readonly Obsidean _markdownProcessor;
|
||||
|
||||
public Logger Log { get; }
|
||||
|
||||
private readonly Dictionary<string, string> _languageMap = new Dictionary<string, string>
|
||||
{
|
||||
{ "en", "English" },
|
||||
{ "es", "Spanish" },
|
||||
{ "it", "Italian" },
|
||||
{ "pt", "Portuguese" }
|
||||
// Agrega más idiomas según sea necesario
|
||||
{ "en", "English" },
|
||||
{ "es", "Spanish" },
|
||||
{ "it", "Italian" },
|
||||
{ "pt", "Portuguese" }
|
||||
};
|
||||
|
||||
public string IdiomaDetectado;
|
||||
public string TextoACorregir;
|
||||
public string TextoCorregido;
|
||||
public string TextodeSistema;
|
||||
public string IdiomaDetectado { get; private set; }
|
||||
public string TextoACorregir { get; set; }
|
||||
public string TextoCorregido { get; private set; }
|
||||
public string TextodeSistema { get; private set; }
|
||||
private const bool Simulacion = false;
|
||||
|
||||
public gtpask()
|
||||
{
|
||||
try
|
||||
{
|
||||
string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "appsettings.json");
|
||||
if (File.Exists(configPath))
|
||||
{
|
||||
string jsonContent = File.ReadAllText(configPath);
|
||||
var settings = JsonConvert.DeserializeObject<ApiSettings>(jsonContent);
|
||||
Log = new Logger();
|
||||
_httpClient = new HttpClient();
|
||||
_languageDetector = new LanguageDetector();
|
||||
_languageDetector.AddLanguages("en", "es", "it", "pt");
|
||||
_markdownProcessor = new Obsidean();
|
||||
|
||||
openAiApiKey = settings.ApiKeys.OpenAI;
|
||||
groqApiKey = settings.ApiKeys.Groq;
|
||||
grokApiKey = settings.ApiKeys.Grok;
|
||||
LoadApiKeys();
|
||||
InitializeHttpClient();
|
||||
_markdownProcessor.LeerPalabrasTecnicas();
|
||||
|
||||
if (string.IsNullOrEmpty(openAiApiKey) || string.IsNullOrEmpty(groqApiKey) || string.IsNullOrEmpty(grokApiKey))
|
||||
{
|
||||
Log.Log("Warning: One or more API keys are missing in the configuration file.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Log("Error: Configuration file (appsettings.json) not found.");
|
||||
throw new FileNotFoundException("Configuration file (appsettings.json) not found.");
|
||||
}
|
||||
Log.Log("gtpask initialized successfully");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Log($"Error loading configuration: {ex.Message}");
|
||||
throw;
|
||||
Log.Log($"Error initializing gtpask: {ex.Message}");
|
||||
throw new ApplicationException("Failed to initialize gtpask", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private string CrearMensajeDeSistema()
|
||||
private void LoadApiKeys()
|
||||
{
|
||||
switch (Opciones.Instance.modo)
|
||||
try
|
||||
{
|
||||
case Opciones.modoDeUso.Corregir:
|
||||
return "You are an engineer working in industrial automation. Your task is to review texts and rewrite them in a simple and concise manner, making sure to preserve important technical terms and markdown language if present. Please rewrite the following text in " + IdiomaDetectado + " and respond in the following JSON format: { \"Rewritten_text\": \"Your text here\" }.";
|
||||
case Opciones.modoDeUso.Ortografia:
|
||||
return "Please check the following text for spelling errors and provide the corrected version. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find, making sure to preserve important technical terms and markdown language if present. Please write in " + IdiomaDetectado + " and respond in the following JSON format: { \"Rewritten_text\": \"Your text here\" }.";
|
||||
default:
|
||||
return "You are an engineer working specialiazed industrial automation. Please answer the following question in " + IdiomaDetectado + " and respond in the following JSON format: { \"Reply_text\": \"Your text here\" }.";
|
||||
}
|
||||
}
|
||||
string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "appsettings.json");
|
||||
if (!File.Exists(configPath))
|
||||
{
|
||||
throw new FileNotFoundException("Configuration file (appsettings.json) not found.");
|
||||
}
|
||||
|
||||
private string CrearMensajeDeUsuario(string texto)
|
||||
{
|
||||
switch (Opciones.Instance.modo)
|
||||
string jsonContent = File.ReadAllText(configPath);
|
||||
var settings = JsonConvert.DeserializeObject<ApiSettings>(jsonContent);
|
||||
|
||||
_openAiApiKey = settings?.ApiKeys?.OpenAI;
|
||||
_groqApiKey = settings?.ApiKeys?.Groq;
|
||||
_grokApiKey = settings?.ApiKeys?.Grok;
|
||||
|
||||
ValidateApiKeys();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
case Opciones.modoDeUso.Corregir:
|
||||
return "Please rewrite and improve the following text to make it clearer and more concise the words inside brackets are technical words: \"" + texto + "\"";
|
||||
case Opciones.modoDeUso.Ortografia:
|
||||
return "Please check the following text for spelling errors and provide the corrected version. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"" + texto + "\"";
|
||||
case Opciones.modoDeUso.Traducir_a_Ingles:
|
||||
return "Please check the following text for spelling errors and provide the corrected version in English. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"" + texto + "\"";
|
||||
case Opciones.modoDeUso.Traducir_a_Italiano:
|
||||
return "Please check the following text for spelling errors and provide the corrected version in Italian. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"" + texto + "\"";
|
||||
case Opciones.modoDeUso.Traducir_a_Espanol:
|
||||
return "Please check the following text for spelling errors and provide the corrected version in Spanish. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"" + texto + "\"";
|
||||
|
||||
default:
|
||||
return texto;
|
||||
Log.Log($"Error loading API keys: {ex.Message}");
|
||||
throw new ApplicationException("Failed to load API keys", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string DetectarIdioma(string TextoACorregir)
|
||||
private void ValidateApiKeys()
|
||||
{
|
||||
if (Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Ingles)
|
||||
return languageMap["en"];
|
||||
if (Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Italiano)
|
||||
return languageMap["it"];
|
||||
if (Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Espanol)
|
||||
return languageMap["es"];
|
||||
var missingKeys = new List<string>();
|
||||
|
||||
LanguageDetector detector = new LanguageDetector();
|
||||
|
||||
detector.AddLanguages("en", "es", "it");
|
||||
string detectedLanguageCode = detector.Detect(TextoACorregir);
|
||||
if (string.IsNullOrEmpty(_openAiApiKey)) missingKeys.Add("OpenAI");
|
||||
if (string.IsNullOrEmpty(_groqApiKey)) missingKeys.Add("Groq");
|
||||
if (string.IsNullOrEmpty(_grokApiKey)) missingKeys.Add("Grok");
|
||||
|
||||
string detectedLanguageName = languageMap.ContainsKey(detectedLanguageCode)
|
||||
? languageMap[detectedLanguageCode]
|
||||
: "Desconocido";
|
||||
|
||||
return detectedLanguageName;
|
||||
}
|
||||
private bool DetectarIdioma()
|
||||
{
|
||||
if (TextoACorregir.Length>0)
|
||||
if (missingKeys.Any())
|
||||
{
|
||||
IdiomaDetectado = DetectarIdioma(TextoACorregir);
|
||||
Log.Log("Idioma: " + IdiomaDetectado);
|
||||
if(IdiomaDetectado != "Desconocido")
|
||||
return true;
|
||||
else return false;
|
||||
string missingKeysStr = string.Join(", ", missingKeys);
|
||||
throw new ApplicationException($"Missing API keys: {missingKeysStr}");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void InitializeHttpClient()
|
||||
{
|
||||
_httpClient.Timeout = TimeSpan.FromSeconds(30);
|
||||
_httpClient.DefaultRequestHeaders.Clear();
|
||||
_httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
|
||||
}
|
||||
|
||||
public async Task CorregirTexto()
|
||||
{
|
||||
if (Simulacion)
|
||||
TextoACorregir = "\t\t* Sic : Synchronism?\r\n\t\t* Cont ? \r\n\t\t* Sensor for tensioning?\r\n\t\t* Max ? Overspeed?\r\n\t\t* Min : Stop / Start\r\n\t\t* Variable Speed. - = reference by filler\r\n\t\t* Formats: ? 66mm a 93mm => 27mm. How is changed?";
|
||||
|
||||
Log.Log("");
|
||||
Log.Log("Texto a corregir: " + TextoACorregir);
|
||||
if (DetectarIdioma()) {
|
||||
if (IdiomaDetectado == "Desconocido" || this.TextoACorregir.Length == 0)
|
||||
{
|
||||
// Nada que hacer
|
||||
TextoCorregido = TextoACorregir;
|
||||
return;
|
||||
}
|
||||
|
||||
var md = new Obsidean();
|
||||
md.LeerPalabrasTecnicas();
|
||||
|
||||
TextoACorregir = md.MarkTechnicalTerms_IgnoreCase(TextoACorregir);
|
||||
|
||||
Log.Log("Texto marcado: " + TextoACorregir);
|
||||
|
||||
string RespuestaLLM = "";
|
||||
|
||||
if (!Simulacion)
|
||||
{
|
||||
if (Opciones.Instance.LLM == Opciones.LLM_a_Usar.OpenAI) RespuestaLLM = await CallOpenAiApi(TextoACorregir);
|
||||
if (Opciones.Instance.LLM == Opciones.LLM_a_Usar.Ollama) RespuestaLLM = await CallOllamaApi(TextoACorregir);
|
||||
if (Opciones.Instance.LLM == Opciones.LLM_a_Usar.Groq) RespuestaLLM = await CallGroqAiApi(TextoACorregir);
|
||||
if (Opciones.Instance.LLM == Opciones.LLM_a_Usar.Grok) RespuestaLLM = await CallGrokApi(TextoACorregir);
|
||||
} else
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
RespuestaLLM = "Here is the rewritten text in a clearer and more concise manner:\r\n\r\n{\r\n'Rewritten_text': '\r\n### FB Tilting System Overview\r\n\r\nThe FB Tilting system consists of two main components:\r\n\r\n* **FB Tilting**: The main machine responsible for tilting and moving bottles.\r\n* **Sic (Synchronism)**: Ensures synchronized movement of the tilting machine with other system components.\r\n\r\n### Key Components and Functions\r\n\r\n* **Cont (Controller)**: The controlling unit that regulates the system's operation.\r\n* **Sensor for Tensioning**: Monitors and adjusts the tension of the moving parts.\r\n* **Max (Maximum Speed) and Overspeed Protection**: Safeguards the system from excessive speeds.\r\n* **Min (Minimum Speed) and Stop/Start Function**: Manages the system's startup and shutdown sequences.\r\n* **Variable Speed**: Allows for adjustable speed control, referenced by the filling machine.\r\n\r\n### Format Adaptation\r\n\r\nThe system accommodates various formats, including:\r\n* 66mm to 93mm, which are adapted to 27mm formats. The format change process is implemented as follows:\r\n\r\n### Startup Sequence\r\n\r\nThe startup procedure involves:\r\n\r\n1. **Fill to Sic with Minimum Accumulation**: Fills the Sic component with a minimum amount of material.\r\n2. **Run Chain at Fixed Speed**: Operates the chain at a constant speed.\r\n3. **Wait for Phase to Start**: Waits for the phase and ramp of the doser to be parameterized.\r\n4. **Ramp to Variable Speed**: Gradually adjusts the speed to the selected variable speed setting after a few bottles have been processed.'\r\n}";
|
||||
}
|
||||
|
||||
Log.Log("Respuesta: " + RespuestaLLM);
|
||||
|
||||
TextoCorregido = ExtraerValorUnicoJSON(RespuestaLLM);
|
||||
if (TextoCorregido is null)
|
||||
TextoCorregido = "Error en la respuesta.";
|
||||
|
||||
// Elimina comillas al principio y al final si existen
|
||||
TextoCorregido = md.RemoveTechnicalTermMarkers_IgnoreCase(TextoCorregido).Trim('\"');
|
||||
|
||||
Log.Log("Texto corregido: " + TextoCorregido);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string ExtraerValorUnicoJSON(string input)
|
||||
{
|
||||
// Encuentra los índices del inicio y del final del JSON
|
||||
int startJson = input.IndexOf('{');
|
||||
int endJson = input.LastIndexOf('}') + 1;
|
||||
|
||||
if (startJson == -1 || endJson == -1 || endJson <= startJson)
|
||||
if (string.IsNullOrWhiteSpace(TextoACorregir))
|
||||
{
|
||||
return "No valid JSON found in the input string.";
|
||||
Log.Log("No hay texto para corregir");
|
||||
return;
|
||||
}
|
||||
|
||||
// Extrae solo la parte JSON de la entrada
|
||||
string jsonString = input.Substring(startJson, endJson - startJson);
|
||||
|
||||
try
|
||||
{
|
||||
// Parsea el JSON
|
||||
JObject jsonObject = JObject.Parse(jsonString);
|
||||
Log.Log("Iniciando proceso de corrección");
|
||||
Log.Log($"Texto original: {TextoACorregir}");
|
||||
|
||||
// Obtiene el primer campo independientemente del nombre de la clave
|
||||
var firstField = jsonObject.Properties().FirstOrDefault();
|
||||
if (firstField != null)
|
||||
if (!DetectarIdioma())
|
||||
{
|
||||
return firstField.Value.ToString(); // Devuelve el valor del primer campo
|
||||
throw new ApplicationException("No se pudo detectar el idioma del texto");
|
||||
}
|
||||
|
||||
string textoMarcado = MarcarPalabrasTecnicas();
|
||||
Log.Log($"Texto marcado: {textoMarcado}");
|
||||
|
||||
if (Simulacion)
|
||||
{
|
||||
await SimularCorreccion();
|
||||
}
|
||||
else
|
||||
{
|
||||
return "JSON does not contain any data.";
|
||||
await ProcesarTextoConLLM(textoMarcado);
|
||||
}
|
||||
|
||||
Log.Log($"Texto corregido: {TextoCorregido}");
|
||||
}
|
||||
catch (JsonException jsonEx)
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Maneja errores de parseo de JSON
|
||||
return "Error parsing JSON: " + jsonEx.Message;
|
||||
Log.Log($"Error en CorregirTexto: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static string ExtractCorrectedText(string input)
|
||||
private bool DetectarIdioma()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (EsModoTraduccion())
|
||||
{
|
||||
IdiomaDetectado = ObtenerIdiomaObjetivo();
|
||||
Log.Log($"Modo traducción: idioma objetivo establecido a {IdiomaDetectado}");
|
||||
return true;
|
||||
}
|
||||
|
||||
string detectedLanguageCode = _languageDetector.Detect(TextoACorregir);
|
||||
IdiomaDetectado = _languageMap.GetValueOrDefault(detectedLanguageCode, "Desconocido");
|
||||
|
||||
Log.Log($"Idioma detectado: {IdiomaDetectado}");
|
||||
return IdiomaDetectado != "Desconocido";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Log($"Error al detectar idioma: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool EsModoTraduccion()
|
||||
{
|
||||
return Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Ingles ||
|
||||
Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Italiano ||
|
||||
Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Espanol;
|
||||
}
|
||||
|
||||
private string ObtenerIdiomaObjetivo()
|
||||
{
|
||||
return Opciones.Instance.modo switch
|
||||
{
|
||||
Opciones.modoDeUso.Traducir_a_Ingles => _languageMap["en"],
|
||||
Opciones.modoDeUso.Traducir_a_Italiano => _languageMap["it"],
|
||||
Opciones.modoDeUso.Traducir_a_Espanol => _languageMap["es"],
|
||||
_ => throw new ArgumentException("Modo de traducción no válido")
|
||||
};
|
||||
}
|
||||
|
||||
private string MarcarPalabrasTecnicas()
|
||||
{
|
||||
try
|
||||
{
|
||||
return _markdownProcessor.MarkTechnicalTerms_IgnoreCase(TextoACorregir);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Log($"Error al marcar palabras técnicas: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ProcesarTextoConLLM(string textoMarcado)
|
||||
{
|
||||
try
|
||||
{
|
||||
string respuestaLLM;
|
||||
|
||||
switch (Opciones.Instance.LLM)
|
||||
{
|
||||
case Opciones.LLM_a_Usar.OpenAI:
|
||||
respuestaLLM = await CallOpenAiApi(textoMarcado);
|
||||
break;
|
||||
case Opciones.LLM_a_Usar.Ollama:
|
||||
respuestaLLM = await CallOllamaApi(textoMarcado);
|
||||
break;
|
||||
case Opciones.LLM_a_Usar.Groq:
|
||||
respuestaLLM = await CallGroqAiApi(textoMarcado);
|
||||
break;
|
||||
case Opciones.LLM_a_Usar.Grok:
|
||||
respuestaLLM = await CallGrokApi(textoMarcado);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("LLM no válido");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(respuestaLLM))
|
||||
{
|
||||
throw new ApplicationException("No se recibió respuesta del LLM");
|
||||
}
|
||||
|
||||
ProcesarRespuestaLLM(respuestaLLM);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Log($"Error al procesar texto con LLM: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcesarRespuestaLLM(string respuestaLLM)
|
||||
{
|
||||
TextoCorregido = ExtraerValorUnicoJSON(respuestaLLM);
|
||||
if (TextoCorregido == null)
|
||||
{
|
||||
throw new ApplicationException("Error al extraer el texto corregido de la respuesta JSON");
|
||||
}
|
||||
|
||||
TextoCorregido = _markdownProcessor.RemoveTechnicalTermMarkers_IgnoreCase(TextoCorregido).Trim('"');
|
||||
}
|
||||
|
||||
private async Task SimularCorreccion()
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
TextoCorregido = "Texto simulado de prueba";
|
||||
Log.Log("Simulación completada");
|
||||
}
|
||||
|
||||
public string ExtraerValorUnicoJSON(string input)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Encuentra el índice del inicio y del final del JSON
|
||||
int startJson = input.IndexOf('{');
|
||||
int endJson = input.LastIndexOf('}') + 1;
|
||||
|
||||
if (startJson == -1 || endJson == -1 || endJson <= startJson)
|
||||
{
|
||||
throw new Exception("No valid JSON found in the input string.");
|
||||
Log.Log("Formato JSON inválido en la respuesta");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Extrae solo la parte JSON de la entrada
|
||||
string jsonString = input.Substring(startJson, endJson - startJson);
|
||||
string jsonString = input[startJson..endJson];
|
||||
JObject jsonObject = JObject.Parse(jsonString);
|
||||
var firstField = jsonObject.Properties().FirstOrDefault();
|
||||
|
||||
// Busca el inicio del texto después de "Rewritten_text':"
|
||||
int startKey = jsonString.IndexOf("'Rewritten_text':") + 17; // 17 es la longitud de "'Rewritten_text':"
|
||||
if (startKey == -1)
|
||||
{
|
||||
throw new Exception("Key 'Rewritten_text' not found.");
|
||||
}
|
||||
|
||||
// Ajusta para encontrar el inicio del texto después de las comillas simples adicionales
|
||||
int startText = jsonString.IndexOf('\'', startKey) + 1;
|
||||
int endText = jsonString.LastIndexOf('\'');
|
||||
|
||||
if (startText == -1 || endText == -1 || endText <= startText)
|
||||
{
|
||||
throw new Exception("No valid text found in the JSON string.");
|
||||
}
|
||||
|
||||
// Extrae el texto entre las comillas simples
|
||||
string rewrittenText = jsonString.Substring(startText, endText - startText);
|
||||
|
||||
return rewrittenText;
|
||||
return firstField?.Value?.ToString();
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (JsonException ex)
|
||||
{
|
||||
Console.WriteLine("An error occurred: " + ex.Message);
|
||||
Log.Log($"Error al procesar JSON: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private string CrearMensajeDeSistema()
|
||||
{
|
||||
return Opciones.Instance.modo switch
|
||||
{
|
||||
Opciones.modoDeUso.Corregir =>
|
||||
"You are an engineer working in industrial automation. Your task is to review texts and rewrite them in a simple and concise manner, making sure to preserve important technical terms and markdown language if present. Please rewrite the following text in " + IdiomaDetectado + " and respond in the following JSON format: { \"Rewritten_text\": \"Your text here\" }.",
|
||||
|
||||
Opciones.modoDeUso.Ortografia =>
|
||||
"Please check the following text for spelling errors and provide the corrected version. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find, making sure to preserve important technical terms and markdown language if present. Please write in " + IdiomaDetectado + " and respond in the following JSON format: { \"Rewritten_text\": \"Your text here\" }.",
|
||||
|
||||
_ => "You are an engineer working specialiazed industrial automation. Please answer the following question in " + IdiomaDetectado + " and respond in the following JSON format: { \"Reply_text\": \"Your text here\" }."
|
||||
};
|
||||
}
|
||||
|
||||
private string CrearMensajeDeUsuario(string texto) =>
|
||||
Opciones.Instance.modo switch
|
||||
{
|
||||
Opciones.modoDeUso.Corregir =>
|
||||
$"Please rewrite and improve the following text to make it clearer and more concise the words inside brackets are technical words: \"{texto}\"",
|
||||
|
||||
Opciones.modoDeUso.Ortografia =>
|
||||
$"Please check the following text for spelling errors and provide the corrected version. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"{texto}\"",
|
||||
|
||||
Opciones.modoDeUso.Traducir_a_Ingles =>
|
||||
$"Please check the following text for spelling errors and provide the corrected version in English. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"{texto}\"",
|
||||
|
||||
Opciones.modoDeUso.Traducir_a_Italiano =>
|
||||
$"Please check the following text for spelling errors and provide the corrected version in Italian. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"{texto}\"",
|
||||
|
||||
Opciones.modoDeUso.Traducir_a_Espanol =>
|
||||
$"Please check the following text for spelling errors and provide the corrected version in Spanish. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"{texto}\"",
|
||||
|
||||
_ => texto
|
||||
};
|
||||
|
||||
private async Task<string> CallGrokApi(string input)
|
||||
{
|
||||
using var httpClient = new HttpClient();
|
||||
string Mensaje_Sistema = CrearMensajeDeSistema();
|
||||
string Mensaje_Usuario = CrearMensajeDeUsuario(input);
|
||||
|
||||
// Configurar headers
|
||||
httpClient.DefaultRequestHeaders.Clear();
|
||||
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {grokApiKey}");
|
||||
|
||||
// Crear el objeto de solicitud siguiendo exactamente el formato del ejemplo curl
|
||||
var requestData = new
|
||||
{
|
||||
messages = new[]
|
||||
{
|
||||
new { role = "system", content = Mensaje_Sistema },
|
||||
new { role = "user", content = Mensaje_Usuario }
|
||||
},
|
||||
model = "grok-beta",
|
||||
stream = false,
|
||||
temperature = 0
|
||||
};
|
||||
|
||||
var content = new StringContent(
|
||||
JsonConvert.SerializeObject(requestData),
|
||||
Encoding.UTF8,
|
||||
"application/json"
|
||||
);
|
||||
|
||||
try
|
||||
{
|
||||
Log.Log("Ask Grok: " + JsonConvert.SerializeObject(requestData));
|
||||
_httpClient.DefaultRequestHeaders.Clear();
|
||||
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_grokApiKey}");
|
||||
|
||||
// URL corregida para coincidir con el ejemplo
|
||||
var response = await httpClient.PostAsync("https://api.x.ai/v1/chat/completions", content);
|
||||
response.EnsureSuccessStatusCode();
|
||||
var requestData = new
|
||||
{
|
||||
messages = new[]
|
||||
{
|
||||
new { role = "system", content = CrearMensajeDeSistema() },
|
||||
new { role = "user", content = CrearMensajeDeUsuario(input) }
|
||||
},
|
||||
model = "grok-beta",
|
||||
stream = false,
|
||||
temperature = 0
|
||||
};
|
||||
|
||||
var jsonResponse = await response.Content.ReadAsStringAsync();
|
||||
Log.Log("Grok Response: " + jsonResponse); // Logging la respuesta para debug
|
||||
|
||||
dynamic data = JsonConvert.DeserializeObject(jsonResponse);
|
||||
return data.choices[0].message.content;
|
||||
return await EnviarSolicitudLLM("https://api.x.ai/v1/chat/completions", requestData);
|
||||
}
|
||||
catch (HttpRequestException e)
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Log($"Error en la solicitud HTTP: {e.Message}");
|
||||
Console.WriteLine($"Error making HTTP request: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
catch (JsonException e)
|
||||
{
|
||||
Log.Log($"Error al procesar JSON: {e.Message}");
|
||||
Console.WriteLine($"Error processing JSON response: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Log($"Error general: {e.Message}");
|
||||
Console.WriteLine($"An error occurred: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient?.Dispose();
|
||||
Log.Log($"Error en llamada a Grok API: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async Task<string> CallOllamaApi(string input)
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
string Mensaje_Sistema = CrearMensajeDeSistema();
|
||||
string Mensaje_Usuario = CrearMensajeDeUsuario(input);
|
||||
|
||||
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {openAiApiKey}");
|
||||
|
||||
var requestData = new
|
||||
{
|
||||
model = "llama3.2:latest", // "phi3", //"llama3",
|
||||
messages = new[]
|
||||
{
|
||||
new { role = "system", content = Mensaje_Sistema },
|
||||
new { role = "user", content = Mensaje_Usuario }
|
||||
},
|
||||
stream = false
|
||||
};
|
||||
|
||||
var content = new StringContent(JsonConvert.SerializeObject(requestData), Encoding.UTF8, "application/json");
|
||||
try
|
||||
{
|
||||
Log.Log("Ask Ollama: " + JsonConvert.SerializeObject(requestData));
|
||||
var response = await httpClient.PostAsync("http://127.0.0.1:11434/api/chat", content);
|
||||
response.EnsureSuccessStatusCode();
|
||||
var jsonResponse = await response.Content.ReadAsStringAsync();
|
||||
dynamic data = JsonConvert.DeserializeObject(jsonResponse);
|
||||
|
||||
if (data.done == true && data.message != null)
|
||||
var requestData = new
|
||||
{
|
||||
return data.message.content;
|
||||
}
|
||||
return "No hubo respuesta del asistente o la sesión aún no ha concluido.";
|
||||
}
|
||||
catch (HttpRequestException e)
|
||||
{
|
||||
// Captura errores en la solicitud HTTP, como problemas de red o respuestas de error HTTP.
|
||||
Console.WriteLine($"Error making HTTP request: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Captura cualquier otro error
|
||||
Console.WriteLine($"An error occurred: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
model = "llama3.2:latest",
|
||||
messages = new[]
|
||||
{
|
||||
new { role = "system", content = CrearMensajeDeSistema() },
|
||||
new { role = "user", content = CrearMensajeDeUsuario(input) }
|
||||
},
|
||||
stream = false
|
||||
};
|
||||
|
||||
return await EnviarSolicitudLLM("http://127.0.0.1:11434/api/chat", requestData);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Log($"Error en llamada a Ollama API: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<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;
|
||||
}
|
||||
catch (HttpRequestException e)
|
||||
{
|
||||
// Captura errores en la solicitud HTTP, como problemas de red o respuestas de error HTTP.
|
||||
Console.WriteLine($"Error making HTTP request: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Captura cualquier otro error
|
||||
Console.WriteLine($"An error occurred: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
_httpClient.DefaultRequestHeaders.Clear();
|
||||
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_openAiApiKey}");
|
||||
|
||||
var requestData = new
|
||||
{
|
||||
model = "gpt-4o-mini",
|
||||
messages = new[]
|
||||
{
|
||||
new { role = "system", content = CrearMensajeDeSistema() },
|
||||
new { role = "user", content = CrearMensajeDeUsuario(input) }
|
||||
}
|
||||
};
|
||||
|
||||
return await EnviarSolicitudLLM("https://api.openai.com/v1/chat/completions", requestData);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Log($"Error en llamada a OpenAI API: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> CallGroqAiApi(string input)
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
string Mensaje_Sistema = CrearMensajeDeSistema();
|
||||
string Mensaje_Usuario = CrearMensajeDeUsuario(input);
|
||||
|
||||
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {groqApiKey}");
|
||||
|
||||
var requestData = new
|
||||
{
|
||||
model = "llama-3.1-70b-versatile", // "llama3-70b-8192",
|
||||
messages = new[]
|
||||
{
|
||||
new { role = "system", content = Mensaje_Sistema },
|
||||
new { role = "user", content = Mensaje_Usuario }
|
||||
},
|
||||
max_tokens = 2048,
|
||||
stream = false
|
||||
};
|
||||
|
||||
var content = new StringContent(JsonConvert.SerializeObject(requestData), Encoding.UTF8, "application/json");
|
||||
try
|
||||
{
|
||||
Log.Log("Ask Groq: " + JsonConvert.SerializeObject(requestData));
|
||||
var response = await httpClient.PostAsync("https://api.groq.com/openai/v1/chat/completions", content);
|
||||
response.EnsureSuccessStatusCode();
|
||||
var jsonResponse = await response.Content.ReadAsStringAsync();
|
||||
dynamic data = JsonConvert.DeserializeObject(jsonResponse);
|
||||
return data.choices[0].message.content;
|
||||
}
|
||||
catch (HttpRequestException e)
|
||||
{
|
||||
// Captura errores en la solicitud HTTP, como problemas de red o respuestas de error HTTP.
|
||||
Console.WriteLine($"Error making HTTP request: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Captura cualquier otro error
|
||||
Console.WriteLine($"An error occurred: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
_httpClient.DefaultRequestHeaders.Clear();
|
||||
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_groqApiKey}");
|
||||
|
||||
var requestData = new
|
||||
{
|
||||
model = "llama-3.2-3b-preview",
|
||||
messages = new[]
|
||||
{
|
||||
new { role = "system", content = CrearMensajeDeSistema() },
|
||||
new { role = "user", content = CrearMensajeDeUsuario(input) }
|
||||
},
|
||||
max_tokens = 2048,
|
||||
stream = false
|
||||
};
|
||||
|
||||
return await EnviarSolicitudLLM("https://api.groq.com/openai/v1/chat/completions", requestData);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Log($"Error en llamada a Groq API: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> EnviarSolicitudLLM(string endpoint, object requestData)
|
||||
{
|
||||
try
|
||||
{
|
||||
var content = new StringContent(
|
||||
JsonConvert.SerializeObject(requestData),
|
||||
Encoding.UTF8,
|
||||
"application/json"
|
||||
);
|
||||
|
||||
Log.Log($"Enviando solicitud a {endpoint}");
|
||||
Log.Log($"Datos de solicitud: {JsonConvert.SerializeObject(requestData)}");
|
||||
|
||||
using var response = await _httpClient.PostAsync(endpoint, content);
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
Log.Log($"Respuesta recibida: {responseContent}");
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
throw new HttpRequestException(
|
||||
$"Error en la solicitud HTTP: {response.StatusCode} - {responseContent}"
|
||||
);
|
||||
}
|
||||
|
||||
var data = JsonConvert.DeserializeObject<dynamic>(responseContent);
|
||||
|
||||
// Manejar diferentes formatos de respuesta según el LLM
|
||||
if (endpoint.Contains("ollama"))
|
||||
{
|
||||
if (data.done == true && data.message != null)
|
||||
{
|
||||
return data.message.content;
|
||||
}
|
||||
throw new ApplicationException("Formato de respuesta de Ollama inválido");
|
||||
}
|
||||
else // OpenAI, Groq, Grok
|
||||
{
|
||||
if (data.choices != null && data.choices.Count > 0)
|
||||
{
|
||||
return data.choices[0].message.content;
|
||||
}
|
||||
throw new ApplicationException("No se encontró contenido en la respuesta del LLM");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Log($"Error al enviar solicitud a {endpoint}: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_httpClient?.Dispose();
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
~gtpask()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clase auxiliar para manejar excepciones específicas de la aplicación
|
||||
public class LLMException : Exception
|
||||
{
|
||||
public LLMException(string message) : base(message) { }
|
||||
public LLMException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
// Clase auxiliar para validación
|
||||
public static class Validations
|
||||
{
|
||||
public static void ValidateNotNull(object value, string paramName)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(paramName);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ValidateNotNullOrEmpty(string value, string paramName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
throw new ArgumentException("Value cannot be null or empty", paramName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,63 @@
|
|||
<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"
|
||||
ShowInTaskbar="False" WindowStyle="None" AllowsTransparency="True" Background="Transparent">
|
||||
<Border CornerRadius="10" Background="#AAF0F0F0">
|
||||
<StackPanel>
|
||||
<TextBlock x:Name="TitleText" FontSize="16" FontWeight="Bold" Margin="10" />
|
||||
<TextBlock x:Name="MessageText" FontSize="14" Margin="10" />
|
||||
<Button Content="Cerrar" Width="75" Height="20" Margin="0" Click="CloseButton_Click"
|
||||
HorizontalAlignment="Right" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Window>
|
||||
<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">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</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>
|
||||
</Window>
|
|
@ -1,41 +1,114 @@
|
|||
using System.Windows;
|
||||
using Application = System.Windows.Application;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Animation;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace GTPCorrgir
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for notificacion.xaml
|
||||
/// </summary>
|
||||
public partial class notificacion : Window
|
||||
{
|
||||
private readonly DispatcherTimer autoCloseTimer;
|
||||
private readonly DispatcherTimer progressTimer;
|
||||
private double progressValue = 0;
|
||||
private const int AUTO_CLOSE_SECONDS = 5;
|
||||
private const int PROGRESS_UPDATE_INTERVAL = 50; // milisegundos
|
||||
|
||||
public notificacion()
|
||||
{
|
||||
InitializeComponent();
|
||||
PositionWindow();
|
||||
|
||||
// Configurar el timer para auto-cierre
|
||||
autoCloseTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromSeconds(AUTO_CLOSE_SECONDS)
|
||||
};
|
||||
autoCloseTimer.Tick += AutoCloseTimer_Tick;
|
||||
|
||||
// Configurar el timer para la barra de progreso
|
||||
progressTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(PROGRESS_UPDATE_INTERVAL)
|
||||
};
|
||||
progressTimer.Tick += ProgressTimer_Tick;
|
||||
|
||||
// Iniciar animación de entrada
|
||||
Loaded += (s, e) =>
|
||||
{
|
||||
var storyboard = (Storyboard)FindResource("FadeIn");
|
||||
storyboard.Begin(this);
|
||||
autoCloseTimer.Start();
|
||||
progressTimer.Start();
|
||||
};
|
||||
}
|
||||
|
||||
private void PositionWindow()
|
||||
{
|
||||
// Obtener la posición del cursor
|
||||
var cursorPosition = System.Windows.Forms.Cursor.Position;
|
||||
|
||||
// Determinar en qué pantalla está el cursor
|
||||
var screen = System.Windows.Forms.Screen.FromPoint(cursorPosition);
|
||||
|
||||
// Configurar la ubicación de la ventana para que aparezca en la esquina inferior derecha
|
||||
this.Left = screen.WorkingArea.Right - this.Width;
|
||||
this.Top = screen.WorkingArea.Bottom - this.Height;
|
||||
this.Left = screen.WorkingArea.Right - this.Width - 20;
|
||||
this.Top = screen.WorkingArea.Bottom - this.Height - 20;
|
||||
}
|
||||
|
||||
public void UpdateNotification(string title, string message)
|
||||
{
|
||||
TitleText.Text = title;
|
||||
MessageText.Text = message;
|
||||
|
||||
// Reiniciar timers y progreso
|
||||
progressValue = 0;
|
||||
AutoCloseProgress.Value = 0;
|
||||
|
||||
autoCloseTimer.Stop();
|
||||
progressTimer.Stop();
|
||||
|
||||
autoCloseTimer.Start();
|
||||
progressTimer.Start();
|
||||
}
|
||||
|
||||
private async void AutoCloseTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
autoCloseTimer.Stop();
|
||||
progressTimer.Stop();
|
||||
|
||||
var storyboard = (Storyboard)FindResource("FadeOut");
|
||||
storyboard.Completed += (s, _) => Close();
|
||||
storyboard.Begin(this);
|
||||
}
|
||||
|
||||
private void ProgressTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
progressValue += (PROGRESS_UPDATE_INTERVAL / (AUTO_CLOSE_SECONDS * 1000.0)) * 100;
|
||||
AutoCloseProgress.Value = progressValue;
|
||||
|
||||
if (progressValue >= 100)
|
||||
{
|
||||
progressTimer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Application.Current.Shutdown();
|
||||
autoCloseTimer.Stop();
|
||||
progressTimer.Stop();
|
||||
var storyboard = (Storyboard)FindResource("FadeOut");
|
||||
storyboard.Completed += (s, _) => Close();
|
||||
storyboard.Begin(this);
|
||||
}
|
||||
|
||||
protected override void OnMouseEnter(System.Windows.Input.MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseEnter(e);
|
||||
autoCloseTimer.Stop();
|
||||
progressTimer.Stop();
|
||||
}
|
||||
|
||||
protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseLeave(e);
|
||||
autoCloseTimer.Start();
|
||||
progressTimer.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue