File size: 12,234 Bytes
75164b7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
"""
Code evaluation for all three Groq models
Tests Python and JavaScript code generation
Uses LLM Testing Suite with CCE formula from paper
"""

from groq import Groq
import json
import re
import sys
import os
from datetime import datetime

# Add parent directory to path to import llm_testing_suite
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

from llm_testing_suite import LLMTestSuite

# API Key
GROQ_API_KEY = "your-groq-api-key-here"

# Models to test
MODELS = {
    "GPT-OSS-20B": "openai/gpt-oss-20b",
    "Llama-3.3-70B": "llama-3.3-70b-versatile",
    "Qwen3-32B": "qwen/qwen3-32b"
}

client = Groq(api_key=GROQ_API_KEY)

def create_llm_function(model_name):
    """Create LLM function for specific model with Qwen-safe parameters"""
    def llm_func(prompt: str, max_tokens=600, temperature=0.3) -> str:
        # For Qwen models, use non-thinking mode parameters
        is_qwen = "qwen" in model_name.lower()

        # Enhanced system message to prevent <think> tags
        system_content = """You are an expert programmer. Generate ONLY clean, 
executable code without any explanations, reasoning, or commentary. 
Do not use <think> tags or any surrounding text. Return pure code only."""

        # Enhanced prompt to emphasize code-only output
        enhanced_prompt = f"{prompt}\n\nIMPORTANT: Return ONLY the code, no explanations or reasoning."

        messages = [
            {"role": "system", "content": system_content},
            {"role": "user", "content": enhanced_prompt}
        ]

        try:
            # Parameters based on Qwen best practices
            api_params = {
                "model": model_name,
                "messages": messages,
                "max_tokens": max_tokens,
            }

            if is_qwen:
                # Non-thinking mode for Qwen (general dialogue settings)
                # Note: Groq API doesn't support top_k or min_p
                api_params.update({
                    "temperature": 0.7,
                    "top_p": 0.8,
                })
            else:
                # Standard parameters for other models
                api_params.update({
                    "temperature": temperature,
                    "top_p": 0.8,
                })

            response = client.chat.completions.create(**api_params)
            raw_response = response.choices[0].message.content.strip()

            # Debug: Print raw response for debugging
            if is_qwen:
                print(f"   [DEBUG] Qwen raw response ({len(raw_response)} chars):")
                print(f"   {raw_response[:500]}")

            return raw_response
        except Exception as e:
            print(f"   Error: {e}")
            return ""
    return llm_func

