CuriousLearner / app.py
afmjoaa
Update firebase credential, use from hf space secret
9128c01
import gradio as gr
from datetime import datetime
import hashlib
import json
# Import database functions
from database import (
register_user as db_register_user,
login_user as db_login_user,
create_agent as db_create_agent,
get_user_agents as db_get_user_agents,
get_user_by_id,
get_user_workspace,
FIREBASE_ENABLED,
DEFAULT_WORKSPACE_ID
)
# Session management
user_sessions = {}
# Model configurations by provider
MODEL_OPTIONS = {
"OpenAI": ["gpt-4.1", "gpt-4o-mini"],
"Gemini": ["gemini-2.5-pro", "gemini-2.5-flash"]
}
def get_chatbot_iframe(user_id):
"""Generate iframe HTML for chatbot webview - inline style similar to agent preview"""
if not user_id:
print("[DEBUG] get_chatbot_iframe: user_id is None or empty")
return ""
chatbot_url = f"https://dynamic-ui-chatbot.web.app/#/chats?clientId={user_id}&workspaceId={DEFAULT_WORKSPACE_ID}"
print(f"[DEBUG] get_chatbot_iframe URL: {chatbot_url}")
return f'''
<iframe
src="{chatbot_url}"
style="width: 100%; height: 500px; border: none; border-radius: 12px;"
allow="clipboard-write; clipboard-read"
></iframe>
'''
def register_user(username, email, password, confirm_password):
"""Register a new user"""
if not username or not email or not password:
return "All fields are required!", None
if password != confirm_password:
return "Passwords do not match!", None
if len(password) < 6:
return "Password must be at least 6 characters!", None
success, message, user_id = db_register_user(username, email, password)
if success:
return message + " Please login.", "login"
else:
return message, None
def login_user(email, password):
"""Login user"""
if not email or not password:
return "Email and password are required!", None, None, None, None
success, message, user_id = db_login_user(email, password)
if success:
session_id = hashlib.sha256(f"{email}{datetime.now()}".encode()).hexdigest()
user_sessions[session_id] = user_id
# Create session data for cookie storage
session_data = json.dumps({
"session_id": session_id,
"user_id": user_id})
return "Login successful!", "dashboard", session_id, session_data, user_id
else:
return message, None, None, None, None
def logout_user():
"""Logout user and clear session"""
return "" # Return empty string to clear cookie
def get_username(session_id):
"""Get username for display"""
if not session_id or session_id not in user_sessions:
return ""
user_id = user_sessions[session_id]
user = get_user_by_id(user_id)
return user.get('name', 'User') if user else ""
def create_agent(session_id, agent_name, provider_name, model_name, mcp_github_enabled, github_token, system_prompt):
"""Create a new React agent"""
print(
f"[DEBUG] create_agent: session_id={session_id}, agent_name={agent_name}, provider={provider_name}, model={model_name}")
if not session_id or session_id not in user_sessions:
print(f"[DEBUG] create_agent: session not found")
return "Please login first!", None, None
user_id = user_sessions[session_id]
print(f"[DEBUG] create_agent: user_id={user_id}")
success, message, chatbot_id, share_script = db_create_agent(
user_id, agent_name, provider_name, model_name, mcp_github_enabled, github_token, system_prompt
)
print(f"[DEBUG] create_agent: success={success}, chatbot_id={chatbot_id}")
return message, chatbot_id if success else None, share_script if success else None
def get_user_agents(session_id):
"""Get all agents created by the user"""
if not session_id or session_id not in user_sessions:
return "Please login first!"
user_id = user_sessions[session_id]
agent_list = db_get_user_agents(user_id)
return "\n\n".join(agent_list) if agent_list else "No agents created yet."
def update_model_choices(provider):
"""Update model dropdown based on selected provider"""
models = MODEL_OPTIONS.get(provider, [])
return gr.update(choices=models, value=models[0] if models else None)
# Custom CSS for better styling (with style tags for gr.HTML injection)
custom_css = """
<style>
/* Make container full width */
.gradio-container {
max-width: none !important;
}
/* Auth forms - full width */
.auth-form {
max-width: 100% !important;
width: 100% !important;
padding-right: 60px !important;
padding-left: 60px !important;
padding-bottom: 60px !important;
padding-top: 30px !important;
}
/* Dashboard and form containers - full width */
.dashboard-container, .form-container {
max-width: 100% !important;
width: 100% !important;
padding: 30px !important;
}
/* Wider tabs */
.tabs, .tab-nav, .tabitem {
max-width: 100% !important;
}
.tab-nav button {
font-size: 18px !important;
padding: 16px 32px !important;
min-width: 180px !important;
}
.tabitem {
padding: 20px !important;
}
/* Create Agent Button - Large and prominent */
.create-agent-btn button {
font-size: 24px !important;
padding: 40px 60px !important;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
color: white !important;
border: none !important;
border-radius: 15px !important;
min-height: 120px !important;
width: 100% !important;
margin: 20px 0 !important;
}
.create-agent-btn button:hover {
transform: scale(1.02) !important;
box-shadow: 0 8px 16px rgba(0,0,0,0.2) !important;
}
/* Back button styling */
.back-btn button {
background: linear-gradient(135deg, #6B7280 0%, #4B5563 100%) !important;
color: white !important;
font-size: 16px !important;
padding: 12px 24px !important;
border-radius: 8px !important;
}
/* Logout button styling */
.logout-btn button {
background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%) !important;
color: white !important;
font-size: 14px !important;
padding: 10px 20px !important;
border-radius: 8px !important;
margin-top: 30px !important;
}
.logout-btn button:hover {
background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%) !important;
}
/* MCP Config styling */
.mcp-config-box {
border: 2px solid #e5e7eb;
border-radius: 12px;
padding: 20px;
background: transparent !important;
margin: 15px 0;
}
/* Checkbox labels */
.mcp-checkbox label {
font-size: 16px !important;
font-weight: 500 !important;
}
/* Form inputs larger */
input[type="text"], input[type="email"], input[type="password"], textarea, select {
font-size: 16px !important;
padding: 12px !important;
}
/* Fix checkbox and password field backgrounds */
input[type="password"] {
background-color: var(--input-background-fill) !important;
}
input[type="checkbox"] {
background-color: transparent !important;
}
/* Buttons larger */
button {
font-size: 16px !important;
padding: 12px 24px !important;
}
/* Agent list styling */
.agent-list-container {
background: transparent !important;
border-radius: 12px;
padding: 20px;
margin-top: 20px;
}
/* Workspace chatbot webview styling - inline like agent preview */
#workspace-chatbot-webview {
width: 100% !important;
min-height: 500px !important;
height: 500px !important;
border: 2px solid #e5e7eb;
border-radius: 12px;
overflow: hidden;
margin: 15px 0;
background: #f9fafb;
}
#workspace-chatbot-webview iframe {
width: 100% !important;
height: 500px !important;
border: none !important;
}
/* Agent preview styling */
#agent-preview {
width: 100% !important;
min-height: 500px !important;
height: 500px !important;
border: 2px solid #e5e7eb;
border-radius: 12px;
overflow: hidden;
margin: 15px 0;
background: #f9fafb;
}
#agent-preview iframe {
width: 100% !important;
height: 500px !important;
border: none !important;
}
/* Remove top border from first block in tabs */
.tabitem > .column > .block:first-child {
border-top: none !important;
}
/* Remove border from blocks at the top of form containers */
.form-container > .block:first-child,
.dashboard-container > .block:first-child {
border-top: none !important;
}
</style>
"""
# Agent preview placeholder HTML - using inline styles since custom classes may not apply
AGENT_PREVIEW_PLACEHOLDER = '''
<div style="display: flex; align-items: center; justify-content: center; height: 500px; background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%); border: 2px dashed #9ca3af; border-radius: 12px; color: #374151; font-size: 18px; font-weight: 500; text-align: center; padding: 40px;">
<div>
<div style="font-size: 48px; margin-bottom: 16px;">🤖</div>
<div style="color: #374151;">Agent Preview will be loaded when the Agent is created!</div>
</div>
</div>
'''
# Workspace chatbot placeholder HTML
WORKSPACE_CHATBOT_PLACEHOLDER = '''
<div style="display: flex; align-items: center; justify-content: center; height: 500px; background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%); border: 2px dashed #9ca3af; border-radius: 12px; color: #374151; font-size: 18px; font-weight: 500; text-align: center; padding: 40px;">
<div>
<div style="font-size: 48px; margin-bottom: 16px;">💬</div>
<div style="color: #374151;">Workspace Chatbot will load after login</div>
</div>
</div>
'''
# Build the Gradio interface
with gr.Blocks(title="React Agent Builder", fill_width=True) as app:
# Inject custom CSS
gr.HTML(custom_css)
# State variables
session_state = gr.State(None)
user_id_state = gr.State(None)
with gr.Tabs(selected="login") as tabs:
with gr.Tab("Login", id="login") as login_tab:
with gr.Column(elem_classes="auth-form"):
gr.Markdown("# 🔐 Login")
login_email = gr.Textbox(label="Email", placeholder="Enter your email", scale=1)
login_password = gr.Textbox(label="Password", type="password", placeholder="Enter your password",
scale=1)
login_btn = gr.Button("Login", variant="primary", size="lg", scale=1)
login_msg = gr.Textbox(label="Status", interactive=False, scale=1)
gr.Markdown("Don't have an account? Switch to the Registration tab.")
with gr.Tab("Register", id="register") as register_tab:
with gr.Column(elem_classes="auth-form"):
gr.Markdown("# 📝 Register")
reg_username = gr.Textbox(label="Username", placeholder="Choose a username", scale=1)
reg_email = gr.Textbox(label="Email", placeholder="Enter your email", scale=1)
reg_password = gr.Textbox(label="Password", type="password", placeholder="Choose a password", scale=1)
reg_confirm_password = gr.Textbox(label="Confirm Password", type="password",
placeholder="Confirm your password", scale=1)
reg_btn = gr.Button("Register", variant="primary", size="lg", scale=1)
reg_msg = gr.Textbox(label="Status", interactive=False, scale=1)
with gr.Tab("Dashboard", id="dashboard", visible=False) as dashboard_tab:
with gr.Column(elem_classes="dashboard-container"):
gr.Markdown("# 🚀 React Agent Dashboard")
create_agent_btn = gr.Button(
"➕ Create React Agent",
size="lg",
variant="primary",
elem_classes="create-agent-btn"
)
# Workspace Chatbot section - inline webview like agent preview
gr.Markdown("### 💬 Workspace Chatbot")
workspace_chatbot_webview = gr.HTML(
value=WORKSPACE_CHATBOT_PLACEHOLDER,
elem_id="workspace-chatbot-webview"
)
# Workspace Share Script section
gr.Markdown("### 📋 All Chatbots Share Script")
workspace_share_script = gr.Textbox(
label="All Chatbots Share Script (Copy this to embed your workspace chatbot)",
interactive=False,
lines=3,
placeholder="All Chatbots share script will appear here after login...",
scale=1
)
# with gr.Column(elem_classes="agent-list-container"):
gr.Markdown("### 📋 Your Agents")
agents_list = gr.Textbox(
label="Created Agents",
interactive=False,
lines=15,
placeholder="Your created agents will appear here...",
scale=2
)
refresh_btn = gr.Button("🔄 Refresh List", size="sm")
# Logout button at the bottom of dashboard, inside the container
logout_btn_dashboard = gr.Button("🚪 Logout", size="sm", variant="stop", elem_classes="logout-btn")
with gr.Tab("Create Agent", id="create_agent", visible=False) as create_agent_tab:
with gr.Column(elem_classes="form-container"):
# Back button at the top
back_btn = gr.Button("← Back to Dashboard", size="lg", elem_classes="back-btn")
gr.Markdown("# 🤖 Create New React Agent")
agent_name_input = gr.Textbox(
label="Agent Name",
placeholder="Enter a name for your agent",
info="Give your agent a descriptive name",
scale=1
)
provider_dropdown = gr.Dropdown(
label="Provider",
choices=["OpenAI", "Gemini"],
value="OpenAI",
info="Select the AI provider",
scale=1
)
model_dropdown = gr.Dropdown(
label="Model Name",
choices=MODEL_OPTIONS["OpenAI"],
value="gpt-4o-mini",
info="Select the AI model to use",
scale=1
)
# MCP Server Config section
gr.Markdown("### 🔌 MCP Server Configuration")
with gr.Column(elem_classes="mcp-config-box"):
mcp_github = gr.Checkbox(
label="GitHub - Functions like commit, push, pull, update etc.",
value=False,
elem_classes="mcp-checkbox"
)
github_token_input = gr.Textbox(
label="Token",
placeholder="ghp_xxxxxxxxxxxxxxxxxxxx",
type="password",
visible=False,
scale=1
)
system_prompt_input = gr.Textbox(
label="System Context Prompt",
placeholder="Enter the system prompt for your agent...",
lines=10,
info="Define how your agent should behave and respond",
scale=1
)
submit_btn = gr.Button("✅ Submit & Create Agent", variant="primary", size="lg", scale=1)
create_msg = gr.Textbox(label="Status", interactive=False, lines=2, scale=1)
agent_url_output = gr.Textbox(label="Agent URL", interactive=False, lines=3, scale=1)
agent_share_script_output = gr.Textbox(label="Agent Share Script (Copy this to embed your agent)",
interactive=False, lines=3, scale=1)
# Agent preview iframe - shows placeholder initially, loads iframe after creation
gr.Markdown("### 🤖 Agent Preview")
agent_preview = gr.HTML(value=AGENT_PREVIEW_PLACEHOLDER, elem_id="agent-preview")
# Logout button at the bottom of create agent form
logout_btn_create = gr.Button("🚪 Logout", size="sm", variant="stop", elem_classes="logout-btn")
# Event handlers
def handle_login(email, password):
"""Handle login and return all necessary updates"""
msg, page, sess_id, cookie, user_id = login_user(email, password)
print(f"[DEBUG] handle_login: page={page}, sess_id={sess_id}, user_id={user_id}")
if page == "dashboard" and sess_id:
# Successful login - show dashboard and load agents list
# Use user_id directly to fetch agents
agent_list = db_get_user_agents(user_id)
agents_text = "\n\n".join(agent_list) if agent_list else "No agents created yet."
print(f"[DEBUG] handle_login: Generating chatbot iframe for user_id={user_id}")
chatbot_html = get_chatbot_iframe(user_id)
print(f"[DEBUG] handle_login: chatbot_html length={len(chatbot_html)}")
# Get workspace share script
workspace_data = get_user_workspace(user_id)
print(f"[DEBUG] handle_login: workspace_data={workspace_data}")
workspace_script = workspace_data.get('shareScript', '') if workspace_data else ''
print(
f"[DEBUG] handle_login: workspace_script={workspace_script[:100] if workspace_script else 'empty'}...")
return {
login_msg: msg,
login_tab: gr.update(visible=False),
register_tab: gr.update(visible=False),
dashboard_tab: gr.update(visible=True),
create_agent_tab: gr.update(visible=False),
session_state: sess_id,
user_id_state: user_id,
agents_list: agents_text,
workspace_share_script: workspace_script,
workspace_chatbot_webview: gr.update(value=chatbot_html),
tabs: gr.update(selected="dashboard")
}
else:
# Failed login - stay on login page
return {
login_msg: msg,
login_tab: gr.update(),
register_tab: gr.update(),
dashboard_tab: gr.update(),
create_agent_tab: gr.update(),
session_state: None,
user_id_state: None,
agents_list: gr.update(),
workspace_share_script: gr.update(),
workspace_chatbot_webview: gr.update(),
tabs: gr.update()
}
def handle_logout():
"""Handle logout"""
return {
login_tab: gr.update(visible=True),
register_tab: gr.update(visible=True),
dashboard_tab: gr.update(visible=False),
create_agent_tab: gr.update(visible=False),
session_state: None,
user_id_state: None,
login_email: "",
login_password: "",
login_msg: "",
workspace_share_script: "",
workspace_chatbot_webview: gr.update(value=WORKSPACE_CHATBOT_PLACEHOLDER),
tabs: gr.update(selected="login")
}
def switch_to_create_agent():
return {
dashboard_tab: gr.update(visible=False),
create_agent_tab: gr.update(visible=True),
tabs: gr.update(selected="create_agent")
}
def switch_back_to_dashboard(user_id):
chatbot_html = get_chatbot_iframe(user_id) if user_id else WORKSPACE_CHATBOT_PLACEHOLDER
return {
dashboard_tab: gr.update(visible=True),
create_agent_tab: gr.update(visible=False),
agent_name_input: "",
provider_dropdown: "OpenAI",
model_dropdown: gr.update(choices=MODEL_OPTIONS["OpenAI"], value="gpt-4o-mini"),
mcp_github: False,
github_token_input: gr.update(value="", visible=False),
system_prompt_input: "",
create_msg: "",
agent_url_output: "",
agent_share_script_output: "",
agent_preview: AGENT_PREVIEW_PLACEHOLDER,
workspace_chatbot_webview: gr.update(value=chatbot_html),
tabs: gr.update(selected="dashboard")
}
def toggle_github_token(enabled):
"""Show/hide GitHub token input based on checkbox"""
return gr.update(visible=enabled)
def handle_agent_creation(sess_id, user_id, name, provider, model, mcp_enabled, github_token, prompt):
print(
f"[DEBUG] handle_agent_creation: sess_id={sess_id}, user_id={user_id}, name={name}, provider={provider}, model={model}")
msg, chatbot_id, share_script = create_agent(sess_id, name, provider, model, mcp_enabled, github_token, prompt)
print(f"[DEBUG] handle_agent_creation: msg={msg}, chatbot_id={chatbot_id}")
# Build the individual agent URL locally if creation was successful
agent_url = ""
agent_iframe = AGENT_PREVIEW_PLACEHOLDER # Default to placeholder
agent_share_script = ""
if chatbot_id and user_id:
agent_url = f"https://dynamic-ui-chatbot.web.app/#/individual_chat_screen?clientId={user_id}&workspaceId={DEFAULT_WORKSPACE_ID}&chatbotId={chatbot_id}"
print(f"[DEBUG] handle_agent_creation: agent_url={agent_url}")
agent_iframe = f'''<iframe src="{agent_url}" style="width: 100%; height: 500px; border: none;" allow="clipboard-write; clipboard-read"></iframe>'''
print(f"[DEBUG] handle_agent_creation: iframe built, length={len(agent_iframe)}")
agent_share_script = share_script if share_script else ""
else:
print(f"[DEBUG] handle_agent_creation: chatbot_id or user_id is None/empty")
# Also refresh the agents list after creation
agent_list = db_get_user_agents(user_id) if user_id else []
updated_agents = "\n\n".join(agent_list) if agent_list else "No agents created yet."
return msg, agent_url, agent_share_script, agent_iframe, updated_agents
# Refresh agents list function
def refresh_agents_list(user_id):
"""Refresh agents list using user_id"""
if not user_id:
return "Please login first!"
agent_list = db_get_user_agents(user_id)
return "\n\n".join(agent_list) if agent_list else "No agents created yet."
# Load chatbot webview function
def load_chatbot_webview(user_id):
"""Load chatbot webview for user"""
if not user_id:
return gr.update(value=WORKSPACE_CHATBOT_PLACEHOLDER)
chatbot_html = get_chatbot_iframe(user_id)
return gr.update(value=chatbot_html)
# Load workspace share script function
def load_workspace_share_script(user_id):
"""Load workspace share script for user"""
if not user_id:
return "Workspace share script will appear here after login..."
workspace_data = get_user_workspace(user_id)
print(f"[DEBUG] load_workspace_share_script: workspace_data={workspace_data}")
if workspace_data:
share_script = workspace_data.get('shareScript', '')
print(f"[DEBUG] load_workspace_share_script: share_script found, length={len(share_script)}")
return share_script if share_script else "No share script found in workspace"
return "Workspace not found"
# Login event - chain refresh and webview load after login
login_btn.click(
fn=handle_login,
inputs=[login_email, login_password],
outputs=[login_msg, login_tab, register_tab, dashboard_tab, create_agent_tab, session_state,
user_id_state, agents_list, workspace_share_script, workspace_chatbot_webview, tabs]
).then(
fn=refresh_agents_list,
inputs=[user_id_state],
outputs=[agents_list]
).then(
fn=load_workspace_share_script,
inputs=[user_id_state],
outputs=[workspace_share_script]
).then(
fn=load_chatbot_webview,
inputs=[user_id_state],
outputs=[workspace_chatbot_webview]
)
# Logout events (both buttons do the same thing)
logout_outputs = [login_tab, register_tab, dashboard_tab, create_agent_tab, session_state,
user_id_state, login_email, login_password, login_msg, workspace_share_script,
workspace_chatbot_webview, tabs]
logout_btn_dashboard.click(
fn=handle_logout,
outputs=logout_outputs
)
logout_btn_create.click(
fn=handle_logout,
outputs=logout_outputs
)
# Register event
reg_btn.click(
fn=register_user,
inputs=[reg_username, reg_email, reg_password, reg_confirm_password],
outputs=[reg_msg, gr.State()]
)
# Create agent button
create_agent_btn.click(
fn=switch_to_create_agent,
outputs=[dashboard_tab, create_agent_tab, tabs]
)
# Back button
back_btn.click(
fn=switch_back_to_dashboard,
inputs=[user_id_state],
outputs=[dashboard_tab, create_agent_tab, agent_name_input, provider_dropdown,
model_dropdown, mcp_github, github_token_input, system_prompt_input,
create_msg, agent_url_output, agent_share_script_output, agent_preview,
workspace_chatbot_webview, tabs]
)
# Provider dropdown change - updates model choices
provider_dropdown.change(
fn=update_model_choices,
inputs=[provider_dropdown],
outputs=[model_dropdown]
)
# MCP GitHub checkbox toggle
mcp_github.change(
fn=toggle_github_token,
inputs=[mcp_github],
outputs=[github_token_input]
)
# Submit agent
submit_btn.click(
fn=handle_agent_creation,
inputs=[session_state, user_id_state, agent_name_input, provider_dropdown,
model_dropdown, mcp_github, github_token_input, system_prompt_input],
outputs=[create_msg, agent_url_output, agent_share_script_output, agent_preview, agents_list]
)
# Refresh agents list button
refresh_btn.click(
fn=refresh_agents_list,
inputs=[user_id_state],
outputs=[agents_list]
)
if __name__ == "__main__":
app.launch(
server_name="0.0.0.0",
server_port=7860,
share=True
)
def main():
"""Entry point for the application"""
app.launch(
server_name="0.0.0.0",
server_port=7860,
share=True
)