import streamlit as st import tempfile import json from backend import ( clone_repository, read_code_files, analyze_code, check_api_keys ) def get_severity_color(severity): """Get color based on severity level.""" colors = { "LOW": "#FFA500", # Orange "MEDIUM": "#FF6B6B", # Light Red "HIGH": "#FF0000" # Red } return colors.get(severity.upper(), "#000000") def render_analysis_results(analysis_text): """Render the analysis results according to the Pydantic model schema.""" try: # Parse the analysis text as JSON analysis_data = json.loads(analysis_text) # Custom CSS for styling st.markdown(""" """, unsafe_allow_html=True) # Calculate severity level based on number of files impacted severity_level = analysis_data['severity_level'] if(analysis_data['number_of_files_impacted'] == None or analysis_data['number_of_files_impacted'] == 0): severity_level = "No Impact" elif(analysis_data['number_of_files_impacted'] > 0 and analysis_data['number_of_files_impacted'] <= 3): severity_level = "Low" elif(analysis_data['number_of_files_impacted'] > 3 and analysis_data['number_of_files_impacted'] <= 8): severity_level = "Medium" else: severity_level = "High" # Display Severity Level with custom styling severity_color = get_severity_color(severity_level) st.markdown(f"""

Severity Level: {severity_level}

""", unsafe_allow_html=True) # Display Number of Files Impacted with custom styling st.markdown(f"""

Number of Files Impacted: {analysis_data['number_of_files_impacted']}

""", unsafe_allow_html=True) # Display Files Impacted with custom styling st.markdown("

Files Impacted

", unsafe_allow_html=True) for file_impact in analysis_data['files_impacted']: with st.expander(f"📄 {file_impact['files_impacted']}", expanded=False): st.markdown(f"""

{file_impact['impact_details']}

""", unsafe_allow_html=True) except json.JSONDecodeError: # If the response is not valid JSON, display it as plain text st.markdown(analysis_text) except Exception as e: st.error(f"Error rendering analysis results: {str(e)}") st.markdown(analysis_text) def main(): st.title("Git Repository Code Analyzer") st.write("Enter a Git repository URL and a prompt to analyze the code.") # Example data examples = [ { "Git URL": "https://github.com/kedar-bhumkar/SFRoutingFramework", "Code/Config Changes": "Enum USER_INTERFACE removed from file: BaseAppLiterals.cls" }, { "Git URL": "https://github.com/kedar-bhumkar/SFDynamicFields", "Code/Config Changes": "Removed a field Value__c from DynamicFieldTable__c.object" } ] # Initialize session state if not exists if 'selected_example' not in st.session_state: st.session_state.selected_example = None if 'openai_key' not in st.session_state: st.session_state.openai_key = "" # API Key input section with st.expander("🔑 API Key Settings", expanded=False): st.markdown(""" """, unsafe_allow_html=True) st.markdown("""

Enter your OpenAI API key to use the GPT-4 model. The key will be stored in the session and not saved permanently.

""", unsafe_allow_html=True) openai_key = st.text_input( "OpenAI API Key", value=st.session_state.openai_key, type="password", help="Enter your OpenAI API key to use GPT-4" ) if openai_key: st.session_state.openai_key = openai_key st.success("API key saved for this session") # Display examples table with Select buttons st.subheader("Example Cases") # Create columns for the table col1, col2, col3 = st.columns([2, 2, 1]) # Table header with col1: st.write("**Git URL**") with col2: st.write("**Code/Config Changes**") with col3: st.write("**Action**") # Table rows for idx, example in enumerate(examples): with col1: st.write(example["Git URL"]) with col2: st.write(example["Code/Config Changes"]) with col3: if st.button("Select", key=f"select_{idx}"): st.session_state.selected_example = idx st.session_state.repo_url = example["Git URL"] st.session_state.prompt = example["Code/Config Changes"] st.experimental_rerun() # Get user inputs repo_url = st.text_input("Git Repository URL", value=st.session_state.get("repo_url", "")) # Model selection model = st.selectbox( "Select AI Model", ["gpt-4", "claude-sonnet (coming soon)"], help="Choose the AI model to analyze the code" ) prompt = st.text_area("Code or configuration changes", value=st.session_state.get("prompt", "List down the code/configuration changes to be performed")) # Clear button if st.button("Clear Selection"): st.session_state.selected_example = None st.session_state.repo_url = "" st.session_state.prompt = "List down the code/configuration changes to be performed" st.experimental_rerun() if st.button("Analyze"): if not repo_url: st.error("Please enter a Git repository URL") return # Check API keys api_keys_status = check_api_keys() if model == "gpt-4": # First check session state for OpenAI key if st.session_state.openai_key: # Use the key from session state api_keys_status["gpt-4"] = True elif not api_keys_status["gpt-4"]: st.error("OpenAI API key not found. Please enter your key in the API Key Settings section or set the OPENAI_API_KEY environment variable.") return elif model == "claude-sonnet" and not api_keys_status["claude-sonnet"]: st.error("Anthropic API key not found. Please set the ANTHROPIC_API_KEY environment variable.") return with st.spinner("Cloning repository and analyzing code..."): # Create a temporary directory with tempfile.TemporaryDirectory() as temp_dir: # Clone the repository success, error = clone_repository(repo_url, temp_dir) if not success: st.error(f"Error cloning repository: {error}") return # Read code files code_files, warnings = read_code_files(temp_dir) # Display any warnings from reading files for warning in warnings: st.warning(warning) if not code_files: st.warning("No code files found in the repository.") return # Analyze the code analysis, error = analyze_code(code_files, prompt, model) if error: st.error(f"Error during analysis: {error}") return if analysis: st.subheader("Analysis Results") render_analysis_results(analysis) if __name__ == "__main__": main()