Se agregó la opción "Claude Web Search" al menú y se implementó la lógica para manejar las solicitudes a la API de Claude, incluyendo la extracción de enlaces de búsqueda. Se mejoró la detección de idioma y se estableció español como predeterminado en casos específicos. Además, se optimizó el procesamiento de respuestas para el modo Claude Web Search.
This commit is contained in:
parent
a48e64f372
commit
a8aca9a82a
|
@ -81,6 +81,7 @@ namespace GTPCorrgir
|
||||||
case Opciones.modoDeUso.Corregir:
|
case Opciones.modoDeUso.Corregir:
|
||||||
case Opciones.modoDeUso.Ortografia:
|
case Opciones.modoDeUso.Ortografia:
|
||||||
case Opciones.modoDeUso.PreguntaRespuesta:
|
case Opciones.modoDeUso.PreguntaRespuesta:
|
||||||
|
case Opciones.modoDeUso.ClaudeWebSearch:
|
||||||
case Opciones.modoDeUso.Traducir_a_Espanol:
|
case Opciones.modoDeUso.Traducir_a_Espanol:
|
||||||
case Opciones.modoDeUso.Traducir_a_Ingles:
|
case Opciones.modoDeUso.Traducir_a_Ingles:
|
||||||
case Opciones.modoDeUso.Traducir_a_Italiano:
|
case Opciones.modoDeUso.Traducir_a_Italiano:
|
||||||
|
@ -155,9 +156,9 @@ namespace GTPCorrgir
|
||||||
$"Corrección en: {Math.Round(stopwatch.ElapsedMilliseconds / 1000.0, 1)} s");
|
$"Corrección en: {Math.Round(stopwatch.ElapsedMilliseconds / 1000.0, 1)} s");
|
||||||
|
|
||||||
if (Opciones.Instance.modo == Opciones.modoDeUso.Corregir || Opciones.Instance.modo == Opciones.modoDeUso.Ortografia ||
|
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.PreguntaRespuesta || Opciones.Instance.modo == Opciones.modoDeUso.ClaudeWebSearch ||
|
||||||
Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Ingles || Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Italiano ||
|
Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Espanol || Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Ingles ||
|
||||||
Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Portugues)
|
Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Italiano || Opciones.Instance.modo == Opciones.modoDeUso.Traducir_a_Portugues)
|
||||||
{
|
{
|
||||||
if (Opciones.Instance.FuncionesOpcionales == Opciones.funcionesOpcionales.MostrarPopUp)
|
if (Opciones.Instance.FuncionesOpcionales == Opciones.funcionesOpcionales.MostrarPopUp)
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,6 +47,7 @@ namespace GTPCorrgir
|
||||||
new MenuOption { DisplayName = "Revisar ortografía", Value = Opciones.modoDeUso.Ortografia },
|
new MenuOption { DisplayName = "Revisar ortografía", Value = Opciones.modoDeUso.Ortografia },
|
||||||
new MenuOption { DisplayName = "Chat", Value = Opciones.modoDeUso.Chat },
|
new MenuOption { DisplayName = "Chat", Value = Opciones.modoDeUso.Chat },
|
||||||
new MenuOption { DisplayName = "Pregunta-Respuesta", Value = Opciones.modoDeUso.PreguntaRespuesta },
|
new MenuOption { DisplayName = "Pregunta-Respuesta", Value = Opciones.modoDeUso.PreguntaRespuesta },
|
||||||
|
new MenuOption { DisplayName = "Claude Web Search", Value = Opciones.modoDeUso.ClaudeWebSearch },
|
||||||
new MenuOption { DisplayName = "Traducir a inglés", Value = Opciones.modoDeUso.Traducir_a_Ingles },
|
new MenuOption { DisplayName = "Traducir a inglés", Value = Opciones.modoDeUso.Traducir_a_Ingles },
|
||||||
new MenuOption { DisplayName = "Traducir a italiano", Value = Opciones.modoDeUso.Traducir_a_Italiano },
|
new MenuOption { DisplayName = "Traducir a italiano", Value = Opciones.modoDeUso.Traducir_a_Italiano },
|
||||||
new MenuOption { DisplayName = "Traducir a español", Value = Opciones.modoDeUso.Traducir_a_Espanol },
|
new MenuOption { DisplayName = "Traducir a español", Value = Opciones.modoDeUso.Traducir_a_Espanol },
|
||||||
|
@ -167,6 +168,12 @@ namespace GTPCorrgir
|
||||||
var modeValue = (Opciones.modoDeUso)selectedMode.Value;
|
var modeValue = (Opciones.modoDeUso)selectedMode.Value;
|
||||||
var llmValue = (Opciones.LLM_a_Usar)selectedLLM.Value;
|
var llmValue = (Opciones.LLM_a_Usar)selectedLLM.Value;
|
||||||
|
|
||||||
|
// Si se selecciona Claude Web Search, forzar el uso de Claude
|
||||||
|
if (modeValue == Opciones.modoDeUso.ClaudeWebSearch)
|
||||||
|
{
|
||||||
|
llmValue = Opciones.LLM_a_Usar.Claude;
|
||||||
|
}
|
||||||
|
|
||||||
Opciones.Instance.modo = modeValue;
|
Opciones.Instance.modo = modeValue;
|
||||||
Opciones.Instance.LLM = llmValue;
|
Opciones.Instance.LLM = llmValue;
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ namespace GTPCorrgir
|
||||||
Traducir_a_Portugues,
|
Traducir_a_Portugues,
|
||||||
OCRaTexto,
|
OCRaTexto,
|
||||||
Menu,
|
Menu,
|
||||||
|
ClaudeWebSearch,
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<LLM_a_Usar, string> nombreLLM = new Dictionary<LLM_a_Usar, string>
|
public Dictionary<LLM_a_Usar, string> nombreLLM = new Dictionary<LLM_a_Usar, string>
|
||||||
|
@ -130,6 +131,8 @@ namespace GTPCorrgir
|
||||||
Opciones.Instance.modo = Opciones.modoDeUso.Traducir_a_Portugues;
|
Opciones.Instance.modo = Opciones.modoDeUso.Traducir_a_Portugues;
|
||||||
if (arg.Contains("OCRaTexto"))
|
if (arg.Contains("OCRaTexto"))
|
||||||
Opciones.Instance.modo = Opciones.modoDeUso.OCRaTexto;
|
Opciones.Instance.modo = Opciones.modoDeUso.OCRaTexto;
|
||||||
|
if (arg.Contains("ClaudeWebSearch"))
|
||||||
|
Opciones.Instance.modo = Opciones.modoDeUso.ClaudeWebSearch;
|
||||||
if (arg.Contains("AutoCopy"))
|
if (arg.Contains("AutoCopy"))
|
||||||
Opciones.Instance.AutoCopy = true;
|
Opciones.Instance.AutoCopy = true;
|
||||||
if (arg.Contains("Menu"))
|
if (arg.Contains("Menu"))
|
||||||
|
|
388
gtpask.cs
388
gtpask.cs
|
@ -176,16 +176,43 @@ namespace GTPCorrgir
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
string detectedLanguageCode = _languageDetector.Detect(TextoACorregir);
|
// Si el texto es solo una URL, usar español como predeterminado
|
||||||
IdiomaDetectado = _languageMap.GetValueOrDefault(detectedLanguageCode, "Desconocido");
|
if (EsSoloURL(TextoACorregir))
|
||||||
|
{
|
||||||
|
IdiomaDetectado = _languageMap["es"]; // Español como predeterminado
|
||||||
|
Log.Log($"Texto es URL, usando idioma predeterminado: {IdiomaDetectado}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si el texto es muy corto, usar español como predeterminado
|
||||||
|
if (string.IsNullOrWhiteSpace(TextoACorregir) || TextoACorregir.Trim().Length < 10)
|
||||||
|
{
|
||||||
|
IdiomaDetectado = _languageMap["es"]; // Español como predeterminado
|
||||||
|
Log.Log($"Texto muy corto, usando idioma predeterminado: {IdiomaDetectado}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string detectedLanguageCode = _languageDetector.Detect(TextoACorregir);
|
||||||
|
|
||||||
|
// Si no se detectó idioma o es desconocido, usar español como fallback
|
||||||
|
if (string.IsNullOrEmpty(detectedLanguageCode) || !_languageMap.ContainsKey(detectedLanguageCode))
|
||||||
|
{
|
||||||
|
IdiomaDetectado = _languageMap["es"]; // Español como fallback
|
||||||
|
Log.Log($"Idioma no detectado, usando fallback: {IdiomaDetectado}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
IdiomaDetectado = _languageMap[detectedLanguageCode];
|
||||||
Log.Log($"Idioma detectado: {IdiomaDetectado}");
|
Log.Log($"Idioma detectado: {IdiomaDetectado}");
|
||||||
return IdiomaDetectado != "Desconocido";
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Log($"Error al detectar idioma: {ex.Message}");
|
Log.Log($"Error al detectar idioma: {ex.Message}");
|
||||||
return false;
|
// En caso de error, usar español como fallback
|
||||||
|
IdiomaDetectado = _languageMap["es"];
|
||||||
|
Log.Log($"Error en detección, usando fallback: {IdiomaDetectado}");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,26 +254,37 @@ namespace GTPCorrgir
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string respuestaLLM;
|
string respuestaLLM;
|
||||||
|
string respuestaCompleta = "";
|
||||||
|
|
||||||
switch (Opciones.Instance.LLM)
|
// Si es el modo Claude Web Search, usar el método específico
|
||||||
|
if (Opciones.Instance.modo == Opciones.modoDeUso.ClaudeWebSearch)
|
||||||
{
|
{
|
||||||
case Opciones.LLM_a_Usar.OpenAI:
|
var resultadoWebSearch = await CallClaudeWebSearchApiCompleto(textoMarcado);
|
||||||
respuestaLLM = await CallOpenAiApi(textoMarcado);
|
respuestaLLM = resultadoWebSearch.texto;
|
||||||
break;
|
respuestaCompleta = resultadoWebSearch.respuestaCompleta;
|
||||||
case Opciones.LLM_a_Usar.Ollama:
|
}
|
||||||
respuestaLLM = await CallOllamaApi(textoMarcado);
|
else
|
||||||
break;
|
{
|
||||||
case Opciones.LLM_a_Usar.Groq:
|
switch (Opciones.Instance.LLM)
|
||||||
respuestaLLM = await CallGroqAiApi(textoMarcado);
|
{
|
||||||
break;
|
case Opciones.LLM_a_Usar.OpenAI:
|
||||||
case Opciones.LLM_a_Usar.Grok:
|
respuestaLLM = await CallOpenAiApi(textoMarcado);
|
||||||
respuestaLLM = await CallGrokApi(textoMarcado);
|
break;
|
||||||
break;
|
case Opciones.LLM_a_Usar.Ollama:
|
||||||
case Opciones.LLM_a_Usar.Claude:
|
respuestaLLM = await CallOllamaApi(textoMarcado);
|
||||||
respuestaLLM = await CallClaudeApi(textoMarcado);
|
break;
|
||||||
break;
|
case Opciones.LLM_a_Usar.Groq:
|
||||||
default:
|
respuestaLLM = await CallGroqAiApi(textoMarcado);
|
||||||
throw new ArgumentException("LLM no válido");
|
break;
|
||||||
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(respuestaLLM))
|
if (string.IsNullOrEmpty(respuestaLLM))
|
||||||
|
@ -254,7 +292,7 @@ namespace GTPCorrgir
|
||||||
throw new ApplicationException("No se recibió respuesta del LLM");
|
throw new ApplicationException("No se recibió respuesta del LLM");
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcesarRespuestaLLM(respuestaLLM);
|
ProcesarRespuestaLLM(respuestaLLM, respuestaCompleta);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -263,26 +301,141 @@ namespace GTPCorrgir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcesarRespuestaLLM(string respuestaLLM)
|
private void ProcesarRespuestaLLM(string respuestaLLM, string respuestaCompleta)
|
||||||
{
|
{
|
||||||
string respuestaExtraida = ExtraerValorUnicoJSON(respuestaLLM);
|
// Para Claude Web Search, la respuesta ya viene en formato de texto final
|
||||||
if (respuestaExtraida == null)
|
if (Opciones.Instance.modo == Opciones.modoDeUso.ClaudeWebSearch)
|
||||||
|
{
|
||||||
|
// Claude Web Search ya devuelve el texto final con formato JSON interno,
|
||||||
|
// intentamos extraer JSON primero, si falla usamos el texto completo
|
||||||
|
string respuestaExtraida = ExtraerValorUnicoJSON(respuestaLLM);
|
||||||
|
if (respuestaExtraida == null)
|
||||||
|
{
|
||||||
|
// Si no se puede extraer JSON, usamos la respuesta completa
|
||||||
|
respuestaExtraida = respuestaLLM;
|
||||||
|
Log.Log("Claude Web Search: No se encontró JSON, usando respuesta completa");
|
||||||
|
}
|
||||||
|
|
||||||
|
respuestaExtraida = System.Text.RegularExpressions.Regex.Replace(respuestaExtraida, @"\*\*(.*?)\*\*", "$1");
|
||||||
|
respuestaExtraida = _markdownProcessor.RemoveTechnicalTermMarkers_IgnoreCase(respuestaExtraida).Trim('"');
|
||||||
|
respuestaExtraida = _markdownProcessor.RemoveDoubleBrackets(respuestaExtraida);
|
||||||
|
|
||||||
|
// Extraer y formatear enlaces de búsqueda web
|
||||||
|
string enlacesFormateados = ExtraerEnlacesWebSearch(respuestaCompleta);
|
||||||
|
|
||||||
|
// Para el modo Pregunta-Respuesta y Claude Web Search, combinar pregunta original con la respuesta y enlaces
|
||||||
|
TextoCorregido = $"{TextoACorregir}\n\n{respuestaExtraida}";
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(enlacesFormateados))
|
||||||
|
{
|
||||||
|
TextoCorregido += $"\n\n## Fuentes consultadas:\n{enlacesFormateados}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Para otros LLMs, procesamiento normal con JSON requerido
|
||||||
|
string respuestaExtraidaNormal = ExtraerValorUnicoJSON(respuestaLLM);
|
||||||
|
if (respuestaExtraidaNormal == null)
|
||||||
{
|
{
|
||||||
throw new ApplicationException("Error al extraer el texto corregido de la respuesta JSON");
|
throw new ApplicationException("Error al extraer el texto corregido de la respuesta JSON");
|
||||||
}
|
}
|
||||||
|
|
||||||
respuestaExtraida = System.Text.RegularExpressions.Regex.Replace(respuestaExtraida, @"\*\*(.*?)\*\*", "$1");
|
respuestaExtraidaNormal = System.Text.RegularExpressions.Regex.Replace(respuestaExtraidaNormal, @"\*\*(.*?)\*\*", "$1");
|
||||||
respuestaExtraida = _markdownProcessor.RemoveTechnicalTermMarkers_IgnoreCase(respuestaExtraida).Trim('"');
|
respuestaExtraidaNormal = _markdownProcessor.RemoveTechnicalTermMarkers_IgnoreCase(respuestaExtraidaNormal).Trim('"');
|
||||||
respuestaExtraida = _markdownProcessor.RemoveDoubleBrackets(respuestaExtraida);
|
respuestaExtraidaNormal = _markdownProcessor.RemoveDoubleBrackets(respuestaExtraidaNormal);
|
||||||
|
|
||||||
// Para el modo Pregunta-Respuesta, combinar pregunta original con la respuesta
|
// Para el modo Pregunta-Respuesta, combinar pregunta original con la respuesta
|
||||||
if (Opciones.Instance.modo == Opciones.modoDeUso.PreguntaRespuesta)
|
if (Opciones.Instance.modo == Opciones.modoDeUso.PreguntaRespuesta)
|
||||||
{
|
{
|
||||||
TextoCorregido = $"{TextoACorregir}\n{respuestaExtraida}";
|
TextoCorregido = $"{TextoACorregir}\n{respuestaExtraidaNormal}";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TextoCorregido = respuestaExtraida;
|
TextoCorregido = respuestaExtraidaNormal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ExtraerEnlacesWebSearch(string respuestaCompleta)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(respuestaCompleta))
|
||||||
|
{
|
||||||
|
Log.Log("ExtraerEnlacesWebSearch: respuestaCompleta está vacía");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Log($"ExtraerEnlacesWebSearch: Procesando respuesta de {respuestaCompleta.Length} caracteres");
|
||||||
|
|
||||||
|
var enlaces = new List<string>();
|
||||||
|
|
||||||
|
// Deserializar la respuesta completa para extraer los resultados de búsqueda
|
||||||
|
var data = JsonConvert.DeserializeObject<dynamic>(respuestaCompleta);
|
||||||
|
|
||||||
|
if (data?.content != null)
|
||||||
|
{
|
||||||
|
Log.Log($"ExtraerEnlacesWebSearch: Encontrados {data.content.Count} elementos de contenido");
|
||||||
|
|
||||||
|
foreach (var contentItem in data.content)
|
||||||
|
{
|
||||||
|
Log.Log($"ExtraerEnlacesWebSearch: Procesando elemento tipo: {contentItem.type}");
|
||||||
|
|
||||||
|
// Buscar elementos de tipo "web_search_tool_result"
|
||||||
|
if (contentItem.type == "web_search_tool_result" && contentItem.content != null)
|
||||||
|
{
|
||||||
|
Log.Log($"ExtraerEnlacesWebSearch: Encontrado web_search_tool_result con {contentItem.content.Count} resultados");
|
||||||
|
|
||||||
|
foreach (var searchResult in contentItem.content)
|
||||||
|
{
|
||||||
|
if (searchResult.type == "web_search_result")
|
||||||
|
{
|
||||||
|
string titulo = searchResult.title?.ToString() ?? "Sin título";
|
||||||
|
string url = searchResult.url?.ToString() ?? "";
|
||||||
|
string pageAge = searchResult.page_age?.ToString() ?? "";
|
||||||
|
|
||||||
|
Log.Log($"ExtraerEnlacesWebSearch: Resultado - Título: {titulo}, URL: {url}");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(url))
|
||||||
|
{
|
||||||
|
string enlaceFormateado;
|
||||||
|
if (!string.IsNullOrEmpty(pageAge))
|
||||||
|
{
|
||||||
|
enlaceFormateado = $"* [{titulo}]({url}) - {pageAge}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enlaceFormateado = $"* [{titulo}]({url})";
|
||||||
|
}
|
||||||
|
|
||||||
|
enlaces.Add(enlaceFormateado);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Log("ExtraerEnlacesWebSearch: No se encontró contenido en la respuesta");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eliminar duplicados y devolver como string
|
||||||
|
var enlacesUnicos = enlaces.Distinct().ToList();
|
||||||
|
|
||||||
|
Log.Log($"ExtraerEnlacesWebSearch: Extraídos {enlacesUnicos.Count} enlaces únicos");
|
||||||
|
|
||||||
|
if (enlacesUnicos.Any())
|
||||||
|
{
|
||||||
|
return string.Join("\n", enlacesUnicos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Log($"Error al extraer enlaces de web search: {ex.Message}");
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,6 +489,17 @@ namespace GTPCorrgir
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string CrearMensajeDeWebSearch()
|
||||||
|
{
|
||||||
|
return "You are a helpful assistant specialized in industrial automation and technical topics with web search capabilities. " +
|
||||||
|
"When users ask questions, you can use web search to find current and accurate information to provide comprehensive answers. " +
|
||||||
|
"If the question contains words in double brackets [[like this]], preserve them exactly as they appear in your response. " +
|
||||||
|
"Use the web search tool when you need to find recent information, current data, or specific technical details that might not be in your training data. " +
|
||||||
|
"Always provide well-researched, accurate answers and cite your sources when using web search results. " +
|
||||||
|
"Please write your answer in " + IdiomaDetectado + ". " +
|
||||||
|
"You can respond in JSON format like { \"Reply_text\": \"Your answer here\" } or provide a direct text response.";
|
||||||
|
}
|
||||||
|
|
||||||
private string CrearMensajeDeUsuario(string texto) =>
|
private string CrearMensajeDeUsuario(string texto) =>
|
||||||
Opciones.Instance.modo switch
|
Opciones.Instance.modo switch
|
||||||
{
|
{
|
||||||
|
@ -348,6 +512,9 @@ namespace GTPCorrgir
|
||||||
Opciones.modoDeUso.PreguntaRespuesta =>
|
Opciones.modoDeUso.PreguntaRespuesta =>
|
||||||
texto, // Para pregunta-respuesta, enviamos el texto directamente como la pregunta
|
texto, // Para pregunta-respuesta, enviamos el texto directamente como la pregunta
|
||||||
|
|
||||||
|
Opciones.modoDeUso.ClaudeWebSearch =>
|
||||||
|
texto, // Para web search, enviamos la pregunta directamente
|
||||||
|
|
||||||
Opciones.modoDeUso.Traducir_a_Ingles =>
|
Opciones.modoDeUso.Traducir_a_Ingles =>
|
||||||
$"Please check the following text for spelling errors and provide the corrected version tranlated to English. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"{texto}\"",
|
$"Please check the following text for spelling errors and provide the corrected version tranlated to English. Do not change the meaning or structure of the sentences. Only correct any spelling mistakes you find on: \"{texto}\"",
|
||||||
|
|
||||||
|
@ -503,6 +670,103 @@ namespace GTPCorrgir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<string> CallClaudeWebSearchApi(string input)
|
||||||
|
{
|
||||||
|
var resultado = await CallClaudeWebSearchApiCompleto(input);
|
||||||
|
return resultado.texto;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<(string texto, string respuestaCompleta)> CallClaudeWebSearchApiCompleto(string input)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_httpClient.DefaultRequestHeaders.Clear();
|
||||||
|
_httpClient.DefaultRequestHeaders.Add("x-api-key", _claudeApiKey);
|
||||||
|
_httpClient.DefaultRequestHeaders.Add("anthropic-version", "2023-06-01");
|
||||||
|
_httpClient.DefaultRequestHeaders.Add("anthropic-beta", "web-search-2025-03-05");
|
||||||
|
|
||||||
|
var requestData = new
|
||||||
|
{
|
||||||
|
model = "claude-sonnet-4-20250514",
|
||||||
|
max_tokens = 4166,
|
||||||
|
temperature = 1,
|
||||||
|
system = CrearMensajeDeWebSearch(),
|
||||||
|
messages = new[]
|
||||||
|
{
|
||||||
|
new { role = "user", content = input } // Para web search, enviamos la pregunta directamente
|
||||||
|
},
|
||||||
|
tools = new[]
|
||||||
|
{
|
||||||
|
new
|
||||||
|
{
|
||||||
|
name = "web_search",
|
||||||
|
type = "web_search_20250305"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
thinking = new
|
||||||
|
{
|
||||||
|
type = "enabled",
|
||||||
|
budget_tokens = 4123
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var content = new StringContent(
|
||||||
|
JsonConvert.SerializeObject(requestData),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json"
|
||||||
|
);
|
||||||
|
|
||||||
|
Log.Log($"Enviando solicitud a https://api.anthropic.com/v1/messages");
|
||||||
|
Log.Log($"Datos de solicitud: {JsonConvert.SerializeObject(requestData)}");
|
||||||
|
|
||||||
|
using var response = await _httpClient.PostAsync("https://api.anthropic.com/v1/messages", content);
|
||||||
|
|
||||||
|
var responseContent = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
// Para Claude Web Search, filtrar campos encrypted_content largos del log
|
||||||
|
string logContent = responseContent;
|
||||||
|
if (responseContent.Contains("encrypted_content") || responseContent.Contains("signature"))
|
||||||
|
{
|
||||||
|
logContent = FiltrarEncryptedContentParaLog(responseContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Log($"Respuesta recibida: {logContent}");
|
||||||
|
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
throw new HttpRequestException(
|
||||||
|
$"Error en la solicitud HTTP: {response.StatusCode} - {responseContent}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = JsonConvert.DeserializeObject<dynamic>(responseContent);
|
||||||
|
|
||||||
|
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.ToString(), responseContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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.ToString(), responseContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ApplicationException("No se encontró contenido en la respuesta de Claude Web Search");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Log($"Error en llamada a Claude Web Search API: {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<string> EnviarSolicitudLLM(string endpoint, object requestData)
|
private async Task<string> EnviarSolicitudLLM(string endpoint, object requestData)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -519,7 +783,15 @@ namespace GTPCorrgir
|
||||||
using var response = await _httpClient.PostAsync(endpoint, content);
|
using var response = await _httpClient.PostAsync(endpoint, content);
|
||||||
|
|
||||||
var responseContent = await response.Content.ReadAsStringAsync();
|
var responseContent = await response.Content.ReadAsStringAsync();
|
||||||
Log.Log($"Respuesta recibida: {responseContent}");
|
|
||||||
|
// Para Claude Web Search, filtrar campos encrypted_content largos del log
|
||||||
|
string logContent = responseContent;
|
||||||
|
if (endpoint.Contains("anthropic") && (responseContent.Contains("encrypted_content") || responseContent.Contains("signature")))
|
||||||
|
{
|
||||||
|
logContent = FiltrarEncryptedContentParaLog(responseContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Log($"Respuesta recibida: {logContent}");
|
||||||
|
|
||||||
if (!response.IsSuccessStatusCode)
|
if (!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
|
@ -575,6 +847,58 @@ namespace GTPCorrgir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string FiltrarEncryptedContentParaLog(string responseContent)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Usar regex para reemplazar campos encrypted_content largos con un placeholder
|
||||||
|
var regex = new System.Text.RegularExpressions.Regex(
|
||||||
|
@"""encrypted_content""\s*:\s*""[^""]{50,}""",
|
||||||
|
System.Text.RegularExpressions.RegexOptions.IgnoreCase
|
||||||
|
);
|
||||||
|
|
||||||
|
string filtered = regex.Replace(responseContent, @"""encrypted_content"": ""[CONTENT_FILTERED_FOR_LOG]""");
|
||||||
|
|
||||||
|
// También filtrar encrypted_index si es muy largo
|
||||||
|
var regexIndex = new System.Text.RegularExpressions.Regex(
|
||||||
|
@"""encrypted_index""\s*:\s*""[^""]{50,}""",
|
||||||
|
System.Text.RegularExpressions.RegexOptions.IgnoreCase
|
||||||
|
);
|
||||||
|
|
||||||
|
filtered = regexIndex.Replace(filtered, @"""encrypted_index"": ""[INDEX_FILTERED_FOR_LOG]""");
|
||||||
|
|
||||||
|
// Filtrar signature si es muy largo
|
||||||
|
var regexSignature = new System.Text.RegularExpressions.Regex(
|
||||||
|
@"""signature""\s*:\s*""[^""]{20,}""",
|
||||||
|
System.Text.RegularExpressions.RegexOptions.IgnoreCase
|
||||||
|
);
|
||||||
|
|
||||||
|
filtered = regexSignature.Replace(filtered, @"""signature"": ""[SIGNATURE_FILTERED_FOR_LOG]""");
|
||||||
|
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Log($"Error al filtrar encrypted_content: {ex.Message}");
|
||||||
|
// Si hay error al filtrar, devolver contenido original
|
||||||
|
return responseContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool EsSoloURL(string texto)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(texto))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
texto = texto.Trim();
|
||||||
|
|
||||||
|
// Verificar si el texto es principalmente una URL
|
||||||
|
return texto.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
texto.StartsWith("https://", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
texto.StartsWith("www.", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
(texto.Contains(".") && texto.Split(' ').Length == 1);
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
|
|
Loading…
Reference in New Issue