Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import torch | |
| from transformers import AutoModelForCausalLM, AutoTokenizer | |
| from peft import PeftModel | |
| import os | |
| # Model configuration | |
| BASE_MODEL = "mistralai/Mistral-7B-Instruct-v0.3" | |
| ADAPTER_MODEL = "mistral-hackaton-2026/Mistral_SmartContract_Security" | |
| print("Loading model... This may take a few minutes on first run.") | |
| # Load tokenizer from base model | |
| tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL) | |
| tokenizer.pad_token = tokenizer.pad_token or tokenizer.eos_token | |
| # Check if CUDA is available | |
| device = "cuda" if torch.cuda.is_available() else "cpu" | |
| print(f"Using device: {device}") | |
| # Load base model (with quantization only if GPU available) | |
| if torch.cuda.is_available(): | |
| try: | |
| print("Loading with 4-bit quantization...") | |
| from transformers import BitsAndBytesConfig | |
| bnb_config = BitsAndBytesConfig( | |
| load_in_4bit=True, | |
| bnb_4bit_quant_type="nf4", | |
| bnb_4bit_compute_dtype=torch.float16, | |
| bnb_4bit_use_double_quant=False, | |
| ) | |
| base_model = AutoModelForCausalLM.from_pretrained( | |
| BASE_MODEL, | |
| quantization_config=bnb_config, | |
| device_map="auto", | |
| torch_dtype=torch.float16, | |
| trust_remote_code=True | |
| ) | |
| except Exception as e: | |
| print(f"Quantization failed ({e}), loading in float16...") | |
| base_model = AutoModelForCausalLM.from_pretrained( | |
| BASE_MODEL, | |
| device_map="auto", | |
| torch_dtype=torch.float16, | |
| trust_remote_code=True | |
| ) | |
| else: | |
| print("Loading on CPU (slower but works without GPU)...") | |
| base_model = AutoModelForCausalLM.from_pretrained( | |
| BASE_MODEL, | |
| device_map="auto", | |
| torch_dtype=torch.float32, | |
| trust_remote_code=True, | |
| low_cpu_mem_usage=True | |
| ) | |
| # Load PEFT adapter | |
| print("Loading fine-tuned adapter...") | |
| model = PeftModel.from_pretrained(base_model, ADAPTER_MODEL) | |
| model.eval() # Set to evaluation mode | |
| print("Model loaded successfully!") | |
| # Sample contracts for demo | |
| SAMPLE_CONTRACTS = { | |
| "Reentrancy Attack": '''// SPDX-License-Identifier: MIT | |
| pragma solidity ^0.8.0; | |
| contract VulnerableBank { | |
| mapping(address => uint256) public balances; | |
| function deposit() public payable { | |
| balances[msg.sender] += msg.value; | |
| } | |
| function withdraw(uint256 amount) public { | |
| require(balances[msg.sender] >= amount); | |
| (bool success, ) = msg.sender.call{value: amount}(""); | |
| require(success); | |
| balances[msg.sender] -= amount; // VULNERABLE: State updated after external call | |
| } | |
| }''', | |
| "Integer Overflow": '''// SPDX-License-Identifier: MIT | |
| pragma solidity 0.7.0; | |
| contract VulnerableToken { | |
| mapping(address => uint256) public balances; | |
| function transfer(address to, uint256 amount) public { | |
| balances[msg.sender] -= amount; // VULNERABLE: No underflow check | |
| balances[to] += amount; | |
| } | |
| }''', | |
| "Access Control Missing": '''// SPDX-License-Identifier: MIT | |
| pragma solidity ^0.8.0; | |
| contract VulnerableAdmin { | |
| address public owner; | |
| constructor() { | |
| owner = msg.sender; | |
| } | |
| function setOwner(address newOwner) public { // VULNERABLE: Anyone can change owner | |
| owner = newOwner; | |
| } | |
| }''', | |
| "Secure Contract": '''// SPDX-License-Identifier: MIT | |
| pragma solidity ^0.8.0; | |
| contract SecureVault { | |
| mapping(address => uint256) public balances; | |
| bool private locked; | |
| modifier noReentrant() { | |
| require(!locked, "No reentrancy"); | |
| locked = true; | |
| _; | |
| locked = false; | |
| } | |
| function withdraw(uint256 amount) public noReentrant { | |
| require(balances[msg.sender] >= amount); | |
| balances[msg.sender] -= amount; | |
| (bool success, ) = msg.sender.call{value: amount}(""); | |
| require(success); | |
| } | |
| }''' | |
| } | |
| def analyze_contract(contract_code, show_tokens=False): | |
| """Analyze smart contract for vulnerabilities""" | |
| if not contract_code.strip(): | |
| return "β οΈ Please enter a smart contract to analyze." | |
| # Prepare input | |
| input_text = f"""<s>[INST] Analyze this contract and provide structured security report: | |
| {contract_code} [/INST] | |
| """ | |
| inputs = tokenizer(input_text, return_tensors="pt", truncation=True, max_length=2048) | |
| if torch.cuda.is_available(): | |
| inputs = inputs.to("cuda") | |
| # Generate analysis | |
| model.eval() | |
| with torch.no_grad(): | |
| outputs = model.generate( | |
| **inputs, | |
| max_new_tokens=300, | |
| temperature=0.3, | |
| do_sample=True, | |
| top_p=0.95 | |
| ) | |
| response = tokenizer.decode(outputs[0], skip_special_tokens=False) | |
| analysis = response.split('[/INST]')[-1].strip() | |
| # Format output | |
| if show_tokens: | |
| output = f"### π Security Analysis (with Custom Tokens)\n\n```\n{analysis}\n```" | |
| else: | |
| # Clean up for display | |
| clean_analysis = analysis.replace('</s>', '').strip() | |
| # Check for vulnerabilities | |
| is_vulnerable = any([ | |
| '<CRITICAL>' in analysis, | |
| '<HIGH>' in analysis, | |
| '<VULN_' in analysis | |
| ]) | |
| if is_vulnerable: | |
| output = f"""### π¨ VULNERABILITY DETECTED | |
| {clean_analysis} | |
| --- | |
| **Model**: Mistral-7B Fine-tuned with 38 Custom Security Tokens | |
| **Accuracy**: 99.6% | **Precision**: 100% | **Recall**: 99.3% | |
| """ | |
| else: | |
| output = f"""### β CONTRACT APPEARS SECURE | |
| {clean_analysis} | |
| --- | |
| **Model**: Mistral-7B Fine-tuned with 38 Custom Security Tokens | |
| **Accuracy**: 99.6% | **Precision**: 100% | **Recall**: 99.3% | |
| """ | |
| return output | |
| # Create Gradio interface | |
| with gr.Blocks(theme=gr.themes.Soft(), title="Smart Contract Security Analyzer") as demo: | |
| gr.Markdown(""" | |
| # π Smart Contract Security Analyzer | |
| ### Powered by Fine-Tuned Mistral-7B with Custom Security Tokens | |
| **Hackathon Submission Features:** | |
| - β¨ 38 custom security tokens (NEW capability) | |
| - π 99.6% accuracy on 30K balanced dataset | |
| - π― 100% precision (zero false positives) | |
| - π +28.6% improvement over base Mistral | |
| - ποΈ Structured XML-style vulnerability reports | |
| """) | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| contract_input = gr.Code( | |
| label="π Paste Solidity Contract Here", | |
| language="solidity", | |
| lines=20, | |
| placeholder="// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract MyContract {\n // Your contract code here\n}" | |
| ) | |
| with gr.Row(): | |
| analyze_btn = gr.Button("π Analyze Contract", variant="primary", size="lg") | |
| clear_btn = gr.Button("ποΈ Clear", size="lg") | |
| show_tokens_checkbox = gr.Checkbox( | |
| label="Show custom security tokens in output", | |
| value=False | |
| ) | |
| with gr.Column(scale=1): | |
| gr.Markdown("### π Sample Contracts") | |
| sample_dropdown = gr.Dropdown( | |
| choices=list(SAMPLE_CONTRACTS.keys()), | |
| label="Load Example", | |
| value=None | |
| ) | |
| load_sample_btn = gr.Button("Load Sample", size="sm") | |
| output_display = gr.Markdown(label="Analysis Result") | |
| # Performance stats | |
| gr.Markdown(""" | |
| --- | |
| ### π Model Performance Metrics | |
| | Metric | Base Mistral | Fine-Tuned | Improvement | | |
| |--------|-------------|------------|-------------| | |
| | **Accuracy** | 71.0% | **99.6%** | +28.6% | | |
| | **Precision** | 64.2% | **100.0%** | +35.8% | | |
| | **Recall** | 100.0% | 99.3% | -0.7% | | |
| | **F1 Score** | 0.782 | **0.996** | +0.214 | | |
| | **Custom Tokens** | 0/38 | **25/38** | NEW! | | |
| | **Structured Output** | No | **Yes** | NEW! | | |
| **Training Details:** | |
| - 30,000 balanced samples (50% vulnerable, 50% safe) | |
| - 6 vulnerability types: Reentrancy, Overflow, Access Control, Unchecked Call, DoS, Timestamp | |
| - 4-bit quantization with LoRA (1.1% trainable params) | |
| - 5.5 hours training on Google Colab G4 GPU | |
| """) | |
| # Event handlers | |
| def load_sample(sample_name): | |
| if sample_name: | |
| return SAMPLE_CONTRACTS[sample_name] | |
| return "" | |
| analyze_btn.click( | |
| fn=analyze_contract, | |
| inputs=[contract_input, show_tokens_checkbox], | |
| outputs=output_display | |
| ) | |
| load_sample_btn.click( | |
| fn=load_sample, | |
| inputs=sample_dropdown, | |
| outputs=contract_input | |
| ) | |
| clear_btn.click( | |
| fn=lambda: ("", ""), | |
| outputs=[contract_input, output_display] | |
| ) | |
| # Launch demo | |
| if __name__ == "__main__": | |
| demo.launch() | |