webui_gateway_step.py
1 import re 2 3 import click 4 from pathlib import Path 5 6 from ...utils import ask_if_not_provided, ask_yes_no_question, load_template 7 8 9 WEBUI_GATEWAY_DEFAULTS = { 10 "webui_frontend_welcome_message": "", 11 "webui_frontend_bot_name": "Solace Agent Mesh", 12 "webui_frontend_logo_url": "", 13 "webui_frontend_collect_feedback": False, 14 "webui_session_secret_key": "please_change_me_in", 15 "webui_fastapi_host": "127.0.0.1", 16 "webui_fastapi_port": 8000, 17 "webui_fastapi_https_port": 8443, 18 "webui_ssl_keyfile": "", 19 "webui_ssl_certfile": "", 20 "webui_ssl_keyfile_password": "", 21 "webui_enable_embed_resolution": True, 22 } 23 24 25 def create_webui_gateway_config( 26 project_root: Path, options: dict, skip_interactive: bool, default_values: dict 27 ) -> bool: 28 """ 29 Gathers WebUI Gateway options and creates the configuration file (configs/gateways/webui.yaml) 30 if the user opts in. It customizes the template based on user input or defaults. 31 Returns True on success or if skipped, False on failure. 32 """ 33 click.echo("Configuring Web UI Gateway options...") 34 35 add_gateway = options.get("add_webui_gateway") 36 if not skip_interactive and add_gateway is None: 37 add_gateway = default_values.get("add_webui_gateway", True) 38 elif add_gateway is None: 39 add_gateway = default_values.get("add_webui_gateway", True) 40 41 options["add_webui_gateway"] = add_gateway 42 43 if not add_gateway: 44 click.echo(click.style(" Skipping Web UI Gateway file creation.", fg="yellow")) 45 return True 46 47 options["webui_session_secret_key"] = ask_if_not_provided( 48 options, 49 "webui_session_secret_key", 50 "Enter Web UI Session Secret Key", 51 default=default_values.get( 52 "webui_session_secret_key", 53 WEBUI_GATEWAY_DEFAULTS["webui_session_secret_key"], 54 ), 55 none_interactive=skip_interactive, 56 hide_input=True, 57 ) 58 options["webui_fastapi_host"] = ask_if_not_provided( 59 options, 60 "webui_fastapi_host", 61 "Enter Web UI FastAPI Host", 62 default=default_values.get( 63 "webui_fastapi_host", WEBUI_GATEWAY_DEFAULTS["webui_fastapi_host"] 64 ), 65 none_interactive=skip_interactive, 66 ) 67 options["webui_fastapi_port"] = ask_if_not_provided( 68 options, 69 "webui_fastapi_port", 70 "Enter Web UI FastAPI Port", 71 default=default_values.get( 72 "webui_fastapi_port", WEBUI_GATEWAY_DEFAULTS["webui_fastapi_port"] 73 ), 74 none_interactive=skip_interactive, 75 ) 76 options["webui_fastapi_https_port"] = ask_if_not_provided( 77 options, 78 "webui_fastapi_https_port", 79 "Enter Web UI FastAPI HTTPS Port", 80 default=default_values.get("webui_fastapi_https_port", 8443), 81 none_interactive=skip_interactive, 82 ) 83 options["webui_enable_embed_resolution"] = ask_if_not_provided( 84 options, 85 "webui_enable_embed_resolution", 86 "Enable Embed Resolution for Web UI? (true/false)", 87 default=default_values.get( 88 "webui_enable_embed_resolution", 89 WEBUI_GATEWAY_DEFAULTS["webui_enable_embed_resolution"], 90 ), 91 none_interactive=skip_interactive, 92 is_bool=True, 93 ) 94 options["webui_ssl_keyfile"] = ask_if_not_provided( 95 options, 96 "webui_ssl_keyfile", 97 "Enter SSL Key File Path", 98 default=default_values.get("webui_ssl_keyfile", ""), 99 none_interactive=skip_interactive, 100 ) 101 options["webui_ssl_certfile"] = ask_if_not_provided( 102 options, 103 "webui_ssl_certfile", 104 "Enter SSL Certificate File Path", 105 default=default_values.get("webui_ssl_certfile", ""), 106 none_interactive=skip_interactive, 107 ) 108 options["webui_ssl_keyfile_password"] = ask_if_not_provided( 109 options, 110 "webui_ssl_keyfile_password", 111 "Enter SSL Key File Passphrase", 112 default=default_values.get("webui_ssl_keyfile_password", ""), 113 none_interactive=skip_interactive, 114 hide_input=True, 115 ) 116 117 options["webui_frontend_welcome_message"] = ask_if_not_provided( 118 options, 119 "webui_frontend_welcome_message", 120 "Enter Frontend Welcome Message for Web UI", 121 default=default_values.get( 122 "webui_frontend_welcome_message", 123 WEBUI_GATEWAY_DEFAULTS["webui_frontend_welcome_message"], 124 ), 125 none_interactive=skip_interactive, 126 ) 127 options["webui_frontend_bot_name"] = ask_if_not_provided( 128 options, 129 "webui_frontend_bot_name", 130 "Enter Frontend Bot Name for Web UI", 131 default=default_values.get( 132 "webui_frontend_bot_name", WEBUI_GATEWAY_DEFAULTS["webui_frontend_bot_name"] 133 ), 134 none_interactive=skip_interactive, 135 ) 136 options["webui_frontend_logo_url"] = ask_if_not_provided( 137 options, 138 "webui_frontend_logo_url", 139 "Enter Frontend Logo URL (PNG, SVG, JPG or data URI)", 140 default=default_values.get( 141 "webui_frontend_logo_url", WEBUI_GATEWAY_DEFAULTS["webui_frontend_logo_url"] 142 ), 143 none_interactive=skip_interactive, 144 ) 145 options["webui_frontend_collect_feedback"] = ask_if_not_provided( 146 options, 147 "webui_frontend_collect_feedback", 148 "Enable Frontend Feedback Collection for Web UI? (true/false)", 149 default=default_values.get( 150 "webui_frontend_collect_feedback", 151 WEBUI_GATEWAY_DEFAULTS["webui_frontend_collect_feedback"], 152 ), 153 none_interactive=skip_interactive, 154 is_bool=True, 155 ) 156 157 click.echo("Creating Web UI Gateway configuration file...") 158 destination_path = project_root / "configs" / "gateways" / "webui.yaml" 159 160 try: 161 template_content = load_template("webui.yaml") 162 163 session_service_lines = [ 164 f'type: "sql"', 165 'database_url: "${WEB_UI_GATEWAY_DATABASE_URL, sqlite:///webui_gateway.db}"', 166 f'default_behavior: "PERSISTENT"', 167 ] 168 session_service_block = "\n" + "\n".join( 169 [f" {line}" for line in session_service_lines] 170 ) 171 172 replacements = { 173 "__FRONTEND_WELCOME_MESSAGE__": str( 174 options.get("webui_frontend_welcome_message", '${FRONTEND_WELCOME_MESSAGE, "Hello, how can I assist you?"}') 175 ), 176 "__FRONTEND_BOT_NAME__": str( 177 options.get("webui_frontend_bot_name", "${FRONTEND_BOT_NAME, Solace Agent Mesh}") 178 ), 179 "__FRONTEND_LOGO_URL__": str( 180 options.get("webui_frontend_logo_url", "${WEBUI_FRONTEND_LOGO_URL}") 181 ), 182 "__FRONTEND_COLLECT_FEEDBACK__": str( 183 options.get("webui_frontend_collect_feedback", "${FRONTEND_COLLECT_FEEDBACK, false}") 184 ).lower(), 185 "__SESSION_SERVICE__": session_service_block, 186 } 187 188 modified_content = template_content 189 for placeholder, value in replacements.items(): 190 if value is not None: 191 modified_content = modified_content.replace(placeholder, str(value)) 192 193 # If no LLM provider, strip the model anchor line (keep model_provider) 194 llm_provider = options.get("llm_provider", "") 195 if not llm_provider: 196 modified_content = re.sub( 197 r"^\s*model: \*general_model\n", 198 "", 199 modified_content, 200 flags=re.MULTILINE, 201 ) 202 203 destination_path.parent.mkdir(parents=True, exist_ok=True) 204 with open(destination_path, "w", encoding="utf-8") as f: 205 f.write(modified_content) 206 207 click.echo(f" Created: {destination_path.relative_to(project_root)}") 208 return True 209 210 except FileNotFoundError: 211 click.echo(click.style("Error: Template file not found.", fg="red"), err=True) 212 return False 213 except IOError as e: 214 click.echo( 215 click.style(f"Error writing file {destination_path}: {e}", fg="red"), 216 err=True, 217 ) 218 return False 219 except Exception as e: 220 click.echo( 221 click.style( 222 f"An unexpected error occurred during Web UI Gateway configuration: {e}", 223 fg="red", 224 ), 225 err=True, 226 ) 227 return False