def extract_code_block(response: str, language: str = "python") -> str:
    """Extract code from markdown code blocks and remove reasoning text"""
    original_response = response

    # FIRST: Aggressively remove <think> tags and their content
    # Use multiple patterns to catch variations
    response = re.sub(r'<think>.*?</think>', '', response, flags=re.DOTALL | re.IGNORECASE)
    response = re.sub(r'<thinking>.*?</thinking>', '', response, flags=re.DOTALL | re.IGNORECASE)

    # Remove any remaining think tags (unclosed or malformed)
    response = re.sub(r'</?think.*?>', '', response, flags=re.IGNORECASE)
    response = re.sub(r'</?thinking.*?>', '', response, flags=re.IGNORECASE)

    # Try to extract from markdown code blocks with language
    pattern = rf"```{language}\n(.*?)\n```"
    match = re.search(pattern, response, re.DOTALL | re.IGNORECASE)
    if match:
        return match.group(1).strip()

    # Try to extract from generic markdown code blocks
    pattern = r"```\n(.*?)\n```"
    match = re.search(pattern, response, re.DOTALL)
    if match:
        return match.group(1).strip()

    # Try just ``` with any language
    pattern = r"```\w*\n(.*?)\n```"
    match = re.search(pattern, response, re.DOTALL)
    if match:
        return match.group(1).strip()

    # Special handling: Extract only valid Python code lines
    lines = response.split('\n')
    code_lines = []
    in_code_block = False

    for line in lines:
        stripped = line.strip()

        # Skip empty lines at the start
        if not code_lines and not stripped:
            continue

        # Skip obvious reasoning/explanation lines
        lower_line = line.lower()
        if any(marker in lower_line for marker in [
            'okay,', 'let me', 'i need to', 'first,', 'to solve', 'the user',
            'then,', 'but need', 'make sure', 'wait,', 'hmm,', 'so,',
            'starting with', 'in the main', 'oh right', 'like if'
        ]):
            continue

        # Check if line looks like valid Python code
        is_code_like = (
            stripped.startswith(('def ', 'class ', 'import ', 'from ', 'if ', 'for ', 'while ',
                               'try:', 'except', 'return ', 'print(', '@')) or
            stripped.startswith('if __name__') or
            (stripped and not stripped[0].isupper() and '=' in stripped) or  # assignment
            (in_code_block and (stripped.startswith((' ', '\t')) or not stripped))  # indented or blank
        )

        # Start collecting code when we find a def, class, import, or if __name__
        if stripped.startswith(('def ', 'class ', 'import ', 'from ', 'if __name__')):
            in_code_block = True
            code_lines.append(line)
        elif in_code_block:
            # Continue collecting if it looks like code
            if is_code_like or not stripped:
                code_lines.append(line)
            elif stripped and (stripped[0].isupper() or ':' not in line):
                # Stop if we hit explanatory text (starts with capital, no colons)
                # But allow docstrings
                if '"""' not in line and "'''" not in line:
                    break
                else:
                    code_lines.append(line)
            else:
                code_lines.append(line)

    if code_lines:
        # Clean up trailing empty lines and explanatory text
        while code_lines and not code_lines[-1].strip():
            code_lines.pop()

        # Remove any trailing lines that look like explanations
        while code_lines:
            last_line = code_lines[-1].strip().lower()
            if any(marker in last_line for marker in ['but need', 'make sure', 'wait', 'note:']):
                code_lines.pop()
            else:
                break

        return '\n'.join(code_lines).strip()

    # Last resort: return cleaned response
    response = re.sub(r'^(Here\'s|Here is|This is).*?:\s*', '', response, flags=re.IGNORECASE)
    return response.strip()

