From 0b232bdb7cfa550a68dd75039b5fdf84028ad41f Mon Sep 17 00:00:00 2001 From: erew123 <35898566+erew123@users.noreply.github.com> Date: Wed, 27 Nov 2024 02:08:21 +0000 Subject: [PATCH] Added SSL Proxy --- config.py | 100 ++++++++++++++++++++++++++++++++++++++++++++++-------- script.py | 92 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 174 insertions(+), 18 deletions(-) diff --git a/config.py b/config.py index 905ed52..3bf4bae 100644 --- a/config.py +++ b/config.py @@ -6,7 +6,7 @@ import shutil from pathlib import Path from filelock import FileLock from types import SimpleNamespace -from dataclasses import dataclass +from dataclasses import dataclass, field from abc import ABC, abstractmethod from typing import Callable, Any, MutableSequence @@ -85,6 +85,7 @@ class AlltalkConfigDebug: debug_narrator: bool = False debug_gradio_IP: bool = False debug_transcribe: bool = False + debug_proxy: bool = False @dataclass class AlltalkConfigGradioPages: @@ -101,6 +102,48 @@ class AlltalkAvailableEngine: name = "" selected_model = "" +@dataclass +class AlltalkConfigProxyEndpoint: + enabled: bool = False + external_port: int = 0 + external_ip: str = "0.0.0.0" + cert_name: str = "" + + def to_dict(self): + return { + "enabled": self.enabled, + "external_port": self.external_port, + "external_ip": self.external_ip, + "cert_name": self.cert_name + } + +@dataclass +class AlltalkConfigProxySettings: + proxy_enabled: bool = False + start_on_startup: bool = False + gradio_endpoint: AlltalkConfigProxyEndpoint = field(default_factory=lambda: AlltalkConfigProxyEndpoint(external_port=444)) + api_endpoint: AlltalkConfigProxyEndpoint = field(default_factory=lambda: AlltalkConfigProxyEndpoint(external_port=443)) + cert_validation: bool = True + logging_enabled: bool = True + log_level: str = "INFO" + + def __post_init__(self): + # Handle conversion from dict to proper objects + if isinstance(self.gradio_endpoint, dict): + self.gradio_endpoint = AlltalkConfigProxyEndpoint(**self.gradio_endpoint) + if isinstance(self.api_endpoint, dict): + self.api_endpoint = AlltalkConfigProxyEndpoint(**self.api_endpoint) + + def to_dict(self): + return { + "proxy_enabled": self.proxy_enabled, + "start_on_startup": self.start_on_startup, + "gradio_endpoint": self.gradio_endpoint.to_dict(), + "api_endpoint": self.api_endpoint.to_dict(), + "cert_validation": self.cert_validation, + "logging_enabled": self.logging_enabled, + "log_level": self.log_level + } class AbstractJsonConfig(ABC): @@ -308,6 +351,7 @@ class AlltalkConfig(AbstractJsonConfig): self.api_def = AlltalkConfigApiDef() self.debugging = AlltalkConfigDebug() self.gradio_pages = AlltalkConfigGradioPages() + self.proxy_settings = AlltalkConfigProxySettings() self._load_config() @staticmethod @@ -334,7 +378,7 @@ class AlltalkConfig(AbstractJsonConfig): def _handle_loaded_config(self, data): from dataclasses import fields, is_dataclass, asdict - debug_me =False + debug_me = False if debug_me: print("=== Loading Config ===") print(f"Initial data state: {vars(data)}") @@ -346,25 +390,48 @@ class AlltalkConfig(AbstractJsonConfig): 'tgwui': AlltalkConfigTgwUi(), 'api_def': AlltalkConfigApiDef(), 'theme': AlltalkConfigTheme(), - 'gradio_pages': AlltalkConfigGradioPages() + 'gradio_pages': AlltalkConfigGradioPages(), + 'proxy_settings': AlltalkConfigProxySettings() } + if debug_me: print("\nDefault values for each class:") + for name, instance in default_instances.items(): if debug_me: - print(f"{name}: {asdict(instance)}") - # Show actual default values from dataclass + print(f"{name}: {asdict(instance)}") print(f"Default values: {[(f.name, getattr(instance, f.name)) for f in fields(instance)]}") + if hasattr(data, name): source = getattr(data, name) if debug_me: - print(f"Source data: {vars(source) if hasattr(source, '__dict__') else source}") + print(f"Source data for {name}: {vars(source) if hasattr(source, '__dict__') else source}") - for field in fields(instance): - if hasattr(source, field.name): - setattr(instance, field.name, getattr(source, field.name)) - if debug_me: - print(f"Field {field.name}: {getattr(instance, field.name)}") + # Special handling for proxy_settings due to nested structure + if name == 'proxy_settings' and hasattr(source, '__dict__'): + new_instance = AlltalkConfigProxySettings() + for field in fields(new_instance): + if hasattr(source, field.name): + field_value = getattr(source, field.name) + if field.name in ['gradio_endpoint', 'api_endpoint']: + # Handle nested endpoint objects + if isinstance(field_value, dict): + setattr(new_instance, field.name, + AlltalkConfigProxyEndpoint(**field_value)) + elif hasattr(field_value, '__dict__'): + setattr(new_instance, field.name, + AlltalkConfigProxyEndpoint(**field_value.__dict__)) + else: + setattr(new_instance, field.name, field_value) + instance = new_instance + else: + # Standard handling for other dataclasses + for field in fields(instance): + if hasattr(source, field.name): + setattr(instance, field.name, getattr(source, field.name)) + + if debug_me: + print(f"Processed instance {name}: {asdict(instance)}") setattr(self, name, instance) @@ -373,12 +440,13 @@ class AlltalkConfig(AbstractJsonConfig): if hasattr(self, n) and not n.startswith("__") and not is_dataclass(type(getattr(self, n))): setattr(self, n, v) + # Special handling for theme class/clazz as before self.theme.clazz = data.theme.__dict__.get("class", data.theme.__dict__.get("clazz", "")) self.get_output_directory().mkdir(parents=True, exist_ok=True) def to_dict(self): from dataclasses import is_dataclass, asdict - debug_me =False + debug_me = False if debug_me: print("=== Converting to dict ===") result = {} @@ -386,7 +454,10 @@ class AlltalkConfig(AbstractJsonConfig): for key, value in vars(self).items(): if not key.startswith('_'): # print(f"\nProcessing {key}:") - if is_dataclass(value): + if key == 'proxy_settings' and is_dataclass(value): + # Special handling for proxy settings + result[key] = value.to_dict() + elif is_dataclass(value): # print(f"Dataclass value before conversion: {vars(value)}") result[key] = asdict(value) # print(f"Converted to dict: {result[key]}") @@ -397,6 +468,7 @@ class AlltalkConfig(AbstractJsonConfig): # print(f"Regular value: {value}") result[key] = value + # Maintain existing theme handling exactly as before if 'theme' in result: if debug_me: print("\nProcessing theme:") @@ -409,5 +481,3 @@ class AlltalkConfig(AbstractJsonConfig): print(f"\nFinal dict: {result}") return result - - diff --git a/script.py b/script.py index 65bbdfc..2c0a93c 100644 --- a/script.py +++ b/script.py @@ -237,6 +237,8 @@ try: ) # TGWUI import from .system.gradio_pages.help_content import AllTalkHelpContent from .system.gradio_pages.alltalk_diskspace import get_disk_interface + from .system.proxy_module.proxy_manager import ProxyManager + from .system.proxy_module.interface import create_proxy_interface except ImportError: from config import ( AlltalkConfig, @@ -245,6 +247,8 @@ except ImportError: ) # Standalone import from system.gradio_pages.help_content import AllTalkHelpContent from system.gradio_pages.alltalk_diskspace import get_disk_interface + from system.proxy_module.proxy_manager import ProxyManager + from system.proxy_module.interface import create_proxy_interface def initialize_configs(): @@ -278,7 +282,8 @@ _state = { 'srv_engines_available': None, # The current TTS engines available, Initally loaded from central config and later pulled from the tts_server's API 'srv_current_engine_loaded': None, # The current TTS engines loaded in, Initally loaded from central config and later pulled from the tts_server's API 'gradio_languages_list': None, # The list of languauges disaplyed in the Gradio interface. - 'whisper_model': None, # Used to track the whisper model used for dictation etc + 'whisper_model': None, # Used to track the whisper model used for dictation etc + 'proxy_manager': None # Used for the Proxy manager } ############################################################ @@ -638,6 +643,64 @@ def update_rvc_settings( print_message(error_msg, message_type="error") return return_message +def update_proxy_settings( + proxy_enabled, + start_on_startup, + gradio_proxy_enabled, + api_proxy_enabled, + external_ip, + gradio_cert_name, + api_cert_name, + cert_validation, + logging_enabled, + log_level +): + """Update proxy settings using the centralized config system""" + debug_func_entry() + try: + # Get the current config instance + config = AlltalkConfig.get_instance() + + # Update proxy settings + config.proxy_settings.proxy_enabled = proxy_enabled + config.proxy_settings.start_on_startup = start_on_startup + config.proxy_settings.gradio_proxy_enabled = gradio_proxy_enabled + config.proxy_settings.api_proxy_enabled = api_proxy_enabled + config.proxy_settings.external_ip = external_ip + config.proxy_settings.gradio_cert_name = gradio_cert_name + config.proxy_settings.api_cert_name = api_cert_name + config.proxy_settings.cert_validation = cert_validation + config.proxy_settings.logging_enabled = logging_enabled + config.proxy_settings.log_level = log_level + + # Save the updated configuration + config.save() + + print_message("Proxy Settings Saved") + return "Proxy settings updated successfully!" + except Exception as e: + print_message(f"Error updating proxy settings: {str(e)}", message_type="error") + return f"Error updating proxy settings: {str(e)}" + +# Add to your state dictionary initialization +def initialize_proxy_state(_state): + """Initialize proxy state""" + config = AlltalkConfig.get_instance() + _state['proxy_process'] = None + _state['proxy_status'] = 'stopped' + _state['proxy_enabled'] = config.proxy_settings.proxy_enabled + _state['proxy_gradio_enabled'] = config.proxy_settings.gradio_proxy_enabled + _state['proxy_api_enabled'] = config.proxy_settings.api_proxy_enabled + return _state + +# Modify your existing initialize_engine_state function: +def initialize_engine_state(_state): + """Initialize engine state from central config""" + _state = initialize_proxy_state(_state) # Add proxy initialization + _state['srv_current_engine_loaded'] = tts_engines_config.engine_loaded + _state['srv_engines_available'] = tts_engines_config.get_engine_names_available() + _state['srv_current_model_loaded'] = tts_engines_config.selected_model + return _state ########################################################################### # START-UP # Silence Character Normaliser when it checks the Ready Status # @@ -1625,7 +1688,14 @@ def send_reload_request(value_sent): params = {"tts_method": value_sent} return send_api_request("/api/reload", params=params) - +################################# +#### Proxy Interface Manager #### +################################# +if _state.get('proxy_manager') is None: + _state['proxy_manager'] = ProxyManager(AlltalkConfig) + if config.proxy_settings.proxy_enabled and config.proxy_settings.start_on_startup: + _state['proxy_manager'].start_proxy() + ######################################## #### Whisper Transcription Handling #### ######################################## @@ -4675,6 +4745,22 @@ if gradio_enabled is True: elem_classes="custom-markdown", ) + with gr.Tab("SSL Proxy Server"): + _proxy_interface = create_proxy_interface(_state['proxy_manager']) + with gr.Accordion("HELP - 🎯 Proxy Quick Start Guide", open=False): + gr.Markdown( + AllTalkHelpContent.PROXY, elem_classes="custom-markdown" + ) + with gr.Row(): + gr.Markdown( + AllTalkHelpContent.PROXY1, + elem_classes="custom-markdown", + ) + gr.Markdown( + AllTalkHelpContent.PROXY2, + elem_classes="custom-markdown", + ) + with gr.Tab("Text-generation-webui Settings"): with gr.Row(): activate = gr.Dropdown( @@ -4750,7 +4836,7 @@ if gradio_enabled is True: ) disk_space_page = get_disk_interface() - disk_space_page() + disk_space_page() if config.gradio_pages.TTS_Engines_Settings_page: with gr.Tab("TTS Engines Settings"):