from typing import Dict, List, Optional import logging from datetime import datetime from .model_manager import ModelManager from .config import Config logger = logging.getLogger(__name__) class CodeReview: def __init__(self, code: str, language: str, review_id: str): self.code = code self.language = language self.review_id = review_id self.timestamp = datetime.now() self.suggestions: List[Dict] = [] self.metrics: Dict = {} class CodeReviewer: def __init__(self, model_manager: ModelManager): self.model_manager = model_manager self.review_history: List[CodeReview] = [] def _create_review_prompt(self, code: str, language: str) -> str: """Create a structured prompt for code review.""" return f"""As a code reviewer, analyze the following {language} code and provide specific suggestions in exactly these sections: - Issues: (list critical problems) - Improvements: (list suggested enhancements) - Best Practices: (list recommendations) - Security: (list security concerns) Code to review: ```{language} {code} ``` Provide your review in exactly these sections: Issues, Improvements, Best Practices, Security. Each section should contain a list of specific points. """ def review_code(self, code: str, language: str, review_id: str) -> CodeReview: """Perform code review using the LLM.""" try: start_time = datetime.now() # Create review instance review = CodeReview(code, language, review_id) # Generate review prompt prompt = self._create_review_prompt(code, language) # Get model response response = self.model_manager.generate_text( prompt, max_new_tokens=Config.MAX_OUTPUT_LENGTH ) # Parse and structure the response sections = self._parse_review_response(response) # Store suggestions review.suggestions = sections # Calculate metrics end_time = datetime.now() review.metrics = { 'response_time': (end_time - start_time).total_seconds(), 'code_length': len(code), 'suggestion_count': sum(len(section['items']) for section in sections) } # Store review in history self._add_to_history(review) return review except Exception as e: logger.error(f"Error during code review: {str(e)}") raise def _parse_review_response(self, response: str) -> List[Dict]: """Parse the LLM response into structured sections.""" sections = [] current_section = None # Split response into lines and process each line lines = response.split('\n') for line in lines: line = line.strip() if not line: continue # Check for section headers if line.startswith('- ') and ':' in line: section_type = line[2:].split(':', 1)[0].strip() current_section = { 'type': section_type, 'items': [] } sections.append(current_section) # Add any content after the colon as first item content = line.split(':', 1)[1].strip() if content: current_section['items'].append(content) # Add items to current section elif current_section and line.strip('-* '): item = line.strip('-* ') if item: # Only add non-empty items current_section['items'].append(item) # Ensure all required sections exist required_sections = ['Issues', 'Improvements', 'Best Practices', 'Security'] result = [] for section_type in required_sections: found_section = next((s for s in sections if s['type'] == section_type), None) if found_section: result.append(found_section) else: result.append({ 'type': section_type, 'items': [] }) return result def _add_to_history(self, review: CodeReview): """Add review to history and maintain size limit.""" self.review_history.append(review) if len(self.review_history) > Config.MAX_HISTORY_ITEMS: self.review_history.pop(0) def get_review_metrics(self) -> Dict: """Calculate aggregate metrics from review history.""" if not self.review_history: return { 'total_reviews': 0, 'avg_response_time': 0.0, 'avg_suggestions': 0.0, 'reviews_today': 0 } total_reviews = len(self.review_history) avg_response_time = sum(r.metrics['response_time'] for r in self.review_history) / total_reviews avg_suggestions = sum(r.metrics['suggestion_count'] for r in self.review_history) / total_reviews return { 'total_reviews': total_reviews, 'avg_response_time': avg_response_time, 'avg_suggestions': avg_suggestions, 'reviews_today': sum(1 for r in self.review_history if r.timestamp.date() == datetime.now().date()) } def get_review_history(self, limit: Optional[int] = None) -> List[CodeReview]: """Get review history with optional limit.""" if limit: return self.review_history[-limit:] return self.review_history