mcp-88 / demo_server.py
alishams21's picture
Upload folder using huggingface_hub
ee0128f verified
#!/usr/bin/env python3
"""
Gradio Web Interface for Data Product Builder Agent
This web application provides the same functionality as the command-line chat interface
but with a modern web UI using Gradio. Users can interact with the DPBuilderAgent through
a chat interface in their browser.
"""
import asyncio
import sys
import os
from pathlib import Path
import gradio as gr
import logging
from typing import List, Tuple, Optional
# Add the project root to Python path
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))
from dp_chat_agent.chat_agent import create_dp_composer_agent
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler(),
logging.FileHandler('dp_builder_gradio.log')
],
force=True
)
logger = logging.getLogger(__name__)
class GradioChatInterface:
def __init__(self):
self.agent = None
self.session_id = None
self.chat_history = []
async def initialize_agent(self, initial_message: str = None):
"""Initialize the DPComposerAgent with a new session"""
try:
logger.info("Initializing Data Product Composer Agent...")
# Create agent instance
self.agent = create_dp_composer_agent(
agent_name="Data Product Composer",
user_message=initial_message or "Hello, I'm ready to help you build a data product!",
model_name="gpt-4-turbo-preview"
)
# Get the session ID that was created
self.session_id = self.agent.session_id
logger.info(f"Agent initialized with session ID: {self.session_id}")
return True
except Exception as e:
logger.error(f"Failed to initialize agent: {e}")
return False
async def process_message(self, user_input: str) -> str:
"""Process user message through the agent"""
try:
if not self.agent:
return "Error: Agent not initialized. Please refresh the page."
logger.info(f"Processing message: {user_input[:50]}...")
# Run the agent with the user message
result = await self.agent.run(current_message=user_input)
# Extract the response from the result
if isinstance(result, dict):
if "error" in result:
return f"Error: {result['error']}"
elif "reply" in result:
# Get the main reply
response = result["reply"]
# Add additional context if available
if result.get("missing_fields"):
missing_fields = result["missing_fields"]
if missing_fields:
response += f"\n\n📋 **Still need:** {', '.join(missing_fields)}"
if result.get("next_action"):
next_action = result["next_action"]
if next_action:
response += f"\n\n🎯 **Next:** {next_action}"
if result.get("confidence") and result["confidence"] < 0.8:
confidence = result["confidence"]
response += f"\n\n⚠️ **Confidence:** {confidence:.1%} (Please provide more details if needed)"
return response
else:
return str(result)
else:
return str(result)
except Exception as e:
logger.error(f"Error processing message: {e}")
return f"Sorry, I encountered an error: {str(e)}"
async def chat_function(self, message: str, history: List[List[str]]) -> Tuple[str, List[List[str]]]:
"""Handle chat messages and return response with updated history"""
if not message.strip():
return "", history
# Add user message to history
history.append([message, None])
# Process the message
response = await self.process_message(message)
# Update history with response
history[-1][1] = response
return "", history
async def clear_chat(self) -> List[List[str]]:
"""Clear chat history and reinitialize agent"""
try:
# Reinitialize agent with a fresh session
await self.initialize_agent()
self.chat_history = []
return []
except Exception as e:
logger.error(f"Error clearing chat: {e}")
return self.chat_history
# Global instance
chat_interface = GradioChatInterface()
async def initialize_app():
"""Initialize the chat interface"""
await chat_interface.initialize_agent()
def create_gradio_interface():
"""Create and configure the Gradio interface"""
# Custom CSS for better styling
css = """
.gradio-container {
max-width: 1200px !important;
margin: auto !important;
}
.chat-message {
padding: 10px;
margin: 5px 0;
border-radius: 10px;
}
.user-message {
background-color: #e3f2fd;
margin-left: 20%;
}
.bot-message {
background-color: #f5f5f5;
margin-right: 20%;
}
"""
with gr.Blocks(css=css, title="MCP-88: MCP Server for data product building") as interface:
gr.Markdown("""
# MCP-88: MCP Server for data product building
Welcome! I'm here to help you build comprehensive data products with structured guidance.
**Instructions:**
• Type your message in the chat box below
• I'll guide you through scoping and data contract creation
• Use the "Clear Chat" button to start a new session
• Look for progress indicators and next steps in my responses
""")
with gr.Row():
with gr.Column(scale=3):
# Chat interface
chatbot = gr.Chatbot(
label="Chat with MCP-88: MCP Server for data product building",
height=500,
show_label=True,
container=True,
bubble_full_width=False
)
with gr.Row():
msg_input = gr.Textbox(
placeholder="Type your message here...",
label="Your Message",
lines=2,
scale=4
)
send_btn = gr.Button("Send", variant="primary", scale=1)
with gr.Row():
clear_btn = gr.Button("Clear Chat", variant="secondary")
with gr.Column(scale=1):
# Instructions panel
gr.Markdown("""
### 💡 Tips
- Be specific about your data product requirements
- I'll show you what information is still needed
- Follow the suggested next steps for best results
- The process includes scoping and data contract creation
""")
# Event handlers
def handle_send(message, history):
"""Handle send button click"""
if not message.strip():
return "", history
# Run the async chat function
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
new_message, updated_history = loop.run_until_complete(
chat_interface.chat_function(message, history)
)
return new_message, updated_history
finally:
loop.close()
def handle_clear():
"""Handle clear button click"""
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
cleared_history = loop.run_until_complete(
chat_interface.clear_chat()
)
return cleared_history
finally:
loop.close()
# Connect event handlers
send_btn.click(
handle_send,
inputs=[msg_input, chatbot],
outputs=[msg_input, chatbot]
)
msg_input.submit(
handle_send,
inputs=[msg_input, chatbot],
outputs=[msg_input, chatbot]
)
clear_btn.click(
handle_clear,
inputs=[],
outputs=[chatbot]
)
return interface
def main():
"""Main entry point for the Gradio app"""
# Check for required environment variables
if not os.getenv("OPENAI_API_KEY"):
print("❌ Error: OPENAI_API_KEY environment variable is required")
print("Please set your OpenAI API key and try again.")
sys.exit(1)
# Initialize the chat interface
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
loop.run_until_complete(initialize_app())
finally:
loop.close()
# Create and launch the Gradio interface
interface = create_gradio_interface()
print("🚀 Starting Data Product Composer Chat Web Interface...")
print("📱 The interface will be available in your browser")
# Launch the interface
interface.launch(
server_name="0.0.0.0", # Allow external access
server_port=7860, # Default Gradio port
share=False, # Set to True if you want a public link
show_error=True, # Show errors in the interface
quiet=False, # Show startup messages
inbrowser=True # Open browser automatically
)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n👋 Chat interface terminated by user.")
except Exception as e:
logger.error(f"Fatal error: {e}")
print(f"❌ Fatal error: {e}")
sys.exit(1)