print("="*80)
print("CODE EVALUATION FOR THREE GROQ MODELS")
print("Using LLM Testing Suite with CCE Formula from Paper")
print("="*80)
print(f"Models: {', '.join(MODELS.keys())}")
print(f"Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("="*80)

# Code generation prompt
PYTHON_PROMPT = """Write a Python program that:
1. Defines a function called 'add_numbers' that takes two integers and returns their sum
2. Includes a docstring for the function
3. Has a main block that reads two space-separated integers from stdin and prints the result
4. The output should be just the number, nothing else

Example: if input is "2 3", output should be "5" """

PYTHON_TEST_CASES = [
    {"input": "2 3\n", "expected_output": "5"},
    {"input": "-1 4\n", "expected_output": "3"},
    {"input": "0 0\n", "expected_output": "0"},
    {"input": "10 -5\n", "expected_output": "5"}
]

# Reference implementation for semantic comparison
REFERENCE_CODE = '''def add_numbers(a, b):
    """Add two numbers and return the result."""
    return a + b

if __name__ == "__main__":
    numbers = input().split()
    a, b = int(numbers[0]), int(numbers[1])
    print(add_numbers(a, b))
'''

all_results = {}

for model_display_name, model_id in MODELS.items():
    print(f"\n{'='*80}")
    print(f"EVALUATING: {model_display_name} ({model_id})")
    print(f"{'='*80}")

    # Create LLM function for this model
    llm_func = create_llm_function(model_id)

    # Initialize testing suite
    suite = LLMTestSuite(llm_func=llm_func)

    print("\nGenerating Python code...")
    code_response = llm_func(PYTHON_PROMPT, max_tokens=500, temperature=0.3)
    generated_code = extract_code_block(code_response, "python")

    print(f"Generated {len(generated_code)} characters of code")
    print("\nCode preview:")
    print("-" * 40)
    print(generated_code[:300] + ("..." if len(generated_code) > 300 else ""))
    print("-" * 40)

    # Run comprehensive evaluation using the suite
    print("\nRunning comprehensive code evaluation...")
    result = suite.comprehensive_code_evaluation(
        prompt=PYTHON_PROMPT,
        code_response=generated_code,
        reference_code=REFERENCE_CODE,
        test_cases=PYTHON_TEST_CASES,
        language="python",
        return_type="dict"
    )

    # Display results
    print(f"\n--- EVALUATION RESULTS ---")
    print(f"Syntax Valid (SV): {result['syntax_valid']} ({1.0 if result['syntax_valid'] else 0.0})")
    print(f"Execution Pass Rate (EPR): {result.get('pass_rate', 1.0):.3f}")
    print(f"Code Quality Score (CQS): {result['quality_score']}/100 ({result['quality_score']/100:.3f})")
    print(f"Security Risk Score (SRS): {result.get('srs', 0.0):.3f}")
    print(f"Security Score (1-SRS): {1 - result.get('srs', 0.0):.3f}")
    print(f"Semantic Correctness (SCC): {result.get('semantic_similarity', 1.0):.3f}")
    print(f"\n--- CCE BREAKDOWN ---")
    breakdown = result.get('metrics_breakdown', {})
    print(f"α*SV  (0.15 × {breakdown.get('sv', 0):.3f}) = {0.15 * breakdown.get('sv', 0):.4f}")
    print(f"β*EPR (0.35 × {breakdown.get('epr', 0):.3f}) = {0.35 * breakdown.get('epr', 0):.4f}")
    print(f"γ*CQS (0.20 × {breakdown.get('cqs', 0):.3f}) = {0.20 * breakdown.get('cqs', 0):.4f}")
    print(f"δ*(1-SRS) (0.15 × {breakdown.get('security_score', 0):.3f}) = {0.15 * breakdown.get('security_score', 0):.4f}")
    print(f"ϵ*SCC (0.15 × {breakdown.get('scc', 0):.3f}) = {0.15 * breakdown.get('scc', 0):.4f}")
    print(f"\nCCE Score: {result['cce_score']:.4f}")
    print(f"Overall Score: {result['overall_score']:.2f}/100")

    all_results[model_display_name] = {
        "model_name": model_display_name,
        "model_id": model_id,
        "python": {
            "syntax_valid": result['syntax_valid'],
            "pass_rate": result.get('pass_rate', 1.0),
            "quality_score": result['quality_score'],
            "srs": result.get('srs', 0.0),
            "security_score": 1 - result.get('srs', 0.0),
            "semantic_similarity": result.get('semantic_similarity', 1.0),
            "cce_score": result['cce_score'],
            "overall_score": result['overall_score'],
            "metrics_breakdown": result.get('metrics_breakdown', {}),
            "generated_code": generated_code
        }
    }

# Save results
output_file = "code_evaluation_results.json"
with open(output_file, 'w') as f:
    json.dump(all_results, f, indent=2)

print(f"\n{'='*80}")
print(f"CODE EVALUATION COMPLETE")
print(f"Results saved to {output_file}")
print(f"{'='*80}")

# Summary table
print("\n\nSUMMARY TABLE - CCE SCORES:")
print("-" * 120)
print(f"{'Model':<20} {'SV':<8} {'EPR':<8} {'CQS':<8} {'1-SRS':<8} {'SCC':<8} {'CCE':<10} {'Overall':<12}")
print("-" * 120)

for model_name, results in all_results.items():
    py = results["python"]
    breakdown = py["metrics_breakdown"]
    print(f"{model_name:<20} "
          f"{breakdown.get('sv', 0):.3f}    "
          f"{breakdown.get('epr', 0):.3f}    "
          f"{breakdown.get('cqs', 0):.3f}    "
          f"{breakdown.get('security_score', 0):.3f}    "
          f"{breakdown.get('scc', 0):.3f}    "
          f"{py['cce_score']:.4f}     "
          f"{py['overall_score']:.2f}/100")

print("-" * 120)

# Formula verification
print("\n\nFORMULA VERIFICATION:")
print("CCE = α*SV + β*EPR + γ*CQS + δ*(1-SRS) + ϵ*SCC")
print("Weights: α=0.15, β=0.35, γ=0.20, δ=0.15, ϵ=0.15")
print("All metrics normalized to [0, 1]")
print("="*80)