sigma-terminal 2.0.1__py3-none-any.whl → 3.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
sigma/setup.py CHANGED
@@ -1,455 +1,358 @@
1
- """Sigma Setup Wizard - Beautiful first-run configuration experience."""
1
+ """Sigma v3.2.0 - Setup Wizard."""
2
2
 
3
3
  import os
4
4
  import sys
5
- import time
5
+ import subprocess
6
6
  from pathlib import Path
7
7
  from typing import Optional
8
8
 
9
9
  from rich.console import Console
10
10
  from rich.panel import Panel
11
11
  from rich.prompt import Prompt, Confirm
12
- from rich.progress import Progress, SpinnerColumn, TextColumn
13
12
  from rich.table import Table
14
13
  from rich.text import Text
15
- from rich import box
16
-
17
- console = Console()
18
-
19
- # Config directory
20
- CONFIG_DIR = Path.home() / ".sigma"
21
- CONFIG_FILE = CONFIG_DIR / "config.env"
22
- SETUP_COMPLETE_FILE = CONFIG_DIR / ".setup_complete"
23
14
 
15
+ from .config import (
16
+ get_settings,
17
+ save_api_key,
18
+ save_setting,
19
+ LLMProvider,
20
+ AVAILABLE_MODELS,
21
+ CONFIG_DIR,
22
+ )
24
23
 
25
- def is_setup_complete() -> bool:
26
- """Check if setup has been completed."""
27
- return SETUP_COMPLETE_FILE.exists()
28
24
 
25
+ __version__ = "3.2.0"
26
+ SIGMA = "σ"
27
+ console = Console()
29
28
 
