""" THISverse AI - Developer Productivity Agent Modern UI with enhanced visual design """ import streamlit as st import json from pathlib import Path import sys import plotly.express as px import plotly.graph_objects as go from datetime import datetime sys.path.append(str(Path(__file__).parent)) from main import DevProductivityAgent, JiraTicket, Config, cost_tracker # ============================================================================ # Page Config # ============================================================================ st.set_page_config( page_title="THISverse AI - Code Assistant", page_icon="🚀", layout="wide", initial_sidebar_state="expanded" ) # ============================================================================ # Enhanced CSS with Modern Design # ============================================================================ st.markdown(""" """, unsafe_allow_html=True) # ============================================================================ # Session State # ============================================================================ if "agent" not in st.session_state: st.session_state.agent = DevProductivityAgent() if "messages" not in st.session_state: st.session_state.messages = [] if "current_plan" not in st.session_state: st.session_state.current_plan = None if "indexed" not in st.session_state: st.session_state.indexed = False if "auto_indexed" not in st.session_state: st.session_state.auto_indexed = False # ============================================================================ # Sidebar # ============================================================================ with st.sidebar: # Modern Brand Header st.markdown("""
THISverse AI
Code Intelligence Platform
""", unsafe_allow_html=True) st.markdown("---") # Configuration Section st.markdown("### âš™ī¸ Configuration") with st.expander("â„šī¸ System Info", expanded=False): st.markdown("""
đŸ—„ī¸ Vector Database: Pinecone
🤖 AI Model: GPT-4o-mini
📊 Architecture: Divided LLM
💾 Embedding: text-embedding-3-small
""", unsafe_allow_html=True) st.markdown("---") # API Keys Section st.markdown("### 🔑 API Configuration") openai_key = st.text_input( "OpenAI API Key", type="password", value=st.session_state.get("openai_key", ""), help="Your OpenAI API key for LLM and embeddings" ) pinecone_key = st.text_input( "Pinecone API Key", type="password", value=st.session_state.get("pinecone_key", ""), help="Your Pinecone API key for vector storage" ) if openai_key and pinecone_key: st.session_state.openai_key = openai_key st.session_state.pinecone_key = pinecone_key st.session_state.agent.set_api_keys(openai_key, pinecone_key) # Auto-index on first load if not st.session_state.get("auto_indexed", False): app_dir = Path(__file__).parent sample_codebase_path = str(app_dir / "sample_codebase") if Path(sample_codebase_path).exists(): try: with st.spinner("🔄 Indexing codebase..."): results = st.session_state.agent.index_codebase( sample_codebase_path, extensions=[".py", ".js", ".ts", ".jsx", ".tsx"] ) st.session_state.auto_indexed = True st.session_state.indexed = True st.success(f"✅ Indexed: {results['files_indexed']} files, {results['total_chunks']} chunks") except Exception as e: st.warning(f"âš ī¸ Indexing failed: {str(e)[:100]}") else: st.markdown('✅ API Keys Configured', unsafe_allow_html=True) else: st.markdown('✅ API Keys Active', unsafe_allow_html=True) else: st.markdown('âš ī¸ API Keys Required', unsafe_allow_html=True) st.markdown("---") # Codebase Status st.markdown("### 📂 Codebase Status") try: stats = st.session_state.agent.indexer.get_stats() total_chunks = stats.get('total_chunks', 0) if total_chunks > 0: st.markdown(f"""
✅ Codebase Indexed
{total_chunks:,} chunks ready
""", unsafe_allow_html=True) st.session_state.indexed = True else: st.markdown("""
â„šī¸ Ready to Index
Set API keys to auto-index
""", unsafe_allow_html=True) except: st.markdown("""
â„šī¸ Awaiting Configuration
Configure API keys above
""", unsafe_allow_html=True) st.markdown("---") # Quick Actions st.markdown("### ⚡ Quick Actions") col1, col2 = st.columns(2) with col1: if st.button("🔄 Refresh", use_container_width=True): st.rerun() with col2: if st.button("đŸ—‘ī¸ Clear Chat", use_container_width=True): st.session_state.messages = [] st.rerun() # ============================================================================ # Main Content # ============================================================================ # Hero Section st.markdown("""

