thimport os
import tempfile
import streamlit as st
from git import Repo, GitCommandError

from agents import (
    FilterAgent,
    AnalysisAgent,
    ConsolidationAgent,
    ImprovementAgent,
)
from file_handling.file_handler import FileHandler
from utils.azure_client import get_azure_client

from dotenv import load_dotenv
load_dotenv()

BASE_PROMPT_DIR = os.path.join(os.path.dirname(__file__), "agents", "prompts")

st.set_page_config(page_title="Project Architecture Analyzer", layout="wide")


def main():
    st.title("🔍 Project Architecture Analyzer")

    repo_url = st.text_input("GitHub Repository URL")

    # Sidebar for credentials & settings
    st.sidebar.header("Configuration")
    pat = st.sidebar.text_input("GitHub Personal Access Token", type="password")
    azure_endpoint = st.sidebar.text_input(
        "Azure OpenAI Endpoint",
        value=os.environ.get("AZURE_OPENAI_ENDPOINT", ""),
    )
    api_key = st.sidebar.text_input(
        "Azure OpenAI API Key",
        type="password",
        value=os.environ.get("AZURE_OPENAI_API_KEY", ""),
    )
    deployment_name = st.sidebar.text_input(
        "Deployment Name",
        value=os.environ.get("AZURE_OPENAI_DEPLOYMENT_NAME", ""),
    )
    analysis_mode = st.sidebar.selectbox("Analysis Mode", ["Technical Blueprint", "Improvement Plan"])

    if st.button("Analyze Project"):
        if not all([repo_url, pat, azure_endpoint, api_key, deployment_name]):
            st.error("Please fill in all configuration fields.")
        else:
            run_analysis(repo_url, pat, azure_endpoint, api_key, deployment_name, analysis_mode)


def run_analysis(repo_url, pat, azure_endpoint, api_key, deployment_name, analysis_mode):
    try:
        client = get_azure_client(azure_endpoint, api_key)
    except Exception as e:
        st.error(f"Azure OpenAI client initialization failed: {e}")
        return

    filter_agent = FilterAgent(client, deployment_name, os.path.join(BASE_PROMPT_DIR, "filter_agent_prompt.txt"))
    analysis_agent = AnalysisAgent(client, deployment_name, os.path.join(BASE_PROMPT_DIR, "analysis_agent_prompt.txt"))
    consolidation_agent = ConsolidationAgent(client, deployment_name, os.path.join(BASE_PROMPT_DIR, "consolidation_agent_prompt.txt"))
    improvement_agent = ImprovementAgent(client, deployment_name, os.path.join(BASE_PROMPT_DIR, "improvement_agent_prompt.txt"))

    with tempfile.TemporaryDirectory() as tmp_dir:
        try:
            with st.spinner("🌀 Cloning repository..."):
                # Use PAT if provided for HTTPS authentication
                if pat:
                    if not repo_url.startswith("https://"):
                        st.error("PAT can only be used with HTTPS URLs")
                        return
                    auth_repo_url = repo_url.replace("https://", f"https://{pat}@", 1)
                else:
                    auth_repo_url = repo_url

                Repo.clone_from(auth_repo_url, tmp_dir)
            st.success("Repository cloned successfully")

            # Loader while FileHandler scans files and Analysis Overview data is prepared
            with st.spinner("🔍 Loading analysis overview..."):
                file_handler = FileHandler(tmp_dir, filter_agent)

                st.subheader("📊 Analysis Overview")
                cols = st.columns(4)
                cols[0].metric("Total Files", file_handler.total_scanned)
                cols[1].metric("Included Files", len(file_handler.files))
                cols[2].metric("Excluded Files", len(file_handler.excluded_files))
                ratio = 0
                if file_handler.total_scanned > 0:
                    ratio = len(file_handler.files) / file_handler.total_scanned * 100
                cols[3].metric("Focus Ratio", f"{ratio:.1f}%")

            consolidated_summary = "## Project Architecture Blueprint\n"
            total_files = len(file_handler.files)

            progress_bar = st.progress(0)
            status_box = st.empty()

            for idx, file_path in enumerate(file_handler.files):
                content = file_handler.read_file_content(file_path)
                rel_path = os.path.relpath(file_path, tmp_dir)

                with st.spinner(f"Analyzing {rel_path}..."):
                    summary = analysis_agent.summarize_file(rel_path, content)
                    consolidated_summary = consolidation_agent.merge_summaries(consolidated_summary, summary)

                progress = (idx + 1) / total_files
                progress_bar.progress(progress)

                status_text = f"""
**Processing:** `{rel_path}`  
**Progress:** {idx + 1}/{total_files} ({progress * 100:.1f}%)  
**Summary Size:** {len(consolidated_summary) // 1024} KB
"""
                status_box.markdown(status_text)

            # Final Report Output
            st.subheader("📄 Architectural Analysis Report")
            if analysis_mode == "Technical Blueprint":
                tab1, tab2 = st.tabs(["Full Report", "Key Components"])
                with tab1:
                    st.markdown(consolidated_summary)
                with tab2:
                    st.markdown("### 🏗️ Architectural Pillars")
                    for file_path in file_handler.files[:10]:
                        st.markdown(f"- `{os.path.basename(file_path)}`")
            else:
                with st.spinner("Generating improvement plan..."):
                    improvements = improvement_agent.generate_improvements(consolidated_summary)
                st.markdown(improvements)

            with st.expander("🚫 Excluded Items"):
                st.markdown("#### Directories")
                for d in sorted(file_handler.excluded_dirs):
                    st.markdown(f"- `{d}`")
                st.markdown("#### Files")
                for f in sorted(file_handler.excluded_files):
                    st.markdown(f"- `{f}`")

        except GitCommandError as e:
            st.error(f"Cloning failed: {e}")
        except Exception as e:
            st.error(f"Analysis error: {e}")


