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() |