30
- def clear_screen():
31
- """Clear the terminal screen."""
32
- os.system('cls' if os.name == 'nt' else 'clear')
33
-
29
+ # Clean banner - just SIGMA, no SETU
30
+ BANNER = """
31
+ [bold blue]███████╗██╗ ██████╗ ███╗ ███╗ █████╗ [/bold blue]
32
+ [bold blue]██╔════╝██║██╔════╝ ████╗ ████║██╔══██╗[/bold blue]
33
+ [bold blue]███████╗██║██║ ███╗██╔████╔██║███████║[/bold blue]
34
+ [bold blue]╚════██║██║██║ ██║██║╚██╔╝██║██╔══██║[/bold blue]
35
+ [bold blue]███████║██║╚██████╔╝██║ ╚═╝ ██║██║ ██║[/bold blue]
36
+ [bold blue]╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝[/bold blue]
34
37
 
35
- def print_logo():
36
- """Print the Sigma logo."""
37
- logo = """
38
- [bold bright_cyan]
39
- ███████╗██╗ ██████╗ ███╗ ███╗ █████╗
40
- ██╔════╝██║██╔════╝ ████╗ ████║██╔══██╗
41
- ███████╗██║██║ ███╗██╔████╔██║███████║
42
- ╚════██║██║██║ ██║██║╚██╔╝██║██╔══██║
43
- ███████║██║╚██████╔╝██║ ╚═╝ ██║██║ ██║
44
- ╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝
45
- [/bold bright_cyan]
38
+ [bold cyan]σ Finance Research Agent[/bold cyan] [dim]- Setup Wizard v3.2.0[/dim]
46
39
  """
47
- console.print(logo)
48
-
49
-
50
- def animate_text(text: str, delay: float = 0.02):
51
- """Animate text character by character."""
52
- for char in text:
53
- console.print(char, end="", highlight=False)
54
- time.sleep(delay)
55
- console.print()
56
-
57
-
58
- def show_welcome():
59
- """Show the welcome screen."""
60
- clear_screen()
61
- print_logo()
62
-
63
- console.print()
64
- console.print(Panel(
65
- "[bold]Welcome to Sigma[/bold]\n\n"
66
- "[dim]The Institutional-Grade Financial Research Agent[/dim]\n\n"
67
- "This setup wizard will help you configure Sigma for\n"
68
- "optimal performance. It only takes about 2 minutes.",
69
- title="[bold bright_green]Setup Wizard[/bold bright_green]",
70
- border_style="bright_green",
71
- padding=(1, 2)
72
- ))
73
- console.print()
74
-
75
- Prompt.ask("[dim]Press Enter to begin[/dim]", default="")
76
-
77
-
78
- def show_progress_step(step: int, total: int, title: str):
79
- """Show progress header."""
80
- console.print()
81
- console.print(f"[bold bright_cyan]Step {step}/{total}:[/bold bright_cyan] {title}")
82
- console.print("[dim]" + "─" * 50 + "[/dim]")
83
- console.print()
84
40
 
85
41
 
86
- def setup_llm_provider() -> dict:
87
- """Configure LLM provider."""
88
- clear_screen()
89
- print_logo()
90
- show_progress_step(1, 4, "Choose Your AI Model")
91
-
92
- providers = [
93
- ("google", "Google Gemini", "Free tier available, fast responses", "GOOGLE_API_KEY"),
94
- ("openai", "OpenAI GPT-4", "Most capable, best for complex analysis", "OPENAI_API_KEY"),
95
- ("anthropic", "Anthropic Claude", "Excellent reasoning, very safe", "ANTHROPIC_API_KEY"),
96
- ("groq", "Groq (Llama)", "Extremely fast, free tier available", "GROQ_API_KEY"),
97
- ("xai", "xAI Grok", "Real-time knowledge, unique insights", "XAI_API_KEY"),
98
- ("ollama", "Ollama (Local)", "Free, private, runs on your machine", None),
99
- ]
100
-
101
- table = Table(box=box.ROUNDED, border_style="bright_blue")
102
- table.add_column("#", style="bold cyan", justify="center", width=3)
103
- table.add_column("Provider", style="bold")
104
- table.add_column("Description", style="dim")
105
-
106
- for i, (key, name, desc, _) in enumerate(providers, 1):
107
- table.add_row(str(i), name, desc)
108
-
109
- console.print(table)
110
- console.print()
111
-
112
- choice = Prompt.ask(
113
- "[bold]Select your preferred AI provider[/bold]",
114
- choices=[str(i) for i in range(1, len(providers) + 1)],
115
- default="1"
116
- )
117
-
118
- selected = providers[int(choice) - 1]
119
- provider_key, provider_name, _, env_key = selected
120
-
121
- config = {"DEFAULT_PROVIDER": provider_key}
122
-
123
- console.print()
124
- console.print(f"[green]Selected:[/green] {provider_name}")
125
-
126
- if env_key:
42
+ class SetupWizard:
43
+ """Interactive setup wizard."""
44
+
45
+ def __init__(self):
46
+ self.settings = get_settings()
47
+ self.providers = {
48
+ LLMProvider.GOOGLE: {
49
+ "name": "Google Gemini",
50
+ "models": AVAILABLE_MODELS.get("google", []),
51
+ "url": "https://aistudio.google.com/apikey",
52
+ "free": True,
53
+ "desc": "Fast, capable, free tier",
54
+ "recommended": True,
55
+ },
56
+ LLMProvider.OPENAI: {
57
+ "name": "OpenAI GPT",
58
+ "models": AVAILABLE_MODELS.get("openai", []),
59
+ "url": "https://platform.openai.com/api-keys",
60
+ "free": False,
61
+ "desc": "Industry standard",
62
+ },
63
+ LLMProvider.ANTHROPIC: {
64
+ "name": "Anthropic Claude",
65
+ "models": AVAILABLE_MODELS.get("anthropic", []),
66
+ "url": "https://console.anthropic.com/",
67
+ "free": False,
68
+ "desc": "Advanced reasoning",
69
+ },
70
+ LLMProvider.GROQ: {
71
+ "name": "Groq (Llama)",
72
+ "models": AVAILABLE_MODELS.get("groq", []),
73
+ "url": "https://console.groq.com/keys",
74
+ "free": True,
75
+ "desc": "Ultra-fast, free tier",
76
+ "recommended": True,
77
+ },
78
+ LLMProvider.XAI: {
79
+ "name": "xAI Grok",
80
+ "models": AVAILABLE_MODELS.get("xai", []),
81
+ "url": "https://console.x.ai/",
82
+ "free": False,
83
+ "desc": "X.com AI",
84
+ },
85
+ LLMProvider.OLLAMA: {
86
+ "name": "Ollama (Local)",
87
+ "models": AVAILABLE_MODELS.get("ollama", []),
88
+ "url": "https://ollama.ai/download",
89
+ "free": True,
90
+ "desc": "Run locally, no API key",
91
+ },
92
+ }
93
+
94
+ def run(self) -> bool:
95
+ """Run setup wizard."""
96
+ console.clear()
97
+ console.print(BANNER)
127
98
  console.print()
99
+
128
100
  console.print(Panel(
129
- f"[bold]Get your API key:[/bold]\n\n"
130
- f"{'https://aistudio.google.com/apikey' if provider_key == 'google' else ''}"
131
- f"{'https://platform.openai.com/api-keys' if provider_key == 'openai' else ''}"
132
- f"{'https://console.anthropic.com/settings/keys' if provider_key == 'anthropic' else ''}"
133
- f"{'https://console.groq.com/keys' if provider_key == 'groq' else ''}"
134
- f"{'https://console.x.ai/' if provider_key == 'xai' else ''}",
135
- title=f"[bold yellow]{provider_name} API Key[/bold yellow]",
136
- border_style="yellow"
101
+ "[bold]Welcome to Sigma Setup[/bold]\n\n"
102
+ "This wizard will configure Sigma for first use.\n"
103
+ f"Configuration stored in [cyan]~/.sigma/[/cyan]\n\n"
104
+ "[bold]Steps:[/bold]\n"
105
+ " 1. Choose AI provider\n"
106
+ " 2. Configure API key\n"
107
+ " 3. Select model\n"
108
+ " 4. Data settings\n"
109
+ " 5. Optional: Ollama, LEAN",
110
+ title=f"[cyan]{SIGMA} Setup[/cyan]",
111
+ border_style="blue",
137
112
  ))
138
113
  console.print()
139
114
 
140
- api_key = Prompt.ask(
141
- f"[bold]Enter your {provider_name} API key[/bold]",
142
- password=True
115
+ if not Confirm.ask("Ready to begin?", default=True):
116
+ console.print("[dim]Cancelled.[/dim]")
117
+ return False
118
+
119
+ console.print()
120
+
121
+ # Steps
122
+ self._setup_provider()
123
+ console.print()
124
+ self._setup_api_key()
125
+ console.print()
126
+ self._setup_model()
127
+ console.print()
128
+ self._setup_data()
129
+ console.print()
130
+ self._setup_integrations()
131
+ console.print()
132
+ self._show_summary()
133
+
134
+ return True
135
+
136
+ def _setup_provider(self):
137
+ """Choose AI provider."""
138
+ console.print(Panel("[bold]Step 1: AI Provider[/bold]", border_style="blue"))
139
+ console.print()
140
+
141
+ providers = list(self.providers.keys())
142
+
143
+ for i, p in enumerate(providers, 1):
144
+ info = self.providers[p]
145
+ name = info["name"]
146
+ desc = info["desc"]
147
+ free = "[green]free[/green]" if info.get("free") else "[yellow]paid[/yellow]"
148
+ rec = " [cyan](recommended)[/cyan]" if info.get("recommended") else ""
149
+ console.print(f" {i}. [bold]{name}[/bold] - {desc} {free}{rec}")
150
+
151
+ console.print()
152
+ choice = Prompt.ask(
153
+ "Choose provider",
154
+ choices=[str(i) for i in range(1, len(providers) + 1)],
155
+ default="1"
143
156
  )
157
+
158
+ provider = providers[int(choice) - 1]
159
+ save_setting("default_provider", provider.value)
160
+ self.settings.default_provider = provider
161
+
162
+ console.print(f"[cyan]{SIGMA}[/cyan] Provider: [bold]{self.providers[provider]['name']}[/bold]")
163
+
164
+ def _setup_api_key(self):
165
+ """Configure API key."""
166
+ console.print(Panel("[bold]Step 2: API Key[/bold]", border_style="blue"))
167
+ console.print()
168
+
169
+ provider = self.settings.default_provider
170
+ info = self.providers[provider]
171
+
172
+ if provider == LLMProvider.OLLAMA:
173
+ console.print("[dim]Ollama runs locally - no API key needed.[/dim]")
174
+ if Confirm.ask("Is Ollama installed?", default=True):
175
+ console.print(f"[cyan]{SIGMA}[/cyan] Ollama configured")
176
+ else:
177
+ console.print(f"Install from: [bold]{info['url']}[/bold]")
178
+ return
179
+
180
+ # Check existing
181
+ key_attr = f"{provider.value}_api_key"
182
+ existing = getattr(self.settings, key_attr, None)
183
+
184
+ if existing:
185
+ masked = f"{existing[:8]}...{existing[-4:]}"
186
+ console.print(f"[dim]Existing key: {masked}[/dim]")
187
+ if not Confirm.ask("Replace?", default=False):
188
+ console.print(f"[cyan]{SIGMA}[/cyan] Keeping existing key")
189
+ return
190
+
191
+ console.print(f"Get key from: [bold]{info['url']}[/bold]")
192
+ console.print()
193
+
194
+ api_key = Prompt.ask("API key", password=True)
195
+
144
196
  if api_key:
145
- config[env_key] = api_key
146
- else:
147
- # Ollama
197
+ save_api_key(provider, api_key)
198
+ setattr(self.settings, key_attr, api_key)
199
+ console.print(f"[cyan]{SIGMA}[/cyan] Key saved for {info['name']}")
200
+ else:
201
+ console.print("[yellow]Skipped[/yellow]")
202
+
203
+ def _setup_model(self):
204
+ """Select model."""
205
+ console.print(Panel("[bold]Step 3: Model[/bold]", border_style="blue"))
206
+ console.print()
207
+
208
+ provider = self.settings.default_provider
209
+ models = self.providers[provider]["models"]
210
+
211
+ if not models:
212
+ console.print("[yellow]No models for this provider[/yellow]")
213
+ return
214
+
215
+ console.print("Available models:")
216
+ for i, m in enumerate(models, 1):
217
+ current = " [cyan](current)[/cyan]" if m == self.settings.default_model else ""
218
+ console.print(f" {i}. {m}{current}")
219
+
220
+ console.print()
221
+ choice = Prompt.ask(
222
+ "Choose model",
223
+ choices=[str(i) for i in range(1, len(models) + 1)],
224
+ default="1"
225
+ )
226
+
227
+ model = models[int(choice) - 1]
228
+ save_setting("default_model", model)
229
+ self.settings.default_model = model
230
+
231
+ console.print(f"[cyan]{SIGMA}[/cyan] Model: [bold]{model}[/bold]")
232
+
233
+ def _setup_data(self):
234
+ """Data settings."""
235
+ console.print(Panel("[bold]Step 4: Data Settings[/bold]", border_style="blue"))
148
236
  console.print()
237
+
238
+ console.print(f"Data stored in: [bold]~/.sigma[/bold]")
239
+ console.print()
240
+
241
+ # Output directory
242
+ default_out = os.path.expanduser("~/Documents/Sigma")
243
+ out_dir = Prompt.ask("Output directory", default=default_out)
244
+
245
+ Path(out_dir).mkdir(parents=True, exist_ok=True)
246
+ save_setting("output_dir", out_dir)
247
+ console.print(f"[cyan]{SIGMA}[/cyan] Output: {out_dir}")
248
+
249
+ # Cache
250
+ if Confirm.ask("Enable caching?", default=True):
251
+ save_setting("cache_enabled", "true")
252
+ console.print(f"[cyan]{SIGMA}[/cyan] Caching enabled")
253
+ else:
254
+ save_setting("cache_enabled", "false")
255
+
256
+ def _setup_integrations(self):
257
+ """Optional integrations."""
258
+ console.print(Panel("[bold]Step 5: Integrations[/bold]", border_style="blue"))
259
+ console.print()
260
+
261
+ # Ollama (if not primary)
262
+ if self.settings.default_provider != LLMProvider.OLLAMA:
263
+ if Confirm.ask("Setup Ollama for local fallback?", default=False):
264
+ console.print("[dim]Install: https://ollama.ai/download[/dim]")
265
+ console.print("[dim]Run: ollama pull llama3.2[/dim]")
266
+
267
+ # LEAN
268
+ if Confirm.ask("Setup LEAN/QuantConnect?", default=False):
269
+ console.print("[dim]LEAN provides advanced backtesting.[/dim]")
270
+ console.print("[dim]Install: pip install lean[/dim]")
271
+ console.print()
272
+
273
+ lean_path = Prompt.ask("LEAN CLI path (or Enter to skip)", default="")
274
+ if lean_path:
275
+ save_setting("lean_cli_path", lean_path)
276
+ console.print(f"[cyan]{SIGMA}[/cyan] LEAN configured")
277
+
278
+ def _show_summary(self):
279
+ """Show summary."""
149
280
  console.print(Panel(
150
- "[bold]Ollama Setup:[/bold]\n\n"
151
- "1. Install Ollama: https://ollama.ai\n"
152
- "2. Run: ollama pull llama3.2\n"
153
- "3. Ollama runs automatically in the background",
154
- title="[bold yellow]Local AI Setup[/bold yellow]",
155
- border_style="yellow"
281
+ "[bold green]Setup Complete![/bold green]",
282
+ border_style="green",
156
283
  ))
157
284
  console.print()
158
- Prompt.ask("[dim]Press Enter to continue[/dim]", default="")
159
-
160
- return config
161
-
162
-
163
- def setup_additional_providers(config: dict) -> dict:
164
- """Configure additional LLM providers."""
165
- clear_screen()
166
- print_logo()
167
- show_progress_step(2, 4, "Additional AI Providers (Optional)")
168
-
169
- console.print(Panel(
170
- "You can add more AI providers to switch between them.\n"
171
- "This is [bold]optional[/bold] - skip if you only need one provider.",
172
- border_style="blue"
173
- ))
174
- console.print()
175
-
176
- if not Confirm.ask("[bold]Add additional AI providers?[/bold]", default=False):
177
- return config
178
-
179
- providers = [
180
- ("GOOGLE_API_KEY", "Google Gemini", "https://aistudio.google.com/apikey"),
181
- ("OPENAI_API_KEY", "OpenAI GPT-4", "https://platform.openai.com/api-keys"),
182
- ("ANTHROPIC_API_KEY", "Anthropic Claude", "https://console.anthropic.com/settings/keys"),
183
- ("GROQ_API_KEY", "Groq (Llama)", "https://console.groq.com/keys"),
184
- ("XAI_API_KEY", "xAI Grok", "https://console.x.ai/"),
185
- ]
186
-
187
- for env_key, name, url in providers:
188
- if env_key in config:
189
- continue
190
285
 
286
+ table = Table(show_header=False, box=None)
287
+ table.add_column("", style="bold")
288
+ table.add_column("")
289
+
290
+ provider = getattr(self.settings.default_provider, 'value', str(self.settings.default_provider))
291
+ table.add_row("Provider", provider)
292
+ table.add_row("Model", self.settings.default_model)
293
+
294
+ console.print(table)
295
+ console.print()
296
+ console.print(f"Run [bold]sigma[/bold] to start!")
191
297
  console.print()
192
- if Confirm.ask(f"[bold]Add {name}?[/bold]", default=False):
193
- console.print(f" [dim]Get key: {url}[/dim]")
194
- api_key = Prompt.ask(f" [bold]API key[/bold]", password=True)
195
- if api_key:
196
- config[env_key] = api_key
197
- console.print(f" [green]Added![/green]")
198
-
199
- return config
200
298
 
201
299
 
202
- def setup_data_providers(config: dict) -> dict:
203
- """Configure financial data providers."""
204
- clear_screen()
205
- print_logo()
206
- show_progress_step(3, 4, "Financial Data Providers (Optional)")
207
-
208
- console.print(Panel(
209
- "[bold]Sigma works great with free data from Yahoo Finance.[/bold]\n\n"
210
- "For premium features, you can add professional data sources.\n"
211
- "All of these are [bold]optional[/bold].",
212
- border_style="blue"
213
- ))
214
- console.print()
215
-
216
- # Table of data providers
217
- table = Table(box=box.ROUNDED, border_style="dim")
218
- table.add_column("Provider", style="bold")
219
- table.add_column("Features", style="dim")
220
- table.add_column("Free Tier")
221
-
222
- table.add_row("Financial Modeling Prep", "Fundamentals, SEC filings", "[green]Yes[/green]")
223
- table.add_row("Polygon.io", "Real-time data, options", "[green]Yes[/green]")
224
- table.add_row("Alpha Vantage", "Technical indicators", "[green]Yes[/green]")
225
- table.add_row("Exa Search", "AI-powered news search", "[yellow]Limited[/yellow]")
226
-
227
- console.print(table)
228
- console.print()
229
-
230
- if not Confirm.ask("[bold]Configure data providers?[/bold]", default=False):
231
- return config
232
-
233
- providers = [
234
- ("FMP_API_KEY", "Financial Modeling Prep", "https://financialmodelingprep.com/developer/docs/"),
235
- ("POLYGON_API_KEY", "Polygon.io", "https://polygon.io/dashboard/api-keys"),
236
- ("ALPHA_VANTAGE_API_KEY", "Alpha Vantage", "https://www.alphavantage.co/support/#api-key"),
237
- ("EXASEARCH_API_KEY", "Exa Search", "https://exa.ai/"),
238
- ]
239
-
240
- for env_key, name, url in providers:
241
- console.print()
242
- if Confirm.ask(f"[bold]Add {name}?[/bold]", default=False):
243
- console.print(f" [dim]Get key: {url}[/dim]")
244
- api_key = Prompt.ask(f" [bold]API key[/bold]", password=True)
245
- if api_key:
246
- config[env_key] = api_key
247
- console.print(f" [green]Added![/green]")
248
-
249
- return config
300
+ def run_setup() -> bool:
301
+ """Run the setup wizard."""
302
+ wizard = SetupWizard()
303
+ return wizard.run()
250
304
 
251
305
 
252
- def setup_preferences(config: dict) -> dict:
253
- """Configure user preferences."""
254
- clear_screen()
255
- print_logo()
256
- show_progress_step(4, 4, "Preferences")
257
-
258
- # Default model selection
259
- provider = config.get("DEFAULT_PROVIDER", "google")
260
-
261
- console.print(Panel(
262
- "Configure your default settings.\n"
263
- "You can change these anytime with /model and /mode commands.",
264
- border_style="blue"
265
- ))
306
+ def quick_setup():
307
+ """Quick setup for first-time users."""
308
+ console.print(BANNER)
266
309
  console.print()
267
310
 
268
- # Analysis mode
269
- modes = [
270
- ("default", "Comprehensive - Uses all available tools"),
271
- ("technical", "Technical - Charts, indicators, price action"),
272
- ("fundamental", "Fundamental - Financials, ratios, valuations"),
273
- ("quant", "Quantitative - Predictions, backtesting"),
274
- ]
275
-
276
- console.print("[bold]Default analysis mode:[/bold]")
277
- for i, (key, desc) in enumerate(modes, 1):
278
- console.print(f" {i}. {desc}")
311
+ console.print("[bold]Quick Setup[/bold]")
279
312
  console.print()
280
313
 
281
- mode_choice = Prompt.ask(
282
- "[bold]Select mode[/bold]",
283
- choices=["1", "2", "3", "4"],
284
- default="1"
285
- )
286
- config["DEFAULT_MODE"] = modes[int(mode_choice) - 1][0]
287
-
288
- return config
289
-
290
-
291
- def save_config(config: dict):
292
- """Save configuration to file."""
293
- # Ensure config directory exists
294
- CONFIG_DIR.mkdir(parents=True, exist_ok=True)
295
-
296
- # Write config file
297
- with open(CONFIG_FILE, 'w') as f:
298
- f.write("# Sigma Configuration\n")
299
- f.write("# Generated by setup wizard\n")
300
- f.write("# You can edit this file or run 'sigma --setup' again\n\n")
301
-
302
- for key, value in config.items():
303
- f.write(f"{key}={value}\n")
304
-
305
- # Mark setup as complete
306
- SETUP_COMPLETE_FILE.touch()
307
-
308
- # Also create/update .env in current directory if it exists
309
- cwd_env = Path.cwd() / ".env"
310
- if cwd_env.exists() or Path.cwd().name == "sigma":
311
- with open(cwd_env, 'a') as f:
312
- f.write("\n# Added by Sigma setup\n")
313
- for key, value in config.items():
314
- if "API_KEY" in key:
315
- f.write(f"{key}={value}\n")
316
-
317
-
318
- def show_completion(config: dict):
319
- """Show completion screen."""
320
- clear_screen()
321
- print_logo()
322
-
323
- console.print()
324
- console.print(Panel(
325
- "[bold bright_green]Setup Complete![/bold bright_green]\n\n"
326
- "Sigma is ready to use. Here's what's configured:",
327
- border_style="bright_green",
328
- padding=(1, 2)
329
- ))
314
+ # Pick provider
315
+ console.print("Choose provider:")
316
+ console.print(" 1. [bold]Google Gemini[/bold] [green](free, recommended)[/green]")
317
+ console.print(" 2. [bold]Groq[/bold] [green](free, fast)[/green]")
318
+ console.print(" 3. [bold]Ollama[/bold] [green](local, no key)[/green]")
330
319
  console.print()
331
320
 
332
- # Summary table
333
- table = Table(box=box.ROUNDED, border_style="green")
334
- table.add_column("Setting", style="bold")
335
- table.add_column("Value", style="cyan")
321
+ choice = Prompt.ask("Provider", choices=["1", "2", "3"], default="1")
336
322
 
337
- provider_names = {
338
- "google": "Google Gemini",
339
- "openai": "OpenAI GPT-4",
340
- "anthropic": "Anthropic Claude",
341
- "groq": "Groq (Llama)",
342
- "xai": "xAI Grok",
343
- "ollama": "Ollama (Local)"
323
+ providers = {
324
+ "1": ("google", "gemini-2.0-flash"),
325
+ "2": ("groq", "llama-3.3-70b-versatile"),
326
+ "3": ("ollama", "llama3.2"),
344
327
  }
345
328
 
346
- table.add_row("AI Provider", provider_names.get(config.get("DEFAULT_PROVIDER", "google"), "Google Gemini"))
347
- table.add_row("Config Location", str(CONFIG_FILE))
329
+ provider_key, model = providers[choice]
330
+ provider_name = {"google": "Google Gemini", "groq": "Groq", "ollama": "Ollama"}[provider_key]
348
331
 
349
- # Count configured APIs
350
- api_count = sum(1 for k in config if "API_KEY" in k)
351
- table.add_row("API Keys Configured", str(api_count))
332
+ if provider_key != "ollama":
333
+ urls = {
334
+ "google": "https://aistudio.google.com/apikey",
335
+ "groq": "https://console.groq.com/keys",
336
+ }
337
+ console.print(f"\nGet key from: [bold]{urls[provider_key]}[/bold]")
338
+ api_key = Prompt.ask("API key", password=True)
339
+
340
+ if api_key:
341
+ save_api_key(LLMProvider(provider_key), api_key)
352
342
 
353
- console.print(table)
343
+ save_setting("default_provider", provider_key)
344
+ save_setting("default_model", model)
354
345
 
355
346
  console.print()
356
- console.print(Panel(
357
- "[bold]Quick Start:[/bold]\n\n"
358
- " [cyan]sigma[/cyan] Start Sigma\n"
359
- " [cyan]sigma --help[/cyan] Show help\n"
360
- " [cyan]sigma --setup[/cyan] Run setup again\n\n"
361
- "[bold]Inside Sigma:[/bold]\n\n"
362
- " [dim]Analyze NVDA stock[/dim]\n"
363
- " [dim]Compare AAPL, MSFT, GOOGL[/dim]\n"
364
- " [dim]/lean run TSLA macd_momentum[/dim]\n\n"
365
- "[dim]Type /help for all commands[/dim]",
366
- title="[bold bright_cyan]Getting Started[/bold bright_cyan]",
367
- border_style="cyan",
368
- padding=(1, 2)
369
- ))
347
+ console.print(f"[bold green]{SIGMA} Setup complete![/bold green]")
348
+ console.print(f"Provider: {provider_name}")
349
+ console.print(f"Model: {model}")
370
350
  console.print()
371
-
372
-
373
- def run_setup(force: bool = False) -> dict:
374
- """Run the setup wizard.
375
-
376
- Args:
377
- force: Force setup even if already complete
378
-
379
- Returns:
380
- Configuration dictionary
381
- """
382
- if is_setup_complete() and not force:
383
- return load_config()
384
-
385
- try:
386
- show_welcome()
387
-
388
- config = {}
389
- config = setup_llm_provider()
390
- config = setup_additional_providers(config)
391
- config = setup_data_providers(config)
392
- config = setup_preferences(config)
393
-
394
- # Save with progress
395
- console.print()
396
- with Progress(
397
- SpinnerColumn(),
398
- TextColumn("[bold]Saving configuration...[/bold]"),
399
- console=console
400
- ) as progress:
401
- task = progress.add_task("save", total=None)
402
- save_config(config)
403
- time.sleep(0.5)
404
-
405
- show_completion(config)
406
-
407
- Prompt.ask("\n[dim]Press Enter to start Sigma[/dim]", default="")
408
-
409
- return config
410
-
411
- except KeyboardInterrupt:
412
- console.print("\n\n[yellow]Setup cancelled. Run 'sigma --setup' to try again.[/yellow]")
413
- sys.exit(0)
414
-
415
-
416
- def load_config() -> dict:
417
- """Load existing configuration."""
418
- config = {}
419
-
420
- if CONFIG_FILE.exists():
421
- with open(CONFIG_FILE) as f:
422
- for line in f:
423
- line = line.strip()
424
- if line and not line.startswith('#') and '=' in line:
425
- key, value = line.split('=', 1)
426
- config[key.strip()] = value.strip()
427
-
428
- return config
429
-
430
-
431
- def apply_config_to_env(config: dict):
432
- """Apply loaded config to environment variables."""
433
- for key, value in config.items():
434
- if key not in os.environ:
435
- os.environ[key] = value
436
-
437
-
438
- def ensure_setup() -> dict:
439
- """Ensure setup is complete, running wizard if needed.
440
-
441
- Returns:
442
- Configuration dictionary
443
- """
444
- if is_setup_complete():
445
- config = load_config()
446
- apply_config_to_env(config)
447
- return config
448
- else:
449
- config = run_setup()
450
- apply_config_to_env(config)
451
- return config
351
+ console.print("Run [bold]sigma[/bold] to start!")
452
352
 
453
353
 
454
354
  if __name__ == "__main__":
455
- run_setup(force=True)
355
+ if "--quick" in sys.argv:
356
+ quick_setup()
357
+ else:
358
+ run_setup()