diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..7270f18 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + "version": "0.2.0", + "configurations": [ + { + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/Debug/net8.0-windows/GTPCorrgir.dll", + "args": [], + "cwd": "${workspaceFolder}", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "internalConsole", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..faa660f --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,41 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/GTPCorrgir.sln", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary;ForceNoAlign" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/GTPCorrgir.sln", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary;ForceNoAlign" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "--project", + "${workspaceFolder}/GTPCorrgir.sln" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/App.xaml.cs b/App.xaml.cs index c4828c8..69e73e8 100644 --- a/App.xaml.cs +++ b/App.xaml.cs @@ -154,9 +154,9 @@ namespace GTPCorrgir ShowCustomNotification("Se puede pegar", $"Corrección en: {Math.Round(stopwatch.ElapsedMilliseconds / 1000.0, 1)} s"); - if (Opciones.Instance.modo == Opciones.modoDeUso.Corregir || Opciones.Instance.modo == Opciones.modoDeUso.Ortografia || - Opciones.Instance.modo == Opciones.modoDeUso.PreguntaRespuesta || Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Espanol || - Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Ingles || Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Italiano || + if (Opciones.Instance.modo == Opciones.modoDeUso.Corregir || Opciones.Instance.modo == Opciones.modoDeUso.Ortografia || + Opciones.Instance.modo == Opciones.modoDeUso.PreguntaRespuesta || Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Espanol || + Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Ingles || Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Italiano || Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Portugues) { if (Opciones.Instance.FuncionesOpcionales == Opciones.funcionesOpcionales.MostrarPopUp) @@ -215,10 +215,10 @@ namespace GTPCorrgir { _cancellationTokenSource?.Cancel(); _cancellationTokenSource?.Dispose(); - + // Limpiar recursos de PaddleOCR PaddleOCRManager.Cleanup(); - + base.OnExit(e); } @@ -226,7 +226,7 @@ namespace GTPCorrgir { try { - GTP.Log.Log($"Mostrando notificación: {title} - {message}"); + // GTP.Log.Log($"Mostrando notificación: {title} - {message}"); // Comentado para limpiar logs if (notificationWindow == null) { notificationWindow = new notificacion(); diff --git a/ContextMenuWindow.xaml.cs b/ContextMenuWindow.xaml.cs index d140aeb..50b5880 100644 --- a/ContextMenuWindow.xaml.cs +++ b/ContextMenuWindow.xaml.cs @@ -59,7 +59,8 @@ namespace GTPCorrgir new MenuOption { DisplayName = "OpenAI", Value = Opciones.LLM_a_Usar.OpenAI }, new MenuOption { DisplayName = "Ollama", Value = Opciones.LLM_a_Usar.Ollama }, new MenuOption { DisplayName = "Groq", Value = Opciones.LLM_a_Usar.Groq }, - new MenuOption { DisplayName = "Grok", Value = Opciones.LLM_a_Usar.Grok } + new MenuOption { DisplayName = "Grok", Value = Opciones.LLM_a_Usar.Grok }, + new MenuOption { DisplayName = "Claude", Value = Opciones.LLM_a_Usar.Claude } }; InitializeComponent(); diff --git a/Program.cs b/Program.cs index be054d1..734391e 100644 --- a/Program.cs +++ b/Program.cs @@ -14,7 +14,8 @@ namespace GTPCorrgir OpenAI, Ollama, Groq, - Grok + Grok, + Claude } [Flags] @@ -45,6 +46,7 @@ namespace GTPCorrgir { LLM_a_Usar.Groq, "Groq" }, { LLM_a_Usar.Grok, "Grok" }, { LLM_a_Usar.OpenAI, "OpenAI" }, + { LLM_a_Usar.Claude, "Claude" }, }; private static Opciones _instance; @@ -102,6 +104,8 @@ namespace GTPCorrgir Opciones.Instance.LLM = Opciones.LLM_a_Usar.Grok; else if (arg.Contains("OpenAI")) Opciones.Instance.LLM = Opciones.LLM_a_Usar.OpenAI; + else if (arg.Contains("Claude")) + Opciones.Instance.LLM = Opciones.LLM_a_Usar.Claude; if (arg.Contains("CtrlA")) Opciones.Instance.FuncionesOpcionales = Opciones.funcionesOpcionales.CtrlA; diff --git a/gtpask.cs b/gtpask.cs index 496e838..9edd019 100644 --- a/gtpask.cs +++ b/gtpask.cs @@ -20,6 +20,7 @@ namespace GTPCorrgir public string OpenAI { get; set; } public string Groq { get; set; } public string Grok { get; set; } + public string Claude { get; set; } } public ApiKeySection ApiKeys { get; set; } @@ -30,6 +31,7 @@ namespace GTPCorrgir private string _openAiApiKey; private string _groqApiKey; private string _grokApiKey; + private string _claudeApiKey; private readonly HttpClient _httpClient; private bool _disposed; private readonly LanguageDetector _languageDetector; @@ -90,6 +92,7 @@ namespace GTPCorrgir _openAiApiKey = settings?.ApiKeys?.OpenAI; _groqApiKey = settings?.ApiKeys?.Groq; _grokApiKey = settings?.ApiKeys?.Grok; + _claudeApiKey = settings?.ApiKeys?.Claude; ValidateApiKeys(); } @@ -107,6 +110,7 @@ namespace GTPCorrgir if (string.IsNullOrEmpty(_openAiApiKey)) missingKeys.Add("OpenAI"); if (string.IsNullOrEmpty(_groqApiKey)) missingKeys.Add("Groq"); if (string.IsNullOrEmpty(_grokApiKey)) missingKeys.Add("Grok"); + if (string.IsNullOrEmpty(_claudeApiKey)) missingKeys.Add("Claude"); if (missingKeys.Any()) { @@ -238,6 +242,9 @@ namespace GTPCorrgir case Opciones.LLM_a_Usar.Grok: respuestaLLM = await CallGrokApi(textoMarcado); break; + case Opciones.LLM_a_Usar.Claude: + respuestaLLM = await CallClaudeApi(textoMarcado); + break; default: throw new ArgumentException("LLM no válido"); } @@ -462,6 +469,40 @@ namespace GTPCorrgir } } + private async Task CallClaudeApi(string input) + { + try + { + _httpClient.DefaultRequestHeaders.Clear(); + _httpClient.DefaultRequestHeaders.Add("x-api-key", _claudeApiKey); + _httpClient.DefaultRequestHeaders.Add("anthropic-version", "2023-06-01"); + + var requestData = new + { + model = "claude-sonnet-4-20250514", + max_tokens = 4096, + temperature = 1, + system = CrearMensajeDeSistema(), + messages = new[] + { + new { role = "user", content = CrearMensajeDeUsuario(input) } + }, + thinking = new + { + type = "enabled", + budget_tokens = 2048 + } + }; + + return await EnviarSolicitudLLM("https://api.anthropic.com/v1/messages", requestData); + } + catch (Exception ex) + { + Log.Log($"Error en llamada a Claude API: {ex.Message}"); + throw; + } + } + private async Task EnviarSolicitudLLM(string endpoint, object requestData) { try @@ -498,6 +539,26 @@ namespace GTPCorrgir } throw new ApplicationException("Formato de respuesta de Ollama inválido"); } + else if (endpoint.Contains("anthropic")) + { + if (data.content != null && data.content.Count > 0) + { + // Buscar el elemento con type = "text" en el array de content + foreach (var contentItem in data.content) + { + if (contentItem.type == "text") + { + return contentItem.text; + } + } + // Si no encuentra un elemento con type="text", usar el primer elemento como fallback + if (data.content[0].text != null) + { + return data.content[0].text; + } + } + throw new ApplicationException("No se encontró contenido en la respuesta de Claude"); + } else // OpenAI, Groq, Grok { if (data.choices != null && data.choices.Count > 0)