| import requests |
| import streamlit as st |
| import textwrap |
|
|
| |
| |
| |
|
|
| st.set_page_config( |
| page_title="CodeSight AI", |
| page_icon="", |
| layout="wide", |
| ) |
|
|
| |
| |
| |
| st.markdown( |
| textwrap.dedent( |
| """ |
| <style> |
| .main { |
| background-color: #0E1117; |
| } |
| |
| .hero { |
| padding: 1.5rem 0rem; |
| } |
| |
| .hero-title { |
| font-size: 3rem; |
| font-weight: 800; |
| color: white; |
| margin-bottom: 0; |
| } |
| |
| .gradient-text { |
| background: linear-gradient(90deg, #00C6FF, #7B61FF); |
| -webkit-background-clip: text; |
| -webkit-text-fill-color: transparent; |
| } |
| .hero-subtitle { |
| font-size: 1.15rem; |
| color: #B0B3B8; |
| margin-top: 0; |
| line-height: 1.8; |
| margin-bottom: 30px; |
| } |
| |
| .highlight-blue { |
| color: #00C6FF; |
| font-weight: 700; |
| } |
| |
| .highlight-purple { |
| color: #7B61FF; |
| font-weight: 700; |
| } |
| |
| |
| .card { |
| background-color: #161B22; |
| border-radius: 20px; |
| padding: 20px; |
| border: 1px solid rgba(255,255,255,0.08); |
| box-shadow: 0px 4px 15px rgba(0,0,0,0.3); |
| } |
| |
| .source-card { |
| background-color: #1E2530; |
| border-radius: 12px; |
| padding: 12px; |
| margin-bottom: 10px; |
| border-left: 4px solid #7B61FF; |
| } |
| |
| .success-box { |
| background-color: rgba(0,200,100,0.1); |
| padding: 12px; |
| border-radius: 12px; |
| } |
| |
| .footer { |
| text-align: center; |
| color: gray; |
| padding-top: 30px; |
| font-size: 14px; |
| } |
| </style> |
| """ |
| ).lstrip("\n"), |
| unsafe_allow_html=True, |
| ) |
|
|
| |
| |
| |
| with st.sidebar: |
| st.markdown("## CodeSight AI") |
| st.caption("AI-Powered Codebase Intelligence") |
|
|
| API_URL = st.text_input( |
| "Backend URL", |
| "http://127.0.0.1:8000/api" |
| ) |
|
|
| st.markdown("---") |
|
|
| st.markdown("### π Features") |
| st.markdown(""" |
| - Hybrid Retrieval (BM25 + Vector) |
| - Graph RAG with NetworkX |
| - GitHub Repository Understanding |
| - Codebase Question Answering |
| - Dependency Tracing |
| """) |
|
|
| |
| |
| |
| if "repo_id" not in st.session_state: |
| st.session_state.repo_id = "" |
|
|
|
|
| |
| |
| |
| def show_api_error(response: requests.Response) -> None: |
| try: |
| detail = response.json().get( |
| "detail", |
| response.text |
| ) |
| except ValueError: |
| detail = response.text |
|
|
| st.error( |
| f"β API request failed " |
| f"({response.status_code}): {detail}" |
| ) |
|
|
| |
| |
| |
|
|
| |
| |
| |
|
|
| st.markdown( |
| textwrap.dedent( |
| """ |
| <div class="hero"> |
| <h1 class="hero-title"> |
| <span class="gradient-text"> |
| CodeSight AI |
| </span> |
| </h1> |
| |
| |
| </div> |
| """ |
| ).lstrip("\n"), |
| unsafe_allow_html=True, |
| ) |
|
|
| st.text("Chat with any codebase using Graph RAG,Hybrid Retrieval and AI-powered repository reasoning.") |
|
|
| |
| |
| |
| |
| tab_local, tab_github, tab_ask = st.tabs( |
| [ |
| "π Local Repository", |
| "π GitHub Repository", |
| "π¬ Ask Questions" |
| ] |
| ) |
|
|
| |
| |
| |
| with tab_local: |
|
|
| st.markdown("### π Index Local Repository") |
|
|
| path = st.text_input( |
| "Repository Path", |
| placeholder=r"G:\Code Base RAG" |
| ) |
|
|
| if st.button( |
| "π Index Repository", |
| type="primary" |
| ) and path: |
|
|
| with st.spinner( |
| "Indexing repository..." |
| ): |
|
|
| response = requests.post( |
| f"{API_URL}/repos/local", |
| json={"path": path}, |
| timeout=120 |
| ) |
|
|
| if response.ok: |
|
|
| summary = response.json() |
|
|
| st.session_state.repo_id = ( |
| summary["repo_id"] |
| ) |
|
|
| st.success( |
| f"β
Indexed " |
| f"{summary['files_indexed']} " |
| f"files into " |
| f"{summary['chunks_indexed']} chunks" |
| ) |
|
|
| st.json(summary) |
|
|
| else: |
| show_api_error(response) |
|
|
| |
| |
| |
| with tab_github: |
|
|
| st.markdown( |
| "### π Clone & Index GitHub Repository" |
| ) |
|
|
| url = st.text_input( |
| "GitHub URL", |
| placeholder=( |
| "https://github.com/" |
| "user/project" |
| ) |
| ) |
|
|
| if st.button( |
| "π Clone & Index", |
| type="primary" |
| ) and url: |
|
|
| with st.spinner( |
| "Cloning and indexing..." |
| ): |
|
|
| response = requests.post( |
| f"{API_URL}/repos/github", |
| json={"url": url}, |
| timeout=240 |
| ) |
|
|
| if response.ok: |
|
|
| summary = response.json() |
|
|
| st.session_state.repo_id = ( |
| summary["repo_id"] |
| ) |
|
|
| st.success( |
| f"β
Indexed " |
| f"{summary['name']}" |
| ) |
|
|
| st.json(summary) |
|
|
| else: |
| show_api_error(response) |
|
|
| |
| |
| |
| with tab_ask: |
|
|
| st.markdown( |
| "### π¬ Ask Questions About Your Codebase" |
| ) |
|
|
| repo_id = st.text_input( |
| "Repository ID", |
| value=st.session_state.repo_id |
| ) |
|
|
| question = st.text_area( |
| "Ask a Question", |
| placeholder=( |
| "Explain the authentication " |
| "flow." |
| ) |
| ) |
|
|
| top_k = st.slider( |
| "Retrieved Sources", |
| 3, |
| 12, |
| 8 |
| ) |
|
|
| if st.button( |
| "π§ Ask CodeSight", |
| type="primary" |
| ) and repo_id and question: |
|
|
| with st.spinner( |
| "Thinking..." |
| ): |
|
|
| response = requests.post( |
| f"{API_URL}/repos/" |
| f"{repo_id}/query", |
| json={ |
| "question": question, |
| "top_k": top_k |
| }, |
| timeout=120, |
| ) |
|
|
| if response.ok: |
|
|
| result = response.json() |
|
|
| st.markdown( |
| "## π§ Answer" |
| ) |
|
|
| st.info( |
| result["answer"] |
| ) |
|
|
| st.markdown( |
| "## π Source Citations" |
| ) |
|
|
| for source in ( |
| result["sources"] |
| ): |
|
|
| st.markdown( |
| textwrap.dedent( |
| f""" |
| <div class="source-card"> |
| <b>π File:</b> |
| {source['path']}<br> |
| |
| <b>π Lines:</b> |
| {source['start_line']} |
| - |
| {source['end_line']}<br> |
| |
| <b>π§© Type:</b> |
| {source['kind']}<br> |
| |
| <b>π Symbol:</b> |
| {source['symbol']}<br> |
| |
| <b>β Score:</b> |
| {round(source['score'], 3)} |
| </div> |
| """ |
| ).lstrip("\n"), |
| unsafe_allow_html=True, |
| ) |
|
|
| else: |
| show_api_error(response) |
|
|
| |
| |
| |
| st.markdown( |
| textwrap.dedent( |
| """ |
| <div class="footer"> |
| Built using |
| FastAPI β’ Streamlit β’ Qdrant β’ |
| Graph RAG β’ Gemini |
| </div> |
| """ |
| ).lstrip("\n"), |
| unsafe_allow_html=True, |
| ) |
|
|
|
|