kyorlin2001/code-analysis-tool
0
1from __future__ import annotations2 3import json4 5import streamlit as st6 7from orchestrator import AnalysisOrchestrator8from tools.github_loader import load_repository_from_github9from tools.repo_loader import load_repository_from_zip10 11 12st.set_page_config(page_title="Agentic Code Analyst", layout="wide")13st.title("Agentic Code Analyst 🤖")14st.write("Analyze a zip archive, or GitHub repository.")15 16 17if "last_result" not in st.session_state:18 st.session_state.last_result = None19if "zip_temp_dir" not in st.session_state:20 st.session_state.zip_temp_dir = None21if "github_temp_dir" not in st.session_state:22 st.session_state.github_temp_dir = None23if "repo_root_path" not in st.session_state:24 st.session_state.repo_root_path = None25 26 27input_mode = st.radio(28 "Choose input type",29 ["Zip file upload", "GitHub repository"],30 horizontal=True,31)32 33repo_path = ""34uploaded_zip = None35github_owner = ""36github_repo = ""37github_branch = "main"38github_token = ""39 40if input_mode == "Local folder path":41 repo_path = st.text_input(42 "Local repository folder path",43 placeholder=r"C:\\path\\to\\your\\repo",44 )45elif input_mode == "Zip file upload":46 uploaded_zip = st.file_uploader(47 "Upload a zip file containing your codebase",48 type=["zip"],49 accept_multiple_files=False,50 )51else:52 github_owner = st.text_input("GitHub owner", placeholder="octocat")53 github_repo = st.text_input("GitHub repo", placeholder="hello-world")54 github_branch = st.text_input("Branch", value="main")55 github_token = st.text_input("GitHub token (optional)", type="password")56 57focus = st.selectbox(58 "Analysis focus",59 ["full", "architecture", "dependencies", "issues"],60 index=0,61)62 63enable_rag = st.checkbox("Enable RAG follow-up questions", value=True)64 65rag_question = ""66if enable_rag:67 rag_question = st.text_area(68 "Optional RAG question",69 placeholder="What should I improve in this repository?",70 height=100,71 )72 73baseline_file = st.file_uploader(74 "Optional baseline findings JSON for regression analysis",75 type=["json"],76 accept_multiple_files=False,77)78 79baseline_findings = []80if baseline_file is not None:81 try:82 baseline_findings = json.loads(baseline_file.getvalue().decode("utf-8"))83 if not isinstance(baseline_findings, list):84 st.warning("Baseline JSON must be a list of finding objects.")85 baseline_findings = []86 except Exception as exc:87 st.warning(f"Could not parse baseline JSON: {exc}")88 baseline_findings = []89 90run_button = st.button("Run analysis")91 92if run_button:93 try:94 with st.spinner("Analyzing repository..."):95 orchestrator = AnalysisOrchestrator(enable_rag=enable_rag)96 repo_data = None97 resolved_repo_path = ""98 99 if input_mode == "Local folder path":100 if not repo_path.strip():101 st.error("Please enter a folder path.")102 st.stop()103 104 resolved_repo_path = repo_path.strip()105 result = orchestrator.run_analysis(106 repo_path=resolved_repo_path,107 focus=focus,108 baseline_findings=baseline_findings,109 rag_question=rag_question.strip() or None,110 )111 112 elif input_mode == "Zip file upload":113 if uploaded_zip is None:114 st.error("Please upload a zip file.")115 st.stop()116 117 loaded = load_repository_from_zip(118 uploaded_zip.getvalue(),119 uploaded_zip.name,120 )121 st.session_state.zip_temp_dir = loaded.temp_dir122 repo_data = loaded.data123 resolved_repo_path = loaded.data.root_dir or ""124 125 result = orchestrator.run_analysis(126 repo_path=resolved_repo_path,127 focus=focus,128 baseline_findings=baseline_findings,129 repo_data=repo_data,130 rag_question=rag_question.strip() or None,131 )132 133 else:134 if not github_owner.strip() or not github_repo.strip():135 st.error("Please enter both GitHub owner and repo.")136 st.stop()137 138 loaded = load_repository_from_github(139 owner=github_owner.strip(),140 repo=github_repo.strip(),141 branch=github_branch.strip() or "main",142 token=github_token.strip() or None,143 )144 st.session_state.github_temp_dir = loaded.temp_dir145 repo_data = loaded.data146 resolved_repo_path = loaded.data.root_dir or ""147 148 result = orchestrator.run_analysis(149 repo_path=resolved_repo_path,150 focus=focus,151 baseline_findings=baseline_findings,152 repo_data=repo_data,153 rag_question=rag_question.strip() or None,154 )155 156 st.session_state.last_result = result157 st.session_state.repo_root_path = resolved_repo_path158 159 except Exception as exc:160 st.error(f"Analysis failed: {exc}")161 162 163result = st.session_state.last_result164 165if result:166 st.subheader("Summary")167 st.markdown(result.summary)168 169 st.subheader("Recommendations")170 for rec in result.recommendations:171 st.write(f"- {rec}")172 173 st.subheader("Findings")174 if result.findings:175 for finding in result.findings:176 severity = finding.get("severity", "info")177 message = finding.get("message", "")178 st.write(f"- **[{severity}]** {message}")179 else:180 st.write("No findings reported.")181 182 if result.rag_answer:183 st.divider()184 st.subheader("RAG Answer")185 st.write(result.rag_answer)186 187 if result.rag_suggestions:188 st.subheader("RAG Suggestions")189 for suggestion in result.rag_suggestions:190 st.write(f"- {suggestion}")191 192 if result.rag_citations:193 st.subheader("RAG Citations")194 for citation in result.rag_citations:195 st.write(f"- {citation.get('label', citation)}")196 197 if result.rag_follow_up_questions:198 st.subheader("RAG Follow-up Questions")199 for item in result.rag_follow_up_questions:200 st.write(f"- {item}")201 202 if result.rag_notes:203 st.subheader("RAG Notes")204 for note in result.rag_notes:205 st.write(f"- {note}")206 207 rag_debug = {}208 if isinstance(result.metadata, dict):209 rag_debug = result.metadata.get("rag", {}) or {}210 211 if rag_debug:212 with st.expander("RAG Debug Info"):213 st.json(rag_debug)214 215 prompt_preview = rag_debug.get("prompt_preview")216 if prompt_preview:217 st.subheader("Prompt Preview")218 st.text(prompt_preview)219 220 selected_files = rag_debug.get("selected_files", [])221 if selected_files:222 st.subheader("Selected Files")223 for file_path in selected_files:224 st.write(f"- {file_path}")225 226 selected_chunk_previews = rag_debug.get("selected_chunk_previews", [])227 if selected_chunk_previews:228 st.subheader("Selected Chunk Previews")229 for i, preview in enumerate(selected_chunk_previews, start=1):230 st.markdown(f"**Chunk {i}**")231 st.code(preview)232 233 with st.expander("Raw metadata"):234 st.json(result.metadata)235else:236 st.info("Run an analysis to see results here.")