"""
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
- Single GPT-4 model
- $30/1M input tokens
- $60/1M output tokens
- ~15,000 tokens/ticket
- ~$0.45 per ticket
""", unsafe_allow_html=True)
with col2:
st.markdown("""
Our Divided Approach
- Two GPT-4o-mini models
- $0.15/1M input tokens
- $0.60/1M output tokens
- ~9,000 tokens/ticket
- ~$0.0023 per ticket
""", 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)