email-formatter / app.py
ProximileAdmin's picture
Update app.py
94f9077 verified
import os
import gradio as gr
from email_processor import (
load_examples,
setup_clients,
process_email,
AVAILABLE_MODELS,
load_email_guidelines
)
# Initialize global variables
PASSWORD_PROTECTION_ENABLED = False
PASSWORD = os.getenv("PASSWD")
EMAIL_EXAMPLES = load_examples()
CLIENTS = setup_clients()
DEFAULT_GUIDELINES = load_email_guidelines()
def process_email_wrapper(
preceding_conversation,
drafted_user_reply,
session_password,
system_message,
model_choice,
max_tokens,
temperature,
top_p,
custom_guidelines,
identity
):
"""
Wrapper function to call the email processor with all necessary parameters.
This separates the Gradio interface from the core processing logic.
When PASSWORD_PROTECTION_ENABLED is False, we bypass password validation entirely.
"""
if not PASSWORD_PROTECTION_ENABLED:
# If password protection is disabled, use a dummy password that will always match
dummy_password = "dummy_password"
return process_email(
preceding_conversation,
drafted_user_reply,
dummy_password, # Use dummy password for session_password
system_message,
model_choice,
max_tokens,
temperature,
top_p,
dummy_password, # Use same dummy password for PASSWORD
CLIENTS,
custom_guidelines,
identity
)
else:
# Normal flow with password protection
return process_email(
preceding_conversation,
drafted_user_reply,
session_password,
system_message,
model_choice,
max_tokens,
temperature,
top_p,
PASSWORD,
CLIENTS,
custom_guidelines,
identity
)
def check_password(input_password):
"""
Validates the password and, if valid, shows the interface.
If password protection is disabled, always grants access.
Returns updates to UI components based on password validation.
"""
if not PASSWORD_PROTECTION_ENABLED or input_password == PASSWORD:
return gr.update(visible=False), gr.update(visible=True), input_password, gr.update(visible=False)
else:
return gr.update(value="", interactive=True), gr.update(visible=False), "", gr.update(value="Invalid password. Please try again.", visible=True)
def reset_form():
"""Reset all input fields."""
return "", ""
def reset_guidelines():
"""Reset guidelines to default from file."""
return DEFAULT_GUIDELINES
# Define load functions for each example
def load_example_0():
return EMAIL_EXAMPLES[0]["preceding_conversation"], EMAIL_EXAMPLES[0]["drafted_user_reply"]
def load_example_1():
return EMAIL_EXAMPLES[1]["preceding_conversation"], EMAIL_EXAMPLES[1]["drafted_user_reply"]
def load_example_2():
return EMAIL_EXAMPLES[2]["preceding_conversation"], EMAIL_EXAMPLES[2]["drafted_user_reply"]
def load_example_3():
return EMAIL_EXAMPLES[3]["preceding_conversation"], EMAIL_EXAMPLES[3]["drafted_user_reply"]
def load_example_4():
return EMAIL_EXAMPLES[4]["preceding_conversation"], EMAIL_EXAMPLES[4]["drafted_user_reply"]
# Build the Gradio interface
with gr.Blocks(title="Email Assistant") as demo:
# Session password state
session_password = gr.State("")
# Password interface - initially hidden if password protection is disabled
with gr.Column(visible=PASSWORD_PROTECTION_ENABLED) as password_interface:
gr.Markdown("# Email Assistant")
gr.Markdown("Please enter the password to access the application.")
password_input = gr.Textbox(
type="password", label="Enter Password", interactive=True
)
submit_button = gr.Button("Submit")
error_message = gr.Textbox(
label="Error", visible=False, interactive=False
)
# Main application interface - initially visible if password protection is disabled
with gr.Column(visible=not PASSWORD_PROTECTION_ENABLED) as app_interface:
gr.Markdown("# Email Assistant")
gr.Markdown("This tool helps you improve your email responses using AI.")
# Create empty containers for our layout
examples_section = gr.Column() # Container for examples
main_inputs = gr.Column() # Container for textboxes
buttons_section = gr.Row() # Container for action buttons
outputs_section = gr.Column() # Container for outputs
advanced_section = gr.Column() # Container for advanced options
# Define input textboxes first (for variable references), but don't render yet
with gr.Column(visible=True) as temp_container:
preceding_conversation = gr.Textbox(
label="Email Thread Context",
placeholder="Paste the complete email thread that you want to reply to...",
lines=15,
render=False # Don't render immediately
)
drafted_user_reply = gr.Textbox(
label="Your Draft Reply",
placeholder="Type your draft reply here. The assistant will help improve it.",
lines=8,
render=False # Don't render immediately
)
# Define the advanced options for later use (but don't render them yet)
with gr.Accordion("Advanced Options", open=False, render=False) as advanced_options:
with gr.Row():
with gr.Column(scale=2):
system_prompt = gr.Textbox(
value="You are a helpful assistant specialized in email communication. Help the user craft a professional, clear, and effective email response.",
label="System Instructions",
lines=2
)
with gr.Column(scale=1):
model_choice = gr.Dropdown(
choices=list(AVAILABLE_MODELS.keys()),
value=list(AVAILABLE_MODELS.keys())[0],
label="Select Model"
)
with gr.Row():
with gr.Column(scale=1):
max_tokens = gr.Slider(
minimum=1, maximum=4096, value=1024, step=100, label="Max Tokens"
)
with gr.Column(scale=1):
temperature = gr.Slider(
minimum=0.1, maximum=1.0, value=0.7, step=0.1, label="Temperature"
)
with gr.Column(scale=1):
top_p = gr.Slider(
minimum=0.1, maximum=1.0, value=0.95, step=0.05, label="Top-p"
)
with gr.Row():
identity = gr.Textbox(
value="",
label="Reply Identity (optional)",
placeholder="Enter the perspective this email is being written from (e.g., 'Sales Manager', 'Customer Support')",
lines=1
)
with gr.Row():
with gr.Column():
email_guidelines = gr.Textbox(
value=DEFAULT_GUIDELINES,
label="Email Formatting Guidelines",
lines=10,
placeholder="Enter custom email formatting guidelines here..."
)
with gr.Row():
reset_guidelines_button = gr.Button("Reset Guidelines to Default")
# Define output components (but don't render yet)
assistant_response = gr.Textbox(
label="Improved Email Response",
lines=10,
render=False
)
suggestions = gr.Textbox(
label="Suggestions",
lines=5,
render=False
)
# Now populate each section in the desired order
# 1. Examples section first (at the top)
with examples_section:
gr.Markdown("### Click to Load Example Email Threads and Draft Replies")
with gr.Row():
for i in range(min(5, len(EMAIL_EXAMPLES))):
gr.Button(
EMAIL_EXAMPLES[i]["title"],
size="sm",
variant="secondary",
).click(
fn=globals()[f"load_example_{i}"],
inputs=[],
outputs=[preceding_conversation, drafted_user_reply]
)
# 2. Main input textboxes next
with main_inputs:
# Render the textboxes here
preceding_conversation.render()
drafted_user_reply.render()
# 3. Action buttons
with buttons_section:
clear_button = gr.Button("Clear")
process_button = gr.Button("Process Email", variant="primary")
# 4. Output section
with outputs_section:
# Render the output components here
assistant_response.render()
suggestions.render()
# 5. Advanced options last (at the bottom)
with advanced_section:
# Render the advanced options accordion here
advanced_options.render()
# Set up the processing function
process_button.click(
fn=process_email_wrapper,
inputs=[
preceding_conversation,
drafted_user_reply,
session_password,
system_prompt,
model_choice,
max_tokens,
temperature,
top_p,
email_guidelines,
identity
],
outputs=[assistant_response, suggestions]
)
# Set up the clear function
clear_button.click(
fn=reset_form,
inputs=[],
outputs=[preceding_conversation, drafted_user_reply]
)
# Set up the reset guidelines function
reset_guidelines_button.click(
fn=reset_guidelines,
inputs=[],
outputs=[email_guidelines]
)
# Password validation
submit_button.click(
fn=check_password,
inputs=password_input,
outputs=[password_interface, app_interface, session_password, error_message]
)
if __name__ == "__main__":
demo.launch()