From 4148de5d66d86098df7570d829d3cce07e8c809a Mon Sep 17 00:00:00 2001 From: Nurfog Date: Thu, 23 Apr 2026 10:45:23 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20agregar=20l=C3=B3gica=20para=20identifi?= =?UTF-8?q?car=20respuestas=20fuera=20de=20tema=20y=20mejorar=20la=20clasi?= =?UTF-8?q?ficaci=C3=B3n=20de=20contenido=20relacionado=20con=20programaci?= =?UTF-8?q?=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- services/lms-service/src/handlers.rs | 50 ++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/services/lms-service/src/handlers.rs b/services/lms-service/src/handlers.rs index 0ac5eda..a0b5bec 100644 --- a/services/lms-service/src/handlers.rs +++ b/services/lms-service/src/handlers.rs @@ -84,9 +84,42 @@ fn tokenize_significant_terms(text: &str) -> Vec { .collect() } +fn contains_any_keyword(text: &str, keywords: &[&str]) -> bool { + let lc = text.to_lowercase(); + keywords.iter().any(|k| lc.contains(k)) +} + +fn is_programming_related(text: &str) -> bool { + const PROGRAMMING_KEYWORDS: [&str; 20] = [ + "c++", "cpp", "python", "java", "javascript", "typescript", "rust", "golang", "fibonacci", + "algoritmo", "algorithm", "recursiv", "funcion", "function", "codigo", "program", "compilar", + "compilar", "array", "puntero", + ]; + contains_any_keyword(text, &PROGRAMMING_KEYWORDS) +} + +fn looks_like_off_topic_response(response: &str) -> bool { + const OFF_TOPIC_RESPONSE_MARKERS: [&str; 10] = [ + "si deseas saber", + "puedo darte una pista", + "fibonacci", + "c++", + "```", + "algoritmo", + "recursiv", + "int fibonacci", + "tiempo de complejidad", + "memorizaci", + ]; + contains_any_keyword(response, &OFF_TOPIC_RESPONSE_MARKERS) +} + fn heuristic_out_of_scope(message: &str, lesson_scope: &str) -> bool { let msg_terms = tokenize_significant_terms(message); if msg_terms.len() < 3 { + if is_programming_related(message) && !is_programming_related(lesson_scope) { + return true; + } return false; } @@ -96,7 +129,11 @@ fn heuristic_out_of_scope(message: &str, lesson_scope: &str) -> bool { .filter(|term| scope_lc.contains(term.as_str())) .count(); - overlap == 0 + if is_programming_related(message) && !is_programming_related(lesson_scope) { + return true; + } + + overlap <= 1 } pub async fn get_me( @@ -3834,11 +3871,20 @@ pub async fn chat_with_tutor( ) })?; - let tutor_response = ai_data["choices"][0]["message"]["content"] + let raw_tutor_response = ai_data["choices"][0]["message"]["content"] .as_str() .unwrap_or("Lo siento, tuve un problema procesando tu pregunta.") .to_string(); + let tutor_response = if looks_like_off_topic_response(&raw_tutor_response) + && is_programming_related(&payload.message) + && !is_programming_related(&lesson_scope) + { + scope_rejection_message(&lesson.title) + } else { + raw_tutor_response + }; + // Calcular y registrar el uso de tokens let input_tokens = count_tokens(&system_prompt) + count_tokens(&payload.message); let output_tokens = count_tokens(&tutor_response);