""" Summarizer Feature - Generates summaries of study notes """ from typing import Tuple from config import LLM_PROVIDER from core.llm_engine import LLMEngine from core.prompt_builder import PromptBuilder from core.validator import InputValidator, ContentValidator from core.utils import log_event, format_summary class Summarizer: """Generates summaries of notes and content.""" def __init__(self, llm_provider: str = LLM_PROVIDER): """ Initialize summarizer. Args: llm_provider: LLM provider to use """ self.engine = LLMEngine(llm_provider) self.prompt_builder = PromptBuilder() self.validator = InputValidator() def summarize( self, text: str, mode: str = "normal", max_length: int = 500, quality_check: bool = True ) -> Tuple[bool, str]: """ Generate a summary of the text. Args: text: Text to summarize mode: Prompt mode (normal, detailed, teacher, exam) max_length: Maximum summary length quality_check: Whether to validate output quality Returns: Tuple of (success, summary_text) """ # Validate input is_valid, msg = self.validator.validate_input(text) if not is_valid: log_event("VALIDATION_ERROR", f"Summarizer: {msg}") return False, msg # Build prompt try: prompt = self.prompt_builder.build_summary_prompt( text, mode=mode, max_length=max_length ) log_event("PROMPT_BUILT", "Summary prompt ready") except Exception as e: log_event("PROMPT_ERROR", f"Error building prompt: {str(e)}") return False, f"Error building prompt: {str(e)}" # Generate summary success, summary = self.engine.generate(prompt, max_tokens=max_length) if not success: log_event("SUMMARY_ERROR", summary) return False, summary if not isinstance(summary, str): summary = str(summary) summary = summary.strip() if not summary: log_event("SUMMARY_ERROR", "Empty summary from model") return False, "Summary generation failed: empty response from model." # Retry once if summary is too short. if not ContentValidator.is_acceptable_summary(summary, min_chars=80): log_event("SUMMARY_RETRY", "Summary too short, retrying with higher max tokens") retry_tokens = max(max_length + 200, 300) success_retry, summary_retry = self.engine.generate(prompt, max_tokens=retry_tokens) if success_retry and isinstance(summary_retry, str) and summary_retry.strip(): summary = summary_retry.strip() # Quality check if quality_check: is_acceptable = ContentValidator.is_acceptable_summary(summary, min_chars=80) if not is_acceptable: log_event("QUALITY_CHECK_FAILED", "Summary too short") return False, "Summary generated but quality is low. Please try again with more input text." quality_score = ContentValidator.estimate_quality(summary) log_event("QUALITY_SCORE", f"Summary quality: {quality_score:.2f}") # Format summary formatted_summary = format_summary(summary) log_event("SUMMARY_SUCCESS", f"Summary generated ({len(formatted_summary)} chars)") return True, formatted_summary def quick_summary(self, text: str) -> Tuple[bool, str]: """ Generate a quick 1-2 line summary. Args: text: Text to summarize Returns: Tuple of (success, summary) """ return self.summarize(text, mode="exam", max_length=200) def detailed_summary(self, text: str) -> Tuple[bool, str]: """ Generate a detailed summary with context. Args: text: Text to summarize Returns: Tuple of (success, summary) """ return self.summarize(text, mode="detailed", max_length=1000) def educational_summary(self, text: str) -> Tuple[bool, str]: """ Generate a summary suitable for learning. Args: text: Text to summarize Returns: Tuple of (success, summary) """ return self.summarize(text, mode="teacher", max_length=800)