🚀 AI-Powered Code Assistant

Analyze tickets, generate code, and understand your codebase with AI

""", unsafe_allow_html=True) # Tabs tab1, tab2, tab3, tab4 = st.tabs([ "đŸ’Ŧ Chat Assistant", "đŸŽĢ Ticket Processing", "📋 Implementation Plan", "📊 Cost Analytics" ]) # ============================================================================ # Tab 1: Chat Assistant # ============================================================================ with tab1: st.markdown("### đŸ’Ŧ Ask Questions About Your Code") # Check indexing status if not st.session_state.get("indexed", False): try: stats = st.session_state.agent.indexer.get_stats() if stats.get('total_chunks', 0) > 0: st.session_state.indexed = True except: pass if not st.session_state.get("indexed", False): st.markdown("""
âš ī¸ Codebase Not Indexed
Please configure your API keys in the sidebar to automatically index the codebase.
""", unsafe_allow_html=True) else: st.markdown("""
✅ Ready to Answer
Your codebase is indexed and ready for questions!
""", unsafe_allow_html=True) # Display chat history for msg in st.session_state.messages: cls = "user-message" if msg["role"] == "user" else "assistant-message" icon = "👤" if msg["role"] == "user" else "🤖" st.markdown( f'
{icon} {msg["content"]}
', unsafe_allow_html=True ) # Chat input st.markdown("---") with st.form("chat_form", clear_on_submit=True): prompt = st.text_input( "💭 Your Question", placeholder="e.g., How does user authentication work in this codebase?", key="chat_input" ) col1, col2 = st.columns([3, 1]) with col2: submit = st.form_submit_button("🚀 Send", type="primary", use_container_width=True) if submit and prompt: if not (st.session_state.get("openai_key") and st.session_state.get("pinecone_key")): st.error("🔑 Please configure API keys in the sidebar") elif not st.session_state.get("indexed", False): st.warning("âš ī¸ Please wait for codebase indexing to complete") else: st.session_state.messages.append({"role": "user", "content": prompt}) with st.spinner("🤔 Thinking..."): try: response = st.session_state.agent.ask_about_code(prompt) st.session_state.messages.append({"role": "assistant", "content": response}) st.rerun() except Exception as e: st.error(f"❌ Error: {str(e)}") st.session_state.messages.append({"role": "assistant", "content": f"❌ Error: {str(e)}"}) st.rerun() # ============================================================================ # Tab 2: Ticket Processing # ============================================================================ with tab2: st.markdown("### đŸŽĢ JIRA Ticket to Implementation") col1, col2 = st.columns([2, 1]) with col1: st.markdown("#### Ticket Details") ticket_id = st.text_input("📋 Ticket ID", placeholder="PROJ-123") ticket_title = st.text_input("📝 Title", placeholder="Add user preferences feature") ticket_desc = st.text_area( "📄 Description", height=150, placeholder="Detailed description of the feature..." ) acceptance = st.text_area( "✅ Acceptance Criteria", height=100, placeholder="List the acceptance criteria..." ) labels = st.text_input("đŸˇī¸ Labels", placeholder="backend, frontend (comma-separated)") with col2: st.markdown("#### Quick Actions") if st.button("📝 Load Example", use_container_width=True): st.session_state.example = { "id": "PROJ-456", "title": "Add notification preferences", "desc": "As a user, I want to customize my notification settings.\n\nFeatures:\n- Email notification toggle\n- Push notification toggle\n- Notification frequency settings\n- Save preferences to database", "accept": "- User can toggle email notifications\n- User can toggle push notifications\n- Settings persist across sessions\n- Changes take effect immediately", "labels": "backend, frontend, notifications" } st.rerun() if "example" in st.session_state: ticket_id = st.session_state.example["id"] ticket_title = st.session_state.example["title"] ticket_desc = st.session_state.example["desc"] acceptance = st.session_state.example["accept"] labels = st.session_state.example["labels"] del st.session_state.example st.markdown("---") st.markdown("""
💡 Tip
Provide detailed descriptions for better code generation
""", unsafe_allow_html=True) st.markdown("---") if st.button("🚀 Generate Implementation Plan", type="primary", use_container_width=True): if not (st.session_state.get("openai_key") and st.session_state.get("pinecone_key")): st.error("🔑 Please configure API keys first") elif not ticket_title or not ticket_desc: st.error("📝 Please provide at least a title and description") else: ticket = JiraTicket( ticket_id=ticket_id or "UNKNOWN", title=ticket_title, description=ticket_desc, acceptance_criteria=acceptance or None, labels=[l.strip() for l in labels.split(",")] if labels else None ) with st.spinner("âš™ī¸ Generating implementation plan..."): try: plan = st.session_state.agent.process_ticket(ticket) st.session_state.current_plan = plan st.session_state.last_ticket = ticket st.success("✅ Plan generated! Check the 'Implementation Plan' tab") st.balloons() except Exception as e: st.error(f"❌ Error: {str(e)}") # ============================================================================ # Tab 3: Implementation Plan # ============================================================================ with tab3: if st.session_state.current_plan: plan = st.session_state.current_plan # Summary Section st.markdown("### 📋 Implementation Summary") st.markdown(f"""
{plan.ticket_summary}
""", unsafe_allow_html=True) # Metrics col1, col2, col3 = st.columns(3) with col1: st.markdown(f"""
{plan.estimated_complexity}
Complexity
""", unsafe_allow_html=True) with col2: st.markdown(f"""
{len(plan.key_entities)}
Key Entities
""", unsafe_allow_html=True) with col3: st.markdown(f"""
{len(plan.relevant_files)}
Related Files
""", unsafe_allow_html=True) st.markdown("---") # Details col1, col2 = st.columns(2) with col1: st.markdown("### đŸˇī¸ Key Entities") for e in plan.key_entities: st.markdown(f'{e}', unsafe_allow_html=True) st.markdown("### âš ī¸ Prerequisites") if plan.prerequisites: for p in plan.prerequisites: st.markdown(f"- {p}") else: st.info("No prerequisites identified") with col2: st.markdown("### 📝 Implementation Steps") for i, s in enumerate(plan.implementation_steps, 1): st.markdown(f"**{i}.** {s}") st.markdown("---") # Architecture st.markdown("### đŸ—ī¸ Architecture Notes") st.markdown(f"""
{plan.architecture_notes}
""", unsafe_allow_html=True) st.markdown("---") # Generated Code st.markdown("### đŸ’ģ Generated Code") for path, code in plan.boilerplate_code.items(): with st.expander(f"📄 {path}", expanded=True): lang = { '.py': 'python', '.js': 'javascript', '.ts': 'typescript', '.jsx': 'javascript', '.tsx': 'typescript' }.get(Path(path).suffix, 'text') st.code(code, language=lang) col1, col2 = st.columns([1, 3]) with col1: st.download_button( "âŦ‡ī¸ Download", code, Path(path).name, key=f"download_{path}" ) st.markdown("---") # Modification Section st.markdown("### âœī¸ Request Modifications") st.markdown("""
💡 Need Changes?
Describe modifications and we'll regenerate the code
""", unsafe_allow_html=True) modification_request = st.text_area( "What would you like to change?", placeholder="e.g., Add error handling, use async/await, add unit tests...", height=100, key="modification_request" ) if st.button("🔄 Regenerate with Modifications", type="primary", use_container_width=True): if not modification_request.strip(): st.warning("âš ī¸ Please describe the modifications") else: with st.spinner("âš™ī¸ Regenerating code..."): try: original_ticket = st.session_state.get("last_ticket") if original_ticket: modified_description = f"{original_ticket.description}\n\n---\n\n**Modification Request:**\n{modification_request}" modified_ticket = JiraTicket( ticket_id=original_ticket.ticket_id, title=original_ticket.title, description=modified_description, acceptance_criteria=original_ticket.acceptance_criteria, labels=original_ticket.labels ) new_plan = st.session_state.agent.process_ticket(modified_ticket) st.session_state.current_plan = new_plan st.success("✅ Code regenerated!") st.rerun() else: st.error("Original ticket not found") except Exception as e: st.error(f"❌ Error: {str(e)}") else: st.markdown("""

