CoolFace
Apppublic

Shivaaaahdjdnd/code_analysis

sourceHugging Faceupdated 3mo agoView on Hugging Face
0likes
coding_analyzer.py766 linesDownload Raw Back to root
1import ast2import re3import difflib4import subprocess5import tempfile6import os7import json8import traceback9from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline10import torch11from config import config, get_complexity_score, get_language_config, AI_PATTERNS12 13 14class CodingAnalyzer:15    def __init__(self):16        self.config = config17        self.setup_ai_model()18 19    def setup_ai_model(self):20        """Setup Qwen2.5-1.5B-Instruct model for code analysis (CPU-friendly)"""21        try:22            model_config = self.config.model23            print(f"๐Ÿ”„ Loading {model_config.model_name} model...")24 25            use_fp16 = torch.cuda.is_available()26            dtype = torch.float16 if use_fp16 else torch.float3227 28            self.model = AutoModelForCausalLM.from_pretrained(29                model_config.model_name,30                torch_dtype=dtype,31                trust_remote_code=model_config.trust_remote_code,32                low_cpu_mem_usage=True33            )34 35            device = "cuda" if torch.cuda.is_available() else "cpu"36            self.model = self.model.to(device)37            print(f"๐Ÿ“ Running on: {device.upper()}")38 39            self.tokenizer = AutoTokenizer.from_pretrained(40                model_config.model_name,41                trust_remote_code=model_config.trust_remote_code42            )43 44            self.pipe = pipeline(45                "text-generation",46                model=self.model,47                tokenizer=self.tokenizer,48                max_new_tokens=model_config.max_new_tokens,49                temperature=model_config.temperature,50                do_sample=model_config.do_sample,51                top_p=model_config.top_p,52                repetition_penalty=model_config.repetition_penalty53            )54 55            param_count = sum(p.numel() for p in self.model.parameters()) / 1e956            print(f"โœ… {model_config.model_name} loaded! ({param_count:.2f}B params)")57 58        except Exception as e:59            print(f"โŒ Model load failed: {e}")60            print(f"๐Ÿ“‹ Traceback:\n{traceback.format_exc()}")61            print("๐Ÿ”„ Falling back to rule-based analysis...")62            self.pipe = None63 64    def _call_ai(self, messages):65        """66        Centralized helper to call the Qwen chat pipeline.67        Supports chat template format.68        Returns generated text string or raises on failure.69        """70        if self.pipe is None:71            raise RuntimeError("AI pipeline not available")72 73        output = self.pipe(messages, return_full_text=False)74 75        if isinstance(output, list) and len(output) > 0:76            first = output[0]77            if isinstance(first, dict) and 'generated_text' in first:78                return first['generated_text']79            if isinstance(first, list) and len(first) > 0 and 'generated_text' in first[0]:80                return first[0]['generated_text']81 82        raise ValueError(f"Unexpected pipeline output format: {type(output)}")83 84    def analyze_solution(self, question, user_code, correct_solution, language="python", difficulty="medium", test_cases=None):85        """Main analysis function"""86        results = {87            'status': 'completed',88            'overall_score': 0,89            'max_score': 100,90            'analysis': {91                'correctness': {},92                'code_quality': {},93                'efficiency': {},94                'ai_detection': {},95                'similarity': {},96                'test_results': {}97            },98            'feedback': '',99            'recommendations': []100        }101 102        try:103            # 1. Correctness Analysis (40 points)104            correctness = self.analyze_correctness(user_code, correct_solution, test_cases, language)105            results['analysis']['correctness'] = correctness106            results['overall_score'] += correctness['score']107 108            # 2. Code Quality Analysis (25 points)109            quality = self.analyze_code_quality(user_code, language)110            results['analysis']['code_quality'] = quality111            results['overall_score'] += quality['score']112 113            # 3. Efficiency Analysis (20 points)114            efficiency = self.analyze_efficiency(user_code, correct_solution, language)115            results['analysis']['efficiency'] = efficiency116            results['overall_score'] += efficiency['score']117 118            # 4. AI Detection (10 points penalty)119            ai_detection = self.detect_ai_generated(user_code, language)120            results['analysis']['ai_detection'] = ai_detection121            results['overall_score'] -= ai_detection['penalty']122 123            # 5. Similarity Analysis (5 points penalty)124            similarity = self.analyze_similarity(user_code, correct_solution)125            results['analysis']['similarity'] = similarity126            results['overall_score'] -= similarity['penalty']127 128            # Generate feedback and recommendations129            results['feedback'] = self.generate_feedback(results['analysis'], question, difficulty)130            results['recommendations'] = self.generate_recommendations(results['analysis'])131 132            results['overall_score'] = max(0, min(100, results['overall_score']))133 134        except Exception as e:135            results['status'] = 'error'136            results['error'] = str(e)137            print(f"โŒ analyze_solution failed: {e}\n{traceback.format_exc()}")138 139        return results140 141    # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€142    # 1. CORRECTNESS143    # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€144 145    def analyze_correctness(self, user_code, correct_solution, test_cases, language):146        """Correctness analysis: syntax + real test execution + AI review"""147        result = {148            'score': 0,149            'max_score': 40,150            'syntax_valid': False,151            'logic_correct': False,152            'test_cases_passed': 0,153            'total_test_cases': 0,154            'execution_errors': [],155            'ai_analysis': ''156        }157 158        try:159            # --- Syntax check (Python only via AST) ---160            if language == 'python':161                try:162                    ast.parse(user_code)163                    result['syntax_valid'] = True164                except SyntaxError as e:165                    result['execution_errors'].append(f"Syntax Error: {str(e)}")166                    result['score'] = 0167                    return result168            else:169                # For other languages assume syntax valid (no AST available)170                result['syntax_valid'] = True171 172            # --- Real test execution for Python ---173            if language == 'python' and test_cases:174                passed, total, errors = self._run_python_tests(user_code, test_cases)175                result['test_cases_passed'] = passed176                result['total_test_cases'] = total177                result['execution_errors'].extend(errors)178 179                if total > 0:180                    pass_ratio = passed / total181                    result['score'] = int(10 + 30 * pass_ratio)  # 10 syntax + up to 30 logic182                    result['logic_correct'] = pass_ratio >= 0.8183                else:184                    result['score'] = 10  # only syntax points if no tests185 186            # --- AI-powered review ---187            if self.pipe:188                correctness_prompt = f"""Analyze this code solution for correctness:189 190User Code:191{user_code}192 193Reference Solution:194{correct_solution}195 196Evaluate:1971. Syntax validity (0-10 points)1982. Logic correctness (0-30 points)1993. Edge case handling2004. Algorithm accuracy201 202Respond ONLY with valid JSON, no extra text:203{{"syntax_score": 8, "logic_score": 25, "analysis": "your explanation here"}}"""204 205                messages = [206                    {"role": "system", "content": "You are an expert code reviewer. Respond with valid JSON only, no markdown, no extra text."},207                    {"role": "user", "content": correctness_prompt}208                ]209 210                try:211                    ai_response = self._call_ai(messages)212                    json_match = re.search(r'\{.*?\}', ai_response, re.DOTALL)213                    if json_match:214                        ai_eval = json.loads(json_match.group())215                        syntax_score = min(10, max(0, int(ai_eval.get('syntax_score', 0))))216                        logic_score = min(30, max(0, int(ai_eval.get('logic_score', 0))))217                        # If no real tests ran, use AI score218                        if result['total_test_cases'] == 0:219                            result['score'] = syntax_score + logic_score220                            result['logic_correct'] = logic_score >= 25221                        result['ai_analysis'] = ai_eval.get('analysis', '')222                except Exception as e:223                    print(f"โš ๏ธ Correctness AI analysis failed: {e}")224                    # Fallback: syntax valid = 10 + 30 base225                    if result['total_test_cases'] == 0:226                        result['score'] = 40 if result['syntax_valid'] else 0227                        result['logic_correct'] = result['syntax_valid']228            else:229                # No AI: give full marks if syntax valid and no tests failed230                if result['total_test_cases'] == 0 and result['syntax_valid']:231                    result['score'] = 40232                    result['logic_correct'] = True233 234        except Exception as e:235            result['execution_errors'].append(str(e))236            print(f"โŒ analyze_correctness failed: {e}")237 238        return result239 240    def _run_python_tests(self, user_code, test_cases):241        """Actually execute Python code against test cases using subprocess"""242        passed = 0243        total = len(test_cases)244        errors = []245 246        for tc in test_cases:247            input_data = tc.get('input', '')248            expected = str(tc.get('expected_output', '')).strip()249            input_repr = repr(input_data)250 251            # Build test script without backslashes inside f-strings (Python 3.10 compat)252            lines = [253                user_code,254                "",255                "import sys",256                "import ast as _ast",257                "result = None",258                "try:",259                "    src = '''",260                user_code,261                "    '''",262                "    tree = _ast.parse(src)",263                "    func_names = [node.name for node in _ast.walk(tree) if isinstance(node, _ast.FunctionDef)]",264                "    if func_names:",265                "        fn = globals()[func_names[0]]",266                "        args = " + input_repr,267                "        if isinstance(args, (list, tuple)):",268                "            result = fn(*args)",269                "        else:",270                "            result = fn(args)",271                "    print(result)",272                "except Exception as e:",273                "    print('ERROR: ' + str(e), file=sys.stderr)",274                "    sys.exit(1)",275            ]276            test_script = "\n".join(lines)277 278            try:279                proc = subprocess.run(280                    ['python3', '-c', test_script],281                    capture_output=True, text=True,282                    timeout=self.config.analysis.test_timeout283                )284                actual = proc.stdout.strip()285                if proc.returncode == 0 and actual == expected:286                    passed += 1287                else:288                    if proc.stderr:289                        errors.append(proc.stderr.strip()[:200])290            except subprocess.TimeoutExpired:291                errors.append("Test timed out (>" + str(self.config.analysis.test_timeout) + "s)")292            except Exception as e:293                errors.append(str(e))294 295        return passed, total, errors296 297    # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€298    # 2. CODE QUALITY299    # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€300 301    def analyze_code_quality(self, user_code, language):302        """Code quality analysis: AI-powered with rule-based fallback"""303        result = {304            'score': 0,305            'max_score': 25,306            'readability': 0,307            'structure': 0,308            'naming': 0,309            'comments': 0,310            'best_practices': 0,311            'ai_analysis': ''312        }313 314        try:315            if self.pipe:316                quality_prompt = f"""Analyze this {language} code for quality:317 318Code:319{user_code}320 321Score each (0-5 points):3221. readability: formatting, line length, clarity3232. structure: functions/classes, organization3243. naming: variable and function names3254. comments: documentation quality3265. best_practices: language conventions327 328Respond ONLY with valid JSON:329{{"readability": 4, "structure": 4, "naming": 3, "comments": 1, "best_practices": 3, "analysis": "explanation"}}"""330 331                messages = [332                    {"role": "system", "content": "You are a code quality expert. Respond with valid JSON only, no markdown."},333                    {"role": "user", "content": quality_prompt}334                ]335 336                try:337                    ai_response = self._call_ai(messages)338                    json_match = re.search(r'\{.*?\}', ai_response, re.DOTALL)339                    if json_match:340                        ai_eval = json.loads(json_match.group())341                        result['readability'] = min(5, max(0, int(ai_eval.get('readability', 0))))342                        result['structure'] = min(5, max(0, int(ai_eval.get('structure', 0))))343                        result['naming'] = min(5, max(0, int(ai_eval.get('naming', 0))))344                        result['comments'] = min(5, max(0, int(ai_eval.get('comments', 0))))345                        result['best_practices'] = min(5, max(0, int(ai_eval.get('best_practices', 0))))346                        result['ai_analysis'] = ai_eval.get('analysis', '')347                        result['score'] = sum([result['readability'], result['structure'],348                                               result['naming'], result['comments'], result['best_practices']])349                        return result350                    else:351                        raise ValueError("No JSON in AI response")352                except Exception as e:353                    print(f"โš ๏ธ Code quality AI failed: {e}")354                    self._basic_quality_analysis(user_code, language, result)355            else:356                self._basic_quality_analysis(user_code, language, result)357 358        except Exception as e:359            print(f"โŒ analyze_code_quality failed: {e}")360            self._basic_quality_analysis(user_code, language, result)361 362        return result363 364    def _basic_quality_analysis(self, user_code, language, result):365        """Rule-based quality analysis fallback"""366        lines = user_code.split('\n')367        avg_line_length = sum(len(l) for l in lines) / len(lines) if lines else 0368        comment_lines = sum(1 for l in lines if l.strip().startswith('#'))369 370        result['readability'] = 5 if avg_line_length < 80 else (3 if avg_line_length < 120 else 1)371        result['structure'] = 4 if 'def ' in user_code else 2372        result['naming'] = 3  # neutral default373        result['comments'] = min(5, comment_lines)374        result['best_practices'] = 3  # neutral default375 376        result['score'] = sum([result['readability'], result['structure'],377                                result['naming'], result['comments'], result['best_practices']])378 379    # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€380    # 3. EFFICIENCY381    # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€382 383    def analyze_efficiency(self, user_code, correct_solution, language):384        """Efficiency analysis: AI complexity detection with regex fallback"""385        result = {386            'score': 0,387            'max_score': 20,388            'time_complexity': 'Unknown',389            'space_complexity': 'Unknown',390            'optimization_score': 0,391            'ai_analysis': ''392        }393 394        try:395            if self.pipe:396                efficiency_prompt = f"""Analyze algorithm efficiency:397 398User Code:399{user_code}400 401Reference Solution:402{correct_solution}403 404Evaluate:4051. Time Complexity in Big O4062. Space Complexity in Big O4073. Efficiency score (0-20 points)4084. Optimization opportunities409 410Respond ONLY with valid JSON:411{{"time_complexity": "O(n)", "space_complexity": "O(1)", "efficiency_score": 15, "analysis": "explanation"}}"""412 413                messages = [414                    {"role": "system", "content": "You are an algorithm complexity expert. Respond with valid JSON only, no markdown."},415                    {"role": "user", "content": efficiency_prompt}416                ]417 418                try:419                    ai_response = self._call_ai(messages)420                    json_match = re.search(r'\{.*?\}', ai_response, re.DOTALL)421                    if json_match:422                        ai_eval = json.loads(json_match.group())423                        result['time_complexity'] = ai_eval.get('time_complexity', 'Unknown')424                        result['space_complexity'] = ai_eval.get('space_complexity', 'Unknown')425                        result['score'] = min(20, max(0, int(ai_eval.get('efficiency_score', 0))))426                        result['optimization_score'] = result['score']427                        result['ai_analysis'] = ai_eval.get('analysis', '')428                        return result429                    else:430                        raise ValueError("No JSON in AI response")431                except Exception as e:432                    print(f"โš ๏ธ Efficiency AI failed: {e}")433                    self._basic_efficiency_analysis(user_code, result)434            else:435                self._basic_efficiency_analysis(user_code, result)436 437        except Exception as e:438            print(f"โŒ analyze_efficiency failed: {e}")439            self._basic_efficiency_analysis(user_code, result)440 441        return result442 443    def _basic_efficiency_analysis(self, user_code, result):444        """Rule-based complexity detection"""445        nested_loops = len(re.findall(r'for\s.+\n.*for\s', user_code))446        while_nested = len(re.findall(r'while\s.+\n.*while\s', user_code))447        total_nested = nested_loops + while_nested448 449        if total_nested == 0:450            complexity_score = 15451            result['time_complexity'] = 'O(n) or better'452        elif total_nested == 1:453            complexity_score = 10454            result['time_complexity'] = 'O(nยฒ)'455        else:456            complexity_score = 5457            result['time_complexity'] = 'O(nยณ) or worse'458 459        # Bonus for efficient data structures460        if 'dict' in user_code or '{' in user_code or 'set(' in user_code:461            complexity_score = min(20, complexity_score + 3)462 463        result['space_complexity'] = 'O(n)' if ('list(' in user_code or '[]' in user_code) else 'O(1)'464        result['optimization_score'] = complexity_score465        result['score'] = min(20, complexity_score)466 467    # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€468    # 4. AI DETECTION469    # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€470 471    def detect_ai_generated(self, user_code, language):472        """Detect AI-generated code patterns"""473        result = {474            'penalty': 0,475            'max_penalty': 10,476            'ai_probability': 0,477            'indicators': [],478            'ai_analysis': ''479        }480 481        try:482            if self.pipe:483                ai_detection_prompt = f"""Analyze if this code is AI-generated:484 485Code:486{user_code}487 488Look for:4891. Overly verbose comments4902. Perfect documentation style4913. Generic variable names (result, output, temp)4924. Unnatural comment patterns4935. Typical ChatGPT/AI structure494 495Respond ONLY with valid JSON:496{{"ai_probability": 20, "penalty_score": 2, "indicators": ["reason1"], "analysis": "explanation"}}497ai_probability: 0-100, penalty_score: 0-10"""498 499                messages = [500                    {"role": "system", "content": "You are an expert at detecting AI-generated code. Respond with valid JSON only, no markdown."},501                    {"role": "user", "content": ai_detection_prompt}502                ]503 504                try:505                    ai_response = self._call_ai(messages)506                    json_match = re.search(r'\{.*?\}', ai_response, re.DOTALL)507                    if json_match:508                        ai_eval = json.loads(json_match.group())509                        result['ai_probability'] = min(100, max(0, int(ai_eval.get('ai_probability', 0))))510                        result['penalty'] = min(10, max(0, int(ai_eval.get('penalty_score', 0))))511                        result['indicators'] = ai_eval.get('indicators', [])512                        result['ai_analysis'] = ai_eval.get('analysis', '')513                        return result514                    else:515                        raise ValueError("No JSON in AI response")516                except Exception as e:517                    print(f"โš ๏ธ AI detection failed: {e}")518                    self._basic_ai_detection(user_code, language, result)519            else:520                self._basic_ai_detection(user_code, language, result)521 522        except Exception as e:523            print(f"โŒ detect_ai_generated failed: {e}")524            self._basic_ai_detection(user_code, language, result)525 526        return result527 528    def _basic_ai_detection(self, user_code, language, result):529        """Rule-based AI detection fallback"""530        ai_score = 0531        lines = user_code.split('\n')532 533        comment_ratio = sum(1 for l in lines if l.strip().startswith('#')) / len(lines) if lines else 0534        if comment_ratio > 0.3:535            ai_score += 3536            result['indicators'].append('Excessive comments (>30% of lines)')537 538        for pattern in AI_PATTERNS:539            if re.search(pattern, user_code, re.IGNORECASE):540                ai_score += 2541                result['indicators'].append(f'Generic AI comment pattern: {pattern}')542                break543 544        # Generic variable names545        if re.search(r'\bresult\b|\boutput\b|\btemp\b|\bans\b', user_code):546            ai_score += 1547            result['indicators'].append('Generic variable names (result/output/temp)')548 549        result['ai_probability'] = min(100, ai_score * 15)550        result['penalty'] = min(10, ai_score)551 552    # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€553    # 5. SIMILARITY554    # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€555 556    def analyze_similarity(self, user_code, correct_solution):557        """Similarity / plagiarism check"""558        result = {559            'penalty': 0,560            'max_penalty': 5,561            'similarity_ratio': 0,562            'ai_analysis': ''563        }564 565        try:566            # Normalize both codes567            user_clean = re.sub(r'#.*', '', user_code).replace(' ', '').replace('\n', '')568            correct_clean = re.sub(r'#.*', '', correct_solution).replace(' ', '').replace('\n', '')569            similarity = difflib.SequenceMatcher(None, user_clean, correct_clean).ratio()570            result['similarity_ratio'] = round(similarity, 2)571 572            if self.pipe:573                similarity_prompt = f"""Analyze code similarity for plagiarism:574 575User Code:576{user_code}577 578Reference Solution:579{correct_solution}580 581Similarity Ratio: {similarity:.2f}582 583Evaluate:5841. Structural similarity5852. Algorithm approach5863. Variable naming patterns5874. Is it copying or just same logic?5885. Penalty (0-5 points)589 590Respond ONLY with valid JSON:591{{"penalty_score": 2, "is_plagiarism": false, "analysis": "explanation"}}"""592 593                messages = [594                    {"role": "system", "content": "You are a plagiarism detection expert. Respond with valid JSON only, no markdown."},595                    {"role": "user", "content": similarity_prompt}596                ]597 598                try:599                    ai_response = self._call_ai(messages)600                    json_match = re.search(r'\{.*?\}', ai_response, re.DOTALL)601                    if json_match:602                        ai_eval = json.loads(json_match.group())603                        result['penalty'] = min(5, max(0, int(ai_eval.get('penalty_score', 0))))604                        result['ai_analysis'] = ai_eval.get('analysis', '')605                        return result606                    else:607                        raise ValueError("No JSON in AI response")608                except Exception as e:609                    print(f"โš ๏ธ Similarity AI failed: {e}")610                    self._basic_similarity_penalty(similarity, result)611            else:612                self._basic_similarity_penalty(similarity, result)613 614        except Exception as e:615            print(f"โŒ analyze_similarity failed: {e}")616 617        return result618 619    def _basic_similarity_penalty(self, similarity, result):620        """Rule-based similarity penalty"""621        if similarity > 0.95:622            result['penalty'] = 5623        elif similarity > 0.85:624            result['penalty'] = 3625        elif similarity > 0.75:626            result['penalty'] = 1627        else:628            result['penalty'] = 0629 630    # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€631    # 6. FEEDBACK & RECOMMENDATIONS632    # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€633 634    def generate_feedback(self, analysis, question, difficulty):635        """Generate comprehensive AI-powered feedback"""636        correctness = analysis['correctness']637        quality = analysis['code_quality']638        efficiency = analysis['efficiency']639        ai_detection = analysis['ai_detection']640        similarity = analysis['similarity']641 642        if not self.pipe:643            total = (correctness['score'] + quality['score'] + efficiency['score']644                     - ai_detection['penalty'] - similarity['penalty'])645            return (646                f"Rule-based analysis completed. "647                f"Correctness: {correctness['score']}/40, "648                f"Quality: {quality['score']}/25, "649                f"Efficiency: {efficiency['score']}/20 | "650                f"Time complexity: {efficiency.get('time_complexity', 'Unknown')}. "651                f"Overall: {total}/100."652            )653 654        try:655            feedback_prompt = f"""Give constructive feedback for this coding solution:656 657Problem: {question}658Difficulty: {difficulty}659 660Scores:661- Correctness: {correctness['score']}/40662- Code Quality: {quality['score']}/25663- Efficiency: {efficiency['score']}/20664- AI Penalty: {ai_detection['penalty']}/10665- Similarity Penalty: {similarity['penalty']}/5666 667Details:668- Syntax Valid: {correctness['syntax_valid']}669- Tests Passed: {correctness.get('test_cases_passed', 0)}/{correctness.get('total_test_cases', 0)}670- Time Complexity: {efficiency['time_complexity']}671- Space Complexity: {efficiency['space_complexity']}672 673Write 3-5 sentences covering strengths, weaknesses, and specific improvements."""674 675            messages = [676                {"role": "system", "content": "You are an expert coding instructor. Give clear, constructive feedback in 3-5 sentences."},677                {"role": "user", "content": feedback_prompt}678            ]679 680            return self._call_ai(messages)681 682        except Exception as e:683            print(f"โš ๏ธ Feedback generation failed: {e}")684            total = (correctness['score'] + quality['score'] + efficiency['score']685                     - ai_detection['penalty'] - similarity['penalty'])686            return f"Analysis completed. Score: {total}/100. Time complexity: {efficiency.get('time_complexity', 'Unknown')}."687 688    def generate_recommendations(self, analysis):689        """Generate actionable recommendations"""690        if not self.pipe:691            return self._basic_recommendations(analysis)692 693        try:694            correctness = analysis['correctness']695            quality = analysis['code_quality']696            efficiency = analysis['efficiency']697            ai_detection = analysis['ai_detection']698 699            recommendations_prompt = f"""Generate 3-5 specific actionable recommendations:700 701Scores:702- Correctness: {correctness['score']}/40703- Quality: {quality['score']}/25704- Efficiency: {efficiency['score']}/20705- AI Detection Penalty: {ai_detection['penalty']}706 707Issues:708- Syntax Valid: {correctness['syntax_valid']}709- Time Complexity: {efficiency['time_complexity']}710- AI Indicators: {ai_detection['indicators']}711 712Respond ONLY with valid JSON:713{{"recommendations": ["action 1", "action 2", "action 3"]}}"""714 715            messages = [716                {"role": "system", "content": "You are a coding mentor. Respond with valid JSON only, no markdown."},717                {"role": "user", "content": recommendations_prompt}718            ]719 720            try:721                ai_response = self._call_ai(messages)722                json_match = re.search(r'\{.*?\}', ai_response, re.DOTALL)723                if json_match:724                    ai_eval = json.loads(json_match.group())725                    recs = ai_eval.get('recommendations', [])726                    if recs:727                        return recs[:5]728            except Exception as e:729                print(f"โš ๏ธ Recommendations AI failed: {e}")730 731        except Exception as e:732            print(f"โŒ generate_recommendations failed: {e}")733 734        return self._basic_recommendations(analysis)735 736    def _basic_recommendations(self, analysis):737        """Rule-based recommendations fallback"""738        recommendations = []739        correctness = analysis['correctness']740        quality = analysis['code_quality']741        efficiency = analysis['efficiency']742        ai_detection = analysis['ai_detection']743 744        if not correctness['syntax_valid']:745            recommendations.append("Fix syntax errors before submission")746        if correctness.get('test_cases_passed', 0) < correctness.get('total_test_cases', 1):747            recommendations.append("Debug logic to pass all test cases")748        if quality['score'] < 15:749            recommendations.append("Improve code readability and add comments")750        if 'O(nยฒ)' in efficiency.get('time_complexity', ''):751            recommendations.append("Optimize algorithm โ€” consider using a hash map to reduce to O(n)")752        if 'O(nยณ)' in efficiency.get('time_complexity', ''):753            recommendations.append("Critical: algorithm is O(nยณ) or worse โ€” needs major optimization")754        if ai_detection['penalty'] > 5:755            recommendations.append("Ensure code originality โ€” avoid AI-generated patterns")756        if quality.get('comments', 0) == 0:757            recommendations.append("Add docstrings and inline comments for better documentation")758 759        return recommendations[:5]760 761    def execute_test_case(self, code, test_case, language):762        """Kept for API compatibility โ€” use _run_python_tests for actual execution"""763        if language == 'python' and test_case:764            passed, total, _ = self._run_python_tests(code, [test_case])765            return passed == total766        return True