if __name__ == "__main__":
    main()

this was app.py


import os
import tiktoken
import streamlit as st

class FileHandler:
    def __init__(self, repo_path: str, agent):
        self.repo_path = repo_path
        self.agent = agent
        self.files = []
        self.excluded_dirs = set()
        self.excluded_files = []
        self.total_scanned = 0
        self.encoder = tiktoken.get_encoding("cl100k_base")
        self._load_files()

    def _load_files(self):
        excluded_dir_names = {
            ".git", ".github", "node_modules", "venv", "dist", "build",
            "__pycache__", "bin", "obj", "packages", "lib", "libs",
            "third_party", "dependencies", ".idea", ".vscode", "coverage"
        }

        for root, dirs, files in os.walk(self.repo_path):
            original_dirs = set(dirs)
            dirs[:] = [d for d in dirs if d not in excluded_dir_names]

            for excluded_dir in (original_dirs - set(dirs)):
                excluded_path = os.path.join(root, excluded_dir)
                self.excluded_dirs.add(os.path.relpath(excluded_path, self.repo_path))

            for f in files:
                self.total_scanned += 1
                full_path = os.path.join(root, f)
                content = self.read_file_content(full_path)
                
                if not content:
                    self.excluded_files.append(os.path.relpath(full_path, self.repo_path))
                    continue
                
                try:
                    should_analyze = self.agent.should_analyze_file(
                        os.path.relpath(full_path, self.repo_path),
                        content[:2000]
                    )
                except Exception as e:
                    st.error(f"Error analyzing {full_path}: {e}")
                    should_analyze = False
                
                if should_analyze:
                    self.files.append(full_path)
                else:
                    self.excluded_files.append(os.path.relpath(full_path, self.repo_path))

    def read_file_content(self, file_path):
        try:
            with open(file_path, "r", encoding="utf-8") as f:
                return f.read()
        except UnicodeDecodeError:
            try:
                with open(file_path, "r", encoding="iso-8859-1") as f:
                    return f.read()
            except Exception:
                return None
        except Exception:
            return None

this was filehandeling.py

what is required when we removed the file with  excluded_dir_namesafter that if number of files present are more than 50 then do not sent to our agent FilterAgent directly show all the file properly on screen ask user to selct the number of file which they thought can go directly to other agents not FilterAgent and whne selected by user we can then send it to other agents, if less then 50 files comes we can send it to Filter agent 

give me full code for both