this is my app.py
import os
import tempfile
import streamlit as st
import streamlit.components.v1 as components
from git import Repo, GitCommandError

from agents import (
FilterAgent,
AnalysisAgent,
ConsolidationAgent,
ImprovementAgent,
DiagramAgent,
)
from file_handling.file_handler import FileHandler
from utils.azure_client import get_azure_client
import json
from diagram_renderer import render_architecture_diagram # New component

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")

Remove render_mermaid function and replace with:
def render_architecture_diagram(diagram_data):
"""Render architecture diagram using custom icons and connections"""
if not diagram_data:
st.warning("No diagram data generated")
return


try:
    # Parse the structured diagram data
    diagram_json = json.loads(diagram_data)
    render_architecture_diagram(diagram_json)
except json.JSONDecodeError:
    st.error("Invalid diagram format. Expected JSON structure")
    st.text_area("Raw Diagram Data", diagram_data, height=200)
In run_analysis() function:
Replace the cloud architecture diagram section with:
def render_mermaid(mermaid_code, height=600):
# Remove markdown code fences if present
mermaid_code = mermaid_code.strip()
if mermaid_code.startswith("```mermaid"):
lines = mermaid_code.splitlines()
mermaid_code = "\n".join(lines[1:-1]).strip()


# Debug: show raw code
st.text_area("Raw Mermaid code for debugging", mermaid_code, height=200)

mermaid_html = f"""
<div class="mermaid">
{mermaid_code}
</div>

<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<script>
  mermaid.initialize({{ startOnLoad: true }});
</script>
"""

components.html(mermaid_html, height=height)
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", "Cloud Architecture Diagram"])

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"))
diagram_agent = DiagramAgent(client, deployment_name, os.path.join(BASE_PROMPT_DIR, "diagram_agent_prompt.txt"))

