Skip to content

Commit 0c1bc46

Browse files
committed
Fixed ngrok issues
1 parent 2dc7e90 commit 0c1bc46

File tree

3 files changed

+176
-130
lines changed

3 files changed

+176
-130
lines changed

locallab/cli/interactive.py

Lines changed: 137 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def get_missing_required_env_vars() -> List[str]:
4343

4444
return missing
4545

46-
def prompt_for_config(use_ngrok: bool = None, port: int = None, ngrok_auth_token: str = None, force_reconfigure: bool = False) -> Dict[str, Any]:
46+
def prompt_for_config(use_ngrok: bool = None, port: int = None, ngrok_auth_token: Optional[str] = None, force_reconfigure: bool = False) -> Dict[str, Any]:
4747
"""
4848
Interactive prompt for configuration
4949
"""
@@ -59,105 +59,153 @@ def prompt_for_config(use_ngrok: bool = None, port: int = None, ngrok_auth_token
5959
# Override with provided parameters
6060
if use_ngrok is not None:
6161
config["use_ngrok"] = use_ngrok
62+
# Set environment variable for use_ngrok
63+
os.environ["LOCALLAB_USE_NGROK"] = str(use_ngrok).lower()
64+
6265
if port is not None:
6366
config["port"] = port
67+
os.environ["LOCALLAB_PORT"] = str(port)
68+
6469
if ngrok_auth_token is not None:
6570
config["ngrok_auth_token"] = ngrok_auth_token
71+
os.environ["NGROK_AUTHTOKEN"] = ngrok_auth_token
6672

6773
# Determine if we're in Colab
6874
in_colab = is_in_colab()
6975

70-
# If in Colab, use simplified configuration
71-
if in_colab:
72-
# Set default values for Colab environment
73-
config.setdefault("port", 8000)
74-
config.setdefault("use_ngrok", True)
75-
config.setdefault("model_id", os.environ.get("HUGGINGFACE_MODEL", DEFAULT_MODEL))
76-
77-
# Use ngrok token from environment if available
78-
if os.environ.get("NGROK_AUTH_TOKEN"):
79-
config["ngrok_auth_token"] = os.environ.get("NGROK_AUTH_TOKEN")
80-
elif ngrok_auth_token:
81-
config["ngrok_auth_token"] = ngrok_auth_token
82-
83-
# Set some reasonable defaults for Colab
84-
config.setdefault("enable_quantization", True)
85-
config.setdefault("quantization_type", "int8")
86-
config.setdefault("enable_attention_slicing", True)
87-
config.setdefault("enable_flash_attention", True)
88-
config.setdefault("enable_better_transformer", True)
89-
90-
return config
91-
92-
# Check for GPU
93-
has_gpu = False
94-
gpu_memory = get_gpu_memory()
95-
if gpu_memory:
96-
has_gpu = True
97-
total_gpu_memory, free_gpu_memory = gpu_memory
98-
click.echo(f"🎮 GPU detected with {free_gpu_memory}MB free of {total_gpu_memory}MB total")
99-
else:
100-
click.echo("⚠️ No GPU detected. Running on CPU will be significantly slower.")
101-
102-
# Get system memory
103-
total_memory, free_memory = get_system_memory()
104-
click.echo(f"💾 System memory: {free_memory}MB free of {total_memory}MB total")
105-
106-
# Check for missing required environment variables
107-
missing_vars = get_missing_required_env_vars()
108-
109-
# Check if we have all required configuration and not forcing reconfiguration
110-
has_model = "model_id" in config or os.environ.get("HUGGINGFACE_MODEL") or os.environ.get("DEFAULT_MODEL")
111-
has_port = "port" in config or port is not None
112-
has_ngrok_config = not in_colab or not config.get("use_ngrok", use_ngrok) or "ngrok_auth_token" in config or ngrok_auth_token is not None or os.environ.get("NGROK_AUTH_TOKEN")
113-
114-
# If we have all required config and not forcing reconfiguration, return early
115-
if not force_reconfigure and has_model and has_port and has_ngrok_config and not missing_vars:
116-
# Ensure port is set in config
117-
if "port" not in config and port is not None:
118-
config["port"] = port
119-
# Ensure use_ngrok is set in config
120-
if "use_ngrok" not in config and use_ngrok is not None:
121-
config["use_ngrok"] = use_ngrok
122-
# Ensure ngrok_auth_token is set in config if needed
123-
if config.get("use_ngrok", False) and "ngrok_auth_token" not in config and ngrok_auth_token is not None:
124-
config["ngrok_auth_token"] = ngrok_auth_token
125-
126-
return config
127-
76+
# If in Colab, ensure ngrok is enabled by default
77+
if in_colab and "use_ngrok" not in config:
78+
config["use_ngrok"] = True
79+
os.environ["LOCALLAB_USE_NGROK"] = "true"
80+
12881
click.echo("\n🚀 Welcome to LocalLab! Let's set up your server.\n")
12982

130-
# Always ask for model when reconfiguring or if not provided
83+
# Basic Configuration
84+
# ------------------
85+
click.echo("\n📋 Basic Configuration")
86+
click.echo("─────────────────────")
87+
88+
# Model selection
13189
model_id = click.prompt(
13290
"📦 Which model would you like to use?",
13391
default=config.get("model_id", DEFAULT_MODEL)
13492
)
135-
os.environ["HUGGINGFACE_MODEL"] = model_id
13693
config["model_id"] = model_id
13794

138-
# Always ask for port when reconfiguring or if not provided
95+
# Port configuration
13996
port = click.prompt(
14097
"🔌 Which port would you like to run on?",
14198
default=config.get("port", 8000),
14299
type=int
143100
)
144101
config["port"] = port
145102

146-
# Ask about ngrok
103+
# Model Optimization Settings
104+
# -------------------------
105+
click.echo("\n⚡ Model Optimization Settings")
106+
click.echo("─────────────────────────────")
107+
108+
config["enable_quantization"] = click.confirm(
109+
"Enable model quantization?",
110+
default=config.get("enable_quantization", ENABLE_QUANTIZATION)
111+
)
112+
113+
if config["enable_quantization"]:
114+
config["quantization_type"] = click.prompt(
115+
"Quantization type (fp16/int8/int4)",
116+
default=config.get("quantization_type", QUANTIZATION_TYPE),
117+
type=click.Choice(["fp16", "int8", "int4"])
118+
)
119+
120+
config["enable_cpu_offloading"] = click.confirm(
121+
"Enable CPU offloading?",
122+
default=config.get("enable_cpu_offloading", ENABLE_CPU_OFFLOADING)
123+
)
124+
125+
config["enable_attention_slicing"] = click.confirm(
126+
"Enable attention slicing?",
127+
default=config.get("enable_attention_slicing", ENABLE_ATTENTION_SLICING)
128+
)
129+
130+
config["enable_flash_attention"] = click.confirm(
131+
"Enable flash attention?",
132+
default=config.get("enable_flash_attention", ENABLE_FLASH_ATTENTION)
133+
)
134+
135+
config["enable_better_transformer"] = click.confirm(
136+
"Enable better transformer?",
137+
default=config.get("enable_bettertransformer", ENABLE_BETTERTRANSFORMER)
138+
)
139+
140+
# Advanced Settings
141+
# ----------------
142+
click.echo("\n⚙️ Advanced Settings")
143+
click.echo("──────────────────")
144+
145+
config["model_timeout"] = click.prompt(
146+
"Model timeout (seconds)",
147+
default=config.get("model_timeout", 3600),
148+
type=int
149+
)
150+
151+
# Cache Settings
152+
# -------------
153+
click.echo("\n💾 Cache Settings")
154+
click.echo("────────────────")
155+
156+
config["enable_cache"] = click.confirm(
157+
"Enable response caching?",
158+
default=config.get("enable_cache", True)
159+
)
160+
161+
if config["enable_cache"]:
162+
config["cache_ttl"] = click.prompt(
163+
"Cache TTL (seconds)",
164+
default=config.get("cache_ttl", 3600),
165+
type=int
166+
)
167+
168+
# Logging Settings
169+
# ---------------
170+
click.echo("\n📝 Logging Settings")
171+
click.echo("──────────────────")
172+
173+
config["log_level"] = click.prompt(
174+
"Log level",
175+
default=config.get("log_level", "INFO"),
176+
type=click.Choice(["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"])
177+
)
178+
179+
config["enable_file_logging"] = click.confirm(
180+
"Enable file logging?",
181+
default=config.get("enable_file_logging", False)
182+
)
183+
184+
if config["enable_file_logging"]:
185+
config["log_file"] = click.prompt(
186+
"Log file path",
187+
default=config.get("log_file", "locallab.log")
188+
)
189+
190+
# Ngrok Configuration
191+
# ------------------
192+
click.echo("\n🌐 Ngrok Configuration")
193+
click.echo("────────────────────")
194+
147195
use_ngrok = click.confirm(
148-
"🌐 Do you want to enable public access via ngrok?",
196+
"Enable public access via ngrok?",
149197
default=config.get("use_ngrok", in_colab)
150198
)
151199
config["use_ngrok"] = use_ngrok
200+
os.environ["LOCALLAB_USE_NGROK"] = str(use_ngrok).lower()
152201

153202
if use_ngrok:
154-
# Show current token if exists
155203
current_token = config.get("ngrok_auth_token") or get_env_var(NGROK_TOKEN_ENV)
156204
if current_token:
157205
click.echo(f"\nCurrent ngrok token: {current_token}")
158206

159207
ngrok_auth_token = click.prompt(
160-
"🔑 Enter your ngrok auth token (get one at https://dashboard.ngrok.com/get-started/your-authtoken)",
208+
"Enter your ngrok auth token (get one at https://dashboard.ngrok.com/get-started/your-authtoken)",
161209
default=current_token,
162210
type=str,
163211
show_default=True
@@ -166,18 +214,26 @@ def prompt_for_config(use_ngrok: bool = None, port: int = None, ngrok_auth_token
166214
if ngrok_auth_token:
167215
token_str = str(ngrok_auth_token).strip()
168216
config["ngrok_auth_token"] = token_str
169-
set_env_var(NGROK_TOKEN_ENV, token_str)
170-
click.echo(f"✅ Ngrok token saved: {token_str}")
217+
# Set both environment variables to ensure compatibility
218+
os.environ["NGROK_AUTHTOKEN"] = token_str
219+
os.environ["LOCALLAB_NGROK_AUTH_TOKEN"] = token_str
220+
221+
# Save immediately to ensure persistence
222+
from .config import save_config
223+
save_config(config)
224+
click.echo(f"✅ Ngrok token saved and activated")
225+
226+
# HuggingFace Token
227+
# ----------------
228+
click.echo("\n🤗 HuggingFace Token")
229+
click.echo("──────────────────")
171230

172-
# Ask about HuggingFace token
173231
current_hf_token = config.get("huggingface_token") or get_env_var(HF_TOKEN_ENV)
174232
if current_hf_token:
175-
click.echo(f"\nCurrent HuggingFace token: {current_hf_token}")
233+
click.echo(f"Current HuggingFace token: {current_hf_token}")
176234

177235
if not current_hf_token or force_reconfigure:
178-
click.echo("\n🔑 HuggingFace Token Configuration")
179-
click.echo("───────────────────────────────")
180-
click.echo("A token is required to download models like microsoft/phi-2")
236+
click.echo("\nA token is required to download models.")
181237
click.echo("Get your token from: https://huggingface.co/settings/tokens")
182238

183239
hf_token = click.prompt(
@@ -190,16 +246,14 @@ def prompt_for_config(use_ngrok: bool = None, port: int = None, ngrok_auth_token
190246
if hf_token:
191247
if len(hf_token) < 20:
192248
click.echo("❌ Invalid token format. Token should be longer than 20 characters.")
193-
return config
194-
195-
token_str = str(hf_token).strip()
196-
config["huggingface_token"] = token_str
197-
set_env_var(HF_TOKEN_ENV, token_str)
198-
click.echo(f"✅ HuggingFace token saved: {token_str}")
199-
200-
# Save immediately
201-
from .config import save_config
202-
save_config(config)
249+
else:
250+
token_str = str(hf_token).strip()
251+
config["huggingface_token"] = token_str
252+
set_env_var(HF_TOKEN_ENV, token_str)
253+
254+
# Save immediately
255+
from .config import save_config
256+
save_config(config)
203257
else:
204258
click.echo("\n⚠️ No token provided. Some models may not be accessible.")
205259

locallab/server.py

Lines changed: 24 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -639,81 +639,60 @@ def _initialize_lifespan(self):
639639

640640

641641
def start_server(use_ngrok: bool = None, port: int = None, ngrok_auth_token: Optional[str] = None):
642-
643642
try:
644643
set_server_status("initializing")
645644

646645
print_initializing_banner(__version__)
647646

647+
# Load configuration
648648
from .cli.config import load_config, set_config_value
649649

650650
try:
651651
saved_config = load_config()
652652
except Exception as e:
653653
logger.warning(f"Error loading configuration: {str(e)}. Using defaults.")
654654
saved_config = {}
655+
656+
# Set up ngrok configuration
657+
use_ngrok = (
658+
use_ngrok if use_ngrok is not None
659+
else saved_config.get("use_ngrok", False)
660+
or os.environ.get("LOCALLAB_USE_NGROK", "").lower() == "true"
661+
)
655662

656-
for key, value in saved_config.items():
657-
if key == "model_id":
658-
os.environ["HUGGINGFACE_MODEL"] = str(value)
659-
elif key == "ngrok_auth_token":
660-
os.environ["NGROK_AUTH_TOKEN"] = str(value)
661-
elif key == "huggingface_token":
662-
os.environ["HUGGINGFACE_TOKEN"] = str(value)
663-
elif key in ["enable_quantization", "enable_attention_slicing", "enable_flash_attention",
664-
"enable_better_transformer", "enable_cpu_offloading", "enable_cache",
665-
"enable_file_logging"]:
666-
env_key = f"LOCALLAB_{key.upper()}"
667-
os.environ[env_key] = str(value).lower()
668-
elif key in ["quantization_type", "model_timeout", "cache_ttl", "log_level", "log_file"]:
669-
env_key = f"LOCALLAB_{key.upper()}"
670-
os.environ[env_key] = str(value)
671-
672-
config = prompt_for_config(use_ngrok, port, ngrok_auth_token)
673-
674-
save_config(config)
675-
676-
use_ngrok = config.get("use_ngrok", use_ngrok)
677-
port = config.get("port", port or 8000)
678-
ngrok_auth_token = config.get("ngrok_auth_token", ngrok_auth_token)
679-
680-
if is_port_in_use(port):
681-
logger.warning(f"Port {port} is already in use. Trying to find another port...")
682-
for p in range(port+1, port+100):
683-
if not is_port_in_use(p):
684-
port = p
685-
logger.info(f"Using alternative port: {port}")
686-
break
687-
else:
688-
raise RuntimeError(f"Could not find an available port in range {port}-{port+100}")
663+
# Get port configuration
664+
port = port or saved_config.get("port", None) or int(os.environ.get("LOCALLAB_PORT", "8000"))
689665

666+
# Handle ngrok auth token
667+
if ngrok_auth_token:
668+
os.environ["NGROK_AUTHTOKEN"] = ngrok_auth_token
669+
elif saved_config.get("ngrok_auth_token"):
670+
os.environ["NGROK_AUTHTOKEN"] = saved_config["ngrok_auth_token"]
671+
672+
# Set up ngrok if enabled
690673
public_url = None
691674
if use_ngrok:
692675
os.environ["LOCALLAB_USE_NGROK"] = "true"
693676

694-
if not ngrok_auth_token and not os.environ.get("NGROK_AUTH_TOKEN"):
677+
if not os.environ.get("NGROK_AUTHTOKEN"):
695678
logger.error("Ngrok auth token is required for public access. Please set it in the configuration.")
696679
logger.info("You can get a free token from: https://dashboard.ngrok.com/get-started/your-authtoken")
697680
raise ValueError("Ngrok auth token is required for public access")
698681

699-
logger.info(f"{Fore.CYAN}Setting up ngrok tunnel to port {port}...{Style.RESET_ALL}")
700-
public_url = setup_ngrok(port=port, auth_token=ngrok_auth_token or os.environ.get("NGROK_AUTH_TOKEN"))
682+
logger.info(f"Setting up ngrok tunnel to port {port}...")
683+
public_url = setup_ngrok(port)
684+
701685
if public_url:
702686
os.environ["LOCALLAB_NGROK_URL"] = public_url
703687

704688
ngrok_section = f"\n{Fore.CYAN}┌────────────────────────── Ngrok Tunnel Details ─────────────────────────────┐{Style.RESET_ALL}\n\n│ 🚀 Ngrok Public URL: {Fore.GREEN}{public_url}{Style.RESET_ALL}\n\n{Fore.CYAN}└──────────────────────────────────────────────────────────────────────────────┘{Style.RESET_ALL}\n"
705689
print(ngrok_section)
706-
707690
else:
708-
709-
710-
711-
logger.warning(f"{Fore.YELLOW}Failed to set up ngrok tunnel. Server will run locally on port {port}.{Style.RESET_ALL}")
712-
713-
691+
logger.error(f"Failed to set up ngrok tunnel. Server will run locally on port {port}.")
692+
raise RuntimeError("Failed to set up ngrok tunnel")
714693
else:
715-
# Set environment variable to indicate ngrok is not enabled
716694
os.environ["LOCALLAB_USE_NGROK"] = "false"
695+
717696
# Set environment variable with the port
718697
os.environ["LOCALLAB_PORT"] = str(port)
719698
# Server info section

0 commit comments

Comments
 (0)