diff --git a/.jules/palette.md b/.jules/palette.md index 7f59acf..c984702 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -15,3 +15,7 @@ ## 2024-05-24 - Interactive Path Completion in CLI **Learning:** When asking for filesystem paths in the CLI, standard text inputs lead to typos and user frustration. Using specialized path inputs with auto-completion significantly improves the installation experience. **Action:** Always use specialized path input widgets (like `questionary.path` with `only_directories=True`) instead of generic text inputs when prompting users for file or directory locations. + +## 2024-05-18 - Visual Feedback for Blocking CLI Operations +**Learning:** Users perceive frozen or slow CLI applications as broken. During operations that require network requests or blocking subprocesses, providing immediate visual feedback is crucial to UX. +**Action:** Wrap blocking operations (like API calls or subprocesses) in `rich.console.status("...", spinner="dots")` context managers to display a loading spinner. diff --git a/src/ledgermind/server/cli.py b/src/ledgermind/server/cli.py index a2300a7..131012d 100644 --- a/src/ledgermind/server/cli.py +++ b/src/ledgermind/server/cli.py @@ -328,9 +328,6 @@ def init_project(path: str): continue # Test model availability via API call - global_console.print( - f"Validating model [bold cyan]{enrichment_model}[/bold cyan] via OpenRouter API..." - ) try: import httpx @@ -346,17 +343,21 @@ def init_project(path: str): "max_tokens": 10, } - response = httpx.post( - "https://openrouter.ai/api/v1/chat/completions", - headers={ - "Authorization": f"Bearer {openrouter_api_key}", - "Content-Type": "application/json", - "HTTP-Referer": "https://github.com/sl4m3/ledgermind", - "X-Title": "LedgerMind Setup", - }, - json=test_payload, - timeout=60, - ) + with global_console.status( + f"Validating model [bold cyan]{enrichment_model}[/bold cyan] via OpenRouter API...", + spinner="dots" + ): + response = httpx.post( + "https://openrouter.ai/api/v1/chat/completions", + headers={ + "Authorization": f"Bearer {openrouter_api_key}", + "Content-Type": "application/json", + "HTTP-Referer": "https://github.com/sl4m3/ledgermind", + "X-Title": "LedgerMind Setup", + }, + json=test_payload, + timeout=60, + ) if response.status_code == 200: result = response.json() @@ -438,9 +439,6 @@ def init_project(path: str): break # Validation - global_console.print( - f"Validating model [bold cyan]{enrichment_model}[/bold cyan] via {client}..." - ) try: import subprocess import shutil @@ -478,7 +476,11 @@ def init_project(path: str): ] # We use a longer timeout for validation because APIs can be slow - result = subprocess.run(cmd, capture_output=True, text=True, timeout=60) # nosec B603 + with global_console.status( + f"Validating model [bold cyan]{enrichment_model}[/bold cyan] via {client}...", + spinner="dots" + ): + result = subprocess.run(cmd, capture_output=True, text=True, timeout=60) # nosec B603 if result.returncode == 0: global_console.print( f"[green]✓ Model {enrichment_model} is available and responsive.[/green]" @@ -556,9 +558,6 @@ def init_project(path: str): break # Validate model with test request - global_console.print( - f"Validating model [bold cyan]{aistudio_model}[/bold cyan] via Google AI Studio..." - ) try: import requests @@ -571,9 +570,13 @@ def init_project(path: str): }, } - response = requests.post( - api_url, params={"key": api_key}, json=test_body, timeout=30 - ) + with global_console.status( + f"Validating model [bold cyan]{aistudio_model}[/bold cyan] via Google AI Studio...", + spinner="dots" + ): + response = requests.post( + api_url, params={"key": api_key}, json=test_body, timeout=30 + ) if response.status_code == 200: result = response.json()