with tempfile.TemporaryDirectory() as tmp_dir:
    try:
        with st.spinner("🌀 Cloning repository..."):
            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")

        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
        if analysis_mode == "Technical Blueprint":
            st.subheader("📄 Architectural Analysis Report")
            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)}`")
        elif analysis_mode == "Improvement Plan":
            st.subheader("⚙️ Improvement Plan")
            with st.spinner("Generating improvement plan..."):
                improvements = improvement_agent.generate_improvements(consolidated_summary)
            st.markdown(improvements)


        elif analysis_mode == "Cloud Architecture Diagram":
            st.subheader("🌥️ Cloud Architecture Diagram")
            with st.spinner("Generating cloud architecture description and diagram..."):
                architecture_description, diagram_data = diagram_agent.generate_architecture_description(
                    consolidated_summary
                )

            st.markdown(architecture_description)

            if diagram_data:
                render_architecture_diagram(diagram_data)
            else:
                st.warning("No cloud architecture diagram generated.")    
    

        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 is daigram_render.py
import streamlit as st

Icon mapping - add more as needed
ICON_MAP = {
"user": "👤",
"azure-bot-services": "🤖",
"azure-openai": "🧠",
"workflow": "⚙️",
"search": "🔍",
"azure-cognitive-search": "🔎",
"azure-logic-apps": "📱",
"ticket": "🎫",
"mail": "✉️",
"bar-chart-2": "📊",
"users": "👥",
"database": "💾",
"cloud": "☁️",
"server": "🖥️",
"api": "🌐",
"storage": "📦",
"default": "⬛"
}

def render_architecture_diagram(diagram_data):
"""Render custom architecture diagram with icons and connections"""
if not diagram_data:
st.warning("No diagram data to render")
return


# Display title if exists
if "title" in diagram_data:
    st.markdown(f"### {diagram_data['title']}")

# Create columns for layout
col1, col2 = st.columns([1, 3])

# Create component lookup
components_by_id = {comp["id"]: comp for comp in diagram_data.get("components", [])}

with col1:
    st.markdown("**Components**")
    for comp in diagram_data.get("components", []):
        icon = ICON_MAP.get(comp.get("icon"), ICON_MAP["default"])
        st.markdown(f"{icon} **{comp['label']}**")

with col2:
    st.markdown("**Connections**")
    for connection in diagram_data.get("connections", []):
        source = components_by_id.get(connection["source"])
        target = components_by_id.get(connection["target"])
        
        if source and target:
            source_icon = ICON_MAP.get(source.get("icon"), ICON_MAP["default"])
            target_icon = ICON_MAP.get(target.get("icon"), ICON_MAP["default"])
            
            conn_text = f"{source_icon} **{source['label']}** → {target_icon} **{target['label']}**"
            if connection.get("label"):
                conn_text += f": *{connection['label']}*"
                
            st.markdown(conn_text)

# Visual diagram representation
st.markdown("---")
st.markdown("### Visual Representation")

# Generate HTML representation
diagram_html = "<div style='line-height: 2.5; font-size: 24px; padding: 20px;'>"

# Add components in a grid layout
diagram_html += "<div style='display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px;'>"
for comp in diagram_data.get("components", []):
    icon = ICON_MAP.get(comp.get("icon"), ICON_MAP["default"])
    diagram_html += f"""
    <div id="{comp['id']}" style="padding: 15px; border: 1px solid #ddd; 
              border-radius: 8px; text-align: center; background-color: #f9f9f9;">
        <div style="font-size: 32px;">{icon}</div>
        <div style="font-weight: bold; margin-top: 10px;">{comp['label']}</div>
    </div>
    """
diagram_html += "</div>"

# Add connections as arrows
diagram_html += "<div style='position: relative; height: 100px; margin: 40px 0;'>"
for i, connection in enumerate(diagram_data.get("connections", [])):
    diagram_html += f"""
    <div style="position: absolute; left: 20%; top: {20 + i*60}px; 
              width: 60%; display: flex; align-items: center;">
        <div style="border-top: 2px dashed #666; width: 100%;"></div>
        <div style="background: white; padding: 0 10px; font-size: 16px;">
            {connection.get('label', '')}
        </div>
    </div>
    """
diagram_html += "</div></div>"

st.markdown(diagram_html, unsafe_allow_html=True)
this is file handler
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 is daigram agent.py
import streamlit as st
import json
from datetime import datetime
from pathlib import Path

class DiagramAgent:
def init(self, client, deployment, prompt_path):
self.client = client
self.deployment = deployment
self.activity_log = []
self.prompt = Path(prompt_path).read_text()


def log_activity(self, action):
    timestamp = datetime.now().strftime("%H:%M:%S")
    log_entry = f"{timestamp} | {'Diagram Agent'.ljust(15)} | {action.ljust(25)}"
    self.activity_log.append(log_entry)

def generate_architecture_description(self, consolidated_summary):
    self.log_activity("Generating architecture description")
    try:
        response = self.client.chat.completions.create(
            model=self.deployment,
            messages=[
                {
                    "role": "system", 
                    "content": self.prompt
                },
                {
                    "role": "user", 
                    "content": (
                        f"Project Summary:\n{consolidated_summary}\n\n"
                        "Generate a structured JSON representation of the cloud architecture with "
                        "components and connections. Use ONLY the specified JSON format."
                    )
                }
            ],
            temperature=0.1,
            max_tokens=2000,
            response_format={"type": "json_object"}
        )
    except Exception as e:
        st.error(f"DiagramAgent API call failed: {e}")
        return "", None  # Return None for diagram data

    content = response.choices[0].message.content
    
    try:
        # The response should be pure JSON due to response_format
        diagram_data = json.loads(content)
        
        # Extract description if exists
        description = diagram_data.get("description", "")
        if description:
            description = "## Architecture Description\n" + description
            
        return description, diagram_data
    except json.JSONDecodeError as e:
        st.error(f"Failed to parse diagram data: {e}")
        st.text_area("Raw Response", content, height=300)
        return content, None
this is daigram prompt
You are an expert in cloud architecture and diagramming. Based on the provided project summary, create:

A clear, concise description of the cloud architecture flow and major components
A structured JSON representation of the architecture with components and connections
Output MUST follow this exact JSON format:

{
"title": "Architecture Title",
"description": "Detailed architecture description...",
"components": [
{
"id": "unique_id_1",
"label": "Component Name",
"icon": "icon_key"
},
// More components...
],
"connections": [
{
"source": "source_component_id",
"target": "target_component_id",
"label": "Connection description"
},
// More connections...
]
}

Guidelines:

Use ONLY valid JSON format
For icons, use these keys: user, azure-bot-services, azure-openai, workflow,
search, azure-cognitive-search, azure-logic-apps, ticket, mail, bar-chart-2,
users, database, cloud, server, api, storage
Components should represent key services/nodes in the architecture
Connections should show relationships with clear labels
Include ALL critical components and connections
Make the title descriptive and concise
getting this error right now
Analysis error: the JSON object must be str, bytes or bytearray, not dict

can you correct my code give me proper one ALSO REMOVE THE MERMID THING