Spaces:
Sleeping
Sleeping
Download app.py from InfiniteTsukuyomi/Detector: direct link, hf CLI and curl.
- Browser
- Download file 34 kB
-
https://huggingface.co/spaces/InfiniteTsukuyomi/Detector/resolve/15ecafcf48fe94de6ef8af0d69eac06f560bb338/app.py
- Command line
-
hf download hf://spaces/InfiniteTsukuyomi/Detector@15ecafcf48fe94de6ef8af0d69eac06f560bb338/app.py
-
curl -L -o app.py https://huggingface.co/spaces/InfiniteTsukuyomi/Detector/resolve/15ecafcf48fe94de6ef8af0d69eac06f560bb338/app.py
34 kB
| import streamlit as st | |
| import torch | |
| import os | |
| from transformers import AutoTokenizer, AutoModelForMaskedLM | |
| import numpy as np | |
| from sklearn.linear_model import LogisticRegression | |
| # Set Hugging Face cache directory | |
| os.environ["HF_HOME"] = "/app/cache" | |
| # Streamlit UI | |
| st.title("Code Analyzer: Tokenization, Probabilities, and Logistic Regression") | |
| # Initialize CodeBERT model and tokenizer with caching to reduce memory usage | |
| def load_model(): | |
| tokenizer = AutoTokenizer.from_pretrained("microsoft/codebert-base-mlm") | |
| model = AutoModelForMaskedLM.from_pretrained("microsoft/codebert-base-mlm") | |
| return tokenizer, model | |
| tokenizer, model = load_model() | |
| # Function to split tokens with 'Ġ' prefix | |
| def split_tokens_with_g(token_list): | |
| new_tokens = [] | |
| for token in token_list: | |
| if token.startswith('Ġ') and len(token) > 1: | |
| new_tokens.append('Ġ') | |
| new_tokens.append(token[1:]) | |
| else: | |
| new_tokens.append(token) | |
| return new_tokens | |
| # Function to estimate token probabilities | |
| def estimate_probabilities_bidirectional_strategy(code_snippet): | |
| tokens = tokenizer.tokenize(code_snippet) | |
| tokens = split_tokens_with_g(tokens) | |
| token_ids = [tokenizer.convert_tokens_to_ids([t])[0] for t in tokens] | |
| max_seq_length = 511 # 512 - 1 for [CLS] | |
| if len(token_ids) > max_seq_length: | |
| token_ids = token_ids[:max_seq_length] | |
| tokens = tokens[:max_seq_length] | |
| probs = [] | |
| for i, token_id in enumerate(token_ids): | |
| input_sequence = token_ids.copy() | |
| input_sequence[i] = tokenizer.mask_token_id | |
| input_ids = [tokenizer.cls_token_id] + input_sequence + [tokenizer.pad_token_id] * (max_seq_length - len(input_sequence)) | |
| input_ids = input_ids[:512] | |
| input_tensor = torch.tensor([input_ids]) | |
| with torch.no_grad(): | |
| outputs = model(input_tensor) | |
| logits = outputs.logits[0, i + 1] # Logits for <mask> position (i + 1 due to [CLS]) | |
| probs_token = torch.softmax(logits, dim=-1)[token_id].item() | |
| probs.append(probs_token) | |
| return tokens, probs | |
| #updated one | |
| import ast | |
| import tokenize | |
| from io import StringIO | |
| import keyword | |
| def counts_in_code(code_snippet): | |
| names = [] | |
| def_count = 0 | |
| def_names=[] | |
| class_count = 0 | |
| conditional_count = 0 | |
| import_count = 0 | |
| total_variables =[] # To store unique variable names | |
| single_variables = [] # To store single variable names | |
| # Try AST parsing for valid code | |
| try: | |
| tree = ast.parse(code_snippet) | |
| for node in ast.walk(tree): | |
| # Class names and count | |
| if isinstance(node, ast.ClassDef): | |
| names.append(node.name) | |
| class_count += 1 | |
| def_names.append(node.name) # Store class names | |
| # Function names, args, and count | |
| elif isinstance(node, ast.FunctionDef): | |
| names.append(node.name) | |
| def_names.append(node.name) # Store function names | |
| def_count += 1 | |
| for arg in node.args.args: | |
| names.append(arg.arg) | |
| total_variables.append(arg.arg) # Store class names | |
| # Variable assignments (including tuple unpacking) | |
| elif isinstance(node, ast.Assign): | |
| for target in node.targets: | |
| if isinstance(target, ast.Name): # Single variable (e.g., `x = 1`) | |
| names.append(target.id) | |
| total_variables.append(target.id) | |
| elif isinstance(target, ast.Tuple): # Tuple unpacking (e.g., `a, b, c = ...`) | |
| for elt in target.elts: | |
| if isinstance(elt, ast.Name): | |
| names.append(elt.id) | |
| total_variables.append(elt.id) | |
| # Count conditionals and loops, and handle loop variables | |
| elif isinstance(node, (ast.If, ast.For, ast.While)): | |
| conditional_count += 1 | |
| if isinstance(node, ast.For): # Handle loop variables | |
| if isinstance(node.target, ast.Name): # Single variable (e.g., `for i in ...`) | |
| names.append(node.target.id) | |
| total_variables.append(node.target.id) | |
| single_variables.append(node.target.id) | |
| elif isinstance(node.target, ast.Tuple): # Tuple unpacking in loop (e.g., `for a, b in ...`) | |
| for elt in node.target.elts: | |
| if isinstance(elt, ast.Name): | |
| names.append(elt.id) | |
| total_variables.append(elt.id) | |
| single_variables.append(elt.id) | |
| # Count import statements | |
| elif isinstance(node, (ast.Import, ast.ImportFrom)): | |
| import_count += 1 | |
| # Augmented assignments (e.g., `a += a + a`) | |
| elif isinstance(node, ast.AugAssign): | |
| if isinstance(node.target, ast.Name): # Single variable (e.g., `a += ...`) | |
| names.append(node.target.id) | |
| total_variables.append(node.target.id) | |
| elif isinstance(node.target, ast.Tuple): # Tuple unpacking in augmented assignment | |
| for elt in node.target.elts: | |
| if isinstance(elt, ast.Name): | |
| names.append(elt.id) | |
| total_variables.append(elt.id) | |
| # Optionally extract variables from the right-hand side (value) | |
| # if isinstance(node.value, ast.BinOp): # Handle binary operations like `a + a` | |
| # for operand in [node.value.left, node.value.right]: | |
| # if isinstance(operand, ast.Name): | |
| # names.append(operand.id) | |
| # total_variables.append(operand.id) | |
| return { | |
| 'names': names, | |
| 'def_count': def_count, | |
| 'class_count': class_count, | |
| 'conditional_count': conditional_count, | |
| 'import_count': import_count, | |
| 'total_variables': total_variables, | |
| 'single_variables': single_variables, # Include single variable names, | |
| 'def_names': def_names # Include function and class names | |
| } | |
| except SyntaxError as e: | |
| # print(f"Unexpected error: {e}") | |
| try: | |
| builtin_names = set(dir(__builtins__)) | |
| tokens = tokenize.generate_tokens(StringIO(code_snippet).readline) | |
| for token in tokens: | |
| if token.type == tokenize.NAME: | |
| if token.string == 'def': | |
| def_count += 1 | |
| elif token.string == 'class': | |
| class_count += 1 | |
| elif token.string in ('if', 'for', 'while'): | |
| conditional_count += 1 | |
| elif token.string == 'import': | |
| import_count += 1 | |
| elif not keyword.iskeyword(token.string) and token.string not in builtin_names: | |
| names.append(token.string) | |
| total_variables.append(token.string) # Add to total_variables for consistency | |
| return { | |
| 'names': names, | |
| 'def_count': def_count, | |
| 'class_count': class_count, | |
| 'conditional_count': conditional_count, | |
| 'import_count': import_count, | |
| 'single_variables': single_variables, # Include single variable names, | |
| 'total_variables': total_variables, # Include total_variables, | |
| 'def_names': def_names # Include function and class names | |
| } | |
| except tokenize.TokenError as e: | |
| # Handle cases where tokenization fails (e.g., unclosed strings) | |
| # pass | |
| return { | |
| 'names': names, | |
| 'def_count': def_count, | |
| 'class_count': class_count, | |
| 'conditional_count': conditional_count, | |
| 'import_count': import_count, | |
| 'single_variables': single_variables, # Include single variable names, | |
| 'total_variables': total_variables, # Include total_variables | |
| 'def_names': def_names # Include function and class names | |
| } | |
| except Exception as e: | |
| return { | |
| 'names': names, | |
| 'def_count': def_count, | |
| 'class_count': class_count, | |
| 'conditional_count': conditional_count, | |
| 'import_count': import_count, | |
| 'single_variables': single_variables, # Include single variable names, | |
| 'total_variables': total_variables, # Include total_variables | |
| 'def_names': def_names # Include function and class names | |
| } | |
| except Exception as e: | |
| print(f"Unexpected error: {e}") | |
| return { | |
| 'names': names, | |
| 'def_count': def_count, | |
| 'class_count': class_count, | |
| 'conditional_count': conditional_count, | |
| 'import_count': import_count, | |
| 'single_variables': single_variables, # Include single variable names, | |
| 'total_variables': total_variables, # Include total_variables | |
| 'def_names': def_names # Include function and class names | |
| } | |
| def extract_comments_from_code(code_snippet, language): | |
| """ | |
| Extract comments from a code snippet based on the specified programming language. | |
| Args: | |
| code_snippet (str): The code to parse for comments. | |
| language (str): The programming language ('python' or 'java'). | |
| Returns: | |
| list: List of tokenized comments processed with split_tokens_with_g. | |
| """ | |
| comments = [] | |
| comment_line_count = 0 | |
| if language.lower() == 'python': | |
| lines = code_snippet.split('\n') | |
| in_multiline_comment = False | |
| multiline_text = [] | |
| quote_delimiter = None | |
| for i, line in enumerate(lines, 1): | |
| stripped_line = line.strip() | |
| comment_line_count += 1 # Count each line in multi-line comment | |
| if in_multiline_comment: | |
| if stripped_line.endswith(quote_delimiter): | |
| multiline_text.append(stripped_line.rstrip(quote_delimiter).strip()) | |
| comment_text = '\n'.join(multiline_text) | |
| tokenized_comment = tokenizer.tokenize(comment_text) | |
| comments.extend(split_tokens_with_g(tokenized_comment)) | |
| in_multiline_comment = False | |
| multiline_text = [] | |
| quote_delimiter = None | |
| else: | |
| multiline_text.append(stripped_line) | |
| elif stripped_line.startswith('"""') or stripped_line.startswith("'''"): | |
| comment_line_count += 1 # Count the line with multi-line comment start | |
| quote_delimiter = '"""' if stripped_line.startswith('"""') else "'''" | |
| if stripped_line.endswith(quote_delimiter) and len(stripped_line) > 6: # Avoid empty """" | |
| comment_text = stripped_line[len(quote_delimiter):-len(quote_delimiter)].strip() | |
| tokenized_comment = tokenizer.tokenize(comment_text) | |
| comments.extend(split_tokens_with_g(tokenized_comment)) | |
| else: | |
| in_multiline_comment = True | |
| multiline_text.append(stripped_line[len(quote_delimiter):].strip()) | |
| elif stripped_line.startswith('#'): | |
| comment_line_count += 1 # Count the line with multi-line comment start | |
| comment_part = stripped_line[1:].strip() | |
| tokenized_comment = tokenizer.tokenize(comment_part) | |
| comments.extend(split_tokens_with_g(tokenized_comment)) | |
| elif '#' in stripped_line and not (stripped_line.startswith('"') or stripped_line.startswith("'")): | |
| comment_line_count += 1 # Count the line with multi-line comment start | |
| comment_part = stripped_line.split('#', 1)[1].strip() | |
| tokenized_comment = tokenizer.tokenize(comment_part) | |
| comments.extend(split_tokens_with_g(tokenized_comment)) | |
| elif language.lower() == 'java': | |
| lines = code_snippet.split('\n') | |
| in_multiline_comment = False | |
| for line in lines: | |
| line = line.strip() | |
| if in_multiline_comment: | |
| comment_line_count += 1 # Count the line with multi-line comment start | |
| if '*/' in line: | |
| in_multiline_comment = False | |
| comment_tokens = tokenizer.tokenize(line[:line.index('*/') + 2]) | |
| comments.extend(split_tokens_with_g(comment_tokens)) | |
| else: | |
| comments.extend(split_tokens_with_g(tokenizer.tokenize(line))) | |
| elif line.startswith('//'): | |
| comment_line_count += 1 # Count single-line comment | |
| comment_part = line.split('//', 1)[1] | |
| comments.extend(split_tokens_with_g(tokenizer.tokenize('//' + comment_part))) | |
| elif '//' in line: | |
| comment_line_count += 1 # Count single-line comment | |
| comment_part = line.split('//', 1)[1] | |
| full_comment = '//' + comment_part | |
| tokenized_comment = tokenizer.tokenize(full_comment) | |
| comments.extend(split_tokens_with_g(tokenized_comment)) | |
| elif line.startswith('/*'): | |
| comment_line_count += 1 # Count single-line comment | |
| if '*/' in line: | |
| comment_tokens = tokenizer.tokenize(line[:line.index('*/') + 2]) | |
| comments.extend(split_tokens_with_g(comment_tokens)) | |
| else: | |
| in_multiline_comment = True | |
| comments.extend(split_tokens_with_g(tokenizer.tokenize(line))) | |
| else: | |
| raise ValueError("Unsupported language. Use 'python' or 'java'.") | |
| return comments | |
| def variables_length_measurer(variables): | |
| total_length = sum(len(var) for var in variables) | |
| if len(variables) == 0: | |
| return 0.0 # Avoid division by zero | |
| avg_length = total_length / len(variables) | |
| return avg_length | |
| def single_letter_count_measurer(variables): | |
| single_letter_count = sum(1 for var in variables if len(var) == 1) | |
| # print(f"Single letter variables count: {single_letter_count}") | |
| if len(variables) == 0: | |
| return 0.0 # Avoid division by zero | |
| proportion =single_letter_count/len(variables) | |
| proportion = round(proportion,4) | |
| # return [single_letter_count,proportion] # Round to 4 decimal places | |
| return [proportion] # Round to 4 decimal places | |
| def calculate_naming_proportions(variables): | |
| snake_count = 0 | |
| camel_count = 0 | |
| for var in variables: | |
| if not var or not var.isidentifier(): # Skip invalid variable names | |
| continue | |
| if '_' in var and var.islower(): | |
| snake_count += 1 | |
| elif any(c.isupper() for c in var) and var[0].islower(): | |
| camel_count += 1 | |
| # print(f"snake_COUNT: {snake_count}") | |
| # print(f"camel_COUNT: {camel_count}") | |
| total = len(variables) | |
| # print(f"total variables: {total}") | |
| if total == 0: | |
| return {"snake_case": 0.0, "camelCase": 0.0} | |
| avg_snake_count =snake_count/total if total>0 else 0 | |
| avg_camel_sount =camel_count/total if total>0 else 0 | |
| return snake_count,camel_count, avg_snake_count, avg_camel_sount | |
| def check_spacing(code): | |
| operators = ['=', '+', '-', '*', '/', '//', '%', '**', '==', '!=', '<', '>', '<=', '>=', | |
| '+=', '-=', '*=', '/=', '//=', '%=', '**=', '&=', '|=', '^=', '<<=', '>>='] | |
| # Initialize counters | |
| total_operators = 0 | |
| spaced_operators = 0 | |
| non_spaced_operators = 0 | |
| total_commas = 0 | |
| spaced_commas = 0 | |
| non_spaced_commas = 0 | |
| lines = code.split('\n') | |
| for line in lines: | |
| # Remove inline comments | |
| line = line.split('#')[0].rstrip() | |
| if not line: | |
| continue | |
| # Process commas | |
| start = 0 | |
| while ',' in line[start:]: | |
| idx = line.find(',', start) | |
| total_commas += 1 | |
| # Check spacing for comma | |
| has_no_space_before = (idx == 0) or (idx > 0 and not line[idx-1].isspace()) | |
| has_space_after = (idx + 1 < len(line) and line[idx+1].isspace()) or (idx + 1 == len(line)) | |
| if has_no_space_before and has_space_after: | |
| spaced_commas += 1 | |
| else: | |
| non_spaced_commas += 1 | |
| start = idx + 1 | |
| # Process operators (sorted by length to handle multi-char operators first) | |
| for op in sorted(operators, key=len, reverse=True): | |
| start = 0 | |
| while op in line[start:]: | |
| idx = line.find(op, start) | |
| total_operators += 1 | |
| # Check spacing for operator | |
| has_space_before = (idx > 0 and line[idx-1].isspace()) or idx == 0 | |
| has_space_after = (idx + len(op) < len(line) and line[idx+len(op)].isspace()) or idx + len(op) == len(line) | |
| if has_space_before and has_space_after: | |
| spaced_operators += 1 | |
| # print(f"Proper spacing operator: {op} at index {idx} in line: {line}") | |
| else: | |
| non_spaced_operators += 1 | |
| # print(f"Improper spacing operator: {op} at index {idx} in line: {line}") | |
| # Mask the operator to avoid double-counting | |
| line = line[:idx] + ' ' * len(op) + line[idx + len(op):] | |
| start = idx + len(op) | |
| return { | |
| 'total_operators': total_operators, | |
| 'spaced_operators': spaced_operators, | |
| 'non_spaced_operators': non_spaced_operators, | |
| 'total_commas': total_commas, | |
| 'spaced_commas': spaced_commas, | |
| 'non_spaced_commas': non_spaced_commas | |
| } | |
| def count_comments(code): | |
| """ | |
| Analyzes comments in source code, counting inline and block comments, | |
| their average lengths (in characters and words), and total lengths. | |
| Args: | |
| code (str): The source code as a string. | |
| Returns: | |
| dict: Contains counts, average lengths, and total lengths for inline and block comments. | |
| """ | |
| lines = code.splitlines() | |
| inline_comment_count = 0 | |
| block_comment_count = 0 | |
| inline_char_length = 0 | |
| block_char_length = 0 | |
| inline_word_count = 0 | |
| block_word_count = 0 | |
| for line in lines: | |
| # Strip leading/trailing whitespace from the line | |
| line = line.strip() | |
| # Check if the line contains a comment | |
| if line and '#' in line: | |
| # Split the line at the first '#' to separate code and comment | |
| code_part, _, comment_part = line.partition('#') | |
| # Remove leading/trailing whitespace from comment | |
| comment_part = comment_part.strip() | |
| # Check if there's actual code before the comment (non-whitespace) | |
| if code_part.strip(): | |
| inline_comment_count += 1 | |
| # Calculate character length of the comment | |
| inline_char_length += len(comment_part) | |
| else: | |
| # If no code before the comment, it's a block comment | |
| block_comment_count += 1 | |
| block_char_length += len(comment_part) | |
| elif line.startswith('#'): | |
| # Lines that start with # are block comments | |
| block_comment_count += 1 | |
| # Remove the # and strip whitespace | |
| comment_part = line[1:].strip() | |
| block_char_length += len(comment_part) | |
| # Calculate averages, avoiding division by zero | |
| avg_inline_char = inline_char_length / inline_comment_count if inline_comment_count > 0 else 0 | |
| avg_block_char = block_char_length / block_comment_count if block_comment_count > 0 else 0 | |
| inline_block_ratio = (inline_comment_count / block_comment_count) if block_comment_count > 0 else 0 | |
| return { | |
| 'inline_comment_count': inline_comment_count, | |
| 'block_comment_count': block_comment_count, | |
| 'avg_inline_char_length': avg_inline_char, | |
| 'avg_block_char_length': avg_block_char, | |
| 'total_inline_char_length': inline_char_length, | |
| 'total_block_char_length': block_char_length, | |
| 'inline_block_ratio': inline_block_ratio | |
| } | |
| import collections | |
| import math | |
| import io | |
| import ast | |
| import tokenize | |
| from io import StringIO | |
| import keyword | |
| def entropy_calculator(code_snippet): | |
| names = [] | |
| def_count = 0 | |
| def_names=[] | |
| class_count = 0 | |
| conditional_count = 0 | |
| import_count = 0 | |
| total_variables =[] # To store unique variable names | |
| single_variables = [] # To store single variable names | |
| in_import = False # Track if we're processing an import statement | |
| try: | |
| builtin_names = set(dir(__builtins__)) | |
| tokens = tokenize.generate_tokens(StringIO(code_snippet).readline) | |
| for token in tokens: | |
| if token.type == tokenize.NAME: | |
| if token.string == 'def': | |
| def_count += 1 | |
| in_import = False | |
| elif token.string == 'class': | |
| class_count += 1 | |
| in_import = False | |
| elif token.string in ('if', 'for', 'while'): | |
| conditional_count += 1 | |
| in_import = False | |
| elif token.string in ('import', 'from'): | |
| # import_count += 1 # Uncomment if you want to count imports | |
| in_import = True | |
| elif not keyword.iskeyword(token.string) and token.string not in builtin_names: | |
| if not in_import: # Only collect if not part of import statement | |
| names.append(token.string) | |
| total_variables.append(token.string) | |
| elif token.type != tokenize.NAME: | |
| # Reset import flag when we encounter non-name tokens | |
| in_import = False | |
| except tokenize.TokenError as e: | |
| # Handle cases where tokenization fails (e.g., unclosed strings) | |
| # pass | |
| print(f"Tokenization error: {e}") | |
| except Exception as e: | |
| print(f"Unexpected error: {e}") | |
| # print("Extracted Names:", names) | |
| token_counts = collections.Counter(names) | |
| # print("Token Counts:", token_counts) | |
| total_tokens = sum(token_counts.values()) | |
| if total_tokens == 0: | |
| print("No valid tokens found") | |
| return 0.0 | |
| entropy = 0.0 | |
| for count in token_counts.values(): | |
| probability = count / total_tokens | |
| entropy -= probability * math.log2(probability) | |
| entropy = round(entropy,4) | |
| # print("Entropy:", entropy) | |
| return entropy | |
| def count_total_lines(code_snippet): | |
| lines = code_snippet.splitlines() | |
| total_lines = len(lines) | |
| pure_code_lines = sum(1 for line in lines if line.strip()) | |
| blank_lines = total_lines - pure_code_lines | |
| return total_lines, pure_code_lines,blank_lines | |
| def filter_names_from_code(code_snippet,tokenizer): | |
| names =extract_names(code_snippet) | |
| text = ' '.join(names) | |
| tokenized_text = tokenizer.tokenize(text) | |
| # print("Tokenized Text:", tokenized_text) | |
| names_token =split_tokens_with_g(tokenized_text) | |
| # print("Names Token:", names_token) | |
| remove_names = ['Ġ','Ċ','ĠĊ','ĠĠ','ĠĠĊ'] | |
| remove_names = [token for token in names_token if token not in remove_names] | |
| # print("filtered names:", remove_names) | |
| remove_names = list(set(remove_names)) # Remove duplicates | |
| # print("Unique Filtered Names:", remove_names) | |
| return remove_names | |
| from collections import defaultdict | |
| def extract_features_of_code(tokens,probs, code_snippet, tokenizer): | |
| #names | |
| names_collection_in_tokens=[] | |
| special_tokens_in_tokens= [] | |
| comment_tokens_in_tokens = [] | |
| others_in_tokens = [] | |
| names = filter_names_from_code(code_snippet, tokenizer) | |
| #Special Tokens | |
| special_tokens_to_collect = ['{', '}', 'Ċ','Ġ','((', '))', '(', ')', '[', ']', ',', ':'] | |
| special_tokens = [t for t in tokens if t in special_tokens_to_collect] | |
| special_tokens =list(set(special_tokens)) # Remove duplicates | |
| #Comments ectraction | |
| comments = extract_comments_from_code(code_snippet, 'python') | |
| comments_to_remove =[ 'Ċ', 'Ġ', 'ĠĊ', 'ĠĠ', 'ĠĠĊ','.',',',':',';'] | |
| comments=[a for a in comments if a not in comments_to_remove] | |
| #Categorize tokens and collect probabilities | |
| name_probs = [] | |
| special_probs = [] | |
| comment_probs = [] | |
| other_probs = [] | |
| others = [] | |
| i=0 | |
| # print(f"length of tokens: {len(tokens)}") | |
| # print(f"length of probs: {len(probs)}") | |
| while i < len(tokens): | |
| token = tokens[i] | |
| prob = probs[i] | |
| if token in names: | |
| names_collection_in_tokens.append(token) | |
| name_probs.append(prob) | |
| elif token in comments: | |
| comment_tokens_in_tokens.append(token) | |
| comment_probs.append(prob) | |
| elif token in special_tokens: | |
| special_tokens_in_tokens.append(token) | |
| special_probs.append(prob) | |
| else: | |
| others_in_tokens.append(token) | |
| others.append(prob) | |
| i += 1 | |
| #Taking the averages in the code | |
| def aggregate(probs_list): | |
| if not probs_list: | |
| return [0.0, 0.0] | |
| # return [0.0] | |
| sum_prob = sum(probs_list) | |
| count = len(probs_list) | |
| avg_prob = sum_prob / count if count > 0 else 0.0 | |
| # scaled_sum = sum_prob / math.sqrt(count) if count > 0 else 0.0 | |
| return [sum_prob,avg_prob] | |
| name_features = aggregate(name_probs) | |
| special_features = aggregate(special_probs) | |
| comment_features=aggregate(comment_probs) | |
| other_features = aggregate(others) | |
| #Calculating the counts in the code | |
| result = counts_in_code(code_snippet) | |
| total_lines, pure_code_lines,blank_lines = count_total_lines(code_snippet) | |
| variables = result['total_variables'] | |
| function_count = [result['def_count']] | |
| fuction_prop = result['def_count']/total_lines if total_lines > 0 else 0 | |
| class_count = [result['class_count']] | |
| class_prop = result['class_count']/total_lines if total_lines > 0 else 0 | |
| conditional_count =[ result['conditional_count']] | |
| conditional_prop = result['conditional_count']/total_lines if total_lines >0 else 0 | |
| import_count = [result['import_count'] ] | |
| import_prop = result['import_count']/total_lines if total_lines >0 else 0 | |
| total_counts= function_count + class_count + conditional_count + import_count | |
| total_prop = [fuction_prop] + [class_prop] + [conditional_prop] + [import_prop] | |
| #Calculating length and count of total variables and single variables | |
| avg_total_variables_length = variables_length_measurer(variables) | |
| count_total_varaibles = len(variables) | |
| single_variable_count_and_proportion = single_letter_count_measurer(variables) | |
| # total_variable_count_and_average = [count_total_varaibles]+[avg_total_variables_length] | |
| total_variable_count_and_average = [avg_total_variables_length] | |
| #Naming Convention snake_case | |
| naming_convention =result['def_names'] + result['total_variables'] | |
| built_in_names =['self','__init__','__str__'] | |
| naming_convention = [name for name in naming_convention if name not in built_in_names] | |
| snake_count,camel_count, avg_snake_count, avg_camel_count = calculate_naming_proportions(naming_convention) | |
| snake_case =[snake_count,avg_snake_count] | |
| # snake_case =[avg_snake_count] | |
| camel_case =[camel_count,avg_camel_count] | |
| # camel_case =[avg_camel_count] | |
| #Improper structure of operatores and commas | |
| spacing_results = check_spacing(code_snippet) | |
| non_spaced_operators = spacing_results['non_spaced_operators'] | |
| non_space_operators_prop = non_spaced_operators/spacing_results['total_operators'] if spacing_results['total_operators'] >0 else 0 | |
| non_spaced_commas = spacing_results['non_spaced_commas'] | |
| non_space_commas_prop = non_spaced_commas/spacing_results['total_commas'] if spacing_results['total_commas'] >0 else 0 | |
| wrong_spacing_operators = [non_spaced_operators, non_space_operators_prop] | |
| # wrong_spacing_operators = [non_space_operators_prop] | |
| wrong_spacing_commas = [non_spaced_commas,non_space_commas_prop] | |
| # wrong_spacing_commas = [non_space_commas_prop] | |
| #Inline and block comments average length and their ratio | |
| comments_results = count_comments(code_snippet) | |
| total_inline_comments = comments_results['inline_comment_count'] | |
| total_block_comments = comments_results['block_comment_count'] | |
| inline_block_ratio = comments_results['inline_block_ratio'] if total_block_comments>0 else 0 | |
| comments_and_ratios = [total_inline_comments]+ [total_block_comments] + [inline_block_ratio] | |
| # comments_and_ratios = [inline_block_ratio] | |
| #Shanon Entropy Calculation | |
| shanon_entropy = [entropy_calculator(code_snippet)] | |
| #Comment present or not | |
| comment_present = 1 if comment_probs else 0 | |
| #blank lines prop: | |
| blank_lines_prop = blank_lines/total_lines if total_lines >0 else 0 | |
| #Keyword_frequency | |
| python_keywords = { | |
| "False", "None", "True", "and", "as", "assert", "async", "await", "break", | |
| "class", "continue", "def", "del", "elif", "else", "except", "finally", | |
| "for", "from", "global", "if", "import", "in", "is", "lambda", "nonlocal", | |
| "not", "or", "pass", "raise", "return", "try", "while", "with", "yield" | |
| } | |
| lowercase_keywords = {keyword.lower() for keyword in python_keywords} | |
| def remove_comments(code): | |
| """Remove single-line and multi-line comments from code.""" | |
| # code = re.sub(r'/\*.*?\*/', '', code, flags=re.DOTALL) # C-style multi-line | |
| code = re.sub(r'\'\'\'.*?\'\'\'', '', code, flags=re.DOTALL) | |
| code = re.sub(r'\"\"\".*?\"\"\"', '', code, flags=re.DOTALL) | |
| # code = re.sub(r'//.*', '', code) # C-style single-line | |
| code = re.sub(r'#.*', '', code) # Python-style comments | |
| return code | |
| def find_keywords(tokens, keywords, max_window=3): | |
| frequency_map = defaultdict(int) | |
| found = [] | |
| count=0 | |
| for i in range(len(tokens)): | |
| for j in range(1, max_window + 1): | |
| if i + j <= len(tokens): | |
| candidate = ''.join(tokens[i:i+j]) | |
| if candidate in keywords: | |
| found.append((candidate)) | |
| frequency_map[candidate] += 1 | |
| count=count + 1 | |
| # Handle empty frequency_map to avoid ZeroDivisionError | |
| if len(frequency_map) == 0: | |
| mean = 0 | |
| else: | |
| mean = count / len(frequency_map) | |
| return [count, mean] | |
| comment_removed_code =remove_comments(code_snippet) | |
| keyword_frequency = find_keywords(split_tokens_with_g(tokenizer.tokenize(comment_removed_code.lower())),lowercase_keywords) | |
| # features = total_counts + total_variable_count_and_average + single_variable_count_and_proportion + snake_case + camel_case + wrong_spacing_operators + wrong_spacing_commas + comments_and_ratios+shanon_entropy | |
| features =name_features+comment_features+special_features +total_prop + total_variable_count_and_average + single_variable_count_and_proportion + snake_case + camel_case + wrong_spacing_operators + wrong_spacing_commas + comments_and_ratios+shanon_entropy+[comment_present]+[blank_lines_prop] | |
| features_dict = { | |
| 'names': name_features, | |
| 'comments': comment_features, | |
| 'special_tokens': special_features, | |
| # 'others': other_features, | |
| # 'total_counts':total_counts, | |
| 'total_prop':total_prop, | |
| 'total_variables':total_variable_count_and_average, | |
| 'single_variables':single_variable_count_and_proportion, | |
| 'snake_case':snake_case, | |
| 'camel_case':camel_case, | |
| 'wrong_spacing_operators':wrong_spacing_operators, | |
| 'wrong_spacing_commas':wrong_spacing_commas, | |
| 'comments_and_ratios':comments_and_ratios, | |
| 'shanon_entropy':shanon_entropy, | |
| # 'keyword_frequency':keyword_frequency, | |
| 'comment_present':comment_present, | |
| 'blank_lines':blank_lines_prop | |
| } | |
| return features,features_dict | |
| # User input: File upload or text input | |
| uploaded_file = st.file_uploader("Upload a code file", type=["py", "java", "txt"]) | |
| code_input = st.text_area("Or enter code here", height=200) | |
| if uploaded_file or code_input: | |
| # Read code | |
| code = uploaded_file.read().decode("utf-8") if uploaded_file else code_input | |
| st.write("### Code Input") | |
| st.code(code, language="python" if code.endswith(".py") else "java") | |
| # Step 1: Tokenize and estimate probabilities | |
| try: | |
| tokens, probs = estimate_probabilities_bidirectional_strategy(code) | |
| features,features_dict = extract_features_of_code(tokens,probs, code, tokenizer) | |
| st.write("### Tokens") | |
| st.write(features) # Limit output for readability | |
| st.write("### Token Probabilities") | |
| st.write(features_dict) # Limit output for readability | |
| except Exception as e: | |
| st.error(f"Error processing code: {str(e)}") | |
| st.write("Upload a code file or enter code to analyze.") |