#!/usr/bin/env python3 """ Hugging Face Spaces deployment for Residential Architecture Assistant Multi-Agent LangGraph System for Architecture Consultation """ import os import gradio as gr import json import traceback from typing import List, Tuple, Dict, Any from datetime import datetime # Import the core system from graph import ArchitectureAssistant class HuggingFaceArchitectureApp: """Hugging Face Spaces compatible wrapper for the Architecture Assistant""" def __init__(self): self.assistant = None self.conversation_history = [] def initialize_assistant(self, api_key: str, user_id: str = None) -> Tuple[str, bool]: """Initialize the assistant with API key""" try: if not api_key or api_key.strip() == "": return "❌ Please provide your OpenAI API key to get started.", False # Initialize the assistant self.assistant = ArchitectureAssistant( openai_api_key=api_key.strip(), user_id=user_id or f"hf_user_{datetime.now().strftime('%Y%m%d_%H%M%S')}" ) return "✅ Architecture Assistant initialized! You can now start your consultation.", True except Exception as e: error_msg = f"❌ Error initializing assistant: {str(e)}" print(f"Initialization error: {traceback.format_exc()}") return error_msg, False def chat_with_assistant(self, message: str, history: List[List[str]], api_key: str) -> Tuple[List[List[str]], str]: """Process chat message and return updated history""" try: # Check if assistant is initialized if not self.assistant or not api_key: error_response = "❌ Please provide your OpenAI API key first." history.append([message, error_response]) return history, "" # Get response from assistant response = self.assistant.chat(message) # Add to history history.append([message, response]) return history, "" except Exception as e: error_response = f"❌ Error: {str(e)}\n\nPlease check your API key and try again." print(f"Chat error: {traceback.format_exc()}") history.append([message, error_response]) return history, "" def get_conversation_summary(self, api_key: str) -> str: """Get current conversation summary""" try: if not self.assistant or not api_key: return "❌ Assistant not initialized. Please provide your API key first." summary = self.assistant.get_conversation_summary() # Format summary nicely formatted_summary = f"""📋 **CONVERSATION SUMMARY** 👤 **User Requirements:** • Budget: ${summary['user_requirements'].get('budget', 0):,} CAD • Location: {summary['user_requirements'].get('location', 'Not specified')} • Family Size: {summary['user_requirements'].get('family_size', 'Not specified')} • Preferences: {', '.join(summary['user_requirements'].get('lifestyle_preferences', []) or ['None specified'])} 🏠 **Floorplan Requirements:** • Total Square Footage: {summary['floorplan_requirements'].get('total_sqft', 'Not specified')} sq ft • Number of Floors: {summary['floorplan_requirements'].get('num_floors', 'Not specified')} • Lot Dimensions: {summary['floorplan_requirements'].get('lot_dimensions', 'Not specified')} • Rooms: {len(summary['floorplan_requirements'].get('rooms', []))} room types specified 📊 **Progress:** • Total Messages: {summary['total_messages']} • Current Topic: {summary['current_topic'] or 'General consultation'} """ return formatted_summary except Exception as e: return f"❌ Error getting summary: {str(e)}" def reset_conversation(self, api_key: str) -> Tuple[List, str, str]: """Reset the conversation""" try: if self.assistant and api_key: self.assistant.reset_conversation() return [], "", "✅ Conversation reset. You can start a new consultation." else: return [], "", "❌ Please initialize with your API key first." except Exception as e: return [], "", f"❌ Error resetting: {str(e)}" # Create app instance app = HuggingFaceArchitectureApp() # Create Gradio interface def create_gradio_interface(): """Create the Gradio interface for Hugging Face Spaces""" with gr.Blocks( title="🏠 Residential Architecture Assistant", theme=gr.themes.Soft(), css=""" .container { max-width: 1200px; margin: auto; } .header { text-align: center; padding: 20px; } .chat-container { height: 500px; } .summary-box { background-color: #f8f9fa; padding: 15px; border-radius: 10px; } """ ) as demo: # Header gr.HTML("""

🏠 Residential Architecture Assistant

Multi-Agent LangGraph System for Professional Architecture Consultation

✨ 7 AI Specialists | 📐 Professional Floorplans | 💰 Montreal Market Analysis | 📋 Building Codes

""") # API Key input (persistent across the session) with gr.Row(): api_key_input = gr.Textbox( label="🔑 OpenAI API Key", placeholder="Enter your OpenAI API key (sk-...)", type="password", info="Your API key is used securely and not stored. Required for AI agent functionality." ) with gr.Row(): init_btn = gr.Button("🚀 Initialize Assistant", variant="primary", size="sm") reset_btn = gr.Button("🔄 Reset Conversation", variant="secondary", size="sm") init_status = gr.HTML("") # Main chat interface with gr.Row(): with gr.Column(scale=2): chatbot = gr.Chatbot( label="💬 Architecture Consultation", height=500, show_label=True ) with gr.Row(): msg_input = gr.Textbox( label="Your Message", placeholder="Ask about home design, budgets, floorplans, building codes...", lines=2, scale=4 ) send_btn = gr.Button("📤 Send", variant="primary", scale=1) with gr.Column(scale=1): gr.HTML("

📊 Project Status

") summary_display = gr.HTML( value="
Initialize the assistant to see your project summary.
", label="Conversation Summary" ) summary_btn = gr.Button("🔄 Update Summary", variant="secondary", size="sm") # Usage instructions with gr.Accordion("📖 How to Use", open=False): gr.HTML("""

🚀 Getting Started:

  1. Enter your OpenAI API key above
  2. Click "Initialize Assistant"
  3. Start your consultation with questions like:

💡 Example Questions:

🤖 Our AI Specialists:

""") # Event handlers def handle_init(api_key): status_msg, success = app.initialize_assistant(api_key) if success: return gr.HTML(f"
{status_msg}
") else: return gr.HTML(f"
{status_msg}
") def handle_chat(message, history, api_key): return app.chat_with_assistant(message, history, api_key) def handle_summary(api_key): summary = app.get_conversation_summary(api_key) return f"
{summary}
" def handle_reset(api_key): history, msg, status = app.reset_conversation(api_key) return history, msg, gr.HTML(f"
{status}
") # Wire up events init_btn.click( handle_init, inputs=[api_key_input], outputs=[init_status] ) msg_input.submit( handle_chat, inputs=[msg_input, chatbot, api_key_input], outputs=[chatbot, msg_input] ) send_btn.click( handle_chat, inputs=[msg_input, chatbot, api_key_input], outputs=[chatbot, msg_input] ) summary_btn.click( handle_summary, inputs=[api_key_input], outputs=[summary_display] ) reset_btn.click( handle_reset, inputs=[api_key_input], outputs=[chatbot, msg_input, init_status] ) # Footer gr.HTML("""

🏠 Residential Architecture Assistant v3.0

Built with LangGraph • Powered by OpenAI • Interface by Gradio

Professional architecture consultation from concept to construction

""") return demo # Create and launch the interface if __name__ == "__main__": demo = create_gradio_interface() # Launch configuration for Hugging Face Spaces demo.launch()