📋 No Plan Generated Yet

Process a ticket in the "Ticket Processing" tab to see the implementation plan here

""", unsafe_allow_html=True) # ============================================================================ # Tab 4: Cost Analytics # ============================================================================ with tab4: st.markdown("### 📊 Cost Analytics Dashboard") stats = st.session_state.agent.get_cost_stats() # Top Metrics col1, col2, col3, col4 = st.columns(4) with col1: st.markdown(f"""
${stats['savings']:.4f}
💰 Total Savings
""", unsafe_allow_html=True) with col2: st.markdown(f"""
${stats['actual_cost']:.4f}
📉 Actual Cost
""", unsafe_allow_html=True) with col3: st.markdown(f"""
{stats['savings_percentage']:.1f}%
📊 Cost Reduction
""", unsafe_allow_html=True) with col4: st.markdown(f"""
{stats['api_calls']}
🔄 API Calls
""", unsafe_allow_html=True) st.markdown("---") # Charts col1, col2 = st.columns(2) with col1: st.markdown("### đŸ’ĩ Cost Comparison") fig = go.Figure(data=[ go.Bar( name='Traditional (GPT-4)', x=['Cost'], y=[stats['traditional_cost']], marker_color='#f5576c', text=[f"${stats['traditional_cost']:.4f}"], textposition='auto' ), go.Bar( name='Our Approach', x=['Cost'], y=[stats['actual_cost']], marker_color='#38ef7d', text=[f"${stats['actual_cost']:.4f}"], textposition='auto' ) ]) fig.update_layout( barmode='group', height=350, margin=dict(l=20, r=20, t=20, b=20), showlegend=True ) st.plotly_chart(fig, use_container_width=True) with col2: st.markdown("### 📈 Token Distribution") tokens = stats['total_tokens'] fig = go.Figure(data=[go.Pie( labels=['Embeddings', 'Architect In', 'Architect Out', 'Developer In', 'Developer Out'], values=[ tokens['embedding'], tokens['architect_input'], tokens['architect_output'], tokens['developer_input'], tokens['developer_output'] ], hole=0.4, marker_colors=['#667eea', '#764ba2', '#f093fb', '#11998e', '#38ef7d'] )]) fig.update_layout(height=350, margin=dict(l=20, r=20, t=20, b=20)) st.plotly_chart(fig, use_container_width=True) st.markdown("---") # Detailed Stats col1, col2, col3 = st.columns(3) with col1: st.markdown("### 📊 Session Stats") st.metric("Tickets Processed", stats['tickets_processed']) st.metric("Questions Answered", stats['questions_answered']) st.metric("Session Duration", f"{stats['session_duration_minutes']} min") with col2: st.markdown("### 💰 Per-Action Costs") st.metric("Cost per Ticket", f"${stats['cost_per_ticket']:.4f}") if stats['tickets_processed'] > 0: trad = stats['traditional_cost'] / stats['tickets_processed'] st.metric("Traditional Cost", f"${trad:.4f}") st.metric("Savings per Ticket", f"${trad - stats['cost_per_ticket']:.4f}") with col3: st.markdown("### đŸ”ĸ Token Breakdown") st.write(f"**Embedding:** {tokens['embedding']:,}") st.write(f"**Architect:** {tokens['architect_input']:,} / {tokens['architect_output']:,}") st.write(f"**Developer:** {tokens['developer_input']:,} / {tokens['developer_output']:,}") st.write(f"**Total:** {tokens['total']:,}") st.markdown("---") # Architecture Comparison st.markdown("### đŸ—ī¸ Architecture Comparison") col1, col2 = st.columns(2) with col1: st.markdown("""

Traditional Approach

""", unsafe_allow_html=True) with col2: st.markdown("""

Our Divided Approach

""", unsafe_allow_html=True) st.markdown("---") # Reset Button col1, col2, col3 = st.columns([1, 1, 1]) with col2: if st.button("🔄 Reset Cost Tracking", use_container_width=True): st.session_state.agent.reset_cost_tracking() st.rerun() # ============================================================================ # Footer # ============================================================================ st.markdown("---") st.markdown("""
THISverse AI - Developer Productivity Agent v2.0
Powered by GPT-4o-mini, Pinecone, and Divided LLM Architecture
""", unsafe_allow_html=True)