File size: 14,497 Bytes
4afc8ce a3af4f1 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce d61bc93 4afc8ce 09f5bfb 4afc8ce 6d11ec6 4afc8ce 892a464 4afc8ce 892a464 4afc8ce 892a464 4afc8ce 892a464 4afc8ce d61bc93 4afc8ce 9d5041f 4afc8ce 9d5041f 4afc8ce d61bc93 4afc8ce 9d5041f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 | """Gradio UI for Context Engineering Visualizer"""
import gradio as gr
from typing import List, Tuple
from .agent import ContextEngineeringAgent
from config.settings import Settings
from config import logger_ui, logger_app
class ContextVisualizerUI:
"""Gradio interface for the Context Engineering Visualizer"""
def __init__(self):
self.agent = None
logger_ui.info("ContextVisualizerUI initialized")
def initialize_agent(self) -> str:
"""Initialize the agent"""
logger_ui.info("Initializing agent from UI")
try:
self.agent = ContextEngineeringAgent()
logger_ui.info("Agent initialized successfully from UI")
return "Agent initialized successfully"
except Exception as e:
logger_ui.error(f"Error initializing agent: {str(e)}")
return f"Error initializing agent: {str(e)}"
def format_context_layers(self, visualizer) -> str:
"""Format context layers for display as stacked container visualization"""
if not visualizer.context_layers:
return "<div style='text-align: center; padding: 20px;'>No context layers available</div>"
total_tokens = sum(visualizer.token_counts.values())
logger_ui.debug(f"Formatting context layers: {len(visualizer.context_layers)} layers, {total_tokens} total tokens")
# Color palette for different layers
colors = [
"#4A90E2", # Blue - System Instructions
"#7B68EE", # Purple - Conversation History
"#50C878", # Green - Retrieved Knowledge
"#F39C12", # Orange - User Query
"#E74C3C" # Red - Available Tools
]
# Build HTML for stacked container
html = f"""
<div style="max-width: 800px; margin: 0 auto; font-family: 'Inter', sans-serif;">
<div style="text-align: center; margin-bottom: 20px;">
<h3 style="margin: 0; color: #2c3e50;">Context Window Structure</h3>
<p style="margin: 5px 0; color: #7f8c8d; font-size: 14px;">Total: {total_tokens} tokens</p>
</div>
<div style="border: 2px solid #34495e; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
"""
for i, layer in enumerate(visualizer.context_layers):
percentage = (layer["tokens"] / total_tokens * 100) if total_tokens > 0 else 0
color = colors[i % len(colors)]
# Create stacked section
html += f"""
<div style="background: linear-gradient(135deg, {color} 0%, {color}dd 100%);
padding: 15px 20px;
border-bottom: 1px solid rgba(255,255,255,0.1);
position: relative;
height: {max(percentage * 3, 30)}px;
display: flex;
align-items: center;
transition: all 0.3s ease;">
<div style="flex: 1;">
<div style="color: white; font-weight: 600; font-size: 14px; margin-bottom: 3px;">
{layer['layer'].upper()}
</div>
<div style="color: rgba(255,255,255,0.9); font-size: 12px;">
{layer['tokens']} tokens ({percentage:.1f}%)
</div>
</div>
<div style="color: rgba(255,255,255,0.8); font-size: 24px; font-weight: bold;">
{percentage:.0f}%
</div>
</div>
"""
html += """
</div>
</div>
"""
return html
def format_context_details(self, visualizer) -> str:
"""Format detailed context layer contents for markdown display"""
if not visualizer.context_layers:
return "No context layers available"
output = []
total_tokens = sum(visualizer.token_counts.values())
for i, layer in enumerate(visualizer.context_layers, 1):
percentage = (layer["tokens"] / total_tokens * 100) if total_tokens > 0 else 0
output.append(f"### {i}. {layer['layer'].upper()}")
output.append(f"**Tokens:** {layer['tokens']} ({percentage:.1f}%)")
output.append(f"\n**Content:**")
output.append(f"```\n{layer['content']}\n```")
output.append("")
return "\n".join(output)
def process_query(
self,
query: str,
history: List,
show_visualization: bool
) -> Tuple[List, str, str, str]:
"""Process user query and return results"""
logger_ui.info(f"Processing query from UI: {query[:50]}..." if len(query) > 50 else f"Processing query from UI: {query}")
if not self.agent:
logger_ui.info("Agent not initialized, initializing now")
self.initialize_agent()
if not query.strip():
logger_ui.warning("Empty query received, skipping")
return history, "", "", ""
try:
logger_ui.info("Delegating query processing to agent")
# Process query
response, visualizer = self.agent.process_query(query)
# Add to chat history (format: list of dicts with role and content)
history.append({"role": "user", "content": query})
history.append({"role": "assistant", "content": response})
logger_ui.info(f"Added exchange to chat history. Total messages: {len(history)}")
# Format outputs
if show_visualization:
logger_ui.debug("Formatting context visualization")
context_viz_html = self.format_context_layers(visualizer)
context_details = self.format_context_details(visualizer)
else:
logger_ui.debug("Visualization disabled by user")
context_viz_html = "<div style='text-align: center; padding: 20px; color: #7f8c8d;'>Visualization disabled</div>"
context_details = "Visualization disabled"
logger_ui.info("Query processed successfully")
return history, "", context_viz_html, context_details
except Exception as e:
error_msg = f"Error processing query: {str(e)}"
logger_ui.error(error_msg)
history.append({"role": "user", "content": query})
history.append({"role": "assistant", "content": error_msg})
return history, "", "", ""
def clear_conversation(self) -> Tuple[List, str, str]:
"""Clear conversation history"""
logger_ui.info("Clearing conversation history")
if self.agent:
previous_count = len(self.agent.memory.messages)
self.agent.memory.messages = []
logger_ui.info(f"Cleared {previous_count} messages from conversation memory")
return [], "", ""
def create_interface(self) -> gr.Blocks:
"""Create the Gradio interface"""
logger_ui.info("Creating Gradio interface")
with gr.Blocks(
title="Context Engineering Visualizer"
) as interface:
gr.Markdown("""
# Context Engineering Visualizer
This tool demonstrates how information flows into an AI agent's context window before inference.
Ask questions about business metrics and data analysis to see the context engineering in action.
""")
with gr.Accordion("About Context Engineering", open=False):
gr.Markdown("""
**Context Engineering** is the practice of carefully managing what information goes into an AI model's context window.
This visualizer shows five key layers:
1. **System Instructions**: Stable guidelines that define the agent's role and behavior
2. **Conversation History**: Recent messages to maintain conversational coherence
3. **Retrieved Knowledge (RAG)**: Relevant information retrieved from a knowledge base
4. **User Query**: The current question or request
5. **Available Tools**: External functions the agent can use
Each layer contributes tokens to the context window. Good context engineering ensures:
- **Relevance**: Only necessary information is included
- **Structure**: Clear separation and organization of context layers
- **Efficiency**: Optimal use of limited context window space
- **Consistency**: Stable system instructions across interactions
""")
with gr.Sidebar(label="Settings & Examples", open=True, width=320):
gr.Markdown("### Settings")
show_viz = gr.Checkbox(
label="Show Context Visualization",
value=True,
info="Display detailed breakdown of context layers"
)
gr.Markdown("""
### Knowledge Base Context
The examples below use a synthetic data of a company internal document: **Product Strategy & Decision Handbook** from Atlas Pay.
📄 [View the source document on Hugging Face](https://huggingface.co/spaces/mcikalmerdeka/context-engineering-visualizer/blob/main/data/Product%20Strategy%20%26%20Decision%20Handbook%20%E2%80%94%20Atlas%20Pay.pdf)
""")
gr.Markdown("### Example Questions")
gr.Markdown("""
**Try these sequential scenarios to see context engineering in action:**
**Scenario 1: Understanding STAM (North Star Metric)**
1. What is STAM and why is it our North Star metric?
2. Calculate STAM if we have 125,000 successful transactions and 500 active merchants
3. What does this STAM value tell us about merchant engagement?
**Scenario 2: Net Revenue Retention Analysis**
1. What is Net Revenue Retention (NRR) and why is it important?
2. Calculate NRR if we have $2.5M retained revenue from $2M starting revenue
3. Is this NRR performance good based on our product goals?
**Scenario 3: Payment Success Rate Monitoring**
1. What is Adjusted Payment Success Rate and how is it used?
2. Calculate the payment success rate with 48,500 successful payments out of 50,000 valid attempts
3. Does this meet our platform reliability standards?
**Scenario 4: Product Strategy & Decision Making**
1. What are AtlasPay's core product principles?
2. Why did we decide to build our fraud detection in-house instead of buying a vendor solution?
3. What were the trade-offs in that decision?
**Scenario 5: Feature Prioritization**
1. How does AtlasPay prioritize features?
2. What are our strategic goals for 2025-2027?
3. Should we prioritize a feature with Customer Impact=5, Revenue Impact=4, Strategic Alignment=5, Engineering Effort=3?
""")
chatbot = gr.Chatbot(
label="Conversation",
height=500,
avatar_images=(None, None)
)
query_input = gr.Textbox(
label="Your Question",
placeholder="e.g., What is Average Order Value and how is it calculated?",
lines=2,
show_label=False
)
with gr.Row():
submit_btn = gr.Button("Submit", variant="primary")
clear_btn = gr.Button("Clear Conversation")
with gr.Accordion("Context Window Breakdown", open=True):
context_viz = gr.HTML(
value="<div style='text-align: center; padding: 20px; color: #7f8c8d;'>Submit a query to see context breakdown</div>"
)
with gr.Accordion("Detailed Layer Contents", open=False):
context_details = gr.Markdown(
value="Submit a query to see detailed breakdown"
)
# Event handlers
submit_btn.click(
fn=self.process_query,
inputs=[query_input, chatbot, show_viz],
outputs=[chatbot, query_input, context_viz, context_details]
)
query_input.submit(
fn=self.process_query,
inputs=[query_input, chatbot, show_viz],
outputs=[chatbot, query_input, context_viz, context_details]
)
clear_btn.click(
fn=self.clear_conversation,
inputs=[],
outputs=[chatbot, context_viz, context_details]
)
gr.Markdown("""
---
**Note**: This visualizer uses OpenAI's GPT model and requires an API key in your environment.
""")
logger_ui.info("Gradio interface created successfully")
return interface
def launch_ui(
share: bool = Settings.GRADIO_SHARE,
server_name: str = Settings.GRADIO_SERVER_NAME,
server_port: int = Settings.GRADIO_SERVER_PORT
):
"""Launch the Gradio interface"""
logger_app.info(f"Launching UI with settings: share={share}, server_name={server_name}, server_port={server_port}")
ui = ContextVisualizerUI()
interface = ui.create_interface()
interface.launch(
share=share,
server_name=server_name,
server_port=server_port,
theme=gr.themes.Soft()
)
logger_app.info("UI launched successfully")
|