Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,18 +1,8 @@
|
|
1 |
#!/usr/bin/env python3
|
2 |
"""
|
3 |
-
Code Flow Analyzer with Gradio Interface - Colab Compatible
|
4 |
-
A single-file application that uses LangChain agents to analyze code structure
|
5 |
and generate Mermaid.js flowchart diagrams through a web interface.
|
6 |
-
|
7 |
-
For Google Colab:
|
8 |
-
1. Run this cell to install dependencies and start the app
|
9 |
-
2. Enter your GROQ_API_KEY when prompted
|
10 |
-
3. The Gradio interface will appear inline
|
11 |
-
|
12 |
-
For local usage:
|
13 |
-
1. Set your API key: export GROQ_API_KEY="your-key-here"
|
14 |
-
2. Run: python code_flow_analyzer.py
|
15 |
-
3. Open the provided URL in your browser
|
16 |
"""
|
17 |
|
18 |
import ast
|
@@ -30,21 +20,22 @@ try:
|
|
30 |
print("π’ Running in Google Colab")
|
31 |
except ImportError:
|
32 |
IN_COLAB = False
|
33 |
-
print("π‘ Running locally")
|
34 |
|
35 |
# Install dependencies if in Colab
|
36 |
if IN_COLAB:
|
37 |
print("π¦ Installing dependencies...")
|
38 |
-
os.system("pip install -q gradio langchain langgraph langchain-
|
39 |
print("β
Dependencies installed")
|
40 |
|
41 |
import gradio as gr
|
42 |
from langchain.chat_models import init_chat_model
|
|
|
43 |
from langchain.tools import tool
|
44 |
from langgraph.prebuilt import create_react_agent
|
45 |
from langgraph.checkpoint.memory import MemorySaver
|
46 |
|
47 |
-
# Sample code examples
|
48 |
SAMPLE_PYTHON = '''def main():
|
49 |
user_input = get_user_input()
|
50 |
if user_input:
|
@@ -147,29 +138,29 @@ SAMPLE_JAVA = '''public class Calculator {
|
|
147 |
}
|
148 |
}'''
|
149 |
|
150 |
-
#
|
151 |
def setup_api_key():
|
152 |
-
"""Setup API key for
|
153 |
-
api_key = os.getenv("
|
154 |
|
155 |
if not api_key:
|
156 |
if IN_COLAB:
|
157 |
-
print("π Please enter your
|
158 |
-
print(" Get a
|
159 |
-
api_key = getpass.getpass("
|
160 |
if api_key:
|
161 |
-
os.environ["
|
162 |
print("β
API key set successfully")
|
163 |
else:
|
164 |
print("β οΈ No API key provided - agent features will be disabled")
|
165 |
else:
|
166 |
-
print("β οΈ
|
167 |
-
print("
|
168 |
-
print("
|
169 |
else:
|
170 |
-
print("β
|
171 |
|
172 |
-
return api_key or os.getenv("
|
173 |
|
174 |
# Setup API key
|
175 |
api_key = setup_api_key()
|
@@ -181,15 +172,16 @@ agent_executor = None
|
|
181 |
|
182 |
if api_key:
|
183 |
try:
|
184 |
-
model =
|
|
|
185 |
memory = MemorySaver()
|
186 |
-
print("β
Groq model initialized successfully")
|
187 |
except Exception as e:
|
188 |
-
print(f"β Could not initialize
|
189 |
-
print(" Please check your API key and internet connection")
|
190 |
model = None
|
191 |
memory = None
|
192 |
|
|
|
193 |
@tool
|
194 |
def analyze_code_structure(source_code: str) -> Dict[str, Any]:
|
195 |
"""
|
@@ -481,7 +473,7 @@ def analyze_code_with_agent(source_code: str, language: str = "auto") -> Tuple[s
|
|
481 |
return "", "No code provided", [], 0, "Please enter some source code to analyze"
|
482 |
|
483 |
if not agent_executor:
|
484 |
-
return "", "Agent not available", [], 0, "β LangChain agent not initialized. Please check your
|
485 |
|
486 |
try:
|
487 |
# Detect language if auto
|
@@ -497,62 +489,46 @@ def analyze_code_with_agent(source_code: str, language: str = "auto") -> Tuple[s
|
|
497 |
else:
|
498 |
language = "Unknown"
|
499 |
|
500 |
-
config = {
|
|
|
|
|
|
|
501 |
|
|
|
502 |
prompt = f"""
|
503 |
-
You are a code analysis expert. Analyze the following {language} source code
|
504 |
-
|
505 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
506 |
```{language.lower()}
|
507 |
{source_code}
|
508 |
```
|
509 |
-
|
510 |
-
Please follow these steps exactly:
|
511 |
-
1. First use the analyze_code_structure tool to understand the code structure
|
512 |
-
2. Then use the generate_mermaid_diagram tool to create a flowchart
|
513 |
-
3. Use the calculate_complexity_score tool to assess code complexity
|
514 |
-
4. Provide a brief summary of what the code does and its structure
|
515 |
-
|
516 |
-
Important guidelines:
|
517 |
-
- Focus on the main flow between functions and important control structures
|
518 |
-
- Keep the diagram clean and readable
|
519 |
-
- Identify all functions and their relationships
|
520 |
-
- Note any loops, conditionals, and function calls
|
521 |
-
- Provide insights about code organization and complexity
|
522 |
-
|
523 |
-
Please be thorough in your analysis and make sure to use all three tools in order.
|
524 |
"""
|
525 |
|
526 |
-
# Execute the agent
|
527 |
result = agent_executor.invoke(
|
528 |
{"messages": [{"role": "user", "content": prompt}]},
|
529 |
config
|
530 |
)
|
531 |
|
532 |
if result and "messages" in result:
|
533 |
-
|
534 |
-
|
535 |
# Extract Mermaid diagram
|
536 |
-
mermaid_match = re.search(r'```mermaid\n(.*?)\n```',
|
537 |
-
if
|
538 |
-
mermaid_match = re.search(r'flowchart TD.*?(?=\n\n|\Z)', response, re.DOTALL)
|
539 |
-
|
540 |
-
mermaid_diagram = mermaid_match.group(1) if mermaid_match else mermaid_match.group(0) if mermaid_match else ""
|
541 |
-
|
542 |
-
# If no mermaid found in response, try to generate directly
|
543 |
-
if not mermaid_diagram:
|
544 |
-
print("β οΈ No Mermaid diagram found in response, generating fallback...")
|
545 |
-
# Fallback: analyze directly
|
546 |
-
analysis_result = analyze_code_structure.invoke({"source_code": source_code})
|
547 |
-
mermaid_diagram = generate_mermaid_diagram.invoke({"analysis_data": analysis_result})
|
548 |
|
549 |
# Extract complexity score
|
550 |
-
complexity_match = re.search(r'complexity.*?(\d+)',
|
551 |
-
complexity_score = int(complexity_match.group(1)) if complexity_match else
|
552 |
|
553 |
# Extract functions
|
554 |
functions_found = []
|
555 |
-
func_matches = re.findall(r'Functions found:.*?([^\n]+)',
|
556 |
if func_matches:
|
557 |
functions_found = [f.strip() for f in func_matches[0].split(',')]
|
558 |
else:
|
@@ -561,17 +537,26 @@ def analyze_code_with_agent(source_code: str, language: str = "auto") -> Tuple[s
|
|
561 |
functions_found = [f["name"] for f in analysis_result.get("functions", [])]
|
562 |
|
563 |
# Clean up the response for summary
|
564 |
-
summary = re.sub(r'```mermaid.*?```', '',
|
565 |
summary = re.sub(r'flowchart TD.*?(?=\n\n|\Z)', '', summary, flags=re.DOTALL)
|
566 |
summary = summary.strip()
|
567 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
568 |
return mermaid_diagram, summary, functions_found, complexity_score, ""
|
569 |
|
570 |
except Exception as e:
|
571 |
error_msg = f"β Analysis failed: {str(e)}"
|
572 |
-
print(f"Error details: {traceback.format_exc()}")
|
573 |
return "", "", [], 0, error_msg
|
574 |
|
|
|
575 |
def create_gradio_interface():
|
576 |
"""Create and configure the Gradio interface"""
|
577 |
|
@@ -633,7 +618,10 @@ def create_gradio_interface():
|
|
633 |
""")
|
634 |
|
635 |
# API Status
|
636 |
-
|
|
|
|
|
|
|
637 |
gr.Markdown(f"**Status:** {api_status}")
|
638 |
|
639 |
with gr.Row():
|
@@ -728,16 +716,16 @@ def create_gradio_interface():
|
|
728 |
)
|
729 |
|
730 |
# Footer
|
731 |
-
environment_info = "Google Colab" if IN_COLAB else "Local Environment"
|
732 |
gr.Markdown(f"""
|
733 |
---
|
734 |
**π οΈ Running in:** {environment_info}
|
735 |
|
736 |
-
**π¦ Dependencies:** gradio, langchain, langgraph, langchain-
|
737 |
|
738 |
-
**π§ Powered by:** LangChain Agents,
|
739 |
|
740 |
-
**π Get
|
741 |
""")
|
742 |
|
743 |
return interface
|
@@ -746,37 +734,29 @@ def main():
|
|
746 |
"""Main function to run the application"""
|
747 |
print("π Code Flow Analyzer with Gradio")
|
748 |
print("=" * 50)
|
749 |
-
print(f"π Environment: {'Google Colab' if IN_COLAB else 'Local'}")
|
750 |
|
751 |
if agent_executor:
|
752 |
print("β
LangChain agent ready")
|
753 |
else:
|
754 |
print("β LangChain agent not available")
|
755 |
if IN_COLAB:
|
756 |
-
print(" π‘ Restart this cell and enter your
|
|
|
|
|
757 |
|
758 |
print("\nπ Starting Gradio interface...")
|
759 |
|
760 |
# Create and launch the interface
|
761 |
interface = create_gradio_interface()
|
762 |
|
763 |
-
# Launch configuration for Colab vs local
|
764 |
-
|
765 |
-
|
766 |
-
|
767 |
-
|
768 |
-
|
769 |
-
|
770 |
-
show_error=True
|
771 |
-
)
|
772 |
-
else:
|
773 |
-
# For local usage
|
774 |
-
interface.launch(
|
775 |
-
server_name="0.0.0.0",
|
776 |
-
server_port=7860,
|
777 |
-
share=False, # Disable sharing for local use
|
778 |
-
debug=False
|
779 |
-
)
|
780 |
|
781 |
# Auto-run if in Colab or when script is executed directly
|
782 |
if __name__ == "__main__" or IN_COLAB:
|
|
|
1 |
#!/usr/bin/env python3
|
2 |
"""
|
3 |
+
Code Flow Analyzer with Gradio Interface - Hugging Face Spaces & Colab Compatible
|
4 |
+
A single-file application that uses LangChain agents with the Gemini model to analyze code structure
|
5 |
and generate Mermaid.js flowchart diagrams through a web interface.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
"""
|
7 |
|
8 |
import ast
|
|
|
20 |
print("π’ Running in Google Colab")
|
21 |
except ImportError:
|
22 |
IN_COLAB = False
|
23 |
+
print("π‘ Running locally or in Hugging Face Spaces")
|
24 |
|
25 |
# Install dependencies if in Colab
|
26 |
if IN_COLAB:
|
27 |
print("π¦ Installing dependencies...")
|
28 |
+
os.system("pip install -q gradio langchain langgraph langchain-google-genai")
|
29 |
print("β
Dependencies installed")
|
30 |
|
31 |
import gradio as gr
|
32 |
from langchain.chat_models import init_chat_model
|
33 |
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
34 |
from langchain.tools import tool
|
35 |
from langgraph.prebuilt import create_react_agent
|
36 |
from langgraph.checkpoint.memory import MemorySaver
|
37 |
|
38 |
+
# Sample code examples (unchanged)
|
39 |
SAMPLE_PYTHON = '''def main():
|
40 |
user_input = get_user_input()
|
41 |
if user_input:
|
|
|
138 |
}
|
139 |
}'''
|
140 |
|
141 |
+
# --- Gemini API Key Setup ---
|
142 |
def setup_api_key():
|
143 |
+
"""Setup API key for Colab, Hugging Face Spaces, and local environments"""
|
144 |
+
api_key = os.getenv("GOOGLE_API_KEY")
|
145 |
|
146 |
if not api_key:
|
147 |
if IN_COLAB:
|
148 |
+
print("π Please enter your Google API key:")
|
149 |
+
print(" Get a key from: https://aistudio.google.com/app/apikey")
|
150 |
+
api_key = getpass.getpass("GOOGLE_API_KEY: ")
|
151 |
if api_key:
|
152 |
+
os.environ["GOOGLE_API_KEY"] = api_key
|
153 |
print("β
API key set successfully")
|
154 |
else:
|
155 |
print("β οΈ No API key provided - agent features will be disabled")
|
156 |
else:
|
157 |
+
print("β οΈ GOOGLE_API_KEY not found in environment variables")
|
158 |
+
print(" Set it with: export GOOGLE_API_KEY='your-key-here'")
|
159 |
+
print(" In Hugging Face Spaces, use the 'Secrets' tab to set the key.")
|
160 |
else:
|
161 |
+
print("β
Google API key found")
|
162 |
|
163 |
+
return api_key or os.getenv("GOOGLE_API_KEY")
|
164 |
|
165 |
# Setup API key
|
166 |
api_key = setup_api_key()
|
|
|
172 |
|
173 |
if api_key:
|
174 |
try:
|
175 |
+
model = ChatGoogleGenerativeAI(model="gemini-pro", temperature=0)
|
176 |
+
print("β
Gemini model initialized successfully: gemini-pro")
|
177 |
memory = MemorySaver()
|
|
|
178 |
except Exception as e:
|
179 |
+
print(f"β Could not initialize Gemini model: {e}")
|
180 |
+
print(" Please check your API key and internet connection.")
|
181 |
model = None
|
182 |
memory = None
|
183 |
|
184 |
+
# --- Tool Definitions (unchanged) ---
|
185 |
@tool
|
186 |
def analyze_code_structure(source_code: str) -> Dict[str, Any]:
|
187 |
"""
|
|
|
473 |
return "", "No code provided", [], 0, "Please enter some source code to analyze"
|
474 |
|
475 |
if not agent_executor:
|
476 |
+
return "", "Agent not available", [], 0, "β LangChain agent not initialized. Please check your GOOGLE_API_KEY"
|
477 |
|
478 |
try:
|
479 |
# Detect language if auto
|
|
|
489 |
else:
|
490 |
language = "Unknown"
|
491 |
|
492 |
+
config = {
|
493 |
+
"configurable": {"thread_id": f"session_{hash(source_code) % 10000}"},
|
494 |
+
"recursion_limit": 100
|
495 |
+
}
|
496 |
|
497 |
+
# Refined prompt for better tool use
|
498 |
prompt = f"""
|
499 |
+
You are a code analysis expert. Analyze the following {language} source code.
|
500 |
+
Your task is to:
|
501 |
+
1. Use the 'analyze_code_structure' tool with the full source code provided below.
|
502 |
+
2. Use the 'generate_mermaid_diagram' tool with the output of the first tool.
|
503 |
+
3. Use the 'calculate_complexity_score' tool with the output of the first tool.
|
504 |
+
4. Provide a brief, human-readable summary of the analysis, including the generated Mermaid diagram, complexity score, and a list of functions found.
|
505 |
+
5. Present the final result in a clear, easy-to-read format.
|
506 |
+
|
507 |
+
Source Code to Analyze:
|
508 |
```{language.lower()}
|
509 |
{source_code}
|
510 |
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
511 |
"""
|
512 |
|
|
|
513 |
result = agent_executor.invoke(
|
514 |
{"messages": [{"role": "user", "content": prompt}]},
|
515 |
config
|
516 |
)
|
517 |
|
518 |
if result and "messages" in result:
|
519 |
+
response_content = result["messages"][-1].content
|
520 |
+
|
521 |
# Extract Mermaid diagram
|
522 |
+
mermaid_match = re.search(r'```mermaid\n(.*?)\n```', response_content, re.DOTALL)
|
523 |
+
mermaid_diagram = mermaid_match.group(1) if mermaid_match else ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
524 |
|
525 |
# Extract complexity score
|
526 |
+
complexity_match = re.search(r'complexity.*?(\d+)', response_content, re.IGNORECASE)
|
527 |
+
complexity_score = int(complexity_match.group(1)) if complexity_match else 0
|
528 |
|
529 |
# Extract functions
|
530 |
functions_found = []
|
531 |
+
func_matches = re.findall(r'Functions found:.*?([^\n]+)', response_content, re.IGNORECASE)
|
532 |
if func_matches:
|
533 |
functions_found = [f.strip() for f in func_matches[0].split(',')]
|
534 |
else:
|
|
|
537 |
functions_found = [f["name"] for f in analysis_result.get("functions", [])]
|
538 |
|
539 |
# Clean up the response for summary
|
540 |
+
summary = re.sub(r'```mermaid.*?```', '', response_content, flags=re.DOTALL)
|
541 |
summary = re.sub(r'flowchart TD.*?(?=\n\n|\Z)', '', summary, flags=re.DOTALL)
|
542 |
summary = summary.strip()
|
543 |
|
544 |
+
if not mermaid_diagram and not summary:
|
545 |
+
# Last resort fallback if agent fails entirely
|
546 |
+
analysis_result = analyze_code_structure.invoke({"source_code": source_code})
|
547 |
+
mermaid_diagram = generate_mermaid_diagram.invoke({"analysis_data": analysis_result})
|
548 |
+
complexity_score = calculate_complexity_score.invoke({"analysis_data": analysis_result})
|
549 |
+
functions_found = [f["name"] for f in analysis_result.get("functions", [])]
|
550 |
+
summary = "Agent failed to provide a detailed summary, but a fallback analysis was successful."
|
551 |
+
|
552 |
return mermaid_diagram, summary, functions_found, complexity_score, ""
|
553 |
|
554 |
except Exception as e:
|
555 |
error_msg = f"β Analysis failed: {str(e)}"
|
556 |
+
print(f"Error details: {traceback.format_exc()}")
|
557 |
return "", "", [], 0, error_msg
|
558 |
|
559 |
+
# --- Gradio Interface Setup (unchanged) ---
|
560 |
def create_gradio_interface():
|
561 |
"""Create and configure the Gradio interface"""
|
562 |
|
|
|
618 |
""")
|
619 |
|
620 |
# API Status
|
621 |
+
model_info = ""
|
622 |
+
if agent_executor and model:
|
623 |
+
model_info = " (Gemini LLM)"
|
624 |
+
api_status = f"π’ Gemini LangChain Agent Ready{model_info}" if agent_executor else "π΄ Agent Not Available (Check GOOGLE_API_KEY)"
|
625 |
gr.Markdown(f"**Status:** {api_status}")
|
626 |
|
627 |
with gr.Row():
|
|
|
716 |
)
|
717 |
|
718 |
# Footer
|
719 |
+
environment_info = "Google Colab" if IN_COLAB else "Hugging Face Spaces or Local Environment"
|
720 |
gr.Markdown(f"""
|
721 |
---
|
722 |
**π οΈ Running in:** {environment_info}
|
723 |
|
724 |
+
**π¦ Dependencies:** gradio, langchain, langgraph, langchain-google-genai
|
725 |
|
726 |
+
**π§ Powered by:** LangChain Agents, Google Gemini, Mermaid.js, Gradio
|
727 |
|
728 |
+
**π Get Google API Key:** [aistudio.google.com/app/apikey](https://aistudio.google.com/app/apikey)
|
729 |
""")
|
730 |
|
731 |
return interface
|
|
|
734 |
"""Main function to run the application"""
|
735 |
print("π Code Flow Analyzer with Gradio")
|
736 |
print("=" * 50)
|
737 |
+
print(f"π Environment: {'Google Colab' if IN_COLAB else 'Hugging Face Spaces or Local'}")
|
738 |
|
739 |
if agent_executor:
|
740 |
print("β
LangChain agent ready")
|
741 |
else:
|
742 |
print("β LangChain agent not available")
|
743 |
if IN_COLAB:
|
744 |
+
print(" π‘ Restart this cell and enter your GOOGLE_API_KEY when prompted")
|
745 |
+
else:
|
746 |
+
print(" π‘ Please set your GOOGLE_API_KEY as an environment variable or secret")
|
747 |
|
748 |
print("\nπ Starting Gradio interface...")
|
749 |
|
750 |
# Create and launch the interface
|
751 |
interface = create_gradio_interface()
|
752 |
|
753 |
+
# Launch configuration for Colab vs local/Spaces
|
754 |
+
interface.launch(
|
755 |
+
share=True if IN_COLAB else False,
|
756 |
+
debug=False,
|
757 |
+
height=600,
|
758 |
+
show_error=True
|
759 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
760 |
|
761 |
# Auto-run if in Colab or when script is executed directly
|
762 |
if __name__ == "__main__" or IN_COLAB:
|