scratch_chat / chat_agent /services /programming_assistance.py
WebashalarForML's picture
Upload 178 files
330b6e4 verified
"""
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)