Spaces:
Sleeping
Sleeping
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() |