mkhekare/Lineage
0
1import gradio as gr2import networkx as nx3import ast4import os5import tempfile6from pathlib import Path7import shutil8import uuid9import spacy10from pyvis.network import Network11from git import Repo12from huggingface_hub import InferenceClient13import re14 15# Initialize NLP and AI16nlp = spacy.load("en_core_web_sm")17HF_TOKEN = os.getenv("HF_TOKEN")18 19class CodeAnalyzer:20 def __init__(self):21 self.graph = nx.DiGraph()22 self.entity_map = {}23 self.code_context = ""24 self.current_file = ""25 self.imports = []26 27 def parse_code(self, code: str, language: str = "python", file_path: str = ""):28 self.current_file = file_path if file_path else "input.py"29 self.code_context = code30 self.graph = nx.DiGraph()31 self.entity_map = {}32 self.imports = []33 34 if language == "python":35 return self._parse_python(code)36 else:37 raise ValueError(f"Unsupported language: {language}")38 39 def _parse_python(self, code: str):40 try:41 tree = ast.parse(code)42 self._analyze_ast(tree)43 self._analyze_comments(code)44 self._analyze_import_statements(code)45 self._infer_relationships()46 return self._generate_visualization(), self._generate_report()47 except SyntaxError as e:48 raise ValueError(f"Syntax error in code: {str(e)}")49 except Exception as e:50 raise ValueError(f"Error parsing code: {str(e)}")51 52 # [All analysis methods remain the same as previous version]53 54 def _generate_visualization(self):55 """Generate interactive visualization with error handling"""56 try:57 if len(self.graph.nodes) == 0:58 raise ValueError("No entities found to visualize")59 60 net = Network(61 height="750px",62 width="100%",63 bgcolor="#f9f9f9",64 font_color="#333",65 directed=True,66 notebook=False67 )68 69 # [Rest of visualization code remains the same]70 71 return html72 except Exception as e:73 return f"<div class='error'>Visualization Error: {str(e)}</div>"74 75 def _generate_report(self):76 """Generate report with error handling"""77 try:78 if len(self.graph.nodes) == 0:79 raise ValueError("No code entities found to report")80 81 # [Rest of report generation code remains the same]82 83 return report84 except Exception as e:85 return f"# Report Generation Error\n\n{str(e)}"86 87def analyze_local_code(code: str):88 """Analyze local code with proper error handling"""89 analyzer = CodeAnalyzer()90 try:91 if not code.strip():92 raise ValueError("No code provided")93 return analyzer.parse_code(code)94 except Exception as e:95 return f"<div class='error'>Analysis Error: {str(e)}</div>", f"# Error\n\n{str(e)}"96 97def analyze_github_repo(repo_url: str):98 """Analyze GitHub repository with robust error handling"""99 try:100 if not repo_url.strip():101 raise ValueError("No repository URL provided")102 103 # Clean and validate URL104 if 'github.com' not in repo_url:105 raise ValueError("Invalid GitHub URL - must contain 'github.com'")106 107 if '/blob/' in repo_url:108 # Convert blob URL to raw repository URL109 parts = repo_url.split('/blob/')110 repo_url = f"{parts[0]}.git"111 elif not repo_url.endswith('.git'):112 repo_url = f"{repo_url.rstrip('/')}.git"113 114 # Clone repository115 repo_name = repo_url.split('/')[-1].replace('.git', '')116 repo_dir = Path(tempfile.gettempdir()) / repo_name117 118 if repo_dir.exists():119 shutil.rmtree(repo_dir)120 121 print(f"Cloning repository: {repo_url}") # Debug log122 Repo.clone_from(repo_url, repo_dir)123 124 # Analyze Python files125 analyzer = CodeAnalyzer()126 master_graph = nx.DiGraph()127 analyzed_files = 0128 129 for py_file in repo_dir.glob('**/*.py'):130 try:131 with open(py_file, 'r', encoding='utf-8') as f:132 code = f.read()133 graph, _ = analyzer.parse_code(code, file_path=str(py_file))134 master_graph = nx.compose(master_graph, graph)135 analyzed_files += 1136 except Exception as e:137 print(f"Skipping {py_file}: {str(e)}")138 continue139 140 if analyzed_files == 0:141 raise ValueError("No valid Python files found in repository")142 143 analyzer.graph = master_graph144 analyzer.current_file = f"GitHub Repository: {repo_name}"145 return analyzer._generate_visualization(), analyzer._generate_report()146 147 except Exception as e:148 error_msg = f"Repository Analysis Failed: {str(e)}"149 print(error_msg) # Debug log150 return f"<div class='error'>{error_msg}</div>", f"# Error\n\n{error_msg}"151 152def query_deepseek(prompt: str, code_context: str = ""):153 """Query DeepSeek AI with proper error handling"""154 try:155 if not prompt.strip():156 return "Please enter a question"157 158 if not HF_TOKEN:159 return "AI features disabled - missing API key"160 161 client = InferenceClient(162 provider="together",163 api_key=HF_TOKEN164 )165 166 messages = [{167 "role": "user",168 "content": f"""Analyze this Python code and answer the question:169 170 {code_context[:2000]}171 172 Question: {prompt}173 174 Provide detailed technical analysis focusing on:175 - Data flow and dependencies176 - Potential issues177 - Optimization suggestions178 """179 }]180 181 response = client.chat.completions.create(182 model="deepseek-ai/DeepSeek-R1",183 messages=messages,184 max_tokens=500185 )186 187 if not response.choices:188 return "No response generated from AI"189 190 output = response.choices[0].message.content191 return re.sub(r"<think>.*?</think>", "", output, flags=re.DOTALL).strip()192 193 except Exception as e:194 return f"AI Error: {str(e)}"195 196# Gradio Interface with improved UI197with gr.Blocks(198 title="Code Lineage Analyzer",199 css="""200 .gradio-container {max-width: 1200px !important; margin: 0 auto;}201 .error {color: #ff4d4d; padding: 10px; background: #fff0f0; border-radius: 5px; margin: 10px 0;}202 .graph-container {border: 1px solid #e0e0e0; border-radius: 8px; padding: 15px; background: white; box-shadow: 0 2px 4px rgba(0,0,0,0.05); min-height: 800px;}203 .tab {padding: 20px; background: #f9f9f9; border-radius: 8px; margin-top: 10px;}204 .header {background: linear-gradient(135deg, #6e8efb, #a777e3); padding: 20px; color: white; border-radius: 8px 8px 0 0; margin-bottom: 20px;}205 .input-section {background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.05); margin-bottom: 20px;}206 .btn-primary {background: linear-gradient(135deg, #6e8efb, #a777e3) !important; border: none !important; color: white !important;}207 .btn-primary:hover {background: linear-gradient(135deg, #5d7de9, #9666d6) !important;}208 .loading {color: #666; font-style: italic;}209 """210) as demo:211 with gr.Column():212 # Header213 gr.Markdown("""214 <div class="header">215 <h1 style="margin: 0;">๐ Advanced Code Lineage Analyzer</h1>216 <p style="margin: 0; opacity: 0.9;">Visualize code dependencies, analyze repositories, and get AI-powered insights</p>217 </div>218 """)219 220 # Main Tabs221 with gr.Tabs():222 # Code Analysis Tab223 with gr.Tab("Code Analysis"):224 with gr.Row():225 with gr.Column(scale=1, min_width=400):226 with gr.Group(elem_classes="input-section"):227 code_input = gr.Code(228 label="Python Code",229 language="python",230 lines=20,231 value="""class Person:232 def __init__(self, name):233 self.name = name234 self.parents = []235 self.children = []236 237 def add_parent(self, parent):238 self.parents.append(parent)239 parent.children.append(self)240 241 def get_lineage(self, generation=0):242 lineage = " " * generation + self.name + "\\n"243 for child in self.children:244 lineage += child.get_lineage(generation + 1)245 return lineage246 247# Example usage248alice = Person("Alice")249bob = Person("Bob")250charlie = Person("Charlie")251alice.add_parent(bob)252charlie.add_parent(alice)"""253 )254 analyze_btn = gr.Button("Analyze Code", variant="primary", elem_classes="btn-primary")255 256 with gr.Column(scale=1, min_width=600):257 with gr.Tabs():258 with gr.Tab("Visualization"):259 graph_output = gr.HTML(elem_classes="graph-container", value="<div style='padding:20px;text-align:center;color:#666;'>Visualization will appear here</div>")260 with gr.Tab("Report"):261 report_output = gr.Markdown(value="# Report\n\nAnalysis report will appear here")262 263 analyze_btn.click(264 analyze_local_code,265 inputs=[code_input],266 outputs=[graph_output, report_output],267 api_name="analyze_code"268 )269 270 # GitHub Analysis Tab271 with gr.Tab("GitHub Analysis"):272 with gr.Row():273 with gr.Column(scale=1, min_width=400):274 with gr.Group(elem_classes="input-section"):275 repo_input = gr.Textbox(276 label="GitHub Repository URL",277 placeholder="https://github.com/user/repo"278 )279 gr.Examples(280 examples=[281 "https://github.com/psf/requests",282 "https://github.com/django/django"283 ],284 inputs=[repo_input],285 label="Try these repositories:"286 )287 repo_btn = gr.Button("Analyze Repository", variant="primary", elem_classes="btn-primary")288 289 with gr.Column(scale=1, min_width=600):290 with gr.Tabs():291 with gr.Tab("Visualization"):292 repo_graph = gr.HTML(elem_classes="graph-container", value="<div style='padding:20px;text-align:center;color:#666;'>Repository visualization will appear here</div>")293 with gr.Tab("Report"):294 repo_report = gr.Markdown(value="# Repository Report\n\nAnalysis report will appear here")295 296 repo_btn.click(297 analyze_github_repo,298 inputs=[repo_input],299 outputs=[repo_graph, repo_report],300 api_name="analyze_repo"301 )302 303 # AI Assistant Tab304 with gr.Tab("AI Assistant"):305 with gr.Row():306 with gr.Column(scale=1, min_width=400):307 with gr.Group(elem_classes="input-section"):308 ai_prompt = gr.Textbox(309 label="Ask about the code",310 placeholder="Explain the data flow in this code..."311 )312 ai_context = gr.Code(313 label="Code Context (optional)",314 language="python",315 lines=10,316 interactive=True317 )318 ai_btn = gr.Button("Get AI Analysis", variant="primary", elem_classes="btn-primary")319 320 with gr.Column(scale=1, min_width=600):321 ai_output = gr.Markdown(322 label="AI Analysis",323 value="### AI Insights\n\nAI-powered analysis will appear here"324 )325 326 ai_btn.click(327 query_deepseek,328 inputs=[ai_prompt, ai_context],329 outputs=[ai_output],330 api_name="query_ai"331 )332 333if __name__ == "__main__":334 demo.launch()