""" Programming Assistance Service This module provides specialized programming assistance features including code explanation, debugging, error analysis, code review, and beginner-friendly explanations for the multi-language chat agent. """ import logging import re from typing import Dict, Any, Optional, List, Tuple from enum import Enum from dataclasses import dataclass logger = logging.getLogger(__name__) class AssistanceType(Enum): """Types of programming assistance available.""" CODE_EXPLANATION = "code_explanation" DEBUGGING = "debugging" ERROR_ANALYSIS = "error_analysis" CODE_REVIEW = "code_review" CONCEPT_CLARIFICATION = "concept_clarification" BEGINNER_HELP = "beginner_help" @dataclass class CodeAnalysis: """Result of code analysis.""" code_type: str language: str complexity_level: str issues_found: List[str] suggestions: List[str] explanation: str @dataclass class ErrorAnalysis: """Result of error analysis.""" error_type: str error_message: str likely_causes: List[str] solutions: List[str] code_fixes: List[str] class ProgrammingAssistanceService: """ Service providing specialized programming assistance features. Handles code explanation, debugging assistance, error analysis, code review, and beginner-friendly explanations. """ def __init__(self): """Initialize the programming assistance service.""" self.code_patterns = self._initialize_code_patterns() self.error_patterns = self._initialize_error_patterns() logger.info("ProgrammingAssistanceService initialized") def get_assistance_prompt_template(self, assistance_type: AssistanceType, language: str, context: Dict[str, Any] = None) -> str: """ Get specialized prompt template for specific assistance type. Args: assistance_type: Type of assistance needed language: Programming language context: Additional context information Returns: Formatted prompt template string """ context = context or {} base_template = self._get_base_template(language) assistance_template = self._get_assistance_template(assistance_type, language) # Combine templates with context full_template = f"{base_template}\n\n{assistance_template}" # Add context-specific instructions if context.get('beginner_mode', False): full_template += "\n\nIMPORTANT: The user is a beginner. Use simple language, avoid jargon, and provide step-by-step explanations with examples." if context.get('code_provided', False): full_template += "\n\nThe user has provided code. Analyze it carefully and provide specific feedback." if context.get('error_provided', False): full_template += "\n\nThe user has provided an error message. Focus on explaining the error and providing solutions." return full_template def analyze_code(self, code: str, language: str) -> CodeAnalysis: """ Analyze provided code for issues, complexity, and suggestions. Args: code: Code to analyze language: Programming language Returns: CodeAnalysis object with analysis results """ try: # Detect code type code_type = self._detect_code_type(code, language) # Assess complexity complexity_level = self._assess_complexity(code, language) # Find potential issues issues_found = self._find_code_issues(code, language) # Generate suggestions suggestions = self._generate_code_suggestions(code, language, issues_found) # Create explanation explanation = self._generate_code_explanation(code, language, code_type) return CodeAnalysis( code_type=code_type, language=language, complexity_level=complexity_level, issues_found=issues_found, suggestions=suggestions, explanation=explanation ) except Exception as e: logger.error(f"Error analyzing code: {e}") return CodeAnalysis( code_type="unknown", language=language, complexity_level="unknown", issues_found=[], suggestions=[], explanation="Unable to analyze the provided code." ) def analyze_error(self, error_message: str, code: str = None, language: str = "python") -> ErrorAnalysis: """ Analyze error message and provide debugging assistance. Args: error_message: Error message to analyze code: Optional code that caused the error language: Programming language Returns: ErrorAnalysis object with debugging information """ try: # Detect error type error_type = self._detect_error_type(error_message, language) # Extract clean error message clean_message = self._clean_error_message(error_message) # Find likely causes likely_causes = self._find_error_causes(error_message, code, language) # Generate solutions solutions = self._generate_error_solutions(error_type, error_message, language) # Generate code fixes if code is provided code_fixes = [] if code: code_fixes = self._generate_code_fixes(error_message, code, language) return ErrorAnalysis( error_type=error_type, error_message=clean_message, likely_causes=likely_causes, solutions=solutions, code_fixes=code_fixes ) except Exception as e: logger.error(f"Error analyzing error message: {e}") return ErrorAnalysis( error_type="unknown", error_message=error_message, likely_causes=["Unable to analyze the error"], solutions=["Please provide more context about the error"], code_fixes=[] ) def generate_beginner_explanation(self, topic: str, language: str, code_example: str = None) -> str: """ Generate beginner-friendly explanation for programming concepts. Args: topic: Programming topic or concept language: Programming language code_example: Optional code example Returns: Beginner-friendly explanation string """ try: # Get concept information concept_info = self._get_concept_info(topic, language) # Build explanation explanation_parts = [] # Simple definition explanation_parts.append(f"**What is {topic}?**") explanation_parts.append(concept_info.get('simple_definition', f"{topic} is a programming concept.")) # Why it's useful explanation_parts.append(f"\n**Why do we use {topic}?**") explanation_parts.append(concept_info.get('purpose', f"{topic} helps make your code better.")) # Simple example if code_example or concept_info.get('example'): explanation_parts.append(f"\n**Simple Example:**") example_code = code_example or concept_info.get('example', '') explanation_parts.append(f"```{language}\n{example_code}\n```") # Explain the example explanation_parts.append(concept_info.get('example_explanation', 'This example shows how to use the concept.')) # Common mistakes if concept_info.get('common_mistakes'): explanation_parts.append(f"\n**Common Mistakes to Avoid:**") for mistake in concept_info['common_mistakes']: explanation_parts.append(f"- {mistake}") # Next steps explanation_parts.append(f"\n**What to Learn Next:**") explanation_parts.append(concept_info.get('next_steps', f"Practice using {topic} in small programs.")) return "\n".join(explanation_parts) except Exception as e: logger.error(f"Error generating beginner explanation: {e}") return f"I'd be happy to explain {topic}, but I need a bit more context. Could you ask a specific question about it?" def detect_assistance_type(self, message: str, code: str = None) -> AssistanceType: """ Detect what type of assistance the user needs based on their message. Args: message: User's message code: Optional code provided by user Returns: AssistanceType enum value """ message_lower = message.lower() # Check for error-related keywords error_keywords = ['error', 'exception', 'traceback', 'bug', 'broken', 'not working', 'fails'] if any(keyword in message_lower for keyword in error_keywords): return AssistanceType.ERROR_ANALYSIS if not code else AssistanceType.DEBUGGING # Check for explanation keywords explain_keywords = ['explain', 'what does', 'how does', 'what is', 'understand'] if any(keyword in message_lower for keyword in explain_keywords): if code: return AssistanceType.CODE_EXPLANATION else: return AssistanceType.CONCEPT_CLARIFICATION # Check for review keywords review_keywords = ['review', 'improve', 'better', 'optimize', 'feedback'] if any(keyword in message_lower for keyword in review_keywords) and code: return AssistanceType.CODE_REVIEW # Check for beginner keywords beginner_keywords = ['beginner', 'new to', 'just started', 'learning', 'basic'] if any(keyword in message_lower for keyword in beginner_keywords): return AssistanceType.BEGINNER_HELP # Default based on whether code is provided return AssistanceType.CODE_EXPLANATION if code else AssistanceType.CONCEPT_CLARIFICATION def format_assistance_response(self, assistance_type: AssistanceType, analysis_result: Any, language: str) -> str: """ Format assistance response based on type and analysis results. Args: assistance_type: Type of assistance provided analysis_result: Result from analysis (CodeAnalysis or ErrorAnalysis) language: Programming language Returns: Formatted response string """ try: if assistance_type == AssistanceType.CODE_EXPLANATION: return self._format_code_explanation_response(analysis_result, language) elif assistance_type == AssistanceType.ERROR_ANALYSIS: return self._format_error_analysis_response(analysis_result, language) elif assistance_type == AssistanceType.CODE_REVIEW: return self._format_code_review_response(analysis_result, language) elif assistance_type == AssistanceType.DEBUGGING: return self._format_debugging_response(analysis_result, language) else: return str(analysis_result) except Exception as e: logger.error(f"Error formatting assistance response: {e}") return "I encountered an issue formatting the response. Please try again." # Private helper methods def _initialize_code_patterns(self) -> Dict[str, Dict[str, List[str]]]: """Initialize code pattern recognition.""" return { 'python': { 'function_def': [r'def\s+\w+\s*\(', r'lambda\s+'], 'class_def': [r'class\s+\w+'], 'import': [r'import\s+', r'from\s+\w+\s+import'], 'loop': [r'for\s+\w+\s+in', r'while\s+'], 'conditional': [r'if\s+', r'elif\s+', r'else:'], 'exception': [r'try:', r'except', r'raise\s+'] }, 'javascript': { 'function_def': [r'function\s+\w+', r'const\s+\w+\s*=\s*\(', r'=>'], 'class_def': [r'class\s+\w+'], 'import': [r'import\s+', r'require\s*\('], 'loop': [r'for\s*\(', r'while\s*\(', r'forEach'], 'conditional': [r'if\s*\(', r'else\s+if', r'else\s*{'], 'exception': [r'try\s*{', r'catch\s*\(', r'throw\s+'] } } def _initialize_error_patterns(self) -> Dict[str, Dict[str, List[str]]]: """Initialize error pattern recognition.""" return { 'python': { 'syntax_error': ['SyntaxError', 'invalid syntax'], 'name_error': ['NameError', 'is not defined'], 'type_error': ['TypeError', 'unsupported operand'], 'index_error': ['IndexError', 'list index out of range'], 'key_error': ['KeyError'], 'attribute_error': ['AttributeError', 'has no attribute'], 'import_error': ['ImportError', 'ModuleNotFoundError'] }, 'javascript': { 'syntax_error': ['SyntaxError', 'Unexpected token'], 'reference_error': ['ReferenceError', 'is not defined'], 'type_error': ['TypeError', 'is not a function'], 'range_error': ['RangeError'], 'uri_error': ['URIError'] } } def _get_base_template(self, language: str) -> str: """Get base prompt template for language.""" return f"""You are an expert {language} programming tutor and assistant. Your role is to help students learn programming by providing clear, accurate, and educational responses. Always: 1. Use simple, beginner-friendly language 2. Provide practical examples 3. Explain the 'why' behind concepts 4. Encourage good programming practices 5. Be patient and supportive""" def _get_assistance_template(self, assistance_type: AssistanceType, language: str) -> str: """Get specific template for assistance type.""" templates = { AssistanceType.CODE_EXPLANATION: f""" TASK: Explain the provided {language} code in detail. Your response should include: - What the code does (high-level purpose) - How it works (step-by-step breakdown) - Key concepts used - Any potential improvements - Beginner-friendly explanations of complex parts Format your response with clear sections and use code comments to explain specific lines.""", AssistanceType.DEBUGGING: f""" TASK: Help debug the provided {language} code and error. Your response should include: - Clear explanation of what the error means - Why the error occurred - Step-by-step solution to fix it - The corrected code - Tips to prevent similar errors in the future Be specific about line numbers and exact changes needed.""", AssistanceType.ERROR_ANALYSIS: f""" TASK: Analyze the provided error message and explain it in simple terms. Your response should include: - What the error means in plain English - Common causes of this error - General solutions and debugging steps - Examples of code that might cause this error - How to prevent this error in the future Focus on education rather than just fixing the immediate problem.""", AssistanceType.CODE_REVIEW: f""" TASK: Review the provided {language} code and provide constructive feedback. Your response should include: - What the code does well - Areas for improvement - Code quality issues (readability, efficiency, best practices) - Specific suggestions with examples - Alternative approaches if applicable Be encouraging while providing actionable feedback.""", AssistanceType.CONCEPT_CLARIFICATION: f""" TASK: Explain the requested {language} programming concept clearly. Your response should include: - Simple definition of the concept - Why it's useful/important - Basic example with explanation - Common use cases - Related concepts to explore next Use analogies and real-world examples when helpful.""", AssistanceType.BEGINNER_HELP: f""" TASK: Provide beginner-friendly help with {language} programming. Your response should include: - Very simple explanations - Step-by-step instructions - Basic examples with detailed comments - Common beginner mistakes to avoid - Encouragement and next learning steps Assume no prior programming knowledge and explain everything clearly.""" } return templates.get(assistance_type, templates[AssistanceType.CONCEPT_CLARIFICATION]) def _detect_code_type(self, code: str, language: str) -> str: """Detect the type of code (function, class, script, etc.).""" patterns = self.code_patterns.get(language, {}) for code_type, pattern_list in patterns.items(): for pattern in pattern_list: if re.search(pattern, code, re.IGNORECASE): return code_type return "script" def _assess_complexity(self, code: str, language: str) -> str: """Assess code complexity level.""" lines = code.strip().split('\n') line_count = len([line for line in lines if line.strip()]) # Simple heuristic based on line count and patterns if line_count <= 5: return "beginner" elif line_count <= 20: return "intermediate" else: return "advanced" def _find_code_issues(self, code: str, language: str) -> List[str]: """Find potential issues in code.""" issues = [] # Common issues to check for if language == 'python': # Check for common Python issues if 'print ' in code and not 'print(' in code: issues.append("Using Python 2 print syntax - should use print() function") if re.search(r'==\s*True', code): issues.append("Comparing with 'True' explicitly - use 'if condition:' instead") if re.search(r'len\([^)]+\)\s*==\s*0', code): issues.append("Checking length == 0 - use 'if not sequence:' instead") elif language == 'javascript': # Check for common JavaScript issues if '==' in code and '===' not in code: issues.append("Using loose equality (==) - consider strict equality (===)") if 'var ' in code: issues.append("Using 'var' - consider 'let' or 'const' for better scoping") return issues def _generate_code_suggestions(self, code: str, language: str, issues: List[str]) -> List[str]: """Generate improvement suggestions for code.""" suggestions = [] # Add suggestions based on found issues for issue in issues: if "print syntax" in issue: suggestions.append("Update to Python 3 print function syntax") elif "loose equality" in issue: suggestions.append("Use strict equality (===) for more predictable comparisons") elif "var" in issue: suggestions.append("Use 'let' for variables that change, 'const' for constants") # General suggestions if not any(comment in code for comment in ['#', '//', '/*']): suggestions.append("Add comments to explain complex logic") if len(code.split('\n')) > 10 and 'def ' not in code and 'function' not in code: suggestions.append("Consider breaking long code into smaller functions") return suggestions def _generate_code_explanation(self, code: str, language: str, code_type: str) -> str: """Generate explanation for code.""" return f"This {language} code appears to be a {code_type}. It contains {len(code.split())} lines and demonstrates various programming concepts." def _detect_error_type(self, error_message: str, language: str) -> str: """Detect the type of error from error message.""" patterns = self.error_patterns.get(language, {}) for error_type, pattern_list in patterns.items(): for pattern in pattern_list: if pattern.lower() in error_message.lower(): return error_type return "unknown_error" def _clean_error_message(self, error_message: str) -> str: """Clean and extract the main error message.""" # Remove file paths and line numbers for cleaner message lines = error_message.split('\n') for line in lines: if any(error_type in line for error_type in ['Error:', 'Exception:']): return line.strip() return error_message.strip() def _find_error_causes(self, error_message: str, code: str, language: str) -> List[str]: """Find likely causes of the error.""" causes = [] error_type = self._detect_error_type(error_message, language) if error_type == 'name_error': causes.extend([ "Variable or function name is misspelled", "Variable is used before being defined", "Variable is defined in a different scope" ]) elif error_type == 'syntax_error': causes.extend([ "Missing or extra parentheses, brackets, or quotes", "Incorrect indentation", "Invalid Python syntax" ]) elif error_type == 'type_error': causes.extend([ "Trying to use incompatible data types together", "Calling a method that doesn't exist for this data type", "Passing wrong number of arguments to a function" ]) return causes def _generate_error_solutions(self, error_type: str, error_message: str, language: str) -> List[str]: """Generate solutions for the error.""" solutions = [] if error_type == 'name_error': solutions.extend([ "Check spelling of variable and function names", "Make sure variables are defined before use", "Check variable scope and indentation" ]) elif error_type == 'syntax_error': solutions.extend([ "Check for matching parentheses, brackets, and quotes", "Verify proper indentation", "Review Python syntax rules" ]) elif error_type == 'type_error': solutions.extend([ "Check data types being used in operations", "Verify function arguments and their types", "Use type conversion if needed" ]) return solutions def _generate_code_fixes(self, error_message: str, code: str, language: str) -> List[str]: """Generate specific code fixes.""" fixes = [] # This would contain more sophisticated code analysis # For now, return general guidance fixes.append("Review the code around the line mentioned in the error") fixes.append("Check for common syntax issues like missing colons or parentheses") return fixes def _get_concept_info(self, topic: str, language: str) -> Dict[str, Any]: """Get information about a programming concept.""" # This would be expanded with a comprehensive concept database concepts = { 'variables': { 'simple_definition': 'Variables are containers that store data values.', 'purpose': 'Variables let you store information and use it later in your program.', 'example': 'name = "Alice"\nage = 25\nprint(f"Hello, {name}! You are {age} years old.")', 'example_explanation': 'This creates two variables: name (storing text) and age (storing a number).', 'common_mistakes': [ 'Forgetting to assign a value before using the variable', 'Using spaces in variable names', 'Starting variable names with numbers' ], 'next_steps': 'Learn about different data types like strings, integers, and lists.' }, 'functions': { 'simple_definition': 'Functions are reusable blocks of code that perform specific tasks.', 'purpose': 'Functions help organize code and avoid repetition.', 'example': 'def greet(name):\n return f"Hello, {name}!"\n\nmessage = greet("Alice")\nprint(message)', 'example_explanation': 'This function takes a name and returns a greeting message.', 'common_mistakes': [ 'Forgetting to call the function with parentheses', 'Not returning a value when needed', 'Incorrect indentation inside the function' ], 'next_steps': 'Learn about function parameters, return values, and scope.' } } return concepts.get(topic.lower(), { 'simple_definition': f'{topic} is an important programming concept.', 'purpose': f'{topic} helps make your code more effective.', 'next_steps': f'Practice using {topic} in small programs.' }) def _format_code_explanation_response(self, analysis: CodeAnalysis, language: str) -> str: """Format code explanation response.""" response_parts = [ f"## Code Analysis\n", f"**Language:** {language.title()}", f"**Type:** {analysis.code_type.replace('_', ' ').title()}", f"**Complexity:** {analysis.complexity_level.title()}\n", f"**Explanation:**\n{analysis.explanation}\n" ] if analysis.issues_found: response_parts.append("**Issues Found:**") for issue in analysis.issues_found: response_parts.append(f"- {issue}") response_parts.append("") if analysis.suggestions: response_parts.append("**Suggestions for Improvement:**") for suggestion in analysis.suggestions: response_parts.append(f"- {suggestion}") return "\n".join(response_parts) def _format_error_analysis_response(self, analysis: ErrorAnalysis, language: str) -> str: """Format error analysis response.""" response_parts = [ f"## Error Analysis\n", f"**Error Type:** {analysis.error_type.replace('_', ' ').title()}", f"**Error Message:** {analysis.error_message}\n", f"**What This Means:**\nThis error occurs when {analysis.error_message.lower()}\n" ] if analysis.likely_causes: response_parts.append("**Likely Causes:**") for cause in analysis.likely_causes: response_parts.append(f"- {cause}") response_parts.append("") if analysis.solutions: response_parts.append("**How to Fix It:**") for solution in analysis.solutions: response_parts.append(f"- {solution}") response_parts.append("") if analysis.code_fixes: response_parts.append("**Specific Code Changes:**") for fix in analysis.code_fixes: response_parts.append(f"- {fix}") return "\n".join(response_parts) def _format_code_review_response(self, analysis: CodeAnalysis, language: str) -> str: """Format code review response.""" response_parts = [ f"## Code Review\n", f"**Overall Assessment:** Your {analysis.code_type.replace('_', ' ')} looks {analysis.complexity_level}!\n", f"**What's Working Well:**\n- Code structure is clear", f"- Appropriate use of {language} syntax\n" ] if analysis.issues_found: response_parts.append("**Areas for Improvement:**") for issue in analysis.issues_found: response_parts.append(f"- {issue}") response_parts.append("") if analysis.suggestions: response_parts.append("**Recommendations:**") for suggestion in analysis.suggestions: response_parts.append(f"- {suggestion}") response_parts.append("\n**Keep up the great work! 🚀**") return "\n".join(response_parts) def _format_debugging_response(self, analysis: ErrorAnalysis, language: str) -> str: """Format debugging response.""" response_parts = [ f"## Debugging Help\n", f"**The Problem:** {analysis.error_message}\n", f"**Let's Fix This Step by Step:**\n" ] for i, solution in enumerate(analysis.solutions, 1): response_parts.append(f"{i}. {solution}") if analysis.code_fixes: response_parts.append("\n**Code Changes Needed:**") for fix in analysis.code_fixes: response_parts.append(f"- {fix}") response_parts.append("\n**Pro Tip:** Test your code after each change to make sure it works!") return "\n".join(response_parts)