Agregada la opción para utilizar el modelo Claude en la aplicación, incluyendo la implementación de la llamada a su API y la validación de la clave API correspondiente. Se realizaron ajustes en el menú y se mejoró la gestión de logs.

This commit is contained in:
Miguel 2025-06-17 11:48:15 +02:00
parent 6d8f70d15b
commit a48e64f372
6 changed files with 141 additions and 8 deletions

26
.vscode/launch.json vendored Normal file
View File

@ -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"
}
]
}

41
.vscode/tasks.json vendored Normal file
View File

@ -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"
}
]
}

View File

@ -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();

View File

@ -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();

View File

@ -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;

View File

@ -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<string> 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<string> 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)