scratch_chat / chat_agent /services /programming_assistance.py
WebashalarForML's picture
Upload 178 files
330b6e4 verified
Raw History Blame Contribute Delete
31.1 kB
"""
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)